이 글은 Hetzner Cloud에서 운영 중인 n8n을 Oracle Cloud 인스턴스로 옮기는 전체 과정을 단계별로 정리했어요. 기존에 Docker Compose로 구동했기에 컨테이너 볼륨 백업과 복원하는 절차와 더 나아가 클라우드플레어와 오라클 클라우드 연동을 위해 보안 설정까지 작성했어요.
Docker Compose로 구동 중인 서비스를 다른 서버로 마이그레이션을 진행해 볼게요.
저는 헤츠너 클라우드에 동작하던 N8N을 오라클 클라우드의 인스턴스로 마이그레이션 할 거예요.
N8N이 Docker Compose로 구동 중이므로 다른 Docker Compose 서비스들도 유사하게 마이그레이션 할 수 있어요.
마이그레이션을 위해 아래 순서에 맞춰서 진행해 볼게요.
- 출발지(Hetzner)에서 볼륨/DB/설정 파일을 백업해요.
- 도착지(Oracle)에 Docker 환경을 준비하고, 백업 데이터를 복원해요.
- Cloudflare·NSG로 보안 경로를 구성하고, 도메인을 Oracle로 전환해요.
- HTTPS 접속 및 워크플로 정상 동작을 확인해요.
기존 서버에서 Docker Compose로 구동 중이던 컨테이너 설정을 파악하고, 마이그레이션을 진행해야 해요.
그래서 마이그레이션 하려는 Docker의 yaml 파일을 확인해서 어떤 설정으로 사용 중인지 확인해요.
저 같은 경우는 헤츠너 클라우드에 기존 컨테이너가 구동 중이기에 해당 환경을 확인해야 해요.
그래서 일반적으로 YAML 파일 내 아래 항목들을 확인해야 해요.
| YAML 항목 | 확인 이유 | 체크 포인트 |
| version: | Compose 파일 형식이 새 Docker 버전과 호환되는지 | 너무 낮은 버전(2.x)이면 일부 키가 인식 안 됨. 일반적으로 3.8 이상 유지 |
| services: | 실제 컨테이너 정의가 들어있는 핵심 블록 | 각 서비스 이름이 고유한지, 누락된 컨테이너가 없는지 확인 |
| services → image / build |
어떤 이미지를 가져오는지, 새 서버에서 다시 빌드해야 하는지 | image:는 태그 고정 / build:는 경로 유효성 확인 |
| services → environment / env_file |
서버 환경(IP, 도메인, 계정 등)이 이전 서버와 다름 | .env 파일 포함 여부, 절대경로 수정, DB 접속 정보 갱신 |
| services → volumes | 데이터 저장 경로 / 볼륨명이 달라지면 실행 불가 | named volume은 새 서버에 동일 이름 존재해야 함, bind mount는 경로 확인 |
| services → networks | 컨테이너 간 통신 구조 | external 네트워크를 쓰면 새 서버에 같은 이름으로 미리 생성 필요 |
| services → ports | 외부 접근 경로가 바뀜 | 새 서버 포트(80, 443 등) 충돌 여부, 방화벽·NSG 허용 확인 |
| volumes: | Named volume 정의 | external: true면 새 서버에서도 동일 이름으로 docker volume create 필요 |
| networks: | 내부/외부 네트워크 정의 | external: true인 경우 네트워크 미리 만들어야 함, driver: 지정 확인 |
| restart: | 서버 재부팅 후 자동 실행 여부 | always 또는 unless-stopped로 유지해야 안정적 운영 |
| logging: | 로그가 계속 쌓이는 문제 예방 | max-size, max-file 설정 있는지 점검 (없으면 로그 폭주 위험) |
YAML 파일 내 주요 정보들을 확인했다면 실제 정의된 이름과 똑같이 구동되고 있는지 파악해요.
아래 명령어는 현재 사용 중인 컨테이너·볼륨, 그리고 네트워크 이름을 파악해요.
# 컨테이너/볼륨/네트워크 확인
docker ps
docker compose ls
docker volume ls
docker network ls
주의할 점으로 Docker Compose 구동 시 리소스(볼륨, 컨테이너, 네트워크 등) 이름 앞에 프로젝트 이름이 자동으로 붙어서 생성돼요.
프로젝트는 현재 Docker Compose를 실행할 Yaml 파일이 위치한 디렉터리의 이름예요.
예시로 아래 헤츠너 클라우드에 구동 중인 제 N8N의 볼륨 정보를 확인하면 아래와 같이 출력이 나와요.
현재 제 N8N은 n8n_domain 이름을 가진 디렉터리 아래에서 구동중인데 볼륨 이름 앞에 디렉토리 이름이 붙어있어요.

운영 중 중단 시간을 줄이려면, 사전 덤프 후 전환 직전에 짧게 중지하고 최종 백업을 받는 방식을 권장해요.
저는 개인적으로 사용하는 서비스이기 때문에 상관없이 서비스를 내리고 백업 후 복원했어요.
저는 PostgreSQL / Redis / N8N 3개의 볼륨을 백업해야 했어요.
그래서 위에서 확인한 볼륨 이름을 기준으로 아래 명령어로 3개의 볼륨을 백업했어요.
docker run --rm \
-v <볼륨 이름>:/target_data \
-v $(pwd):/backup \
alpine tar -czvf /backup/<볼륨 이름>.tar.gz -C /target_data .
위 명령어는 alpine 이미지를 실행해서 제가 백업하고자 하는 볼륨을 마운트하고, 해당 볼륨 내 데이터를 압축해서 추출하는 방법이에요.
중간의 <볼륨 이름> 부분만 조회한 이름으로 변경하면 데이터를 백업할 수 있어요.
그래서 백업을 수행하면 아래 이미지와 같이 수행되면서 나온 출력을 볼 수 있어요.

Docker Volume을 백업했다면 이제 YAML, .env 및 기타 호환성 파일들을 백업해야 해요.
일반적으로 Docker Compose 실행 시 하나의 프로젝트 디렉터리 내 포함되어 있기 때문에 폴더 자체를 백업해요.
그래서 저는 Docker Compose를 실행하는 디렉터리에서 아래 명령어를 수행해요.
cd ..
tar -czvf migration_package.tar.gz <프로젝트 폴더 이름>/
그럼 프로젝트 폴더 아래 모든 파일이 migration_package.tar.gz 이름으로 압축되어 떨어져요.
저 같은 경우는 아래와 같이 실행해서 백업했어요.

FileZilla에서 SFTP로 Hetzner 인스턴스에 접속해요.
그리고 백업 파일을 다운로드해요.
저는 'migration_package.tar.gz' 내 볼륨 백업 파일까지 전부 포함되어 있기에 해당 파일만 Filezilla를 통해 가져왔어요.

헤츠너 클라우드에서 백업을 완료했다면, 이제는 신규 서버로 백업한 파일을 옮긴 뒤 복원해야 해요.
저는 Oracle Cloud로 이전 예정이라 오라클 인스턴스로 마이그레이션을 진행할게요.
Oracle 인스턴스에 SFTP로 접속해서 헤츠너 클라우드에서 내려받은 백업 파일을 업로드해요.
보통 파일질라로 접속하면 기본 위치가 홈 디렉터리이기에 보통 해당 위치에 업로드해요.

Oracle Instance Ubuntu 24.04 이미지 기준으로 도커 설치가 필요하고 신규 계정 생성 시 필요하신 분들은
먼저 아래 스크립트를 받아서 실행해요.
기본 계정(Ubuntu)이 아닌 신규 계정을 생성하며 Docker/Compose를 설치하고 볼륨을 만들어둬요.
위 스크립트를 실행하면 아래 정보를 입력받고, 입력받은걸 토대로 계정을 생성해요.
예전 헤츠너 클라우드 설정 시 포스팅했던 글에 있던 스크립트와 유사해요.
차이점이 있다면 아래 스크립트는 오라클 클라우드 설정에 맞춰서 새로 수정한 스크립트예요.

아니면 현재 사용 중인 사용자를 그대로 사용하시려면 아래 명령어로 도커 설치와 볼륨 생성 그리고 백업 압축해제를 같이하시면 돼요.
### 도커 설치 및 사용자 도커 권한 추가
sudo apt update && sudo apt install -y docker.io docker-compose
sudo usermod -aG docker $USER
newgrp docker
## 도커 볼륨 생성 명령어
docker volume create <생성할 볼륨 이름>
## 백업 파일 압축 해제 명령어
tar -xzvf migration_package.tar.gz
업로드한 백업 파일을 압축해제하면 docker compose 실행에 필요한 모든 파일(yaml, .env 등)과 볼륨 백업 파일이 생성돼요.
압축 해제 후 도커 볼륨을 생성했어요.
도커 볼륨 이름은 헤츠너 클라우드에서 백업 시 확인했던 볼륨 이름과 동일해야 해요.


도커 볼륨 생성까지 완료했다면 이제 볼륨 내 데이터를 복원해 볼게요.
아래 명령어로 수행할 수 있어요.
아래 명령어에 앞서 생성한 볼륨 이름과 매칭되는 복원해야 하는 백업한 파일을 넣어서 명령어를 실행해 주세요.
docker run --rm \
-v <도커 볼륨 이름>:/target_data \
-v $(pwd):/backup \
alpine tar -xzvf /backup/<백업한 파일> -C /target_data
저는 N8N / Redis / PostgreSQL 3개를 백업했기에 아래와 같이 복원했어요.

볼륨 복원을 수행했다면 이제 docker compose로 실행해 볼게요.
yaml 파일이 있는 위치에서 아래 명령어를 실행하면 돼요.
docker compose up -d
저는 아래와 같이 실행해서 다음 출력을 받았어요.
아래 WARN[0073] 에러의 경우 같은 이름의 볼륨이 이미 생성되어 있어서 발생되는 에러예요.
YAML 파일 내 'external: true'를 추가하면 에러가 사라져요. 추가하지 않아도 사용하는 데는 문제가 없어요.

주의 사항
일부 컨테이너들은 동작에 필요한 IP나 도메인이 YAML 파일 내 기재되어 있어요.
해당 값들은 확인해서 YAML 파일 내 도메인이나 IP 수정이 필요해요.
저 같은 경우는 클라우드플레어에서 도메인을 구매했고, 이제는 오라클에 N8N을 실행하려고 해요.
도메인명은 그대로 쓸 거라 그래서 YAML 파일 수정은 필요하지 않지만
클라우드플레어 도메인 레코드에서 도메인과 연결된 IP 수정이 필요해요.
*기존 헤츠너 클라우드 IP -> 오라클 클라우드 IP 변경 필요
그리고 오라클 클라우드에서 클라우드 플레어 IP를 허용하는 방화벽 규칙 작업도 필요해요.
그래서 아래 단계는 오라클 클라우드와 클라우드플레어에서 필요한 작업을 수행해 볼게요.
먼저 클라우드플레어 레코드 설정에서 오라클 IP로 변경 후, 오라클에서 방화벽 설정을 변경할게요.
Cloudflare에서 도메인을 Oracle 인스턴스의 Reserved IP로 향하게 변경해요.
- 경로: Cloudflare 대시보드 → DNS → Records → A 레코드 편집
- Proxy(구름 아이콘)는 Proxied로 두는 걸 권장해요.
- SSL/TLS 모드는 Full (Strict)가 좋아요.
그래서 아래와 같이 설정돼요.

VCN 보안 목록(Security List)에서 443 포트를 Any로 열어 HTTPS 트래픽을 허용해요.
단, 실제 접근 제어는 NSG에서 더 세밀하게 제한할 거예요. 오라클 클라우드에서 아래 경로로 이동해 주세요.
- 경로: OCI Console → Networking → Virtual Cloud Networks(VCN) → 대상 VCN → Security Lists → Ingress Rule 추가
그럼 아래와 같은 화면을 볼 수 있어요. 제 오라클 인스턴스가 속한 서브넷에 적용된 Security List예요.
여기서 [ Add Ingress Rules ] 버튼을 통해 새로운 룰을 추가할게요.

[ Add Ingress Rules ] 페이지가 나타나면 아래와 같이 설정해요
HTTPS(443)을 허용하는 룰로 설정해요.
- Source Type: CIDR
- Source CIDR: 0.0.0.0/0
- IP Protocol: TCP
- Destination Port Ragne: 443
- Description: 원하는 설명

그럼 Security List에서 모든 소스에 대해서 443 포트가 허용돼요.
오라클 클라우드의 NSG(Network Security Group)는 인스턴스 단위에 붙여서 포트·소스·프로토콜을 제어하는 세밀한 방화벽이에요.
Security List가 서브넷 단위인 반면, NSG는 인스턴스/인터페이스 단위로 유연하게 적용할 수 있어요.
저는 이 NSG를 2개를 만들 거예요.
- Cloudflare NSG: 소스에 Cloudflare CDN IP 대역만 등록해요(443 허용).
- 인스턴스 NSG: 소스 = Cloudflare NSG 만 허용해요. 직접 IP 접근은 차단돼요.
왜 분리하나요? Cloudflare NSG는 글로벌 CDN 주소만 담은 화이트리스트 역할을 해요. 인스턴스 NSG는 Cloudflare NSG에서 들어온 요청만 통과시키므로, 우회 접근이나 직접 공격을 차단해요. 이중 구조라서 도메인이 유출돼도 직접 IP로는 접근이 불가능해요.
- 경로: OCI Console → Networking → VCN → Network Security Groups → Cloudflare NSG / Instance NSG 각각 생성 → Ingress 규칙 추가
NSG를 웹 콘솔을 통해 등록하려면 IP 1개당 1개의 룰을 사용해야 해요.
등록해야 할 IP가 적으면 문제없지만, 많은 수의 IP를 등록해야 한다면 많은 수작업이 동반되어야 해요.
그래서 우리는 NSG에 IP 등록을 CLI을 통해 자동화할 거예요.
그전에 NSG부터 만들어볼게요.
경로 : OCI -> Networking -> Virtual Cloud Networks -> [ 생성한 VCN 선택 ] -> Security
위 경로로 이동한 뒤 스크롤을 내리면 'Network Security Groups' 항목에서 [ Create Network Security Group ]을 눌러주세요.
그럼 NSG 생성 화면이 나타나는데 아래와 같이 설정해 주세요.
- Name : 생성할 NSG 이름(*저는 'Cloudflare-IP-Range'로 설정했어요.)
- Create In Compartment : NSG가 속할 Compartment 지정
그리고 Rule 부분 끝에 'X' 버튼을 눌러서 Rule을 제거해 준 뒤 생성해 주세요.
(*Rule을 제거하지 않으면 값을 넣어야지만 NSG를 생성할 수 있어요.)

생성하고 나면 생성한 NSG 화면으로 이동돼요.
여기서 CLI로 자동화 시 필요한 OCID 값이 있는 것을 볼 수 있어요.
우측 끝의 [ Copy ]를 통해 해당 값을 복사해 주세요

그리고 아래 화면과 같이 우측 상단의 컴퓨터 아이콘 -> Cloud Shell을 선택해 주세요.

그럼 아래와 같이 화면 하단에 터미널이 나타나요.
여기서 실제 리눅스처럼 명령어를 사용하거나 스크립트를 실행하는 등 다양한 작업을 수행할 수 있어요.

여기에 이제 아래 코드를 넣어서 파일을 생성해 주세요.
NSG_ID 부분에 위에서 복사한 NSG의 OCID 값을 넣어주셔야 해요.
NSG_ID="<NSG OCID>"
CLOUDFLARE_IPS=(
"173.245.48.0/20"
"103.21.244.0/22"
"103.22.200.0/22"
"103.31.4.0/22"
"141.101.64.0/18"
"108.162.192.0/18"
"190.93.240.0/20"
"188.114.96.0/20"
"197.234.240.0/22"
"198.41.128.0/17"
"162.158.0.0/15"
"104.16.0.0/13"
"104.24.0.0/14"
"172.64.0.0/13"
"131.0.72.0/22"
)
for CIDR in "${CLOUDFLARE_IPS[@]}"; do
echo "✅ Adding $CIDR..."
oci network nsg rules add \
--nsg-id $NSG_ID \
--security-rules '[
{
"direction": "INGRESS",
"protocol": "6",
"source": "'"$CIDR"'",
"tcpOptions": { "destinationPortRange": { "min": 443, "max": 443 } }
}
]'
done
그리고 아래 명령어를 실행해 주세요.
그럼 스크립트가 실행되면서 저희가 생성했던 NSG에 Cloudflare IP가 등록돼요.
sh nsg.sh

웹 브라우저에서 이전에 생성했던 NSG -> Security rules로 이동해 주세요.
그럼 아래와 같이 Cloudflare IP 가 추가된 것을 볼 수 있어요.

이제 인스턴스에 적용할 NSG를 생성해 볼게요.
경로 : OCI -> Networking -> Virtual Cloud Networks -> [ 생성한 VCN 선택 ] -> Security
위 경로로 이동한 다음 스크롤을 아래로 내려서 [ Create Network Security Group ]를 눌러주세요.
먼저 이름 및 Compartment를 설정해 주세요.
그리고 Rule에서 아래와 같이 설정한 뒤 생성해 주세요.
- Direction: Ingress
- Source Type: Network Security Group(NSG)
- Source NSG compartment: 지정할 NSG가 속한 Compartment
- Source NSG: Cloudflare IP가 있는 NSG

이제 생성한 NSG를 인스턴스에 적용해 볼게요.
인스턴스 세부정보 화면에서 NSG를 부착할 수 있어요.
- 경로: OCI Console → Compute → Instances → 대상 인스턴스 → Netwotking → Network Security Groups에 Edit 선택
아래와 같은 화면이 나타나면 직전에 만든 NSG를 선택해 주세요.

그럼 인스턴스에 NSG 설정 적용이 완료돼요.
브라우저에서 https://<도메인>으로 접속해 n8n 콘솔이 정상적으로 표시되는지 확인해요.
만약 모든 작업이 정상적인데 접속이 안 되는 분들은 아직 클라우드플레어에서 레코드 변경한 게 적용되지 않아서 그럴 수도 있어요.
그런 경우 1~2시간 후 다시 접속하면 정상 접속될 수 있어요.

클라우드를 바꾸면서 기존 헤츠너 클라우드에서 사용하던 Docker Compose를 다른 서버로 마이그레이션 작업을 진행했어요.
마이그레이션 시 확인해야 하는 도커 리소스, 백업, 복원 절차 등을 확인했어요.
그리고 기존 클라우드에서 신규 클라우드로 마이그레이션 하시던 분들은 작업 완료 후,
기존 클라우드 리소스를 꼭 잊지 않고 정리하셔야 해요.
저도 헤츠너 클라우드에 있던 모든 리소스를 정리했어요.
정리하지 않으면 과금되기 때문에 정리하시는 것을 추천해요.
'오라클 클라우드' 카테고리의 다른 글
| 오라클 클라우드 - 인스턴스 생성 및 Reserved IP 설정 (0) | 2025.10.21 |
|---|---|
| 오라클 클라우드 - VCN 생성(+ 서브넷, IGW, Security List) (0) | 2025.10.15 |
| 오라클 클라우드 - Identity Domain 생성 및 권한 할당 (0) | 2025.10.13 |
| 오라클 클라우드 최초 로그인 및 2FA 인증 + PAYG(유료계정) 업그레이드 (2) | 2025.09.30 |
| 오라클 클라우드 회원 가입 완료(계정 리뷰 보류 해결) (0) | 2025.09.28 |