Caddy V2 how to proxy websoket (v2ray websocket + tls)

Like my title ,on caddy v2,i don’t know how to use caddy2 proxy websocket.in caddy1,i can write my caddyfile like this :

mydomain.me
{
  log ./caddy.log
  proxy /ray localhost:10000 {
    websocket
    header_upstream -Origin
  }
}

but in caddy V2 ,i don’t how to privoxy websocket.

1 Like

Do you need a websocket, or do you need an unix socket?

There is an example of an unix socket given here: Conventions — Caddy Documentation

As for web sockets, the documentation for matchers shows an entire websocket proxy: Caddyfile Concepts — Caddy Documentation

1 Like

Hey! Thanks for your reply,I want proxy a websocket,and the websocket path is /ray.
I can give you the nginx config:

server {
  listen  443 ssl;
  ssl on;
  ssl_certificate       /etc/v2ray/v2ray.crt;
  ssl_certificate_key   /etc/v2ray/v2ray.key;
  ssl_protocols         TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers           HIGH:!aNULL:!MD5;
  server_name           mydomain.me;
        location /ray { # v2ray path
        proxy_redirect off;
        proxy_pass http://127.0.0.1:10000;#v2ray listen port
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $http_host;

        # Show realip in v2ray access.log
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

so can you help me?how two set same config on caddy2?

Hi @amColinzzz,

Use the example in the Named matcher (also linked above) section of the documentation, adapting the matcher to your path prefix (/ray) and the reverse proxy your upstream server (http://127.0.0.1:10000), and you should be done.

If it doesn’t work, post what you’ve got and we’ll have a closer look.

this is my caddy.json:

{
    "admin": {
        "disabled": false,
        "listen": "localhost:1000",
        "enforce_origin": false,
        "origins": [
            ""
        ],
        "config": {
            "persist": true
        }
    },
    "apps": {
        "http": {
            "servers": {
                "v2_proxy": {
                    "listen": [
                        ":443"
                    ],
                    "routes": [
                        {
                            "match": [
                                {
                                    "host": [
                                        "ray.52g.club"
                                    ]
                                }
                            ],
                            "handle": [
                                {
                                    "handler": "subroute",
                                    "routes": [
                                        {
                                            "handle": [
                                                {
                                                    "handler": "reverse_proxy",
                                                    "transport": {
                                                        "protocol": "http",
                                                        "read_buffer_size": 4096
                                                    },
                                                    "upstreams": [
                                                        {
                                                            "dial": "http://127.0.0.1:3000"
                                                        }
                                                    ]
                                                }
                                            ],
                                            "match": [
                                                {
                                                    "path": [
                                                        "/ray"
                                                    ]
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                }
            }
        },
        "tls": {
            "automation": {},
            "session_tickets": {}
        }
    }
}

caddy error:

2020/02/19 04:18:45.239	ERROR	http.log.error	dial http:: unknown network http:	{"request": {"method": "GET", "uri": "/ray", "proto": "HTTP/1.1", "remote_addr": "182.113.232.104:9821", "host": "ray.52g.club", "headers": {"Upgrade": ["websocket"], "User-Agent": ["Go-http-client/1.1"], "Connection": ["Upgrade"], "Sec-Websocket-Key": ["rk3k22x3LrnSVDrsGlkf5w=="], "Sec-Websocket-Version": ["13"]}, "tls": {"resumed": true, "version": 772, "ciphersuite": 4865, "proto": "http/1.1", "proto_mutual": true, "server_name": "ray.52g.club"}}, "status": 502, "err_id": "1dfs5b0fa", "err_trace": "reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:362)"}

my v2ray websocket is listen on 3000 port.but this caddy2 config is doesn’t work.
i really wangt to use V2 caddy ,but because it is new version ,i cant’t search some demo…

I want if you can give me a config.thank you.

Remove the scheme from this part - it should read: "dial": "127.0.0.1:3000"

(The scheme is specified elsewhere - in the transport key)

I tried the Named matcher to proxy web sockets, I keep getting ‘bad handshake’ when I try to connect to the websocket endpoint. Can websockets be automatically and transparently proxied? Or does the path need to be specified?

reverse_proxy localhost:4124
@websockets {
	header_regexp Connection Upgrade
	header        Upgrade websocket
}
reverse_proxy @websockets localhost:4124

Hmm. Can you post the full output of the ‘bad handshake’ error? Which layer is generating the error - client, Caddy, backend?

Yes, websockets are meant to be automatically proxied.

Transparency isn’t automatic, though. You’ll need to add those headers yourself. The example at the end of the reverse_proxy docs page shows how:

reverse_proxy localhost:9000 {
    header_up Host {host}
    header_up X-Real-IP {remote_host}
    header_up X-Forwarded-For {remote_host}
    header_up X-Forwarded-Proto {scheme}
}

reverse_proxy (Caddyfile directive) — Caddy Documentation

In fact, you don’t even need that named matcher because you’re not doing anything different with your websocket connection, they’re going to the exact same place as everything else in that config (localhost:4124). The matcher doesn’t modify the request in any way, it just singles out websocket connections so you can do something specific with them.

1 Like

Ah, cheers @Whitestrake, I’ve got it working as intended.

1 Like

yeah ,Thank you very much ,I have worked!
But i wish it will have a very full example for caddy2.
just like caddy1 ,this is a project on github caddy example.

1 Like

I don’t believe Caddy v1 ever had full Caddyfile examples for v2ray, but there are plenty of examples for all the working parts you need in the current v2 docs. Also - now you’ve posted yours above and we’ve worked out the problem, I expect people will be able to easily find this topic when searching for Caddy v2 with v2ray / websockets, and hopefully it will help them piece it all together.

I’d like to share my solution to this problem.

(Moderator edit: This is not correct due to improper formatting. See reply below for corrected version. Quote blocks should NOT be used for code for this reason.)

@websockets {
header Connection Upgrade
header Upgrade websocket
}
reverse_proxy @websockets localhost:6001

You only need to configure path for reverse_proxy in v2ray, not in caddy.

2 Likes

Just so somebody doesn’t miss the asterisks. :slight_smile:

@websockets {
	header Connection *Upgrade*
	header Upgrade websocket
}
reverse_proxy @websockets localhost:6001
5 Likes

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