모든 자격 증명이 갑자기 복호화되지 않는다
데이터 볼륨이 다시 만들어지면서 n8n이 새 암호화 키를 생성했습니다. 이전 자격 증명은 무엇으로도 복구되지 않습니다. N8N_ENCRYPTION_KEY는 항상 명시적으로 설정하고, 사본은 서버 밖에 보관하십시오.

맨 Nordic VPS에서 자기 도메인의 TLS 종단 n8n까지, 여섯 단계입니다 — Docker Compose, Caddy, PostgreSQL, 실제로 발동하는 webhook. 실행 횟수는 요금제 등급이 아니라 당신의 CPU가 정합니다. 한 달 $3.90짜리 서버에서요. Debian 12와 n8n 2.x로 테스트했습니다.
프로비저닝
VPS + A 레코드
설치
get.docker.com
Compose
n8n + Caddy + Postgres
최초 부팅
소유자 계정 + 2FA
웹훅
WEBHOOK_URL
보안 강화
정리, 무음화, 백업
n8n은 워크플로우 자동화 엔진입니다. 트리거 — webhook, 스케줄, 데이터베이스의 새 행, 큐의 메시지 — 를 API를 호출하고, 데이터를 변형하고, 조건에 따라 분기하고, 임의의 JavaScript나 Python을 실행하고, 결과를 다음 단계로 넘기는 노드 체인에 연결하는 시각적 캔버스입니다. 수백 개의 연동 노드가 기본으로 딸려 오고, 나머지 모든 걸 커버하는 범용 HTTP Request 노드도 있습니다. 1.x 라인부터는 AI Agent와 LLM 노드도 갖추고 있어서, 2026년에 이걸 설치하는 사람들 상당수가 고전적인 ETL 배관이 아니라 에이전트를 만들고 있는 이유이기도 합니다.
명령어 한 줄 치기도 전에 중요한 부분은 라이선스입니다. n8n은 OSI가 정의하는 의미의 오픈소스가 아니고, 그 차이는 탁상공론이 아니기 때문입니다. 코어는 Sustainable Use License 하에 배포되며, 이는 내부 업무 목적이나 개인·비상업적 용도로 소프트웨어를 사용, 복사, 수정, 배포할 수 있는 비독점적·로열티 없는 전 세계 사용권입니다. 이 라이선스가 주지 않는 것은 n8n이나 그 파생물로 다른 사람에게 요금을 청구할 권리입니다 — 이 조항 때문에 그 위에 유료 "매니지드 n8n" 상품을 짓는 것이 원천적으로 막힙니다. 별개로, 이름에 .ee.가 들어가거나 경로에 .ee가 들어간 파일은 이 라이선스에서 완전히 제외되며 유료 n8n Enterprise License가 필요합니다.
쉽게 풀면 이렇습니다. VPS에서 n8n을 돌려 자기 회사를 자동화하거나, 서비스로 제공하는 자기 클라이언트의 업무를 처리하거나, 자기 개인 생활을 자동화하는 것은 이 무료 조항 안에 있고, 처음부터 그래 왔습니다. n8n을 호스팅 상품으로 파는 것은 아닙니다. 인터넷에서 벌어지는 "n8n이 정말 무료냐" 논쟁 대부분은 바로 이 경계선을 사이에 두고 두 사람이 서로 다른 얘기를 하고 있는 것입니다.
비용 쪽. n8n Cloud는 실행 횟수 기준으로 요금을 매깁니다. Starter 플랜은 연간 청구 기준 월 €20에 2,500회 실행, Pro는 월 €50에 10,000회, Business는 월 €667에 40,000회입니다. 셀프 호스팅에서는 실행 횟수가 아예 청구 항목이 아닙니다 — 그 서버가 가진 CPU와 메모리만큼만 제한을 받을 뿐입니다. 5분마다 API를 폴링하는 워크플로우 하나만 해도 한 달에 8,640회 실행을 태워 버립니다. Cloud에서는 이 워크플로우 하나만으로 이미 Pro 등급을 강제로 써야 하지만, $3.90짜리 VPS에서는 유휴 CPU 대비 오차 범위에 불과합니다.
| 옵션 | 월별 | 포함된 실행 횟수 | 누가 운영하는가 |
|---|---|---|---|
| n8n Cloud · Starter | €20 | 2 500 | n8n GmbH |
| n8n Cloud · Pro | €50 | 10 000 | n8n GmbH |
| n8n Cloud · Business | €667 | 40 000 | n8n GmbH |
| 셀프 호스팅 · Sentinel VPS | $3.90 | 과금 단위가 아니라 CPU 한계 | 당신 |
클라우드 가격은 2026년 8월 기준 n8n.io에 게시된 연간 청구 금액이며, 월간 청구는 이보다 비쌉니다. 여기서 오가는 건 돈만이 아닙니다 — 셀프 호스팅을 선택하면 업그레이드, 백업, TLS 갱신, 가동 시간까지 모두 당신 몫이 됩니다.
n8n 자체 Docker Compose 문서는 최소 사양을 2 vCPU, 4 GB RAM으로 명시합니다. 이건 마케팅용 숫자가 아닙니다 — 이 아래로 내려가면 에디터 프론트엔드와 적당히 분기된 워크플로우가 메모리를 두고 서로 다투게 되고, 첫 번째 큼직한 JSON 페이로드가 컨테이너를 OOM(out-of-memory) 킬로 날려 버립니다.
Sentinel · 2 vCPU, 4 GB, 120 GB NVMe, $3.90/월. 적절한 기본값입니다. 하루 수백 건을 처리하는 개인 또는 소규모 팀 인스턴스에 여유를 두고 n8n, PostgreSQL, Caddy를 함께 실행합니다. 유휴 메모리는 세 컨테이너를 합쳐 약 700 MB 수준입니다.
Garrison · 4 vCPU, 8 GB, 240 GB NVMe, $7.90/월. Redis와 워커 컨테이너 한둘을 곁들인 큐 모드를 추가하거나, 워크플로우가 평소에도 메모리에 수 메가바이트짜리 페이로드를 들고 있거나, 여러 병렬 분기로 뻗어 나가는 AI 에이전트 워크플로우에 여유를 넉넉히 주고 싶을 때 한 단계 올라가는 선택지입니다.
Ravelin · 8 vCPU, 16 GB, 480 GB NVMe, $16.90/월. 하루 수천 건의 실행과 바이너리 위주의 작업 — PDF 생성, 이미지 처리, 오디오 전사 — 을 처리하는 팀용 인스턴스입니다. 이런 작업은 API 병목이 아니라 CPU 병목이기 때문에 전용 코어가 중요합니다.
디스크는 다들 잊어버리는 부분입니다. n8n은 모든 실행에서 모든 노드의 입력과 출력 전체를 저장합니다. 1분마다 도는 수다스러운 워크플로우 하나만 해도 일주일에 수백 메가바이트를 씁니다. 기본값도 정리는 합니다 — EXECUTIONS_DATA_PRUNE은 true, EXECUTIONS_DATA_MAX_AGE는 336시간(14일), EXECUTIONS_DATA_PRUNE_MAX_COUNT는 10 000입니다 — 하지만 바쁜 인스턴스에서는 14일치만 해도 NVMe를 꽤 잡아먹습니다. 6단계에서 이 값들을 더 조입니다.
패널에서: Order → VPS → Sentinel, 이미지는 Debian 12. 계정을 여는 데 이메일 주소가 필요 없고, 어느 단계에서도 신분증을 요구하지 않으며, 청구는 Monero, Bitcoin, Lightning을 비롯해 지원되는 다른 자산으로 정산됩니다. 서버는 자신과의 지연 시간이 아니라 자동화할 서비스와의 지연 시간을 기준으로 고르십시오 — 자동화 서버는 당신보다 API와 훨씬 더 많이 대화합니다.
그다음, 서버를 건드리기 전에 DNS 레코드부터 만드십시오. n8n.example.com이 VPS의 IPv4를 가리키는 A 레코드, IPv6를 쓴다면 AAAA 레코드까지. 이걸 먼저 해야 하는 이유는, 스택이 시작되는 순간 Caddy가 Let's Encrypt에 인증서를 요청하는데, 해석되지 않는 이름으로 인증서를 요청하면 실패하고 — 그다음 재시도 간격을 늘리며 물러나 버려서, 사이트가 왜 안 열리는지 20분을 고민하게 되기 때문입니다.
DNS가 전파될 시간을 1분 정도 주고, 계속하기 전에 자신의 머신에서 확인하십시오:
dig +short n8n.example.com
# → the IPv4 of your VPS, and nothing else
공개 포트에서 뭔가가 리스닝을 시작하기 전에 첫 시간 보안 강화 체크리스트부터 실행하십시오 — 키 전용 SSH, 22, 80, 443 포트만 허용하는 방화벽, 무인 보안 업데이트. 자동화 서버는 자격 증명 금고이니, 그 한 시간을 들일 가치가 있습니다.
SSH로 접속해서 Compose v2 플러그인이 포함된 Docker Engine을 설치하십시오:
apt update && apt install -y ca-certificates curl
curl -fsSL https://get.docker.com | sh
docker compose version
편의 스크립트는 Docker 자체 저장소에서 Engine, CLI, containerd, Compose 플러그인을 설치합니다. 마지막 줄에는 Docker Compose version v2 이상이 출력되어야 합니다. "docker: 'compose' is not a docker command"가 출력된다면 배포판의 구형 docker.io 패키지가 깔려 있는 것이니 먼저 제거하십시오.
이 모든 걸 감싸는 한 줄짜리 n8n 설치 스크립트가 있고, 실제로 잘 작동합니다. 그런데도 이 가이드는 굳이 Compose 파일을 손으로 작성합니다. 나중에 바꿔야 할 모든 것 — 암호화 키, 데이터베이스, webhook URL, 보존 정책, 워커 개수 — 이 전부 그 파일 안에 살아 있고, 읽을 수 없는 스택은 새벽 3시에 고칠 수 없는 스택이기 때문입니다.
디렉터리를 만들고 먼저 두 개의 시크릿을 생성하십시오. 지금, 이 순서대로 생성해서 만들 때마다 .env에 붙여 넣으십시오 — 특히 암호화 키는 n8n이 처음 부팅되기 전에 반드시 존재해야지, 그 후에는 안 됩니다.
mkdir -p /opt/n8n && cd /opt/n8n
openssl rand -hex 32 # → N8N_ENCRYPTION_KEY
openssl rand -hex 24 # → POSTGRES_PASSWORD
/opt/n8n/.env
DOMAIN=n8n.example.com
LETSENCRYPT_EMAIL=you@example.com
GENERIC_TIMEZONE=Europe/Stockholm
N8N_ENCRYPTION_KEY=paste_the_32_byte_hex_here
POSTGRES_DB=n8n
POSTGRES_USER=n8n
POSTGRES_PASSWORD=paste_the_24_byte_hex_here
그 파일은 즉시 잠그십시오 — 이 인스턴스가 앞으로 저장할 모든 자격 증명의 열쇠가 그 안에 들어 있습니다:
chmod 600 /opt/n8n/.env
/opt/n8n/docker-compose.yml
services:
caddy:
image: caddy:2-alpine
restart: unless-stopped
ports:
- "80:80"
- "443:443"
environment:
- DOMAIN=${DOMAIN}
- LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
timeout: 5s
retries: 10
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
- N8N_HOST=${DOMAIN}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- N8N_EDITOR_BASE_URL=https://${DOMAIN}
- WEBHOOK_URL=https://${DOMAIN}/
- N8N_PROXY_HOPS=1
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- TZ=${GENERIC_TIMEZONE}
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
- DB_POSTGRESDB_USER=${POSTGRES_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
- N8N_BLOCK_ENV_ACCESS_IN_NODE=true
- N8N_DIAGNOSTICS_ENABLED=false
- N8N_VERSION_NOTIFICATIONS_ENABLED=false
- N8N_PERSONALIZATION_ENABLED=false
volumes:
- n8n_data:/home/node/.n8n
volumes:
caddy_data:
caddy_config:
pg_data:
n8n_data:
/opt/n8n/Caddyfile
{$DOMAIN} {
encode zstd gzip
tls {$LETSENCRYPT_EMAIL}
reverse_proxy n8n:5678
}
짚고 넘어갈 만한 두 가지 설계 결정. 첫째, n8n은 포트를 외부로 공개하지 않습니다. 80과 443은 Caddy만 바인딩하고, n8n은 Compose 네트워크 내부의 5678에서만 리스닝하므로 호스트 바깥에서는 아무도 닿을 수 없습니다. 그런데도 놀랄 만큼 많은 셀프 호스팅 n8n 인스턴스가 앞단 TLS 없이 5678 포트로 공개 인터넷에 그대로 노출돼 있고, 노출된 서비스를 찾는 검색 엔진들이 이를 색인합니다. 둘째, 이제 워크플로우는 PostgreSQL이 보관하는데도 n8n 데이터 볼륨은 여전히 마운트된 채로 남습니다 — 그 디렉터리에는 여전히 인스턴스 설정, 로그 파일, 소스 컨트롤 자산이 들어 있습니다.
가동하십시오:
cd /opt/n8n
docker compose up -d
docker compose logs -f caddy # watch the certificate being issued
https://n8n.example.com을 여십시오. 첫 화면은 소유자 계정 설정 — 이메일, 비밀번호, 이름입니다. 더 이상 설정해야 할 HTTP 기본 인증 환경 변수는 없습니다. 사용자 관리는 1.x 라인부터 n8n에 내장돼 있으며, 여기서 만드는 계정이 인스턴스 소유자가 됩니다. 비밀번호 관리자에서 뽑은 비밀번호를 쓰고, 곧바로 Settings → Personal → Two-factor authentication으로 가서 켜십시오. 이 로그인은 앞으로 어떤 노드에든 붙여 넣을 모든 API 키로 통하는 현관문입니다.
n8n은 저장된 모든 자격 증명을 N8N_ENCRYPTION_KEY로 암호화합니다. 이 값을 설정하지 않으면 n8n이 첫 부팅 시 하나를 생성해서 데이터 볼륨 안에 적어 둡니다. 그 볼륨을 다시 만들면 — docker compose down -v, 새 서버로의 마이그레이션, 잘못된 복원 등 — 새 인스턴스가 다른 키를 생성하고, 데이터베이스의 모든 자격 증명이 복호화 불가능해지며, 복구할 방법은 전혀 없습니다. API 키, OAuth 토큰, 비밀번호를 하나하나 손으로 다시 입력해야 합니다. 이 가이드처럼 키를 명시적으로 설정하고, 사본은 서버 밖에 보관하십시오.
그 사본이 있어야 할 제자리는 당신이 직접 관리하는 비밀번호 관리자입니다 — 셀프 호스팅 Vaultwarden 가이드에서 그 방법 하나를 다루며, 자물쇠를 여는 물건과 같은 서버에 두어서는 안 된다는 것이 의도된 요점입니다.
데이터베이스가 실제로 PostgreSQL인지, SQLite로 조용히 폴백된 건 아닌지 확인하십시오 — DB_ 변수에 오타가 있으면 n8n은 아무 말 없이 SQLite로 시작해 버리고, 석 달 후에야 그 사실을 알게 됩니다:
docker compose exec postgres psql -U n8n -d n8n -c '\dt' | head
# → a list of n8n tables (workflow_entity, credentials_entity, execution_entity…)
부팅되고 에디터가 뜨고 수동 테스트가 도는 n8n이라고 해서 아직 제대로 작동하는 n8n은 아닙니다. 조용히 고장 나는 절반은 인바운드 webhook이며, 마치 외부 서비스 쪽 문제처럼 보이는 방식으로 고장 납니다.
WEBHOOK_URL. 이게 없으면 n8n은 N8N_HOST와 N8N_PORT를 기준으로 webhook URL을 만들어서 http://localhost:5678/webhook/abc 같은 걸 내주는데, 이걸 Stripe나 GitHub에 붙여 넣어 봤자 절대 닿을 수 없습니다. 위의 Compose 파일은 WEBHOOK_URL을 공개 HTTPS 루트로 설정해 두었으며, 이것이 에디터에 표시되고 외부 세계가 실제로 호출할 수 있는 주소입니다.
N8N_EDITOR_BASE_URL. n8n이 보내는 이메일 속 링크 — 비밀번호 재설정, 사용자 초대 — 에 쓰는 공개 URL입니다. 여기가 잘못되면 localhost를 가리키는 초대 링크가 나가는데, 연동이 깨지는 게 아니라 동료가 보내는 지원 티켓으로 나타납니다.
N8N_PROXY_HOPS. n8n은 X-Forwarded-For에서 클라이언트 IP를 읽으며, 이 숫자가 말하는 만큼의 홉만 신뢰합니다. 리버스 프록시가 하나 앞에 있으면 — 이 스택의 Caddy처럼 — 값은 1입니다. Caddy 앞에 Cloudflare까지 두면 2가 됩니다. 기본값 0으로 두면 모든 요청이 프록시 자신에게서 온 것처럼 보이게 되어, 속도 제한이나 워크플로우 안의 IP 기반 로직이 조용히 깨집니다.
N8N_SECURE_COOKIE. 기본값은 true이며, 세션 쿠키가 HTTPS로만 전송된다는 뜻입니다. 이것이 올바른 설정이고 이 스택은 이를 충족합니다. 알아 둘 가치가 있는 이유는, 순수 http로 처음 접속했을 때 나타나는 전형적인 증상을 설명해 주기 때문입니다 — 로그인 폼이 비밀번호를 받아들이고는 다시 로그인 폼으로 돌려보내기를 끝없이 반복하는 증상 말입니다. 해법은 TLS이지, 이 플래그를 꺼버리는 게 아닙니다.
제대로 테스트하십시오. Webhook 노드가 있는 워크플로우를 만들고, 워크플로우를 활성화하고, Production URL을 복사한 다음, 서버가 아닌 다른 머신에서 호출해 보십시오:
curl -i https://n8n.example.com/webhook/<path>
# → HTTP/2 200, and a new execution visible in the editor
누구나 한 번은 걸려 넘어지는 구분입니다. Test URL은 에디터를 열어 두고 "Listen for test event"를 걸어 둔 동안에만 리스닝합니다. Production URL은 워크플로우가 Active로 토글되어 있을 때만 존재합니다. 에디터에서는 되는데 프로덕션에서 404가 나는 webhook은 거의 항상 비활성 워크플로우 때문입니다.
보존 기간. 기본값은 14일 또는 10 000회 실행 중 먼저 도달하는 쪽까지, 모든 노드의 입력과 출력 데이터 전체를 보관합니다. 바쁜 스케줄 트리거가 달린 작은 NVMe에서는 이게 바로 디스크를 채우는 주범입니다. 다음을 n8n 환경 변수 블록에 추가하고 재시작하십시오:
- EXECUTIONS_DATA_PRUNE=true
- EXECUTIONS_DATA_MAX_AGE=168 # hours — one week
- EXECUTIONS_DATA_PRUNE_MAX_COUNT=5000
- EXECUTIONS_DATA_SAVE_ON_SUCCESS=none # keep failures, drop the noise
EXECUTIONS_DATA_SAVE_ON_SUCCESS=none은 고빈도 인스턴스에서 단연 가장 큰 효과를 냅니다. 성공한 실행의 페이로드는 더 이상 기록하지 않으면서, 실패한 실행은 디버깅할 수 있도록 여전히 전부 저장합니다. 워크플로우를 만드는 동안에는 "all"로 두었다가, 워크플로우가 지루할 정도로 안정되면 그때 전환하십시오.
무음화. Compose 파일은 이미 진단, 버전 알림, 개인화 설문을 꺼 둔 상태입니다. 남은 외부 호출은 api.n8n.io에서 가져오는 템플릿 갤러리뿐이며, 제3자 호출을 아예 없애고 싶다면 N8N_TEMPLATES_ENABLED=false로 설정하십시오. 버전 알림을 끈다면, 릴리스 노트를 읽는 월간 알림을 캘린더에 넣어 두십시오 — 아무도 업데이트하지 않는 셀프 호스팅 인스턴스는 버전을 조회하는 인스턴스보다 더 나쁜 결과입니다.
Code 노드. 이미 파일에 들어 있는 N8N_BLOCK_ENV_ACCESS_IN_NODE=true는 표현식과 Code 노드가 프로세스 환경 변수를 읽지 못하게 막습니다 — 이 서버에서는 곧 PostgreSQL 비밀번호와 암호화 키를 의미합니다. 공개 REST API를 쓰지 않는다면 N8N_PUBLIC_API_DISABLED=true도 추가해서 그 표면도 닫아 두십시오.
백업 — 세 가지 모두이거나, 아무것도 아니거나. 데이터베이스 백업만으로는 암호화 키 없이 아무 가치가 없고, 키만 있어도 아무것도 복원할 수 없습니다. PostgreSQL 덤프, n8n 데이터 볼륨, .env 세 가지를 함께 백업하고, 최소 한 부는 서버 밖에 보관하십시오:
cd /opt/n8n
docker compose exec -T postgres pg_dump -U n8n n8n | gzip > backup-db-$(date +%F).sql.gz
docker run --rm -v n8n_n8n_data:/data -v "$PWD":/backup alpine \
tar czf /backup/backup-vol-$(date +%F).tar.gz -C /data .
cp .env backup-env-$(date +%F)
볼륨 이름은 Compose 프로젝트 이름에 볼륨 이름을 붙인 형태입니다. 디렉터리 이름이 n8n이 아니라면 docker volume ls를 실행해서 나온 이름을 그대로 쓰십시오. 이 세 줄을 cron 작업에 넣고, 아카이브는 다른 곳으로 보내고, 복원도 한 번 테스트해 보십시오 — 테스트해 보지 않은 백업은 백업이 아니라 믿음일 뿐입니다.
업데이트. docker compose pull을 실행한 뒤 docker compose up -d. 먼저 스냅샷부터 뜨십시오 — n8n은 시작할 때 데이터베이스 마이그레이션을 실행하는데, 마이그레이션은 롤백을 염두에 두고 설계되지 않았습니다. 메이저 버전을 건널 때 — 예를 들어 1.x에서 2.x로 — 는 pull하기 전에 릴리스 노트를 먼저 읽으십시오. 그리고 무인 재시작이 어느 날 갑자기 당신을 업그레이드시켜 버리는 일이 없도록, :latest 대신 명시적인 이미지 태그를 고정하는 것도 고려하십시오.
기본적으로 n8n은 일반 모드(regular mode)로 동작합니다. 에디터를 제공하고 webhook을 받는 프로세스가 워크플로우 실행까지 도맡습니다. 단순하고 문제없이 동작하지만, 긴 워크플로우 하나가 다른 것들을 기다리게 만들기 시작하면 이야기가 달라집니다. 증상은 명확합니다 — 실행이 몇 분 동안 "running" 상태로 멈춰 있고, 에디터는 버벅이고, 200ms 안에 응답해야 할 webhook이 8초 만에 응답합니다.
큐 모드는 작업을 분리합니다. 메인 인스턴스는 에디터, 트리거, webhook 엔드포인트를 맡고 실행 ID를 Redis에 밀어 넣습니다. 별도의 워커 프로세스들이 그 ID를 꺼내어 PostgreSQL에서 워크플로우를 불러오고, 실행하고, Redis를 통해 결과를 보고합니다. 이 아키텍처에서 세 가지 규칙이 따라 나오는데, 셋 다 건너뛴 사람을 물어뜯습니다 — 모든 인스턴스는 같은 PostgreSQL 데이터베이스를 공유해야 하고, 모든 인스턴스는 같은 N8N_ENCRYPTION_KEY를 가져야 하며, SQLite는 아예 지원되지 않습니다.
Compose 파일에 추가되는 것은 Redis 서비스 하나와 워커 서비스 하나로, 워커 서비스는 같은 n8n 이미지를 worker 명령으로 실행한 것입니다:
redis:
image: redis:7-alpine
restart: unless-stopped
command: ["redis-server", "--save", "60", "1", "--appendonly", "no"]
volumes:
- redis_data:/data
n8n-worker:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
command: worker --concurrency=5
depends_on:
- redis
- postgres
environment:
# the SAME encryption key and the SAME database as the main instance
- EXECUTIONS_MODE=queue
- QUEUE_BULL_REDIS_HOST=redis
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=postgres
- DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
- DB_POSTGRESDB_USER=${POSTGRES_USER}
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD}
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- TZ=${GENERIC_TIMEZONE}
메인 n8n 서비스에도 EXECUTIONS_MODE=queue와 QUEUE_BULL_REDIS_HOST=redis를 추가하십시오 — 양쪽이 같은 모드를 사용해야 합니다. 처음부터 설정해 둘 만한 옵션이 두 가지 있습니다. 하나는 OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS=true로, 에디터에서 "Test workflow"를 눌러도 메인 프로세스가 묶이지 않게 합니다. 다른 하나는 N8N_GRACEFUL_SHUTDOWN_TIMEOUT으로, 기본값은 30초이며 재배포 중 워커가 진행 중인 작업을 마칠 때까지 허용되는 시간을 결정합니다. 워크플로우가 평소 30초를 넘겨 실행된다면 이 값을 늘리십시오. 그러지 않으면 배포할 때마다 진행 중인 작업이 강제 종료됩니다.
여기서부터 시작하지 마십시오. 큐 모드는 움직이는 부품을 두 개 더 추가하고, 일반 모드에는 아예 없는 종류의 장애까지 함께 끌고 옵니다. 큐가 쌓이거나 워크플로우 하나가 다른 것을 막는 게 눈에 보일 때까지는 일반 모드를 유지하고, 그다음에야 두 번째 서버를 늘리기 전에 같은 서버에 워커를 하나 추가하십시오. Sentinel은 일반 모드로, Garrison은 워커 하나로, Ravelin은 워커 셋으로 — 이 진행 순서면 정말로 대규모인 배포를 제외한 모든 경우를 커버합니다.
대부분의 셀프 호스팅 가이드는 호스트 선택을 성능 문제로 다룹니다. 하지만 자동화 엔진에서는 그렇지 않습니다. n8n 인스턴스는 셀프 호스팅하는 거의 다른 어떤 것도 함께 담지 않는 두 가지를 담고 있습니다. 자동화하는 모든 서비스의 API 키, OAuth 토큰, 메일 비밀번호를 담은 단일 암호화 테이블 하나, 그리고 바로 그 옆에는 조직이 정확히 어떻게 돌아가는지를 그려 낸 그래프. 어떤 CRM을 쓰는지. 어떤 은행 피드를 쓰는지. 어떤 공급업체를 쓰는지. 어떤 고객에게 어떤 트리거로 어떤 이메일이 나가는지. 어느 회사의 워크플로우 목록을 읽으면, 그 회사를 읽은 것이나 다름없습니다.
레이어 1 — 호스트가 인식하는 당신의 신원. 여기서 애플리케이션 계층은 정말로 훌륭합니다. 자격 증명은 저장 시 암호화되고, 에디터는 TLS와 2FA 뒤에 있습니다. 새는 곳은 그 아래 계층입니다. 호스팅 플랜은 당신의 법인, 청구 주소, 카드 정보를 압니다. 하이퍼스케일러도 똑같이 알고, 그걸 몇 년씩 보관합니다. 이건 가정상의 노출이 아닙니다 — "암호화된 금고가 존재한다"와 "그것은 이 이름의 회사 소유다"를 이어 붙이는 조인 키입니다. 이메일도, 신분증도 없이 Monero로 결제하는 가입은 금고가 아니라 바로 이 조인 키를 없애 버립니다.
레이어 2 — 디스크. 저장 데이터 암호화는 키를 갖고 있지 않은 상대에게만 효과가 있는데, 기본 설치에서는 그 키가 데이터베이스와 같은 파일 시스템에 놓입니다. .env는 600 모드로 유지하고, 키 사본은 서버 밖에 따로 보관하며, 데이터센터가 소환장을 전달하기 편한 장소가 되지 않는 관할권의 제공업체를 선택하십시오 — 이것이 Nordic 관할권 가이드의 논지 전체입니다.
레이어 3 — 출구 IP. 모든 HTTP Request 노드는 해당 VPS 주소에서 나가고, 그 주소는 평판을 지니고 다닙니다. 하이퍼스케일러 대역은 인터넷에서 가장 강하게 속도 제한과 CAPTCHA에 걸리는 구간인데, 스크레이퍼들이 거기 몰려 있기 때문입니다. 스크래핑이나 폴링을 하는 워크플로우는 조용한 Nordic 대역에서 실패하기 훨씬 전에 AWS나 DigitalOcean IP에서 먼저 실패하기 시작합니다. n8n은 표준 HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY 변수도 준수하므로, 다른 출구가 필요한 소수의 워크플로우만 로컬 SOCKS 프록시나 Tor로 우회시키고 나머지는 그대로 직행시킬 수 있습니다.
2.x 라인에서 새로 생긴 문이 하나 더 있습니다. n8n은 인스턴스 수준의 MCP 서버를 노출해서 AI 에이전트가 당신의 워크플로우를 도구로 호출할 수 있게 해 줍니다. 실제로 유용하지만, 동시에 자동화 계층으로 이어지는 공개 엔드포인트이기도 하므로 다른 어떤 엔드포인트와도 똑같이 다뤄야 합니다 — TLS, OAuth, 노출 관련 논리는 원격 MCP 서버 가이드를 참고하십시오.
데이터 볼륨이 다시 만들어지면서 n8n이 새 암호화 키를 생성했습니다. 이전 자격 증명은 무엇으로도 복구되지 않습니다. N8N_ENCRYPTION_KEY는 항상 명시적으로 설정하고, 사본은 서버 밖에 보관하십시오.
WEBHOOK_URL이 설정되지 않아서 n8n이 N8N_HOST를 기준으로 URL을 만듭니다. WEBHOOK_URL과 N8N_EDITOR_BASE_URL을 공개 HTTPS 주소로 설정하고 컨테이너를 재시작하십시오.
순수 http로 에디터에 접속하고 있어서 보안 세션 쿠키가 거부되는 상황입니다. 공개 인스턴스에서 N8N_SECURE_COOKIE를 false로 바꾸는 대신 TLS 설정을 마무리하십시오.
1분 간격 트리거에서 나온 14일치 전체 실행 데이터. EXECUTIONS_DATA_MAX_AGE와 PRUNE_MAX_COUNT를 더 빡빡하게 조이고, 성공한 실행은 저장을 중단하십시오.
:latest 태그에, 롤백되지 않는 데이터베이스 마이그레이션까지 겹친 경우입니다. 명시적인 태그를 고정하고, pull하기 전에 매번 스냅샷을 뜨고, 메이저 버전을 넘어갈 때는 릴리스 노트를 읽으십시오.
GENERIC_TIMEZONE의 기본값은 America/New_York인데, 이걸 원하는 사람은 거의 없습니다. GENERIC_TIMEZONE과 TZ를 실제로 쓰는 같은 시간대로 맞추고 재시작하십시오.
n8n 인스턴스를 자기 서버로 옮기기 전, 도중, 후에 나오는 열 가지 질문.
당신 자신의 자동화라면, 네. n8n은 Sustainable Use License 하에 배포되며, 이 라이선스는 내부 업무 목적이나 개인·비상업적 용도로 무료로 사용, 복사, 수정, 배포할 수 있는 권리를 줍니다. 이 라이선스가 막는 것은 n8n이나 그 파생물로 다른 사람에게 요금을 청구하는 것 — 사실상 "n8n hosting"을 상품으로 재판매하는 행위입니다. 파일명에 .ee.가 들어가거나 디렉터리 경로에 .ee가 들어간 파일은 이 라이선스에서 제외되며 유료 n8n Enterprise License가 필요합니다. 정리하면, 빌린 VPS에서 자기 회사를 자동화하는 것은 이 무료 조항 안에 확실히 들어가지만, 그 위에 호스팅 사업을 짓는 것은 아닙니다.
n8n 자체 Docker Compose 문서는 최소 사양을 2 vCPU, 4 GB RAM으로 명시합니다. 이는 정확히 Sentinel 티어($3.90/월 — 2 vCPU, 4 GB, 120 GB NVMe)에 해당하며, 개인 또는 소규모 팀 인스턴스라면 n8n과 PostgreSQL, Caddy를 함께 돌리기에 여유가 있습니다. 큐 모드 워커를 추가하거나 워크플로우가 메모리에 큰 페이로드를 들고 있다면 Garrison(4 vCPU, 8 GB, $7.90/월)으로, PDF·이미지·오디오 같은 바이너리 데이터를 다루며 하루 수천 건을 처리하는 팀 인스턴스라면 Ravelin(8 vCPU, 16 GB, $16.90/월)으로 올라가십시오.
SQLite는 기본값이고, 워크플로우 몇 개를 혼자 쓰는 정도라면 정말로 문제없습니다. 동시 실행이 생기거나, 실행 기록이 수십만 행을 넘어가거나, 규모를 키울 계획이 있다면 PostgreSQL로 옮기십시오 — 큐 모드는 SQLite를 아예 지원하지 않는다는 점도 기억하십시오. 나중에 옮기려면 워크플로우와 자격 증명을 내보내서 새 인스턴스로 다시 가져와야 하는데, 결코 즐겁지 않은 오후가 될 겁니다. 성장 가능성이 조금이라도 있다면 처음부터 PostgreSQL로 시작하십시오. 이 가이드의 Compose 파일도 이미 그렇게 되어 있습니다.
데이터베이스의 모든 자격 증명이 영구히 읽을 수 없게 됩니다. n8n은 저장된 자격 증명 — OAuth 토큰, API 키, SMTP 비밀번호 — 을 그 키로 암호화하는데, 이를 되돌릴 방법도, 되찾아 줄 지원 티켓도 없습니다. 자격 증명을 하나하나 다시 입력해야 합니다. 셀프 호스팅한 n8n 인스턴스가 망가지는 가장 흔한 경로가 바로 이것입니다. 누군가 Docker 볼륨을 다시 만들면 n8n이 새 키를 생성하고, 모든 워크플로우가 한꺼번에 복호화 오류로 실패하기 시작합니다. 첫 부팅 전에 .env에 키를 명시적으로 설정하고, 사본은 서버가 아닌 다른 곳에 보관하십시오.
흔한 순서대로 네 가지 원인이 있습니다. (1) WEBHOOK_URL이 설정되지 않음 — 그러면 에디터가 외부 서비스가 닿을 수 없는 http://localhost:5678/webhook/… URL을 내줍니다. 공개 HTTPS URL로 설정하십시오. (2) 워크플로우가 활성화되지 않음 — 테스트 URL은 에디터가 열려 있는 동안만 리스닝하고, 프로덕션 URL은 워크플로우가 활성화되어야만 존재합니다. (3) DNS나 방화벽 — 레코드가 해석되지 않거나 80/443 포트가 막혀 있습니다. (4) 프록시 계층이 하나 더 있는데 N8N_PROXY_HOPS를 설정하지 않아, n8n이 클라이언트 IP를 잘못 읽습니다. 서버가 아닌 다른 머신에서 순수 curl로 테스트하십시오.
네, 그게 일반적인 패턴입니다 — Caddy 하나를 앞에 두고, Compose 네트워크 하나에, n8n은 한 호스트네임으로, Vaultwarden·Nextcloud·SearXNG는 다른 호스트네임으로. 다만 유의할 점이 둘 있습니다. 메모리 — n8n과 PostgreSQL만으로도 유휴 상태에서 약 700 MB를 쓰고 무거운 워크플로우는 그보다 훨씬 튈 수 있으니 여유를 남겨 두십시오. 파급 범위 — n8n 데이터베이스는 그 서버에서 가장 자격 증명이 밀집된 자산이므로, 같은 호스트를 쓰는 다른 무엇이든 그 위험 프로필을 함께 떠안게 됩니다. 월 $3.90짜리 티어라면 자동화 엔진에 전용 서버를 따로 주는 편이 합리적입니다.
기본적으로 세 개의 엔드포인트가 있습니다. 익명 제품 텔레메트리(N8N_DIAGNOSTICS_ENABLED, 기본값 true), api.n8n.io를 대상으로 한 신규 버전·보안 업데이트 확인(N8N_VERSION_NOTIFICATIONS_ENABLED, 기본값 true), 그리고 https://api.n8n.io에서 가져오는 워크플로우 템플릿 브라우저(N8N_TEMPLATES_ENABLED, 기본값 true)입니다. 이 중 어느 것도 자격 증명이나 워크플로우 데이터를 내보내지는 않지만, 세 가지 모두 해당 IP에 인스턴스가 존재한다는 사실은 알립니다. 서버를 조용히 두고 싶다면 세 값을 모두 false로 설정하십시오 — 템플릿 갤러리와 업데이트 배너를 잃게 되니, 릴리스는 직접 챙겨 보십시오.
n8n Cloud Starter는 연간 청구 기준 월 €20에 2,500회 실행, Pro는 월 €50에 10,000회입니다. Sentinel VPS는 월 $3.90이고 실행 횟수는 오직 CPU와 RAM으로만 제한되는데, 일반적인 webhook·API 워크플로우라면 수만 건 단위를 뜻합니다. 금전적 손익분기점은 바로 넘습니다. 진짜 비용은 운영입니다. 셀프 호스팅을 선택하면 업그레이드, 백업, TLS 갱신, 새벽 3시의 디스크 꽉 참 사고까지 전부 당신 몫이 됩니다. 정직한 기준은 이렇습니다 — 보안 릴리스 후 한 달 안에 스스로 인스턴스를 업그레이드했을 것 같지 않다면 Cloud에 돈을 내십시오. 매달 docker compose pull이 이미 일상이라면 셀프 호스팅하십시오.
n8n 인스턴스가 담고 있는 것 때문입니다. 자격 증명 테이블은 자동화하는 모든 서비스의 API 키, OAuth 토큰, 메일 비밀번호를 담은 단일 암호화 저장소이고, 그 옆의 워크플로우 그래프는 실제로 비즈니스가 어떻게 돌아가는지 그대로 읽히는 지도입니다 — 어떤 CRM을, 어떤 은행 피드를, 어떤 공급업체를, 어떤 고객을 쓰는지까지. 정적 웹사이트는 그중 아무것도 유출하지 않습니다. 애플리케이션 계층은 이를 잘 보호하지만, 유출은 메타데이터 계층에서 일어납니다. 서버 가입에 여권 스캔본과 카드가 딸려 있다면, 금고는 암호화해 놓고 문패에는 자기 이름을 써 붙인 셈입니다. Monero로 결제하는 no-KYC 호스트는 이 두 계층을 어긋나지 않게 맞춰 줍니다.
흔한 형태라면 됩니다 — AI Agent 노드가 원격 모델 API를 호출하는 방식이요. 이런 작업은 I/O 병목이고 제공업체 응답을 기다릴 뿐이라, Sentinel로도 충분히 처리됩니다. 맞지 않는 건 모델 자체를 돌리는 겁니다. 7B급 로컬 모델은 RAM이 약 8 GB 필요하고, 실제로 쓸 만한 추론 속도를 내려면 이 등급에는 없는 GPU가 필요합니다. n8n은 원격 OpenAI 호환 엔드포인트를 가리키게 하고 VPS는 가볍게 유지하십시오. AI 에이전트를 24/7 실행하는 짝가이드에서 재시작 정책, 시크릿, 지출 한도, 크래시 루프 함정 같은 런타임 쪽을 다룹니다.
Sentinel(2 vCPU, 4 GB, 120 GB NVMe, $3.90/월)은 n8n의 최소 사양을 충족하면서도 같은 서버에서 PostgreSQL과 Caddy를 돌릴 여유까지 있습니다. 가입 시 이메일도, 신분증도 필요 없고, 실행 횟수 제한도 없습니다.
마지막 검토일 · 2026-08-24 · 출처 · n8n 호스팅 문서, n8n LICENSE.md(Sustainable Use License), n8n.io 가격 페이지, Docker 및 Caddy 공식 문서 · 주기 · 연간
This guide is one spoke of a larger series. The pillar walks the three privacy layers end to end — the sibling spokes below dive into the specifics.
Three independent layers — signup, payment, network — explained, legal context included, common mistakes flagged.
Deploy your own MCP server on a no-KYC VPS — TLS, streamable HTTP, OAuth.
Host an MCP server with no ID — the privacy stack, crypto-paid.
에이전트를 노트북 밖으로 옮기기 — 크기 정하기, systemd, 시크릿, 지출 상한.
CPU로 로컬 LLM 구동 — GPU 없이 Ollama, 4·8·16·32GB까지.