In Local / Webhook Node UI URL Stays /null After Save (Backend Registers Correctly w/ PostgreSQL, Failed w/ SQLite)

Environment Details:

  • n8n Version: 1.89.2 (Also observed similar backend failure on 1.88.0, 1.87.2 when using SQLite)

  • Database: PostgreSQL 15 (Issue was different but more severe with SQLite - see below)

  • Running n8n via: Docker Compose

  • Operating System: Windows 11 (using Docker Desktop with WSL 2 Backend)

  • Proxy Setup: Separate Nginx container (image: nginx:alpine) in the same Docker Compose network, handling HTTPS termination.

  • Key n8n Environment Variables (PostgreSQL setup):

- DB_TYPE=postgresdb
- DB_POSTGRESDB_HOST=n8n_postgres_db
- DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=n8n
- DB_POSTGRESDB_PASSWORD=[My_Secure_Password]
- DB_POSTGRESDB_SSL_ENABLED=false
- N8N_PUBLIC_URL=https://n8n.example.app/
- WEBHOOK_URL=https://n8n.example.app/
- N8N_TRUST_PROXY=true
- N8N_LOG_LEVEL=info # (Also tested with debug)

content_copydownload

Use code with caution.Yaml

Problem Description:

When using PostgreSQL as the database, the backend logic for registering webhook paths (both auto-generated and custom) appears to work correctly. Testing the actual webhook URL (e.g., https://n8n.example.app/webhook/mycustompath) results in the expected behavior (either a successful response from a connected “Respond to Webhook” node or a “webhook is not registered for GET requests” error if using the wrong method, but critically, NOT a 404 “not registered” error ).

However, the frontend UI for the Webhook node configuration panel fails to update the displayed Test and Production URLs after saving the workflow. They consistently remain showing /null at the end (e.g., https://n8n.example.app/webhook-test/null), even though the correct path is saved in the “Path” input field itself (if custom) and is functional in the backend.

Steps to Reproduce (with PostgreSQL setup):

  1. Run n8n v1.89.2 using Docker Compose with PostgreSQL DB and Nginx proxy as described.

  2. Access the n8n editor via the public HTTPS URL (https://n8n.example.app).

  3. Create a new, empty workflow.

  4. Add a Webhook node.

  5. Scenario 1 (Auto-path): Leave the “Path” field empty. Click “Save” workflow. Reload the browser page (Ctrl+Shift+R) or close/re-open the node panel.

  6. Scenario 2 (Custom-path): Enter a custom path (e.g., testpostgres) in the “Path” field. Click “Save” workflow. Reload the browser page or close/re-open the node panel.

  7. Observe the Test and Production URLs displayed within the node’s panel.

Expected Behavior:

  • After saving (and potentially reloading), the displayed Test/Production URLs in the Webhook node panel should update to reflect the registered path (either auto-generated or custom). E.g., …/webhook/testpostgres or …/webhook/a1b2c3d4…

Actual Behavior:

  • After saving and reloading, the displayed Test/Production URLs in the Webhook node panel consistently remain ending in /null .

  • In Scenario 2, the custom path text (e.g., testpostgres) is correctly saved and displayed in the “Path” input field, but the URLs below it do not update.

  • Testing the actual webhook URL constructed manually (e.g., https://n8n.example.app/webhook/testpostgres) confirms the backend did register the path correctly (returns success or wrong method error, not 404 “not registered”).

Important Context - Previous SQLite Issue:

  • Prior to switching to PostgreSQL, extensive troubleshooting was performed using the default SQLite database.

  • With SQLite (tested on n8n v1.87.2, v1.88.0, v1.89.2), the problem was more severe: the backend failed entirely to register the webhook path. Saving the workflow resulted in the UI showing /null, AND testing the actual webhook URL resulted in a 404 “webhook is not registered” error .

  • This SQLite failure occurred both with Docker named volumes and direct bind mounts.

  • Significant issues were encountered with Docker Desktop/WSL 2 failing to create/access the volume/bind mount paths (No such file or directory inside WSL), requiring a full Docker Desktop reinstall and WSL instance recreation (wsl --unregister docker-desktop). Even after resolving the Docker/WSL volume access issues (verified by n8n successfully writing config/running migrations on SQLite via bind mount), the webhook registration still failed with SQLite.

  • Switching to PostgreSQL resolved the backend registration failure, isolating the remaining issue to the UI display.

Troubleshooting Summary:

  • Confirmed backend webhook registration works correctly with PostgreSQL.

  • Confirmed frontend UI fails to update displayed URLs from /null.

  • Confirmed the issue is not browser cache (tested incognito).

  • Checked n8n logs (info and debug levels) during webhook save - no relevant errors are logged for the UI update failure.

  • Confirmed environment variables (WEBHOOK_URL, etc.) are correct.

This appears to be a frontend/UI bug specific to updating the displayed webhook URLs after saving, potentially masked or exacerbated by underlying backend issues when using SQLite in a Docker Desktop/WSL 2 on Windows environment.

Hi,

Not sure but I think the only configurable parameters are

WEBHOOK_URL
N8N_ENDPOINT_WEBHOOK
N8N_ENDPOINT_WEBHOOK_TEST
N8N_ENDPOINT_WEBHOOK_WAIT

I doubt that yiu are meant to play around with the uuid part.

Reg
J

Solved: Webhook /null URL & Content Security Policy (CSP) Errors with n8n on Docker + Nginx Proxy

Hi everyone,

I wanted to share my experience and solution after facing a couple of frustrating issues with a self-hosted n8n setup using Docker Compose (n8n, Nginx, Postgres) behind an Nginx reverse proxy. Hopefully, this helps others who might run into the same problems!.

(I was running n8n version 1.89.2, attempting to update to :latest during debugging).

Problem 1: Webhook Node Shows /null URL and No Connection Dot

The main initial issue was that the Webhook node in the UI wouldn’t display the correct URL (it ended in /null) and the connection dot was missing, making it impossible to copy the correct URL or edit the path properly.

Solution 1: Environment Variables & Proxy Headers

After much debugging (thanks to AI assistance!), the fix involved ensuring n8n knows its public URL and trusts the proxy:

  1. WEBHOOK_URL is CRUCIAL: In your docker-compose.yml file, under the n8n service’s environment: section, you must define WEBHOOK_URL. It needs the full URL including the protocol (https://) and, most importantly, a trailing slash / :
services:
  n8n:
    # ... other settings
    environment:
      # ... other vars (DB_*, etc.)
      WEBHOOK_URL: https://your-n8n-domain.com/  # TRAILING SLASH IS ESSENTIAL!
      # ... more vars
  1. Trust the Proxy: n8n needs to trust the headers coming from your Nginx proxy. You can use either N8N_TRUST_PROXY or, often more reliably, N8N_TRUSTED_PROXIES specifying your Docker network’s subnet:
  • Find your Docker network subnet (e.g., using docker network inspect <your_n8n_network_name>).

  • Add this to your n8n environment variables:

# Option A: Simple boolean (might work)
  # N8N_TRUST_PROXY: "true"

  # Option B: Specific Subnet (Recommended) - Replace with your actual subnet
  N8N_TRUSTED_PROXIES: "127.0.0.1, ::1, 172.19.0.0/16" # Example subnet
  1. Essential Nginx Proxy Headers: In your Nginx configuration file (nginx.conf) within the location / { … } block that proxies to n8n, make sure you have these headers:
proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme; # Tells n8n the original protocol (HTTPS)
      # Headers for WebSocket (n8n UI needs this)
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
  1. Restart Correctly: After changing docker-compose.yml, a simple docker-compose restart n8n is not enough . You need to recreate the container to apply new environment variables:
docker-compose down
docker-compose up -d

Problem 2: Content Security Policy (CSP) Errors in Browser Console

After getting the webhook URL fixed, I noticed many errors in the browser’s developer console related to Content Security Policy (CSP). N8N was trying to connect to external domains for things like telemetrics, community node search, version checks, etc., but these were being blocked by the default or a custom CSP header set in Nginx.

Solution 2: Adjusting the Content-Security-Policy Header in Nginx

I had to modify the add_header Content-Security-Policy … directive in my Nginx server block (the one listening on port 443) to allow connections and scripts from the necessary n8n domains. I also needed to allow ‘unsafe-eval’ as it seems the n8n frontend uses it.

Here’s the final CSP header that worked for me (add this inside your server { … } block):

add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn-rs.n8n.io https://ph.n8n.io; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self' https://api.n8n.io https://api.github.com https://telemetry.n8n.io https://ph.n8n.io https://api-rs.n8n.io https://api.npms.io; frame-src https://n8n.io; object-src 'none'";

Note on ‘unsafe-eval’: Allowing ‘unsafe-eval’ slightly reduces protection against certain XSS attacks. While generally acceptable in a self-hosted environment if the app requires it, be aware of the implication.

Final Configuration Snippets:

  • docker-compose.yml (n8n service environment):
# ... inside services: n8n: environment: ...
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: db # Or your DB service name
      DB_POSTGRESDB_PORT: 5432
      DB_POSTGRESDB_DATABASE: your_user_db
      DB_POSTGRESDB_USER: your_user_db
      DB_POSTGRESDB_PASSWORD: 'YOUR_DB_PASSWORD' # Use secrets/env ideally
      WEBHOOK_URL: https://your-n8n-domain.com/ # Remember the trailing slash!
      # N8N_TRUST_PROXY: "true" # Use one or the other
      N8N_TRUSTED_PROXIES: "127.0.0.1, ::1, YOUR_DOCKER_SUBNET/xx" # Replace with actual subnet
      GENERIC_TIMEZONE: Your/Timezone # e.g. America/Santiago
      # ... any other variables you need ...
  • nginx.conf (HTTPS Server Block):
server {
    listen 443 ssl;
    listen [::]:443 ssl;
    http2 on;
    server_name your-n8n-domain.com;

    ssl_certificate /etc/nginx/ssl/your_cert.crt;
    ssl_certificate_key /etc/nginx/ssl/your_key.key;
    # Add other SSL best practices (protocols, ciphers, etc.)

    access_log /var/log/nginx/n8n.access.log main;
    error_log /var/log/nginx/n8n.error.log;

    # Security Headers (Including the fixed CSP)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always; # Note: Changed from frame-src in CSP - adjust if needed
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn-rs.n8n.io https://ph.n8n.io; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self' https://api.n8n.io https://api.github.com https://telemetry.n8n.io https://ph.n8n.io https://api-rs.n8n.io https://api.npms.io; frame-src https://n8n.io; object-src 'none'";


    location / {
        proxy_pass http://n8n:5678; # Point to your n8n service name in Docker
        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Add other proxy settings if needed (timeouts, body size, X-Forwarded-For, etc.)
        # proxy_set_header X-Real-IP $remote_addr;
        # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # client_max_body_size 100M;
        # proxy_read_timeout 300s;
    }
}

After applying these changes and restarting correctly, my webhook node finally showed the proper URL, and the CSP errors disappeared from the console.

It was a bit of a journey, but hopefully sharing these steps saves someone else some time!

Best regards,

Gustavo007