
기본적으로 GCP나 AWS가 제일 편하고 좋다. 다만 OCI는 평생 무료 서버를 제공해준다. 그것도 4Core VCPU, VLAM 24GB, BootVoulme 200GB내로 총 4개의 VM Instance를 제공한다. 가장 좋은 무료 자원을 제공하는 것이다. 그렇기에 이번에 오사카 리전에 계정을 하나 만들었다. 다만 문제는 가장 좋은 구성으로 무료 서버 하나를 구성하려고 했더니, 총 할당량이 부족하여 생성할 수 없단다... 역시 무료는 총량이 정해져있고, 그 중에 배분해주나 보다.. 운 좋게 만든 사람도 갖가지 이유로 멈추고, 계정이 정지당하기도 한다고 한다. 계속해서 만들다보면 언젠가 할당량이 잠시 비었을 때 들어갈 수 있다는 글도 본 것 같다. 가장 좋은 방식은 유료 버전으로 바꾸고, 거기서 평생 무료 인스턴스를 만드는 방법이다. 그러나 과금 발생의 우려가 있다고는 한다. 나의 경우 현재 400달러/1month 크레딧을 받았기 때문에 좋은 서버로 만들어서 이것저것 해보고, 그 동안 평생 무료 서버를 구성해보다가 안 되면 1달 뒤에 유료로 변경하고 무료 서버를 생성해보려고 한다.

마이그레이션 방법이 따로 있다고는 하나, 나의 경우 도커와 페이지 생성 연습을 위해서 그냥 해보려고 한다.
### 필수 패키지 업데이트 및 설치
ubuntu@instance-gcp-backup:~/gcpbackup$ sudo apt-get update
ubuntu@instance-gcp-backup:~/gcpbackup$ sudo apt-get install -y ca-certificates curl gnupg lsb-release
### 2. Docker 공식 GPG 키 등록 및 도커 저장소 추가
ubuntu@instance-gcp-backup:~/gcpbackup$ sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
### 패키지 인덱스 업데이트
ubuntu@instance-gcp-backup:~/gcpbackup$ sudo apt-get update
### 도커 설치
ubuntu@instance-gcp-backup:~/gcpbackup$ sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
### 서비스 시작 및 자동 실행 등록
ubuntu@instance-gcp-backup:~/gcpbackup$ sudo systemctl enable docker
sudo systemctl start docker
### 사용자를 도커에 등록하여 sudo 사용 없이 도커 명령어 사용
ubuntu@instance-gcp-backup:~/gcpbackup$ sudo usermod -aG docker $USER
ubuntu@instance-gcp-backup:~/gcpbackup$ exit
### 다시 접속
### 도커 명령어 사용하여 확인하기
ubuntu@instance-gcp-backup:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
### 사용자 디렉토리 내부에 새로운 디렉토리 생성
ubuntu@instance-gcp-backup:~$ mkdir gcpbackup
ubuntu@instance-gcp-backup:~/gcpbackup$ mkdir -p npm/{data,letsencrypt,mysql}
ubuntu@instance-gcp-backup:~/gcpbackup/npm$ vim .env
# MariaDB 설정
MYSQL_ROOT_PASSWORD=StrongRootPass123!
MYSQL_DATABASE=npm
MYSQL_USER=npm
MYSQL_PASSWORD=StrongUserPass123!
ubuntu@instance-gcp-backup:~/gcpbackup/npm$ vim docker-compose.yml
version: '3.8'
services:
db:
image: mariadb:10.11
container_name: npm-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- ./mysql:/var/lib/mysql
command: >
mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
app:
image: jc21/nginx-proxy-manager:latest
container_name: nginx-proxy-manager
restart: unless-stopped
depends_on:
- db
ports:
- '80:80' # HTTP
- '443:443' # HTTPS
- '81:81' # 관리자 UI
environment:
DB_MYSQL_HOST: db
DB_MYSQL_PORT: 3306
DB_MYSQL_USER: ${MYSQL_USER}
DB_MYSQL_PASSWORD: ${MYSQL_PASSWORD}
DB_MYSQL_NAME: ${MYSQL_DATABASE}
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
env_file:
- .env
ubuntu@instance-gcp-backup:~/gcpbackup/npm$ docker compose up -d
ubuntu@instance-gcp-backup:~/gcpbackup/npm$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8c2a80bf5f90 jc21/nginx-proxy-manager:latest "/init" About a minute ago Up About a minute 0.0.0.0:80-81->80-81/tcp, [::]:80-81->80-81/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcp nginx-proxy-manager
11fe5800a428 mariadb:10.11 "docker-entrypoint.s…" About a minute ago Up About a minute 3306/tcp
두 개의 도커 컨테이너가 구동 중인 것을 볼 수 있다. DB와 NPM이다.이제 서버의 포트를 열어주고, ip 주소의 81번 포트로 접속해주면 내가 만든 nginx proxy manager을 볼 수 있다. 초기 아이디와 비밀번호를 확인한 후 이를 넣고 변경해줘야 한다.
대충 다음과 같이 만든다.
songwoo@instance-dypile:/opt/pqm.kr$ cat docker-compose.yml
version: '3.8'
services:
web:
image: nginx:latest
restart: unless-stopped
ports:
- "8083:80"
volumes:
- ./pqm.conf:/etc/nginx/conf.d/default.conf
- ./html:/usr/share/nginx/html
songwoo@instance-dypile:/opt/pqm.kr$ cat pqm.conf
server {
listen 80;
server_name pqm.kr;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
expires off;
}
}
SPA는 다음과 같이 conf에 try_files $uri $uri/ /index.html이 들어가줘야 한다. 특히 history mode일 때 그렇다. history mode는 MPA일 때처럼 /구조로 url이 설정되는 모드를 말한다. 해쉬모드일 때는 또 다르다. #이게 url에 붙게 된다.
docker-compose.yml이 존재하는 디렉토리에서 docker compose up -d 명령어를 작성하여 서비스를 올리고, 해당 포트로 접속하여 제대로 동작하는지 확인한다.
songwoo@instance-dypile:/opt/npm$ ls
data docker-compose.yml letsencrypt
songwoo@instance-dypile:/opt/npm$ pwd
/opt/npm
songwoo@instance-dypile:/opt/npm$ cat docker-compose.yml
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
# These ports are in format <host-port>:<container-port>
- '80:80' # Public HTTP Port
- '443:443' # Public HTTPS Port
- '81:81' # Admin Web UI
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
songwoo@instance-dypile:/opt/npm$ cd ..
songwoo@instance-dypile:/opt$ ls
containerd dy.pile.kr google-cloud-ops-agent npm posco.pile.kr pqm.kr
songwoo@instance-dypile:/opt$ cd dy.pile.kr/
songwoo@instance-dypile:/opt/dy.pile.kr$ ls
docker-compose.yml dy.conf html
songwoo@instance-dypile:/opt/dy.pile.kr$ cat docker-compose.yml dy.conf
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "8082:80"
volumes:
- ./dy.conf:/etc/nginx/conf.d/default.conf
- ./html:/usr/share/nginx/html
server {
listen 80;
server_name dy.pile.kr;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
expires off;
}
}
songwoo@instance-dypile:/opt/dy.pile.kr$ cd ..
songwoo@instance-dypile:/opt$ ls
containerd dy.pile.kr google-cloud-ops-agent npm posco.pile.kr pqm.kr
songwoo@instance-dypile:/opt$ cd posco.pile.kr/
songwoo@instance-dypile:/opt/posco.pile.kr$ ls
docker-compose.yml html posco.conf
songwoo@instance-dypile:/opt/posco.pile.kr$ cat docker-compose.yml posco.conf
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "8081:80"
volumes:
- ./posco.conf:/etc/nginx/nginx.conf
- ./html:/usr/share/nginx/html
events {}
http {
include /etc/nginx/mime.types;
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
expires off;
}
}
}
songwoo@instance-dypile:/opt/posco.pile.kr$ cd ../pqm.kr/
songwoo@instance-dypile:/opt/pqm.kr$ ls
docker-compose.yml html pqm.conf
songwoo@instance-dypile:/opt/pqm.kr$ cat docker-compose.yml pqm.conf
version: '3.8'
services:
web:
image: nginx:latest
restart: unless-stopped
ports:
- "8083:80"
volumes:
- ./pqm.conf:/etc/nginx/conf.d/default.conf
- ./html:/usr/share/nginx/html
server {
listen 80;
server_name pqm.kr;
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0";
expires off;
}
}