Hello, n8n community!
I’m facing a very persistent issue with my self-hosted n8n setup and I’m hoping someone can point me in the right direction.
My Telegram bot workflow, triggered by a webhook, becomes completely unresponsive after a few minutes of inactivity (approx. 3-5 minutes). When it’s not responding, there are absolutely no logs in the n8n container, as if the request from Traefik never reaches it.
A restart of the entire docker-compose stack, or even just deactivating/activating the workflow in the UI, temporarily fixes the problem for the next few minutes.
My Setup
-
n8n Version: (вставь свою версию, например: 1.45.1)
-
Traefik Version: (вставь свою версию, например: 3.0.0)
-
Database: PostgreSQL
-
Queue Mode: Redis
-
Execution Mode: main + queue with 3 workers
-
Deployment: Docker Compose on a Linux VPS.
Troubleshooting Steps I’ve Already Taken
I have tried extensively to solve this for many hours. Here is what I’ve done:
-
Verified Environment Variables: Confirmed that N8N_HOST, WEBHOOK_URL, and N8N_EDITOR_BASE_URL are all correctly set to https://n8n.kochalka.store/.
-
Enabled WebSocket Backend: Added N8N_PUSH_BACKEND=websocket to both n8n-main and n8n-worker. This significantly improved the situation (the bot stayed alive for 3-5 minutes instead of less than 1), but did not fully solve the problem.
-
Investigated TCP Connection: Using the ss command on the host, I confirmed that the TCP connection between the Traefik container and the n8n container is not kept alive. It closes almost instantly after a request is completed.
-
Configured Traefik serversTransports: Based on the theory of a “stale connection”, I tried to force Traefik to manage the connection lifecycle. I created a dynamic config file and linked it to the n8n service using labels to set an idleConnTimeout of 60 seconds. This seemed like the most logical solution, but unfortunately, it did not fix the final problem.
My Configuration Files
Here are my current configuration files, which include all the attempted fixes.
docker-compose.yml:
# ~/n8n-compose/compose.yaml
services:
traefik:
image: "traefik"
container_name: traefik
restart: always
command:
- "--log.level=DEBUG"
- "--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"
- "--accesslog=true"
- "--providers.file.directory=/etc/traefik/dynamic"
- "--providers.file.watch=true"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- traefik_data:/letsencrypt
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik-dynamic.yml:/etc/traefik/dynamic/config.yml:ro
networks:
- proxy_net
redis:
image: "redis:alpine"
container_name: redis
restart: always
networks:
- proxy_net
volumes:
- redis_data:/data
n8n-main:
image: docker.n8n.io/n8nio/n8n:latest
container_name: n8n-main
restart: always
labels:
- "traefik.enable=true"
- "traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)"
- "traefik.http.routers.n8n.entrypoints=websecure"
- "traefik.http.routers.n8n.tls.certresolver=mytlschallenge"
- "traefik.http.services.n8n.loadbalancer.server.port=5678"
- "traefik.docker.network=proxy_net"
- "traefik.http.services.n8n.loadbalancer.healthcheck.path=/healthz"
- "traefik.http.services.n8n.loadbalancer.healthcheck.interval=120s"
- "traefik.http.services.n8n.loadbalancer.healthcheck.timeout=5s"
- "traefik.http.services.n8n.loadbalancer.serversTransport=n8n-transport@file"
environment:
- N8N_EXECUTION_MODE=main
- N8N_HOST=n8n.kochala.store
- N8N_PORT=5678
- N8N_PROTOCOL=https
- NODE_ENV=production
- WEBHOOK_URL=https://n8n.kochala.store/
- N8N_PROXY_HOPS=1
- N8N_EDITOR_BASE_URL=https://n8n.kochala.store/
- GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
- DB_TYPE=${DB_TYPE}
- DB_POSTGRESDB_HOST=${DB_POSTGRESDB_HOST}
- DB_POSTGRESDB_PORT=${DB_POSTGRESDB_PORT}
- DB_POSTGRESDB_DATABASE=${DB_POSTGRESDB_DATABASE}
- DB_POSTGRESDB_USER=${DB_POSTGRESDB_USER}
- DB_POSTGRESDB_PASSWORD=${DB_POSTGRESDB_PASSWORD}
- QUEUE_BULL_REDIS_HOST=${QUEUE_BULL_REDIS_HOST}
- QUEUE_BULL_REDIS_PORT=${QUEUE_BULL_REDIS_PORT}
- N8N_PUSH_BACKEND=websocket
volumes:
- n8n_data:/home/node/.n8n
networks:
- proxy_net
depends_on:
- redis
n8n-worker:
image: docker.n8n.io/n8nio/n8n:latest
restart: always
command: start
environment:
- N8N_EXECUTION_MODE=queue
- N8N_ENCRYPTION_KEY=${ENCRYPTION_KEY}
# ... (rest of DB and Redis config as above) ...
- N8N_PUSH_BACKEND=websocket
networks:
- proxy_net
depends_on:
- redis
- n8n-main
deploy:
replicas: 3
volumes:
n8n_data:
traefik_data:
redis_data:
networks:
proxy_net:
external: true
traefik-dynamic.yml:
http:
serversTransports:
n8n-transport:
forwardingTimeouts:
idleConnTimeout: 60s
My Question
Despite all these attempts, the webhook listener still “falls asleep”. It feels like there’s a networking layer (either Docker, the Linux kernel, or Traefik’s core) that is aggressively terminating the idle connection, and Traefik isn’t creating a new one for the subsequent request.
Has anyone encountered this specific behavior? What is the definitive, recommended configuration for n8n behind a Traefik proxy to ensure long-term webhook stability?
Any help would be greatly appreciated. Thank you