Workflow execution not work after publishing, all are pending in queue.[self-hosted n8n]

Describe the problem/error/question

N8N was installed in Ubuntu, nginx has been configured with reverse proxy.
All my workflows works perfectly in Test mode, like I shared here a very simple RSS reader, click button and the workflow will load remote RSS feed and display the first time in the ending form.
If I test it with Test URL, it works as expected. But if I publish it(or any other workflows), when I run the Production URL, after clicking button in the first Form, it’s button keeps loading and nothing happened(the backend RSS feed has never been read remotely).
In the Executions list, all of my published workflows’s status are “Queued”, Started are always “Starting soon”, the Run Time will keep increasing and never end.
My assumption is something blocks the prodution exection in the n8n backend. Thank you for helping out, I am stacked here for 2 days.

This screenshot is when I run the workflow in Test mode, work perfectly.

What is the error message (if any)?

This screenshot is after publishing the workflow, all executions are pending.

Please share your workflow

(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)
{
  "nodes": [
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "e2ffe594-180d-4e1d-b869-8056ac67015d",
              "name": "title",
              "type": "string",
              "value": "={{ $json.title }}"
            },
            {
              "id": "87c5a171-9ab9-4043-a72a-32aec218fe63",
              "name": "pubDate",
              "type": "string",
              "value": "={{ $json.pubDate }}"
            },
            {
              "id": "978b05c9-6e6b-4a18-bc06-4de785b19413",
              "name": "conteudo",
              "type": "string",
              "value": "={{ $json.content }}"
            }
          ]
        },
        "options": {}
      },
      "id": "3bc80f1d-ba03-4e66-bc75-e191777196a0",
      "name": "Edit Fields3",
      "type": "n8n-nodes-base.set",
      "position": [
        496,
        320
      ],
      "typeVersion": 3.4
    },
    {
      "parameters": {
        "maxItems": 10
      },
      "id": "5585ebb1-e06b-42e2-aa0a-4011e94ece3f",
      "name": "Limit",
      "type": "n8n-nodes-base.limit",
      "position": [
        928,
        320
      ],
      "typeVersion": 1
    },
    {
      "parameters": {
        "url": "https://www.technologyreview.com/topic/artificial-intelligence/feed/",
        "options": {
          "ignoreSSL": false
        }
      },
      "id": "ecba6a40-44cb-4834-8927-aa87a55cca8f",
      "name": "My RSS 01",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        272,
        320
      ],
      "typeVersion": 1.1,
      "alwaysOutputData": true,
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "30d4f694-9378-42b4-b1d5-cbc38fb3e7fe",
              "operator": {
                "type": "dateTime",
                "operation": "after"
              },
              "leftValue": "={{ $json.pubDate }}",
              "rightValue": "={{ $today.minus({ days: 1 }) }}"
            }
          ]
        },
        "options": {}
      },
      "id": "8fdb9e97-6046-437f-926b-8a9f4eaf3854",
      "name": "Filter1",
      "type": "n8n-nodes-base.filter",
      "position": [
        736,
        320
      ],
      "typeVersion": 2.2,
      "disabled": true
    },
    {
      "parameters": {
        "formTitle": "test",
        "formFields": {
          "values": [
            {
              "fieldLabel": "test",
              "placeholder": "aaaa",
              "defaultValue": "test",
              "requiredField": true
            }
          ]
        },
        "responseMode": "lastNode",
        "options": {
          "appendAttribution": false,
          "buttonLabel": "GO "
        }
      },
      "id": "d7998250-8903-4318-a44e-2bc4ec3fae38",
      "name": "On form submission",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        64,
        320
      ],
      "webhookId": "b1244062-414d-4635-94bb-3999d8ba7287",
      "typeVersion": 2.2
    },
    {
      "parameters": {
        "operation": "completion",
        "completionTitle": "={{ $json.title }}",
        "completionMessage": "={{ $json.conteudo }}",
        "options": {}
      },
      "type": "n8n-nodes-base.form",
      "typeVersion": 2.5,
      "position": [
        1136,
        320
      ],
      "id": "40f53bbb-dda0-4ab6-a47b-e656b9ce4ed0",
      "name": "Form",
      "webhookId": "ac0921e8-ef8d-4d19-bbf5-601072cd36d6"
    }
  ],
  "connections": {
    "Edit Fields3": {
      "main": [
        [
          {
            "node": "Filter1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit": {
      "main": [
        [
          {
            "node": "Form",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "My RSS 01": {
      "main": [
        [
          {
            "node": "Edit Fields3",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter1": {
      "main": [
        [
          {
            "node": "Limit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On form submission": {
      "main": [
        [
          {
            "node": "My RSS 01",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": true,
    "instanceId": "d3bbdc95153e6946dbacaffe72cbd2c695d3923240e6e037f8990bdb0f62c236"
  }
}

Share the output returned by the last node

This is my docker compose yml for deploying n8n, n8n-runner, postgres, redis and nginx.

services:
    postgres:
        image: postgres:16-alpine
        container_name: n8n-postgres
        hostname: n8n-postgres-host
        restart: unless-stopped
        env_file:
            - .env
        environment:
            - POSTGRES_USER
            - POSTGRES_PASSWORD
            - POSTGRES_DB
            - POSTGRES_NON_ROOT_USER
            - POSTGRES_NON_ROOT_PASSWORD
        volumes:
            - ./init-data.sh:/docker-entrypoint-initdb.d/init-data.sh
            - db-postgres-volume:/var/lib/postgresql/data
            - db-postgres-backup-volume:/var/backups
        healthcheck:
            test: [ 'CMD-SHELL', 'pg_isready -h localhost -U ${POSTGRES_USER} -d ${POSTGRES_DB}' ]
            interval: 10s
            timeout: 5s
            retries: 5
        ports:
            - 5432:5432
        networks:
            - n8n-network

    n8n:
        image: docker.n8n.io/n8nio/n8n:${N8N_VERSION}
        container_name: n8n-n8n
        restart: unless-stopped
        environment:
            - N8N_HOST=n8n.mydomain.com
            - N8N_PORT=5678
            - N8N_PROTOCOL=https
            - N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
            - DB_TYPE=postgresdb
            - DB_POSTGRESDB_HOST=n8n-postgres-host
            - DB_POSTGRESDB_PORT=5432
            - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
            - DB_POSTGRESDB_USER=${POSTGRES_NON_ROOT_USER}
            - DB_POSTGRESDB_PASSWORD=${POSTGRES_NON_ROOT_PASSWORD}
            - EXECUTIONS_PROCESS=main
            - N8N_RUNNERS_ENABLED=true
            - N8N_RUNNERS_MODE=external
            - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_AUTH_TOKEN}
            - N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
            - N8N_NATIVE_PYTHON_RUNNER=true
            - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
            - TZ=${GENERIC_TIMEZONE}
            - N8N_BASIC_AUTH_ACTIVE=true
            - N8N_BASIC_AUTH_USER=${N8N_BASIC_AUTH_USER}
            - N8N_BASIC_AUTH_PASSWORD=${N8N_BASIC_AUTH_PASSWORD}
            - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
            - WEBHOOK_URL=https://n8n.mydomain.com/
            - N8N_PROXY_HOPS=1
            - NODES_EXCLUDE='["n8n-nodes-base.executeCommand","n8n-nodes-base.ssh"]'
            - EXECUTIONS_DATA_PRUNE=true
            - EXECUTIONS_DATA_SAVE_SUCCESSFUL=true
            - EXECUTIONS_MODE=queue
            - QUEUE_BULL_REDIS_HOST=n8n-redis-host
            - N8N_EXECUTIONS_CACHE_ENABLED=true
            - N8N_SCHEDULER_ENABLED=true
            # Security audit list
            - N8N_LOG_LEVEL=debug
            - N8N_LOG_FILE_SIZE_MAX=50
            - N8N_LOG_FILE_COUNT_MAX=10
            # Durable scheduler
            - N8N_COMMUNITY_PACKAGES_ENABLED=true
            - N8N_USE_WORKFLOW_PUBLICATION_SERVICE=true
            #- NODE_FUNCTION_ALLOW_EXTERNAL=ioredis
            #- NODE_FUNCTION_ALLOW_BUILTIN="*"
        ports:
            - 5678:5678
        links:
            - postgres
        volumes:
            - n8n-storage-volume:/home/node/.n8n
            - n8n-file-volume:/files
        depends_on:
            postgres:
                condition: service_healthy
            redis:
                condition: service_started
        healthcheck:
            test: ["CMD", "wget", "--spider", "-q", "http://localhost:5678/healthz"]
            interval: 30s
            timeout: 10s
            retries: 3
        networks:
            - n8n-network
            - shared-network

    redis:
        image: redis:7-alpine
        container_name: n8n-redis
        hostname: n8n-redis-host
        restart: unless-stopped
        volumes:
            - redis-data-volume:/data
        networks:
            - n8n-network

    n8n-runner:
        image: n8nio/runners:${N8N_VERSION}
        container_name: n8n-n8n-runner
        restart: unless-stopped
        ports:
            - 5680:5680
        environment:
            - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_AUTH_TOKEN}
            - N8N_RUNNERS_TASK_BROKER_URI=http://n8n-n8n:5679
            - N8N_RUNNERS_AUTO_SHUTDOWN_TIMEOUT=20
            - N8N_RUNNERS_LAUNCHER_LOG_LEVEL=debug
        depends_on:
            - n8n
        networks:
            - n8n-network

Nginx reverse proxy configuration

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}
server {
        #listen 80;
        listen 443 ssl;
        listen [::]:443 ssl;
        http2  on;
        server_name n8n.mydomain.com;

        ssl_certificate /var/server-auth/n8n.mydomain.com.crt;
        ssl_certificate_key /var/server-auth/n8n.mydomain.com.key;
        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 1d;

        # access_log /var/log/nginx/n8n.mydomain.com_access.log;
        error_log /var/log/nginx/n8n.mydomain.com_error.log;

        # letsencrypt file verify
        location /.well-known/acme-challenge {
            root /var/www/letsencrypt;
        }

        client_max_body_size 50m;
        client_body_timeout 60s;

        # Security Header for n8n
        add_header X-Frame-Options "SAMEORIGIN" always;
        add_header X-XSS-Protection "1; mode=block" always;
        add_header X-Content-Type-Options "nosniff" always;
        #add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' wss://n8n.mydomain.com; frame-ancestors 'none'" always;

        location / {
            proxy_pass    http://n8n-n8n:5678/;
            proxy_http_version 1.1;

            # Preserve headers
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            # For n8n Webhook SSL
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_set_header X-Forwarded-Host $host;
            proxy_set_header X-Forwarded-Port $server_port;
            proxy_set_header X-Original-Host $host;

            # (Optional) origin passthrough if your app needs it
            proxy_set_header Origin $http_origin;

            # WebSocket (n8n Editor)
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;

            # Disable buffering/caching for streaming/WS
            chunked_transfer_encoding off;
            proxy_buffering off;
            proxy_cache off;

            proxy_cache_bypass $http_upgrade;

            proxy_connect_timeout       600;
            proxy_send_timeout          600;
            proxy_read_timeout          600;
            send_timeout                600;
        }
}

Information on your n8n setup

  • n8n version: 2.30.7
  • Database (default: SQLite): postgres:16-alpine
  • n8n EXECUTIONS_PROCESS setting (default: own, main): main
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker Compose
  • Operating system: Ubuntu 24.04 LTS 64bit

Hey @mobabel, while you wait for a response, here are some things that might help:

Suggested resources

Automatically matched to your question.

Docs:

Forum:

@manishkhanna, @Shraddha_Singh, @houda_ben - you’ve helped with similar issues before, can you take a look?

Automatically suggested by n8n’s community bot. It’s a pilot - please share feedback here.

Your Compose file contains the cause: EXECUTIONS_MODE=queue is enabled, but the services shown do not include an n8n queue worker. The external n8n-runner is a task runner for Code/Python tasks; it does not consume workflow execution jobs from Redis. The main n8n process therefore enqueues every production execution and they remain Queued / Starting soon.

You can fix this in either of two ways:

  1. For a single-instance setup, remove EXECUTIONS_MODE=queue (or set it back to the default regular mode) and redeploy.
  2. If you want queue mode, add another service using the same n8n image with command: worker. It must use the same Postgres, Redis, N8N_ENCRYPTION_KEY, n8n version, and Docker network as the main service. Confirm its logs show that the worker is ready and connected to Redis.

EXECUTIONS_PROCESS=main does not create a queue worker, so it does not solve this. After redeploying, trigger one new production execution first; once that starts immediately, retry or clear the old queued executions as appropriate.

On top of the above there are env options being set that don’t exist, I would recommend checking your configuration against the docs.

Is it safe to assume you have used an AI based tool to generate the compose file you are using?

Hi @mobabel Welcome!
If you go the queue mode route, the worker container needs its own task runner sidecar. The task broker lives inside each n8n process, so your existing runner container is bound to the main instance only, and a worker running in external mode has no runner attached to it, which leaves Code node tasks sitting with nothing to pick them up. Give the worker the same runner variables you set on main, then point a second runners container at the worker:

  n8n-worker-runner:
    image: n8nio/runners:${N8N_VERSION}
    container_name: n8n-worker-runner
    environment:
      - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_AUTH_TOKEN}
      - N8N_RUNNERS_TASK_BROKER_URI=http://<your-worker-container-name>:5679
    depends_on:
      - n8n-worker
    networks:
      - n8n-network

OFFLOAD_MANUAL_EXECUTIONS_TO_WORKERS defaults to false, so main keeps running manual executions and still needs the runner container you already have. Keep the runners image on the same version as the n8n image.

Hello Jon,

Thank you for your feedback. I did not use AI tools to generate the Docker Compose YAML file because I don’t trust AI in this case. N8N has many versions, and the yml configurations change all the time.

I have read a lot of documents and combined my YAML from some source code.

Hello Byte_Nova,

Thank you so much for your fast support!

Following your answer, I have found the root cause: my YAML file is missing the n8n-worker.

From the official document “Use Docker Compose | Deploy | n8n Docs,” I did not find information about the additional n8n-worker for queue executions. But with your clue of n8n-worker, after searching, I found this example Self hosted n8n with workers, running, but Task Runners are unhealthy?

and this n8n-workers-docker/docker-compose.yml at main · davorpavlov/n8n-workers-docker · GitHub

This is my final working YAML for n8n-worker:

    n8n-worker:
        image: n8nio/n8n:${N8N_VERSION}
        container_name: n8n-worker
        restart: always
        command: worker
        ports:
            - 5679:5678
        environment:
            - 'GENERIC_TIMEZONE=${GENERIC_TIMEZONE:-Europe/Berlin}'
            - 'TZ=${TZ:-Europe/Berlin}'
            - DB_TYPE=postgresdb
            - DB_POSTGRESDB_HOST=n8n-postgres-host
            - DB_POSTGRESDB_PORT=5432
            - DB_POSTGRESDB_DATABASE=${POSTGRES_DB}
            - DB_POSTGRESDB_USER=${POSTGRES_NON_ROOT_USER}
            - DB_POSTGRESDB_PASSWORD=${POSTGRES_NON_ROOT_PASSWORD}
            - EXECUTIONS_MODE=queue
            - QUEUE_BULL_REDIS_HOST=redis
            - QUEUE_BULL_REDIS_PORT:6379
            - QUEUE_HEALTH_CHECK_ACTIVE=true
            #- QUEUE_BULL_REDIS_PASSWORD=""
            - N8N_ENCRYPTION_KEY=${N8N_ENCRYPTION_KEY}
            - N8N_RUNNERS_MODE=external
            - N8N_RUNNERS_BROKER_LISTEN_ADDRESS=0.0.0.0
            - N8N_RUNNERS_BROKER_PORT=5679
            - N8N_RUNNERS_AUTH_TOKEN=${RUNNERS_AUTH_TOKEN}
            - 'N8N_NATIVE_PYTHON_RUNNER=${N8N_NATIVE_PYTHON_RUNNER:-true}'
            - 'N8N_RUNNERS_MAX_CONCURRENCY=${N8N_RUNNERS_MAX_CONCURRENCY:-5}'
            - 'N8N_BLOCK_ENV_ACCESS_IN_NODE=${N8N_BLOCK_ENV_ACCESS_IN_NODE:-true}'
            - 'N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=${N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS:-true}'
            - 'N8N_PROXY_HOPS=${N8N_PROXY_HOPS:-1}'
            #- 'N8N_GIT_NODE_DISABLE_BARE_REPOS=${N8N_GIT_NODE_DISABLE_BARE_REPOS:-true}'
            #- 'N8N_SKIP_AUTH_ON_OAUTH_CALLBACK=${N8N_SKIP_AUTH_ON_OAUTH_CALLBACK:-false}'
            - N8N_LOG_LEVEL=${N8N_LOG_LEVEL}
        healthcheck:
            test:
                - CMD-SHELL
                - 'wget -qO- http://127.0.0.1:5678/healthz'
            interval: 5s
            timeout: 20s
            retries: 10
        depends_on:
            n8n:
                condition: service_healthy
            postgres:
                condition: service_healthy
            redis:
                condition: service_healthy
        networks:
            - n8n-network

After redeployment, the queue executions work like a charm.

Thanks to everyone who supports me here! All the best!!