1. Caddy version (caddy version
): v2
2. How I run Caddy:
I use caddy in docker as a reverse proxy for a bunch of local self-hosted services also running in docker. I have raspberry pi zero that runs as my DNS server on my local network. All services are only exposed internally. I only expose the services through the caddy container. The services are all on the same dedicated docker network.
a. System environment:
OS: Ubuntu Server 20.04, Docker 20.10.7
b. Command:
docker-compose up
c. Service/unit/compose file:
version: "3.7"
services:
caddy:
image: caddy:latest
container_name: caddy
hostname: caddy
restart: unless-stopped
environment:
- MY_DOMAIN
ports:
- "80:80"
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./site:/srv
- ./data:/data
- ./config:/config
networks:
default:
external:
name: $DOCKER_MY_NETWORK
d. My complete Caddyfile or JSON config:
paperless.{$MY_DOMAIN} {
tls internal
reverse_proxy paperless-app:8000
}
nextcloud.{$MY_DOMAIN} {
tls internal
reverse_proxy nextcloud-web:80
header Strict-Transport-Security max-age=31536000;
redir /.well-known/carddav /remote.php/carddav 301
redir /.well-known/caldav /remote.php/caldav 301
}
portainer.{$MY_DOMAIN} {
tls internal
reverse_proxy portainer:9000
}
grafana.{$MY_DOMAIN} {
tls internal
reverse_proxy grafana:3000
}
prometheus.{$MY_DOMAIN} {
tls internal
reverse_proxy prometheus:9090
}
huginn.{$MY_DOMAIN} {
tls internal
reverse_proxy huginn-app:3000
}
rss.{$MY_DOMAIN} {
tls internal
reverse_proxy miniflux-app:8080
}
search.{$MY_DOMAIN} {
tls internal
@api {
path /config
path /status
}
@static {
path /static/*
}
@notstatic {
not path /static/*
}
@morty {
path /morty/*
}
@notmorty {
not path /morty/*
}
header {
# Enable HTTP Strict Transport Security (HSTS) to force clients to always connect via HTTPS
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Enable cross-site filter (XSS) and tell browser to block detected attacks
X-XSS-Protection "1; mode=block"
# Prevent some browsers from MIME-sniffing a response away from the declared Content-Type
X-Content-Type-Options "nosniff"
# Disallow the site to be rendered within a frame (clickjacking protection)
X-Frame-Options "SAMEORIGIN"
# Disable some features
Permissions-Policy "accelerometer=(),ambient-light-sensor=(),autoplay=(),camera=(),encrypted-media=(),focus-without-user-activation=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),speaker=(),sync-xhr=(),usb=(),vr=()"
# Referer
Referrer-Policy "no-referrer"
# X-Robots-Tag
X-Robots-Tag "noindex, noarchive, nofollow"
# Remove Server header
-Server
Connection ""
}
header @api {
Access-Control-Allow-Methods "GET, OPTIONS"
Access-Control-Allow-Origin "*"
}
# Cache
header @static {
# Cache
Cache-Control "public, max-age=31536000"
defer
}
header @notstatic {
# No Cache
Cache-Control "no-cache, no-store"
Pragma "no-cache"
}
# CSP (see http://content-security-policy.com/ )
header @morty {
Content-Security-Policy "default-src 'none'; style-src 'self' 'unsafe-inline'; form-action 'self'; frame-ancestors 'self'; base-uri 'self'; img-src 'self' data:; font-src 'self'; frame-src 'self'"
}
header @notmorty {
Content-Security-Policy "upgrade-insecure-requests; default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; form-action 'self'; font-src 'self'; frame-ancestors 'self'; base-uri 'self'; connect-src 'self' https://overpass-api.de; img-src 'self' data: https://*.tile.openstreetmap.org; frame-src https://www.youtube-nocookie.com https://player.vimeo.com https://www.dailymotion.com https://www.deezer.com https://www.mixcloud.com https://w.soundcloud.com https://embed.spotify.com"
}
# Morty
handle @morty {
reverse_proxy morty-app:3000
}
# Filtron
handle {
encode zstd gzip
reverse_proxy filtron-app:4040 {
header_up X-Forwarded-Port {http.request.port}
header_up X-Forwarded-Proto {http.request.scheme}
header_up X-Forwarded-TlsProto {tls_protocol}
header_up X-Forwarded-TlsCipher {tls_cipher}
header_up X-Forwarded-HttpsProto {proto}
}
}
}
3. The problem I’m having:
Unable to get the url that uses morty to work. I get a 502 response. Everything else runs flawlessly. I took the caddy setup from GitHub - searx/searx-docker: Create a searx instance using Docker. The difference I can see is that they use the host network and not an internal docker network.
4. Error messages and/or full log output:
Caddy Log:
{"level":"debug","ts":1639343222.1266415,"logger":"http.handlers.reverse_proxy","msg":"upstream roundtrip","upstream":"morty-app:3000","request":{"remote_addr":"192.168.0.158:53645","proto":"HTTP/2.0","method":"GET","host":"search.vault.lan","uri":"/morty/?mortyurl=https%3A%2F%2Fencrypted-tbn0.gstatic.com%2Fimages%3Fq%3Dtbn%3AANd9GcSSy0oSxa-m7JajX9-dHV2zndWtCGLsatPSdw%26usqp%3DCAU","headers":{"Sec-Ch-Ua-Platform":["\"Windows\""],"Upgrade-Insecure-Requests":["1"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-Site":["none"],"Cookie":["categories=general; language=en-US; locale=en; autocomplete=; image_proxy=1; safesearch=0; theme=oscar; results_on_new_tab=0; doi_resolver=oadoi.org; oscar-style=logicodev; simple_style=auto; advanced_search=0; query_in_title=; disabled_engines=; enabled_engines=; disabled_plugins=; enabled_plugins=; tokens=; method=POST"],"X-Forwarded-For":["192.168.0.158"],"Sec-Ch-Ua":["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Google Chrome\";v=\"96\""],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"],"Accept-Encoding":["gzip, deflate, br"],"Accept-Language":["en-US,en;q=0.9"],"Pragma":["no-cache"],"Cache-Control":["no-cache"],"Sec-Ch-Ua-Mobile":["?0"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-User":["?1"],"Sec-Fetch-Dest":["document"],"X-Forwarded-Proto":["https"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","proto_mutual":true,"server_name":"search.vault.lan"}},"duration":0.001728427,"error":"dial tcp 192.168.240.23:3000: connect: connection refused"},
{"level":"error","ts":1639343222.1268082,"logger":"http.log.error","msg":"dial tcp 192.168.240.23:3000: connect: connection refused","request":{"remote_addr":"192.168.0.158:53645","proto":"HTTP/2.0","method":"GET","host":"search.vault.lan","uri":"/morty/?mortyurl=https%3A%2F%2Fencrypted-tbn0.gstatic.com%2Fimages%3Fq%3Dtbn%3AANd9GcSSy0oSxa-m7JajX9-dHV2zndWtCGLsatPSdw%26usqp%3DCAU","headers":{"Sec-Fetch-User":["?1"],"Sec-Fetch-Dest":["document"],"Pragma":["no-cache"],"Cache-Control":["no-cache"],"Sec-Ch-Ua-Mobile":["?0"],"Sec-Fetch-Mode":["navigate"],"Cookie":["categories=general; language=en-US; locale=en; autocomplete=; image_proxy=1; safesearch=0; theme=oscar; results_on_new_tab=0; doi_resolver=oadoi.org; oscar-style=logicodev; simple_style=auto; advanced_search=0; query_in_title=; disabled_engines=; enabled_engines=; disabled_plugins=; enabled_plugins=; tokens=; method=POST"],"Sec-Ch-Ua-Platform":["\"Windows\""],"Upgrade-Insecure-Requests":["1"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-Site":["none"],"Sec-Ch-Ua":["\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"96\", \"Google Chrome\";v=\"96\""],"User-Agent":["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"],"Accept-Encoding":["gzip, deflate, br"],"Accept-Language":["en-US,en;q=0.9"]},"tls":{"resumed":false,"version":772,"cipher_suite":4865,"proto":"h2","proto_mutual":true,"server_name":"search.vault.lan"}},"duration":0.002263989,"status":502,"err_id":"nitvcq1cc","err_trace":"reverseproxy.statusError (reverseproxy.go:858)"}
5. What I already tried:
I honestly don’t know where to start.
6. Links to relevant resources:
GitHub - searx/searx-docker: Create a searx instance using Docker,