I have Traefik running in a docker container behind Cloudflare tunnel and works with Whoami as test image. Now I'm trying to setup Nextcloud (using fpm image) with Caddy as webserver and postgres as db with Traefik in the front as reverse proxy.
I know Caddy by default will try to get certificate but in my setup I want it as just a webserver and let Traefik to handle SSL termination and passthrough Nextcloud DNS tranffic to Caddy as either http or https. I have put both Traefik and Caddy containers on the same network but for my life can't workout what labels I need to add to Caddy container for Nextcloud URL to work.
Assume Traefik coantiner is running and using traefik_proxy network.
Below is my docker-compose file for Caddy + Nextcloud fpm + Postgres + redis.
services:
web:
image: ${CADDY_IMAGE}
container_name: web
hostname: web
restart: unless-stopped
user: ${UID}:${GID}
depends_on:
- app
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ${APPDATADIR}/caddy/data:/data
- ${APPDATADIR}/caddy/config:/config
- ${APPDATADIR}/nextcloud:/var/www/html:ro
- ${APPDATADIR}/nextcloud/apps:/var/www/html/custom_apps:ro
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "127.0.0.1:2019/metrics"]
interval: 10s
retries: 3
start_period: 5s
timeout: 5s
networks:
- default
- traefik_proxy
app:
image: nextcloud:fpm
container_name: app
hostname: app
restart: unless-stopped
user: ${UID}:${GID}
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
environment:
- POSTGRES_HOST=db
- POSTGRES_DB=nextcloud
- POSTGRES_USER=nextclouduser
- POSTGRES_PASSWORD=nextcloudpassword
- REDIS_HOST=redis
- REDIS_HOST_PASSWORD=${REDIS_PASSWORD}
- NEXTCLOUD_ADMIN_USER=${NC_ADMIN_USER}
- NEXTCLOUD_ADMIN_PASSWORD=${NC_ADMIN_PASSWORD}
- NEXTCLOUD_TRUSTED_DOMAINS=${NC_DOMAIN} 192.168.1.*
- OVERWRITEHOST=${NC_DOMAIN}
- OVERWRITECLIURL=https://${NC_DOMAIN}
- OVERWRITEPROTOCOL=https
- TRUSTED_PROXIES=192.168.92.0/24
- PHP_MEMORY_LIMIT=1G
- PHP_UPLOAD_LIMIT=10G
volumes:
- ${APPDATADIR}/nextcloud:/var/www/html
- ${APPDATADIR}/nextcloud/apps:/var/www/html/custom_apps
- ${NC_DATA_DIR}:/var/www/html/data
- ${APPDATADIR}/nextcloud/config:/var/www/html/config
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
db:
# https://hub.docker.com/_/postgres
image: ${POSTGRES_IMAGE}
container_name: db
hostname: db
restart: unless-stopped
user: ${UID}:${GID}
environment:
- POSTGRES_HOST=db
- POSTGRES_DB=nextcloud
- POSTGRES_USER=nextclouduser
- POSTGRES_PASSWORD=nextcloudpassword
volumes:
- ${APPDATADIR}/postgresdb:/var/lib/postgresql/data
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -d $$POSTGRES_DB -U $$POSTGRES_USER"]
start_period: 15s
interval: 30s
retries: 3
timeout: 5s
redis:
image: ${REDIS_IMAGE}
container_name: redis
hostname: redis
restart: unless-stopped
user: ${UID}:${GID}
environment:
- REDIS_HOST=redis
- REDIS_HOST_PORT=6379
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- ${APPDATADIR}/redis:/data
healthcheck:
test: redis-cli -a ${REDIS_PASSWORD} ping | grep PONG
start_period: 10s
interval: 5s
retries: 3
timeout: 3s
Below my Caddyfile (found on Nextcloud forurm, haven't tweaked anything).
{
servers {
trusted_proxies static 192.168.92.0/24
}
log DEBUG
}
:80 {
request_body {
max_size 10G
}
# Enable gzip but do not remove ETag headers
encode {
zstd
gzip 4
minimum_length 256
match {
header Content-Type application/atom+xml
header Content-Type application/javascript
header Content-Type application/json
header Content-Type application/ld+json
header Content-Type application/manifest+json
header Content-Type application/rss+xml
header Content-Type application/vnd.geo+json
header Content-Type application/vnd.ms-fontobject
header Content-Type application/wasm
header Content-Type application/x-font-ttf
header Content-Type application/x-web-app-manifest+json
header Content-Type application/xhtml+xml
header Content-Type application/xml
header Content-Type font/opentype
header Content-Type image/bmp
header Content-Type image/svg+xml
header Content-Type image/x-icon
header Content-Type text/cache-manifest
header Content-Type text/css
header Content-Type text/plain
header Content-Type text/vcard
header Content-Type text/vnd.rim.location.xloc
header Content-Type text/vtt
header Content-Type text/x-component
header Content-Type text/x-cross-domain-policy
}
}
header {
# Based on following source:
# https://raw.githubusercontent.com/nextcloud/docker/refs/heads/master/.examples/docker-compose/insecure/mariadb/fpm/web/nginx.conf
#
# HSTS settings
# WARNING: Only add the preload option once you read about
# the consequences in https://hstspreload.org/. This option
# will add the domain to a hardcoded list that is shipped
# in all major browsers and getting removed from this list
# could take several months.
# Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;"
Strict-Transport-Security: "max-age=31536000; includeSubDomains;"
# HTTP response headers borrowed from Nextcloud `.htaccess`
Referrer-Policy no-referrer
X-Content-Type-Options nosniff
X-Download-Options noopen
X-Frame-Options SAMEORIGIN
X-Permitted-Cross-Domain-Policies none
X-Robots-Tag "noindex,nofollow"
X-XSS-Protection "1; mode=block"
Permissions-Policy "accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), cross-origin-isolated=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), keyboard-map=(), magnetometer=(), microphone=(), midi=(), navigation-override=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), screen-wake-lock=(), sync-xhr=(), usb=(), web-share=(), xr-spatial-tracking=()"
}
# Path to the root of your installation
root * /var/www/html
handle_path /push/* {
reverse_proxy http://notify_push:7867
}
route {
# Rule borrowed from `.htaccess` to handle Microsoft DAV clients
@msftdavclient {
header User-Agent DavClnt*
path /
}
redir @msftdavclient /remote.php/webdav/ temporary
route /robots.txt {
log_skip
file_server
}
# Add exception for `/.well-known` so that clients can still access it
# despite the existence of the `error @internal 404` rule which would
# otherwise handle requests for `/.well-known` below
route /.well-known/* {
redir /.well-known/carddav /remote.php/dav/ permanent
redir /.well-known/caldav /remote.php/dav/ permanent
@well-known-static path \
/.well-known/acme-challenge /.well-known/acme-challenge/* \
/.well-known/pki-validation /.well-known/pki-validation/*
route @well-known-static {
try_files {path} {path}/ =404
file_server
}
redir * /index.php{path} permanent
}
@internal path \
/build /build/* \
/tests /tests/* \
/config /config/* \
/lib /lib/* \
/3rdparty /3rdparty/* \
/templates /templates/* \
/data /data/* \
\
/.* \
/autotest* \
/occ* \
/issue* \
/indie* \
/db_* \
/console*
error @internal 404
@assets {
path *.css *.js *.svg *.gif *.png *.jpg *.jpeg *.ico *.wasm *.tflite *.map *.wasm2
file {path} # Only if requested file exists on disk, otherwise /index.php will take care of it
}
route @assets {
header /* Cache-Control "max-age=15552000" # Cache-Control policy borrowed from `.htaccess`
header /*.woff2 Cache-Control "max-age=604800" # Cache-Control policy borrowed from `.htaccess`
log_skip # Optional: Don't log access to assets
file_server {
precompressed gzip
}
}
# Rule borrowed from `.htaccess`
redir /remote/* /remote.php{path} permanent
# Serve found static files, continuing to the PHP default handler below if not found
try_files {path} {path}/
@notphpordir not path /*.php /*.php/* / /*/
file_server @notphpordir {
pass_thru
}
# Required for legacy support
#
# Rewrites all other requests to be prepended by “/index.php” unless they match a known-valid PHP file path.
@notlegacy {
path *.php *.php/
not path /index*
not path /remote*
not path /public*
not path /cron*
not path /core/ajax/update*
not path /status*
not path /ocs/v1*
not path /ocs/v2*
not path /ocs-provider/*
not path /updater/*
not path */richdocumentscode/proxy*
}
rewrite @notlegacy /index.php{uri}
# Let everything else be handled by the PHP-FPM component
php_fastcgi app:9000 {
env modHeadersAvailable true # Avoid sending the security headers twice
env front_controller_active true # Enable pretty urls
}
}
}
Can someone guide what traefik lables I need to add to 'Web' (Caddy) container and is Caddyfile over the top?