Permanent Fix for Portainer Console/Websockets Disconnect (Persists after Reboot)
Posted: 07 Feb 2026, 17:38
Hi everyone,
Like many of you, I ran into the issue where the Console feature in Portainer fails to connect. This happens because the system's Nginx proxy is missing the required headers to allow WebSocket connections.
While you can manually edit to fix this like mentioned here, the problem is that TOS resets this file every time you reboot the NAS, breaking the fix.
Instead of messing with system scripts or SSH cron jobs, I created a "Fixer Container". It's a lightweight Docker container that starts on boot, automatically patches the Nginx config, reloads Nginx, and then sleeps. Because it's a container, you can manage it right inside Portainer and remove it easily if an official update ever fixes this.
How it works
Like many of you, I ran into the issue where the Console feature in Portainer fails to connect. This happens because the system's Nginx proxy is missing the required headers to allow WebSocket connections.
While you can manually edit
Code: Select all
/etc/nginx/conf.d/portainer.confInstead of messing with system scripts or SSH cron jobs, I created a "Fixer Container". It's a lightweight Docker container that starts on boot, automatically patches the Nginx config, reloads Nginx, and then sleeps. Because it's a container, you can manage it right inside Portainer and remove it easily if an official update ever fixes this.
How it works
- On startup, it checks the config file. If the WebSocket headers are missing, it uses sed to insert them.
- It uses pid: host to trigger an Nginx reload on the NAS without restarting the whole service.
- It runs a sleep infinity command at the end. This keeps the container in a "Running" state so that Docker's restart: always policy will automatically start it up again the next time you reboot your NAS.
- Open Portainer.
- Go to Stacks -> Add stack.
- Name it something like nginx-websocket-fix.
- Paste the following into the Web editor:
Code: Select all
version: '3' services: nginx-fixer: image: alpine:latest container_name: nginx-websocket-fix restart: always # 'host' PID mode is required to send the reload signal to the host Nginx pid: host # Mount the directory where the config lives on the TNAS volumes: - /etc/nginx/conf.d:/host_conf_d entrypoint: - /bin/sh - -c - | echo "Checking Portainer Nginx config..." CONF="/host_conf_d/portainer.conf" # 1. Check if file exists and needs patching if [ -f "$$CONF" ] && ! grep -q "proxy_set_header Upgrade" "$$CONF"; then echo "Fix missing. Applying patch..." # Insert the websocket headers before the proxy_pass line # Note: We use $$ to escape variables in docker-compose sed -i '/proxy_pass/i \ proxy_http_version 1.1;\n proxy_set_header Upgrade $$http_upgrade;\n proxy_set_header Connection "Upgrade";' "$$CONF" echo "Patch applied. Reloading Host Nginx..." # Send HUP signal to host nginx processes to reload config kill -HUP $$(pidof nginx) else echo "Config is already patched or missing." fi # 2. Sleep forever to keep container "Running" so it starts on next boot echo "Job done. Sleeping to maintain 'Running' status for next reboot..." sleep infinity - Click Deploy the stack.