Redirect non-WebSocket traffic somewhere else

1. The problem I’m having:

I have Headscale running on my domain. It mainly uses WebSocket traffic to bootstrap Tailscale clients and otherwise doesn’t display anything. (it returns 404).

So I would like to use a redir to instead send visitors to a profile page; Nostree to be exact.

However, how do I distinguish between WS traffic and just HTTP traffic? If a Tailscale client tries to connect, I would prefer them to properly get proxied to the Headscale server - otherwise, redirect.

2. Error messages and/or full log output:

Not an error.

3. Caddy version:

# caddy version
v2.7.4 h1:J8nisjdOxnYHXlorUKXY75Gr6iBfudfoGhrJ8t7/flI=

(Yes, I do need to update that…)

4. How I installed and ran Caddy:

# Run after apt upgrade caddy
xcaddy build \
  --with \
  --with \
  --output /usr/local/bin/caddy
# /etc/systemd/system/caddy.service
# caddy.service
# For using Caddy with a config file.
# Make sure the ExecStart and ExecReload commands are correct
# for your installation.
# See for instructions.
# WARNING: This service does not use the --resume flag, so if you
# use the API to make changes, they will be overwritten by the
# Caddyfile next time the service is restarted. If you intend to
# use Caddy's API to configure it, add the --resume flag to the
# `caddy run` command or use the caddy-api.service file instead.


ExecStart=/usr/local/bin/caddy run --environ --config /srv/Caddyfile
ExecReload=/usr/local/bin/caddy reload --config /srv/Caddyfile --force


a. System environment:

Ubuntu 22.04 LTS on arm64

b. Command:

SystemD - unit is above.

c. Service/unit/compose file:

See above.

d. My complete Caddy config: {
        #handle /.well-known/lnurlp/ingwie {
        #  header Access-Control-Allow-Origin *
        #  redir
        handle /.well-known/lnurlp/ingwie {
                reverse_proxy * {
                        rewrite /lnurl
                        header_up Host
                        transport http {
        handle /.well-known/* {
                uri strip_prefix /.well-known
                header Access-Control-Allow-Origin *
                file_server {
                        root /srv/
        handle /web* {
                root * /srv/headscale-ui/build
                uri strip_prefix /web
        handle {
                reverse_proxy localhost:8080

5. Links to relevant resources:


We have an example in the docs for matching websocket requests:

You can simply put not in front (just after the matcher name before the {) to negate it and do whatever with that.

You can simplify these slightly by using handle_path, skips needing uri strip_prefix:

	handle_path /.well-known/* {
		header Access-Control-Allow-Origin *
		root * /srv/
	handle_path /web* {
		root * /srv/headscale-ui/build
1 Like

I must’ve overlooked the example, sorry - my bad!

And thanks for the hint! Will use it :slight_smile: Makes the config cleaner.

Thanks for your help!

1 Like

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