[Cloud] Baelog: Markdown 기반 정적 웹 사이트 호스팅
Cloud Oracle WebServer Astro
Baelog를 만들게 된 이유
- 인스타그램은 구리고, 블로그는 못생겼고… 그래서 직접 만들었습니다.
- 저는 일단 마크다운을 굉장히 좋아합니다. 메모도 맨날 마크다운으로 합니다. 일단 쓰기 너무 편하고, 지원하는 애플리케이션이나 플랫폼도 어어엄청나게 다양하고, 무엇보다 문서를 소유한다는 느낌이 좋아가지고…
- 원래 그냥 오프라인에서만 쌓아놨었는데, 포트폴리오랑 이력서도 같이 올릴겸 앱을 만들게 되었습니다.
- 그래서 만들 블로그의 조건을
- 마크다운 기반 포스트 (포스트 작성 로직은 없음, 상상만 해도 귀찮음!!!)
- DB 없는 가벼운 정적 웹 사이트
- 로 정했습니다.
애플리케이션
- 프로그램은
Astro
로 작성되었습니다. - Docs에 개발 가이드가 친절히 나와있고, 배포 가이드 또한 잘 설명되어 있습니다.
- 템플릿도 엄청나게 많아 가져다 써도 됩니다.
- 파일 시스템의 .md 파일을 뿌려주기만 하면 끝
배포
- 배포는 Oracle Cloud로 했습니다.
- 공식 문서를 보니 S3 같은 정적 웹 호스팅을 많이 사용하는데, 저는 구성하고 싶은 시스템이 있어서 운영체제 위에 웹 서버를 돌리기로 했습니다.
- 애플리케이션 도커화는 하지 않았습니다. 리소스가 제한적이기도 하고 너무 간단한 애플리케이션이라서요.
- 개인 서버로 돌리고 있는 남는 노트북이 하나 있긴 한데, 좀 번거로워서 그냥 클라우드 쓰기로 했습니다.
- AWS는 프리 티어를 다 써버려서, 새로운 계정을 만들어야 합니다.
- 하지만 관대한 오라클은 인스턴스 두 개까지 (Arm은 네 개까지) 항상 무료…
- 여기서 ‘항상 무료’ 계정은 무료인 리소스만 생성이 가능하기에, 신경쓰지 않아도 되는 것이 장점입니다.
- 오라클 클라우드에서 무료로 쓸 수 있는 Arm 기반 인스턴스가 있는데, 이게 2 코어 12GB 램입니다.
- 근데 이게 리소스가 없어서, 누가 삭제할 때까지는 생성을 못합니다. (몇 개월째 안 됨, 거의 로또임)
인스턴스 생성
- 눈물을 머금고 1 코어 1GB 램 인스턴스를 생성했습니다.
- 그래도 무료니까 감사하게 생각합니다.
- 이미지는 Ubuntu 20.04로 선택했습니다.
- 가상 네트워크, 서브넷, 인터넷 게이트웨이, 라우팅 테이블은 자동으로 생성됩니다.
- 블록 볼륨은 인스턴스 당 100GB 까지 무료입니다.
- 키 페어는 잘 저장해 뒀습니다.
보안 그룹 생성
- HTTP, SSH를 위한 인바운드 트래픽을 허용했고, 모든 아웃바운드를 허용했습니다.
- 조금 나중에 알았는데, 기본적으로 SSH는 열려있었더랬죠…
- 오라클 클라우드에는 ‘보안 목록’과 ‘보안 그룹’이 따로 있습니다.
- 이 중 ‘보안 목록’은 서브넷 수준에서 인/아웃바운드 트래픽을 제어하는데, 여기에서 SSH가 열려있었습니다.
인스턴스에 Reserved-IP 연결
- 인스턴스에 고정 IP를 하나 달아뒀습니다.
- 인스턴스가 혹시 재시작되어 IP가 바뀌면 귀찮아지니까 미리미리 달아놓았습니다.
SSH 접속
> ssh -i ~/.ssh/oracle_blog_instance.key username@public-ip
- 프라이빗 저장소에 올려놓은 코드를 Clone 해옵니다.
- 방법은 정리해두었습니다.
- .gitignore 파일에 마크다운 형식의 모든 파일을 명시해 놓았습니다.
- 리포지토리 용량이 500MB이기 때문에 (매우 크긴 하지만), 용량의 압박을 받기 싫어 로컬 머신에서 직접적으로 동기화할 것입니다.
rsync를 이용한 로컬-인스턴스 마크다운 파일 동기화
> rsync -avz --exclude='**/.obsidian/' --exclude='**/.DS_Store' -e 'ssh -i ~/.ssh/oracle.key' /local-machine-path/ username@public-ip:/instance-path/
- rsync를 사용해 로컬 머신과 인스턴스의 파일 시스템을 동기화할 수 있습니다.
- 경로 마지막에 /를 꼭 붙여야 제대로 동작합니다.
- 매번 저 명령을 치기 번거로우니 로컬 머신에 Alias로 등록해 놓습니다.
- 저는 Alias가 너무 좋습니다.
Nginx 설치 및 설정
- 정적 웹 호스팅을 구성하기 위해 인스턴스에 웹 서버를 설치합니다.
> sudo apt update
> sudo apt upgrade
> sudo apt install nginx
- Nginx 설치가 끝나면 설정을 조금 만져줘야 합니다.
> sudo vi /etc/nginx/nginx.conf
- Astro 공식 문서에는 8080 포트를 열어뒀지만, 저는 80 포트를 열었습니다.
# nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html index.htm;
include /etc/nginx/mime.types;
gzip on;
gzip_min_length 1000;
gzip_proxied expired no-cache no-store private auth;
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
internal;
}
location / {
try_files $uri $uri/index.html =404;
}
}
}
- Nginx를 다시 시작하고, 자동 시작을 활성화한 후 상태를 확인합니다.
> sudo systemctl restart nginx
> sudo systemctl enable nginx
> sudo systemctl status nginx
- netstat 명령어로 80 포트에서 리스닝하고 있는 지 확인합니다.
> netstat -tln | grep 80
- 각 플래그는 다음을 의미합니다.
-t
: TCP 프로토콜에 대한 정보를 보여줍니다.-l
: 리스닝 상태인 소켓들만 보여줍니다.-n
: 주소를 숫자 형태로 보여줍니다. (호스트명을 확인하지 않음)
- iptables를 사용해 방화벽 규칙을 추가합니다.
> sudo iptables -I INPUT 1 -p tcp --dport 80 -j ACCEPT
- 각 플래그는 다음을 의미합니다.
-I INPUT 1
: 입력 체인의 첫 번째 규칙으로 삽입합니다. 즉, 기존의 모든 규칙보다 우선시됩니다.-p tcp
: TCP 프로토콜을 사용하는 트래픽에 대한 규칙을 지정합니다.--dport 80
: 목적지 포트가 80인 트래픽에 대한 규칙을 지정합니다. (즉, HTTP 트래픽)-j ACCEPT
: 해당 트래픽을 허용합니다.
인스턴스에 Node.js 설치
- Node.js를 리눅스 환경에 설치하려면 NVM(Node Version Manager)를 다운로드 받아야 합니다.
- NVM을 활성화 시킨 후 설치 가능한 Node.js 버전을 확인합니다.
> . ~/.nvm/nvm.sh
> nvm ls-remote
- 사용할 Node.js 버전을 설치합니다.
- 설치 옵션은 여러가지가 있습니다.
# 1. 가장 최신 LTS 설치
> nvm install --lts
# 2. 가장 최신 버전 설치
> nvm install
# 3. 버전을 직접 지정해 설치
> nvm install 18.0.7
- 설치한 Node.js 버전을 확인합니다.
> node -v
애플리케이션 빌드
- 쉘 스크립트를 미리 작성해두었습니다.
- 애플리케이션을 빌드한 후 생기는 dist 디렉토리 안의 파일(Distribution 파일)들을 Nginx의 기본 문서 루트 디렉토리로 복사하는 스크립트입니다.
# build.sh
#! /bin/bash
cd /home/ubuntu/astrofy
echo "Building the project..."
npm run build
if [ $? -eq 0 ]; then
echo "Build successful. Deploying to web server..."
sudo rm -rf /usr/share/nginx/html/*
sudo cp -R dist/* /usr/share/nginx/html/
echo "Deployment successful. Files are copied to /usr/share/nginx/html."
else
echo "Build failed. No files were copied."
fi
- 스크립트를 실행해 빌드합니다.
> . /home/ubuntu/astrofy/build.sh
- 매번 포스트에 변경이 생길 때마다 SSH 접속해서 이 스크립트를 실행하는 것은 너무 끔찍한 일이기 때문에 이것 또한 로컬 머신에 Alias로 등록해 둡니다.
- 로컬 머신에서 인스턴스로 명령을 전달하는 Alias를 다음과 같이 등록했습니다.
# .zshrc
alias baelog-build="ssh -i ~/.ssh/oracle.key username@public-ip 'bash /instance-path/build.sh';"
도메인 연결
- 가비아에서 “baelog.site” 도메인을 2,090원에 구매했습니다.
- A 레코드로 도메인과 IP를 1:1 매핑했습니다.
- 서브 도메인 없이 @로 설정했습니다.
- DNS 레코드가 캐시되는 시간을 1,800초로 설정했습니다.