docker-compose에서 HAOS Apps로,
그리고 도메인 하나 뚫기까지
기존 compose.yaml로 돌리던 n8n을 Home Assistant Supervisor의 Apps(구 Add-on) 체계로 옮기고, 권한 문제와 서브패스 리버스 프록시 문제를 거쳐 최종적으로 전용 도메인으로 안착시킨 기록.
변환 개요
왜 그대로 못 썼나
HAOS Supervisor는 docker-compose.yaml을 직접 실행하지 않고, 자체 스키마인 config.yaml로 앱(Apps, 구 Add-on)을 정의한다. 다만 이미 빌드된 이미지를 그대로 쓰는 경우 Dockerfile 없이 image: 키만으로 pull해서 실행 가능.
volumes는 어떻게 옮겼나
임의 호스트 경로 바인드는 지원되지 않아, 앱 전용 영구 볼륨(data)을 /home/node에, HAOS 공유 폴더(share)를 /files에 매핑해 원본 볼륨 구조를 재현.
진행 기록
compose.yaml → config.yaml
image, ports, environment는 그대로 이전. /opt/n8n/node, /opt/n8n/files 두 볼륨은 HAOS의 data / share 맵 타입으로 대체.
Local App으로 설치
/addons/local/n8n/config.yaml에 배치 → App Store에서 “Local apps”로 인식 → 설치.
EACCES: permission denied, mkdir ‘/home/node/.n8n’
Supervisor가 만든 호스트 폴더는 기본 root 소유인데, n8n 이미지는 node(uid 1000) 사용자로 실행되어 쓰기 권한이 없었음.
config.yaml에는 compose의 user: 같은 uid 지정 옵션이 없어, 호스트 폴더 소유권을 직접 맞춰줘야 함.호스트 폴더 chown
docker inspect로 실제 호스트 경로 확인 후, 임시 alpine 컨테이너로 마운트해 chown -R 1000:1000 적용. /files는 공유 폴더 전체가 아닌 n8n 전용 하위 폴더만 chown해 다른 애드온 영향 최소화.
docker run --rm -v <source경로>:/target alpine chown -R 1000:1000 /target
/n8n/ 서브패스에서 화면 빈 채로 표시
NPM에서 clipman.ddns.net/n8n/ 서브패스로 연결 시도. N8N_PATH, N8N_EDITOR_BASE_URL까지 정확히 설정했음에도, 모든 정적 리소스가 text/html로 응답되며 로딩 실패.
N8N_PATH 서브패스 배포 시 다수 엔드포인트가 basePath를 반영하지 못해 SPA fallback(index.html)이 대신 응답함.서브패스 → 전용 도메인으로 전환
clipman.ddns.net/n8n/ 서브패스 방식을 포기하고, 새 도메인 w-n8n.duckdns.org를 루트로 사용하도록 전환. N8N_PATH/N8N_EDITOR_BASE_URL 제거, N8N_HOST·WEBHOOK_URL을 새 도메인으로 교체. NPM에도 별도 Proxy Host를 신규 생성.
version 필드와 이미지 태그의 관계
version은 표시용 라벨이 아니라 image:와 결합되는 실제 pull 태그. next/latest는 흐르는 태그라 화면에 버전이 안 뜨고 자동 업데이트 감지도 안 됨 → 실제 릴리스 번호로 고정해야 정상 동작. 자체 Dockerfile로 감싸면 임의 라벨(날짜 등)도 가능하지만, 이번 구성에서는 채택하지 않고 next + image: 직접 pull 방식 유지.
Rebuild 후 EACCES 재발
도메인 전환을 위해 앱을 Rebuild/재설치하면서 데이터 폴더가 새로 생성되어 다시 root 소유로 초기화됨.
chown 재적용 → 정상 기동
동일한 방식으로 /home/node, /files/n8n 소유권을 1000:1000으로 재적용 후 재실행. https://w-n8n.duckdns.org/ 접속 성공.
최종 config.yaml 핵심 값
| 키 | 값 |
|---|---|
| image | docker.n8n.io/n8nio/n8n |
| version | next |
| ports | 5678/tcp → 5678 |
| map (data) | /home/node |
| map (share) | /files |
| N8N_HOST | w-n8n.duckdns.org |
| N8N_PROTOCOL | https |
| N8N_PROXY_HOPS | 1 |
| WEBHOOK_URL | https://w-n8n.duckdns.org/ |
| GENERIC_TIMEZONE | Asia/Seoul |
NPM(Nginx Proxy Manager) 설정
서브패스 대신 도메인 루트를 그대로 프록시하므로 Custom Location 없이 기본 설정만 사용.
| 항목 | 값 |
|---|---|
| Domain Names | w-n8n.duckdns.org |
| Forward Hostname | 192.168.219.130 |
| Forward Port | 5678 |
| Websockets Support | 켜짐 |
| Force SSL / HTTP2 | 켜짐 |
기억해둘 것
data/share 맵은 uid를 자동으로 맞춰주지 않으므로, 데이터 폴더가 새로 생성될 때마다 chown -R 1000:1000이 필요하다.
N8N_PATH를 정확히 설정해도 일부 엔드포인트가 이를 무시하는 알려진 버그가 있어, 가능하면 전용 도메인/서브도메인 루트 배포를 권장.
version은 라벨이 아니라 이미지 태그다. image: 방식에서는 version 값이 그대로 pull 태그가 되므로, 실제 존재하는 태그(릴리스 번호)와 반드시 일치시켜야 한다.