# Managed by Ansible — do not edit manually services: n8n: image: n8nio/n8n:{{ n8n_version }} container_name: n8n restart: unless-stopped environment: N8N_HOST: "{{ domain_n8n }}" N8N_PROTOCOL: "https" N8N_PORT: "5678" # Public URL used to build webhook / chat links behind Traefik WEBHOOK_URL: "https://{{ domain_n8n }}/" N8N_PROXY_HOPS: "1" N8N_ENCRYPTION_KEY: "{{ n8n_encryption_key }}" GENERIC_TIMEZONE: "{{ n8n_timezone }}" TZ: "{{ n8n_timezone }}" N8N_DIAGNOSTICS_ENABLED: "false" N8N_VERSION_NOTIFICATIONS_ENABLED: "false" N8N_TEMPLATES_ENABLED: "false" # Keep the SQLite database small: drop execution history after 7 days EXECUTIONS_DATA_PRUNE: "true" EXECUTIONS_DATA_MAX_AGE: "168" volumes: - {{ n8n_data_dir }}/data:/home/node/.n8n # Workflows and credentials imported by Ansible (see roles/n8n/tasks/main.yml) - {{ n8n_data_dir }}/import:/import:ro mem_limit: {{ n8n_mem_limit }} networks: - traefik_public - ollama_internal - browserless_internal - searxng_internal labels: - "traefik.enable=true" - "traefik.http.services.n8n.loadbalancer.server.port=5678" # Editor, webhooks and chat page — all behind basic auth - "traefik.http.routers.n8n.rule=Host(`{{ domain_n8n }}`)" - "traefik.http.routers.n8n.entrypoints=websecure" - "traefik.http.routers.n8n.tls.certresolver=letsencrypt" - "traefik.http.routers.n8n.service=n8n" - "traefik.http.routers.n8n.middlewares=n8n-auth" # Short link: /chat redirects to the hosted chat page of the chat workflow - "traefik.http.routers.n8n-chat.rule=Host(`{{ domain_n8n }}`) && Path(`/chat`)" - "traefik.http.routers.n8n-chat.priority=100" - "traefik.http.routers.n8n-chat.entrypoints=websecure" - "traefik.http.routers.n8n-chat.tls.certresolver=letsencrypt" - "traefik.http.routers.n8n-chat.service=n8n" - "traefik.http.routers.n8n-chat.middlewares=n8n-auth,n8n-chat-redirect" - "traefik.http.middlewares.n8n-chat-redirect.redirectregex.regex=^https://{{ domain_n8n | replace('.', '\\\\.') }}/chat/?$$" - "traefik.http.middlewares.n8n-chat-redirect.redirectregex.replacement=https://{{ domain_n8n }}/webhook/{{ n8n_chat_webhook_id }}/chat" # Telegram bot webhook: called by Telegram's servers, so no basic auth. Restricted to Telegram's # address ranges; n8n additionally checks Telegram's secret token header and the workflow # only answers the user id in telegram_user_id. - "traefik.http.routers.n8n-telegram.rule=Host(`{{ domain_n8n }}`) && Path(`/webhook/{{ n8n_telegram_webhook_id }}/webhook`) && Method(`POST`)" - "traefik.http.routers.n8n-telegram.priority=200" - "traefik.http.routers.n8n-telegram.entrypoints=websecure" - "traefik.http.routers.n8n-telegram.tls.certresolver=letsencrypt" - "traefik.http.routers.n8n-telegram.service=n8n" {% if telegram_webhook_source_ranges | length > 0 %} - "traefik.http.routers.n8n-telegram.middlewares=n8n-telegram-ips" - "traefik.http.middlewares.n8n-telegram-ips.ipallowlist.sourcerange={{ telegram_webhook_source_ranges | join(',') }}" {% endif %} {% set ns = namespace(entries=[]) %} {% for user in n8n_users %} {% set ns.entries = ns.entries + [user.username + ':' + (user.password | password_hash('bcrypt', (user.username | hash('md5'))[:22]) | replace('$', '$$'))] %} {% endfor %} - "traefik.http.middlewares.n8n-auth.basicauth.users={{ ns.entries | join(',') }}" networks: traefik_public: external: true ollama_internal: external: true browserless_internal: external: true searxng_internal: external: true