Reverse proxy to websocket server failed

1. The problem I’m having:

I want to use caddy reverse proxy to websocket server, but it’s failed.

my Caddyfile is

mysite.com:443 {
    tls s@gmail.com
    encode gzip

    route /mypathWiWL/ {
        reverse_proxy 127.0.0.1:12456
    }

    handle {
        reverse_proxy https://www.sohu.com {
            trusted_proxies 0.0.0.0/0
            header_up Host {upstream_hostport}
        }
    }
}

my request header likes:

GET /mypathWiWL/ HTTP/1.1\r\n
Host: 7.4.3.2\r\n
Connection: Upgrade\r\n
Upgrade: websocket\r\n
Sec-WebSocket-Version: 13\r\n
Sec-WebSocket-Key: dItNpIgo+/PdumK0EPyNxg==\r\n
udp-tunnel: true\r\n
\r\n

Under normal circumstances, caddy will rewrite the Host field and forward this request header to the websocket server, and forward the response data returned from the server to the client.

but caddy did not try to connect to the websocket server at all, and directly returned 200 OK. This is not what I expected.

with nginx, the following settings works fine:

        location /mypathWiWL/ {
            proxy_redirect off;
            proxy_pass http://127.0.0.1:12456;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_set_header Host $http_host;
        }

2. Error messages and/or full log output:

the return info is

HTTP/1.1 200 OK\r\n
Alt-Svc: h3=\":443\"; ma=2592000\r\n
Server: Caddy\r\n
Date: Wed, 25 Sep 2024 00:37:30 GMT\r\n
Content-Length: 0\r\n
\r\n

3. Caddy version:

v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=

4. How I installed and ran Caddy:

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
caddy run --config /etc/caddy/Caddyfile

a. System environment:

Linux main 5.15.0-122-generic #132-Ubuntu SMP Thu Aug 29 13:45:52 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Now I change my request header likes following, just replace the IP with a domain name,

GET /mypathWiWL/ HTTP/1.1\r\n
Host: mysite.com\r\n
Connection: Upgrade\r\n
Upgrade: websocket\r\n
Sec-WebSocket-Version: 13\r\n
Sec-WebSocket-Key: dItNpIgo+/PdumK0EPyNxg==\r\n
udp-tunnel: true\r\n
\r\n

caddy return me this.

HTTP/1.1 404 Not Found\r\n
    Alt-Svc: h3=":443"; ma=2592000\r\n
    Content-Type: text/html\r\n
    Date: Wed, 25 Sep 2024 03:27:18 GMT\r\n
    Server: Caddy\r\n
    Vary: Accept-Encoding\r\n
    X-Cache: MISS from BC19_US-Virginia-Ashburn-1-cache-1(cloudsvr)\r\n
    X-Ser: BC21_dx-lt-yd-zhejiang-jinhua-5-cache-1, BC202_lt-obgp-fujian-xiamen-33-cache-2, BC73_US-DistColumbia-washingtonDC-6-cache-1, BC19_US-Virginia-Ashburn-1-cache-1\r\n
    Transfer-Encoding: chunked\r\n
\r\n
......

Not the websocket response header yet.

server log is

2024/09/25 03:35:15.982 DEBUG   http.handlers.reverse_proxy     selected upstream       {"dial": "www.sohu.com:443", "total_upstreams": 1}
2024/09/25 03:35:16.513 DEBUG   http.handlers.reverse_proxy     upstream roundtrip      {
    "upstream": "www.sohu.com:443", 
    "duration": 0.530901435, 
    "request": {
        "remote_ip": "1.2.3.4", "remote_port": "55148", "client_ip": "1.2.3.4", "proto": "HTTP/1.1", 
        "method": "GET", "host": "www.sohu.com:443", "uri": "/mypathWiWL/", 
        "headers": {
            "Upgrade": ["websocket"], 
            "X-Forwarded-Proto": ["https"], 
            "Connection": ["Upgrade"], 
            "Udp-Tunnel": ["true"], 
            "X-Forwarded-For": ["1.2.3.4"], 
            "X-Forwarded-Host": ["mysite.com"], 
            "User-Agent": [""], 
            "Sec-Websocket-Version": ["13"], 
            "Sec-Websocket-Key": ["U4WOfl7M3Pqg//UZfviIFg=="]
        }, 
        "tls": {"resumed": false, "version": 772, "cipher_suite": 4865, "proto": "", "server_name": "mysite.com"}
    }, 
    "headers": {
        "Vary": ["Accept-Encoding"], 
        "X-Ser": ["BC21_dx-lt-yd-zhejiang-jinhua-5-cache-1, BC202_lt-obgp-fujian-xiamen-33-cache-2, BC73_US-DistColumbia-washingtonDC-6-cache-1, BC19_US-Virginia-Ashburn-1-cache-1"], 
        "X-Cache": ["MISS from BC19_US-Virginia-Ashburn-1-cache-1(cloudsvr)"], 
        "Date": ["Wed, 25 Sep 2024 03:35:16 GMT"], 
        "Content-Type": ["text/html"], 
        "Connection": ["keep-alive"]
    }, 
    "status": 404
}

Now, I change my Caddyfile likes following, the reverse proxy works fine. but it’s not work if i enable the handle block.

How I do to enable multiple proxies?

mysite.com:443 {
    tls s@gmail.com
    encode gzip

    reverse_proxy /mypathWiWL/ 127.0.0.1:12456

    #handle {
    #    reverse_proxy https://www.sohu.com {
    #        trusted_proxies 0.0.0.0/0
    #        header_up Host {upstream_hostport}
    #    }
    #}
}

Howdy @ssrlive, welcome to the Caddy community.

I can’t say for sure because you haven’t actually included the request details of the bad response, but my hunch is that possibly you want /mypathWiWL/* instead of /mypathWiWL/ for your reverse_proxy.

Remember that path matchers in Caddy are LITERAL PATHS and require globs if you want them to match a prefix. This is different from nginx where location directives are automatically path prefixes, or optionally regex.

Remember also that Caddy returns 200 OK for any response where nothing was configured to provide a different response.

1 Like

Hi @Whitestrake , I have changed the Caddyfile likes following, the server not work yet.

mysite.com:443 {
    tls s@gmail.com
    encode gzip

    reverse_proxy /mypathWiWL/* 127.0.0.1:12456

    handle {
        reverse_proxy https://www.sohu.com {
            trusted_proxies 0.0.0.0/0
            header_up Host {upstream_hostport}
        }
    }
}

In the help template for your first post, there’s instructions to enable debug logging and to carry out a curl -v to get information to help troubleshoot.

We’ll need the full results and logs in order to help you.

1 Like

Actually, apologies. This looks like a directive order issue.

Because you put your second reverse_proxy inside a handle, the handle always executes first and routes ALL requests.

You’re not doing anything specific with that handle, just sending it to a reverse_proxy, so you should probably just unwrap that and it should work fine.

2 Likes

Emm, it works fine now. Thanks @Whitestrake

mysite.com:443 {
    tls s@gmail.com
    encode gzip

    reverse_proxy /mypathWiWL/* 127.0.0.1:12456

    reverse_proxy https://www.sohu.com {
        trusted_proxies 0.0.0.0/0
        header_up Host {upstream_hostport}
    }
}
1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.