1. The problem I’m having:
I’d like to utilize the layer4 app with caddy2-ext/layer4 to stick with the YAML Caddyfile, but be able to proxy UDP traffic to certain upstream servers.
Strech goal is to keep H3 running in the http app, so that certain upstream service can still be accessed via QUIC - so not all UDP requests should be covered by the Layer4 app, some still by http
It appears that I don’t quite get the concept or run into limitations of caddy2-ext/layer4. Is there a way to achieve my goal without going down the .json route?
In short, it should work like this:
----> Ingress 443
#Layer4
-------> vpn.domain.tld - proxied to wireguard:5820/udp
-------> turn.domain.tld - proxied to coturn:3389/udp & tls
-------> mumble.domain.tld - proxied to mumbleserver/udp & tls
[…]
#http with h1 h2 h3
-------> cloud.domain.tld - fast cgi to nextcloud:9000/udp&tcp & tls (this one would benefit from h3)
-------> mumble.domain.tld - proxied to mumblserver:/tcp & tls
-------> otherhttp.domain.tld - proxied to other_services:80/tcp & tls
[…]
2. Error messages and/or full log output:
In the caddyfile below the lines for layer4 are commented out. If I remove those comments and try to activate the, say, dot server, the error message below is shown:
"layer4 app module: start: listen udp 0.0.0.0:443: bind: address already in use"
3. Caddy version:
v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=
4. How I installed and ran Caddy:
Built my own caddy image:
FROM caddy:builder AS builder
RUN xcaddy build \
--with github.com/caddy-dns/cloudflare \
--with github.com/greenpau/caddy-security \
--with github.com/mholt/caddy-l4 \
--with github.com/RussellLuo/caddy-ext/layer4
FROM caddy:latest
RUN apk add --no-cache nano
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
a. System environment:
6.1.0-0.deb11.5-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.12-1~bpo11+1 (2023-03-05) x86_64 GNU/Linux
Debian Bullseye with backports for Bookworm Kernel
b. Command:
Docker run command
docker run -d \
--restart always \
-p 80:80 \
-p 443:443 \
-p 80:80/udp \
-p 443:443/udp \
--network=mynetwork \
-v /home/user1/services/caddy/fs:/fs \
-v /home/user1/services/caddy/data:/data \
-v /home/user2/infra/caddy/Caddyfile:/etc/caddy/Caddyfile \
-v /home/user1/services/caddy/config:/config \
-v ~/webserver/nextcloud/pushsocket:/run/notify_push \
-v nextcloud_install:/var/www/html:ro \
-v storagebox_user1_crypt:/var/www/html/data/storagebox/user1:ro \
-v storagebox_user3_crypt:/var/www/html/data/storagebox/user3:ro \
-v ~/webserver/nextcloud/data:/var/www/html/data:ro \
-v ~/webserver/nextcloud/apps:/var/www/html/custom_apps:ro \
-v /home/user1/webserver/dl5gu.radio/hugo/output:/var/www/dl5gu.radio \
-v /home/user1/webserver/productopia/hugo/output:/var/www/productopia \
--name caddy \
gymnae/caddy
d. My complete Caddy config:
{
#https_port 443
#default_bind 0.0.0.0
#http_port 80
servers tcp/0.0.0.0:443 {
protocols h1 h2 h3
}
#layer4 {
# udp/0.0.0.0:443 {
# turn.grundstil.de {
# tls
# proxy {
# to udp/signaling_coturn:3389
# }
# }
# vpn.grundsti.de {
# tls
# proxy {
# to udp/wireguard:51820
# }
#}
# dot.argonath.de, dot.grundstil.de, dot.amonsul.net, dot.wxbu.de {
# tls
# proxy {
# to udp/dnsproxy:853
# }
#}
# dot.amonsul.net {
# tls
# proxy {
# to dnsproxy:853
# }
#}
# }
#}
}
isso.dl5gu.radio, isso.productopia.net {
reverse_proxy isso:8080
}
tube.wxbu.de {
reverse_proxy invidious:3000
}
(matrix-well-known-header) {
# Headers
header Access-Control-Allow-Origin "*"
header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"
header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization"
header Content-Type "application/json"
}
amonsul.net {
handle /.well-known/matrix/server {
import matrix-well-known-header
respond `{"m.server":"matrix.amonsul.net:443"}`
}
handle /.well-known/matrix/client {
import matrix-well-known-header
respond `{"m.homeserver":{"base_url":"https://matrix.amonsul.net"}}`
}
respond "hello world"
encode gzip
file_server
}
grundstil.de, www.grundstil.de {
encode gzip
root * /var/www/dl5gu.radio
handle /.well-known/matrix/server {
import matrix-well-known-header
respond `{"m.server":"matrix.grundstil.de:443"}`
}
handle /.well-known/matrix/client {
import matrix-well-known-header
respond `{"m.homeserver":{"base_url":"https://matrix.grundstil.de"}}`
}
file_server
# Begin - Security
# deny all direct access for these folders
rewrite /(\.git|cache|bin|logs|backups|tests)/.* /403
# deny running scripts inside core system folders
rewrite /(system|vendor)/.*\.(txt|xml|md|html|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ /403
# deny running scripts inside user folder
rewrite /user/.*\.(txt|md|yaml|yml|php|pl|py|cgi|twig|sh|bat)$ /403
# deny access to specific files in the root folder
rewrite /(LICENSE\.txt|composer\.lock|composer\.json|nginx\.conf|web\.config|htaccess\.txt|\.htaccess) /403
respond /403 403
## End - Security
# global rewrite should come last.
try_files {path} {path}/ /index.php?_url={uri}&{query}
}
argonath.de {
handle /.well-known/matrix/server {
import matrix-well-known-header
respond `{"m.server":"matrix.argonath.de:443"}`
}
handle /.well-known/matrix/client {
import matrix-well-known-header
respond `{"m.homeserver":{"base_url":"https://matrix.argonath.de"}}`
}
respond "hello world"
encode gzip
file_server
}
csgofastdl.amonsul.net {
root * /fs/csgo
# respond "hello world"
encode gzip
file_server browse
}
csgo.wxbu.de {
reverse_proxy csgo-webcron-server:8080
}
search:80, search.local:80, search.argonath.de, search.grundstil.de, search.amonsul.net {
reverse_proxy searx:8080
}
pihole.amonsul.net, pihole.argonath.de, pihole.grundstil.de {
reverse_proxy pi-hole:80
}
doh.wxbu.de, doh.productopia.net, doh.grundstil.de, doh.amonsul.net {
reverse_proxy * amonsul-doh-server:8053
}
vpn.grundstil.de, vpn.amonsul.net {
reverse_proxy wireguard:51820
}
mumble.wxbu.de, mumble.grundstil.de, mumble.wxbu.de, mumble.amonsul.net {
reverse_proxy mumble-server:64738
}
space.wxbu.de, space.grundstil.de, space.amonsul.net {
handle_path /radio/* {
reverse_proxy botamusique_space:8181
}
reverse_proxy gomumblesoundboard_space:3000
}
radio.wxbu.de {
reverse_proxy botamusique_space:8181
}
freaks.grundstil.de, freaks.wxbu.de, freaks.amonsul.net {
reverse_proxy gomumblesoundboard_freaks:3000
}
hw.wxbu.de, hw.grundstil.de, hw.amonsul.net {
reverse_proxy gomumblesoundboard_hw:3000
}
http://cloud, cloud.wxbu.de, cloud.local, cloud.dl5gu.radio, cloud.argonath.de, cloud.productopia.net, cloud.grundstil.de, cloud.amonsul.net {
encode gzip
redir /.well-known/webfinger /index.php/.well-known/webfinger 301
redir /.well-known/nodeinfo /index.php/.well-known/nodeinfo 301
redir /.well-known/carddav /remote.php/dav 301
redir /.well-known/caldav /remote.php/dav 301
header {
Strict-Transport-Security max-age=31536000;
}
handle_path /standalone-signaling/* {
reverse_proxy signaling_spreed:8088
}
route /push/* {
uri strip_prefix /push
reverse_proxy * unix//run/notify_push/notify_push.sock {
trusted_proxies private_ranges
}
}
# .htaccess / data / config / ... shouldn't be accessible from outside
@forbidden {
path /.htaccess
path /data/*
path /config/*
path /db_structure
path /.xml
path /README
path /3rdparty/*
path /lib/*
path /templates/*
path /occ
path /console.php
}
respond @forbidden 404
handle {
root * /var/www/html
php_fastcgi nextcloud:9000 {
env front_controller_active true # Remove index.php form url
trusted_proxies private_ranges
}
file_server
}
}
notify.amonsul.net, notify.grundstil.de {
uri strip_prefix /push
reverse_proxy * unix//run/notify_push/notify_push.sock {
trusted_proxies private_ranges
}
}
mail.grundstil.de, mail.dl5gu.radio {
respond "I am a mailserver"
}
turn.grundstil.de {
reverse_proxy * signaling_coturn:3389 {
trusted_proxies private_ranges
}
}
spreed.amonsul.net, spreed.grundstil.de {
handle_path /standalone-signaling/* {
reverse_proxy signaling_spreed:8088
}
}
dot.argonath.de, dot.grundstil.de, dot.amonsul.net, dot.wxbu.de {
reverse_proxy dnsproxy:853
}
speedup.grundstil.de {
reverse_proxy * docker-matomo-web-1:80
}
sftpgrav.grundstil.de {
reverse_proxy * grundstil-grav-sftp:8080
}
calibre.grundstil.de {
reverse_proxy * calibre-web:8083
}
backup.grundstil.de {
reverse_proxy * kopia:51515
}
portainer.argonath.de, portainer.grundstil.de, portainer.productopia.net, portainer.amonsul.net {
reverse_proxy * portainer:9000
}
matrix.wxbu.de, matrix.productopia.net, matrix.amonsul.net, matrix.grundstil.de, matrix.argonath.de {
reverse_proxy /_matrix/* matrix-synapse-1:8008 {
}
reverse_proxy /_synapse/client/* matrix-synapse-1:8008 {
}
}
element.amonsul.net, element.wxbu.de, element.productopia.net, element.grundstil.de, element.argonath.de {
encode zstd gzip
reverse_proxy matrix-element-1:80 {
}
}
monitor.grundstil.de, monitor.amonsul.net {
reverse_proxy netdata:19999
basicauth /* {
<redacted> <redacted>
}
}
glances.wxbu.de {
reverse_proxy glances:61208
basicauth /* {
<redacted> <redacted>
}
}
dl5gu.radio {
root * /var/www/dl5gu.radio
#respond "und der seb darf mit in mein raumschiff"
encode gzip
file_server
}
productopia.net, wxbu.de {
handle /.well-known/matrix/server {
import matrix-well-known-header
respond `{"m.server":"matrix.productopia.net:443"}`
}
handle /.well-known/matrix/client {
import matrix-well-known-header
respond `{"m.homeserver":{"base_url":"https://matrix.productopia.net"}}`
}
#basicauth {
# <redacted> <redacted>
#}
# root * /var/www/productopia
redir https://cloud.wxbu.de/apps/collectives/wxbu.de permanent
# file_server
}
git.dl5gu.radio {
reverse_proxy gitea:3000
}
drone.dl5gu.radio {
reverse_proxy drone:80
}
rxresu.grundstil.de {
handle_path /api/* {
reverse_proxy rxresu_server:3100
}
handle /* {
reverse_proxy rxresu_client:3000
}
}
headscale.grundstil.de, headscale.productopia.net {
reverse_proxy headscale:8080
}
mc.amonsul.net {
reverse_proxy mc:8100
}
# Dashboard
https://dashboard.productopia.net {
# Apply basic security headers
header {
# Enable cross origin access to *.productopia.net
Access-Control-Allow-Origin *.productopia.net
# Enable HTTP Strict Transport Security (HSTS)
Strict-Transport-Security "max-age=31536000;"
# Enable cross-site filter (XSS) and tell browser to block detected attacks
X-XSS-Protection "1; mode=block"
# Disallow the site to be rendered within a frame on a foreign domain (clickjacking protection)
X-Frame-Options "SAMEORIGIN"
# Prevent search engines from indexing
X-Robots-Tag "none"
# Remove the server name
-Server
}
reverse_proxy http://netmaker-ui
}
# API
https://api.productopia.net {
reverse_proxy http://netmaker:8081
}
# mq
wss://broker.productopia.net {
reverse_proxy ws://mq:8883
}
office.productopia.net, office.grundstil.de {
encode gzip
reverse_proxy http://collabora:9980
}
reddit.wxbu.de, reddit.grundstil.de, reddit.productopia.net {
encode gzip
reverse_proxy libreddit:8080
}
Btw, I wanted to say that for a looong time now: Caddy is an absolute blast to use and made my life soooo much easier. Thank you.