Eerro websocket on chat server

Infos:

  • Used Zammad version: 6.2.0-1
  • Used Zammad installation type: Docker-compose Nginx
  • Operating system: Debian 12
  • Browser + version: Chrome 125.0.6422.142 (Build oficial) (64 bits)

Expected behavior:

  • I cant get connect chat and forms on my web site: WebSocket connection to ‘wss://xxx.xxx.xxx/ws’ failed

Actual behavior:

  • i cant get show the chat and forms on my web site.

Steps to reproduce the behavior:

  • I installed zammad very well on my server with docker-compose, I opened the necessary port and did everything so that my reverse-proxy could show the zammad website. Which works very well, I have no problem. But when I want to introduce the chat server on my website, for attention and also to be able to create tickets via the web, I have not been able to. Websocket error appears WebSocket connection to ‘wss://xxx.xxx.xxx/ws’ failed

The configuration I have in the ngix docker-compose:

this is the nginx config for zammad

upstream zammad-railsserver {
server zammad-railsserver:3000;
}

upstream zammad-websocket {
server zammad-websocket:6042;
}

server {
listen 8082;
listen [::]:8082;

# replace 'localhost' with your fqdn if you want to use zammad from remote
server_name _;

# security - prevent information disclosure about server version
server_tokens off;

root /opt/zammad/public;

access_log /dev/stdout;
error_log  /dev/stdout;

client_max_body_size 50M;

location ~ ^/(assets/|robots.txt|humans.txt|favicon.ico|apple-touch-icon.png) {
    expires max;
}

# legacy web socket server
location /ws {
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header CLIENT_IP $remote_addr;
    proxy_set_header Connection "Upgrade";
    proxy_set_header CLIENT_IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 86400;
    proxy_pass http://zammad-websocket;
}

# action cable
location /cable {
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header CLIENT_IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 86400;
    proxy_pass http://zammad-railsserver;
}

location / {
    proxy_set_header Host $http_host;
    proxy_set_header CLIENT_IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

    # Change this line in an SSO setup
    proxy_set_header X-Forwarded-User "";

    proxy_read_timeout 300;
    proxy_pass http://zammad-railsserver;

    gzip on;
    gzip_types text/plain text/xml text/css image/svg+xml application/javascript application/x-javascript application/json application/xml;
    gzip_proxied any;
}

}

this is my config on my reverse-proxy nginx, isconfig 3 panel:

server {
listen *:80;
listen [::]:80;
listen *:443 ssl http2;

    ssl_protocols TLSv1.3 TLSv1.2;
    listen [::]:443 ssl http2;
    ssl_certificate /var/www/clients/client1/web1/ssl/xx.xxx.xxx-le.crt;
    ssl_certificate_key /var/www/clients/client1/web1/ssl/xx.xxx.xxx-le.key;

    server_name xx.xxx.xxx *.xx.xxx.xxx;

    root   /var/www/xx.xxx.xxx/web/;
            disable_symlinks if_not_owner from=$document_root;


    index index.html index.htm index.php index.cgi index.pl index.xhtml standard_index.html;


    error_page 400 /error/400.html;
    error_page 401 /error/401.html;
    error_page 403 /error/403.html;
    error_page 404 /error/404.html;
    error_page 405 /error/405.html;
    error_page 500 /error/500.html;
    error_page 502 /error/502.html;
    error_page 503 /error/503.html;
    recursive_error_pages on;
    location = /error/400.html {

        internal;
        auth_basic off;
    }
    location = /error/401.html {

        internal;
        auth_basic off;
    }
    location = /error/403.html {
        internal;
        auth_basic off;
    }
    location = /error/403.html {

        internal;
        auth_basic off;
    }
    location = /error/404.html {

        internal;
        auth_basic off;
    }
    location = /error/405.html {

        internal;
        auth_basic off;
    }
    location = /error/500.html {

        internal;
        auth_basic off;
    }
    location = /error/502.html {

        internal;
        auth_basic off;
    }
    location = /error/503.html {

        internal;
        auth_basic off;
    }

    error_log /var/log/ispconfig/httpd/xx.xxx.xxx/error.log;
    access_log /var/log/ispconfig/httpd/xx.xxx.xxx/access.log combined;

    location ~ /\. {
             deny all;
    }

    location ^~ /.well-known/acme-challenge/ {
                    access_log off;
                    log_not_found off;
                    auth_basic off;
                    root /usr/local/ispconfig/interface/acme/;
                    autoindex off;
                    index index.html;
                    try_files $uri $uri/ =404;
    }

    location = /favicon.ico {
        log_not_found off;
        access_log off;
        expires max;
        add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    }

    location = /robots.txt {
        allow all;
        log_not_found off;
        access_log off;
    }

    location /stats/ {

        index index.html index.php;
        auth_basic "Members Only";
        auth_basic_user_file /var/www/clients/client1/web1/web//stats/.htpasswd_stats;
        add_header Content-Security-Policy "default-src * 'self' 'unsafe-inline' 'unsafe-eval' data:;";
    }

    location ^~ /awstats-icon {
        alias /usr/share/awstats/icon;
    }

    location ~ \.php$ {
        try_files /dbdf93715ca0e9cee1037316418fb976.htm @php;
    }

    location @php {
        try_files $uri =404;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass unix:/var/lib/php8.2-fpm/web1.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_intercept_errors on;
    }


    location / {
        proxy_pass http://127.0.0.1:8082;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 1M;
    }

}

Can any help me???

Update, i have this error on log.

connect() failed (111: Connection refused) while connecting to upstream, client: 190.66.79.72, server: xxxxxxxxx, request: “GE|T / HTTP/2.0”, upstream: “http://127.0.0.1:3000/”, host: “xxxxxx”
connect() failed (111: Connection refused) while connecting to upstream, client: 190.66.79.72, server: xxxxxxxxx, request: “GE|T / HTTP/2.0”, upstream: “http://127.0.0.1:3000/”, host: “xxxxxx”
connect() failed (111: Connection refused) while connecting to upstream, client: 190.66.79.72, server: xxxxxxxxx, request: “GE|T / HTTP/2.0”, upstream: “http://127.0.0.1:3000/”, host: “xxxxxx”
connect() failed (111: Connection refused) while connecting to upstream, client: 190.66.79.72, server: xxxxxxxxx, request: “GE|T / HTTP/2.0”, upstream: “http://127.0.0.1:3000/”, host: “xxxxxx”

Any idea???

Do you use two proxies behind each other by any chance? If so, the first proxy in line has to proxy all requests (including the websocket requests) to the second proxy without splitting the requests. Other wise this approach will fail.

Please note that this kind of configuration might be troublesome or at least more advanced.

What a shame it was late, I only saw the email that arrived at this moment, when installing zammad via docker-compose, the default nginx file is this:

#
# this is the nginx config for zammad
#

upstream zammad-railsserver {
    server zammad-railsserver:3000;
}

upstream zammad-websocket {
    server zammad-websocket:6042;
}

server {
    listen 8082;
    listen [::]:8082;

    # replace 'localhost' with your fqdn if you want to use zammad from remote
    server_name _;

    # security - prevent information disclosure about server version
    server_tokens off;

    root /opt/zammad/public;

    access_log /dev/stdout;
    error_log /dev/stdout;

    client_max_body_size 100M;

    location ~ ^/(assets/|robots.txt|humans.txt|favicon.ico|apple-touch-icon.png) {
        expires max;
    }

    # legacy web socket server
    location /ws {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header CLIENT_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
        proxy_pass http://zammad-websocket;
    }

    # action cable
    location /cable {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header CLIENT_IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 86400;
        proxy_pass http://zammad-railsserver;
    }

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header CLIENT_IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Change this line in an SSO setup
        proxy_set_header X-Forwarded-User "";

        proxy_read_timeout 300;
        proxy_pass http://zammad-railsserver;

        gzip on;
        gzip_types text/plain text/xml text/css image/svg+xml application/javascript application/x-javascript application/json application/xml;
        gzip_proxied any;
    }
}

In my Ispconfig 3 administration panel, when creating the domain to point to, this is the display, error 502 badgateway, but if I put this configuration in my panel host nginx:

location / {
# proxy_pass http://127.0.0.1:8082;
# proxy_set_header Host $host;
# proxy_set_header X-Forwarded-Proto $scheme;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_fo>
# client_max_body_size 100M;
        }

The zammad server appears normal. How should the configuration be? According to what I read, in my panel I must have the upstream configuration, websocker and cable, rigth?.

You will need to transparently proxy the connections from your upstream proxy to Zammads proxy server. This includes websocket connections without “opening” them.

This is not a trivial setup and requires a lot of things to be aware of. This is out of community scope, I’m sorry.