allinurl / goaccess

GoAccess is a real-time web log analyzer and interactive viewer that runs in a terminal in *nix systems or through your browser.
https://goaccess.io
MIT License
17.88k stars 1.09k forks source link

WebSocket Handshake Fails with 400 Bad Request Error #2545

Open gionapaolini opened 11 months ago

gionapaolini commented 11 months ago

Description:

When trying to set up GoAccess in a Docker container behind an NGINX reverse proxy to handle WebSocket connections, I consistently receive a 400 Bad Request error during the WebSocket handshake.

Setup:

GoAccess is running inside a Docker container. NGINX is set up as a reverse proxy to handle SSL and pass requests to the GoAccess container.

Steps to Reproduce:

  1. Start the GoAccess container.
  2. Configure NGINX to proxy requests to GoAccess.
  3. Attempt to establish a WebSocket connection to GoAccess via the browser or using websocat.

Expected Behavior:

A successful WebSocket handshake and establishment of the connection.

Actual Behavior:

The WebSocket handshake fails, and a 400 Bad Request error is received. The GoAccess logs mention "Missing headers for handshake."

Logs:

GoAccess Logs:

Accepted: 11 [172.17.0.1]
Handling read 11 [172.17.0.1]...
Missing headers for handshake 11 [172.17.0.1]...
Closing TCP 11 [172.17.0.1]
Connection Closed.
Active: 0

Attempts to Resolve:

Checked and reconfigured NGINX to ensure it's passing the necessary headers for a WebSocket connection. Reviewed GoAccess configuration to ensure WebSocket mode is enabled. Monitored the network using developer tools in the browser. No WebSocket connection attempts are visible, just the 400 status error. Used websocat to test the WebSocket connection directly, which also resulted in a 400 Bad Request error.

Additional resources used:

Dockerfile:

FROM alpine
RUN apk add build-base libressl-dev libmaxminddb-dev ncurses-dev
WORKDIR /src
RUN wget https://tar.goaccess.io/goaccess-1.7.2.tar.gz
RUN tar -xzvf goaccess-1.7.2.tar.gz
WORKDIR /src/goaccess-1.7.2
RUN ./configure --enable-geoip=mmdb --enable-debug
RUN make
RUN make install
ENTRYPOINT goaccess -o html \
                    --log-format=COMBINED \
                    --real-time-html \
                    --ws-url=wss://subdomain.domain.org \
                    --origin=https://subdomain.domain.org \
                    -

Run with tail -F /var/log/nginx/access.log | docker run -i -p 7890:7890 goaccess > report.html

NGINX Config:

server {
        listen 443 ssl;
        listen [::]:443 ssl;
        ssl_certificate     /../fullchain.pem;
        ssl_certificate_key /../privkey.pem;
        ssl_protocols TLSv1.2 TLSv1.3;     

        server_name subdomain.domain.org;
        location / {
           proxy_set_header Host $host;
           proxy_pass http://127.0.0.1:7890;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

           # WebSocket support
           proxy_http_version 1.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "Upgrade";
        }
}
allinurl commented 11 months ago

Please feel free to check out the GitHub issues; there have been a number of questions about this. Let me know if you're able to find the information you need.

allinurl commented 11 months ago

e.g., https://github.com/allinurl/goaccess/issues/2487

gionapaolini commented 11 months ago

I tried running the docker command suggested on the readme, with no proxy in front and no ssl. I still have the same issue.

tail -F /var/log/nginx/access.log | docker run -p 7890:7890 --rm -i -e LANG=$LANG allinurl/goaccess -a -o html --log-format COMBINED --real-time-html - > report.html

Tried adding --ws-url

tail -F /var/log/nginx/access.log | docker run -p 7890:7890 --rm -i -e LANG=$LANG allinurl/goaccess -a -o html --log-format COMBINED --real-time-html --ws-url=ws://{IP}:7890 - > report.html

But still no luck.

Is there something I need to configure that might not be mentioned in the readme prior to running the docker image?

allinurl commented 11 months ago

Seems like there might be a problem related to the port. Is there a firewall in place that could be blocking access to port 7890? Could you also share the output from your browser's console?

gionapaolini commented 11 months ago

I tried running a different service on the same port and it does work with no issue, so nothing is blocking that port. Below you can find a screenshot of the browser console. image

In any case, when running in debug mode (no proxy, no ssl, direct access by ip) I do receive the request, so for sure the port is working, and I get the same error from the logs:

WebSocket server ready to accept new client connections
Accepted: 11 [my-ip]
Handling read 11 [my-ip]...
Missing headers for handshake 11 [my-ip]...
Closing TCP 11 [my-ip]
Connection Closed.
Active: 0

So the browser is not passing some required headers I guess?

gionapaolini commented 11 months ago

It seems to be working when I try connecting with the PieSocket Websocket tester extension. So it must the a browser issue which for some reason does not provide the right headers

allinurl commented 11 months ago

Interesting. Could you attempt this using a different browser or in an incognito session?

gionapaolini commented 11 months ago

I have tested it on latest version of chrome, edge and brave. Same issue each time. Maybe I'm missing something, am I supposed to hit the Websocket server directly on the browser (http://{IP}:7890) (which is what I'm currently doing) or is there a different endpoint I should hit, which then initiate the websocket connection?

Do I have to serve the report.html file? Is this what I'm missing?

allinurl commented 11 months ago

are you able to access https://rt.goaccess.io using the same browser or do you get the same error message?

gionapaolini commented 11 months ago

I am able to access it with no issues

allinurl commented 11 months ago

It appears to be a configuration problem specific to your local setup. Could you try running a plain instance of goaccess without using containerization / Docker?

surfaceflinger commented 10 months ago

Using goaccess from NixOS-unstable and latest Google Chrome Canary - same exact behavior. Failed to load resource: the server responded with a status of 400 ().

My cmdline is goaccess /var/log/caddy/access-nekopon.pl.log --log-format caddy --real-time-html -o index.html

Ports are available + I ran goaccess with root permissions

GoAccess - 1.7.2.
For more details visit: https://goaccess.io/
Copyright (C) 2009-2023 by Gerardo Orellana

Build configure arguments:
  --enable-utf8
  --enable-geoip=mmdb
  --with-openssl
allinurl commented 10 months ago

@surfaceflinger Could you check if you experience the same outcomes when using different web browsers or even when using an incognito session?

surfaceflinger commented 10 months ago

@surfaceflinger Could you check if you experience the same outcomes when using different web browsers or even when using an incognito session?

ehh, sorry, I just sat to this again and looks like I didn't get how it's supposed to work and I tried to directly connect to the websocket.

The way I got it working now in a "minimal" fashion, without setting nginx etc is

darkhttpd . --port 9191 &
goaccess /var/log/caddy/access-nekopon.pl.log --log-format caddy --real-time-html -o index.html
allinurl commented 10 months ago

@surfaceflinger Great to hear, appreciate the update, and I'm glad to know it's functioning correctly now.