Dockerfile
FROM n8nio/n8n:latest
USER root
# 0) Restore apk into the image (n8n image is Alpine but apk may be removed)
RUN set -eux; \
ARCH="$(uname -m)"; \
case "$ARCH" in \
x86_64) ALP_ARCH="x86_64" ;; \
aarch64) ALP_ARCH="aarch64" ;; \
armv7l) ALP_ARCH="armv7" ;; \
*) echo "Unsupported arch: $ARCH"; exit 1 ;; \
esac; \
apk_pkg="$(wget -qO- "https://dl-cdn.alpinelinux.org/alpine/latest-stable/main/${ALP_ARCH}/" \
| grep -o 'apk-tools-static-[0-9][^"]*\.apk' \
| head -n 1)"; \
wget -q "https://dl-cdn.alpinelinux.org/alpine/latest-stable/main/${ALP_ARCH}/${apk_pkg}"; \
tar -xzf "${apk_pkg}" -C /; \
ln -sf /sbin/apk.static /sbin/apk; \
rm -f "${apk_pkg}"; \
/sbin/apk --version
# 1) Install required packages (Alpine)
RUN apk update && apk add --no-cache \
python3 \
py3-pip \
py3-virtualenv \
poppler-utils \
ffmpeg \
build-base \
ca-certificates \
&& update-ca-certificates
# 2) Create virtual env + install typhoon-ocr
RUN python3 -m venv /opt/venv && \
/opt/venv/bin/pip install --no-cache-dir --upgrade pip setuptools wheel && \
/opt/venv/bin/pip install --no-cache-dir typhoon-ocr
# 3) Use venv by default
ENV PATH="/opt/venv/bin:$PATH"
USER node
docker-compose.yml
services:
# --- Traefik (Reverse Proxy & SSL) ---
traefik:
image: "traefik"
restart: always
command:
- "--api=true"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
- "--certificatesresolvers.mytlschallenge.acme.email=${SSL_EMAIL}"
- "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
ports:
- "80:80"
- "443:443"
volumes:
- traefik_data:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
# --- n8n (Workflow Automation) ---
n8n:
build:
context: .
dockerfile: Dockerfile
restart: always
ports:
- "192.168.31.219:5678:5678"
labels:
- "traefik.enable=true"
- "traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)"
- "traefik.http.routers.n8n.entrypoints=websecure"
- "traefik.http.routers.n8n.tls=true"
- "traefik.http.routers.n8n.tls.certresolver=mytlschallenge"
- "traefik.http.middlewares.n8n.headers.SSLRedirect=true"
- "traefik.http.middlewares.n8n.headers.STSSeconds=315360000"
- "traefik.http.middlewares.n8n.headers.browserXSSFilter=true"
- "traefik.http.middlewares.n8n.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.n8n.headers.forceSTSHeader=true"
- "traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}"
- "traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true"
- "traefik.http.middlewares.n8n.headers.STSPreload=true"
- "traefik.http.routers.n8n.middlewares=n8n@docker"
environment:
- N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}/
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- N8N_PROXY_HOPS=1
- TYPHOON_OCR_API_KEY=${TYPHOON_OCR_API_KEY}
- N8N_N8N_FILESYSTEM_ROOT=/doc
- NODES_EXCLUDE=[]
- N8N_RESTRICT_FILE_ACCESS_TO=/doc
- N8N_SECURE_COOKIE=false
- TYPHOON_OCR_API_KEY=sk-DyyHJmF46DuqDPYhL0d1xX6HuadBLt6iTktkajyA0rQYa8M
volumes:
- n8n_data:/home/node/.n8n
- ./doc:/doc
# --- Ollama (Local AI Model) ---
#ollama:
# image: ollama/ollama:latest
# container_name: ollama
# restart: always
# volumes:
# - ollama_data:/root/.ollama
volumes:
traefik_data:
n8n_data:
ollama_data: