diff --git a/gateway/caddy/Caddyfile b/gateway/caddy/Caddyfile index e541069..d3dfd83 100644 --- a/gateway/caddy/Caddyfile +++ b/gateway/caddy/Caddyfile @@ -1,4 +1,8 @@ { + crowdsec { + api_url http://crowdsec:8080 + api_key {$CROWDSEC_API_KEY} + } servers { trusted_proxies static private_ranges trusted_proxies_strict @@ -6,38 +10,44 @@ } (secure) { - @static-files { - file - path *.ico *.css *.js *.gif *.webp *.avif *.jpg *.jpeg *.png *.svg *.woff *.woff2 - } + @static-files { + file + path *.ico *.css *.js *.gif *.webp *.avif *.jpg *.jpeg *.png *.svg *.woff *.woff2 + } - header @static-files Cache-Control "max-age=5184000" - header / Cache-Control "no-cache, no-store, must-revalidate" + header @static-files Cache-Control "max-age=5184000" + header / Cache-Control "no-cache, no-store, must-revalidate" - forward_auth authelia:9091 { - uri /api/authz/forward-auth - copy_headers Remote-User Remote-Groups Remote-Name Remote-Email - } + forward_auth authelia:9091 { + uri /api/authz/forward-auth + copy_headers Remote-User Remote-Groups Remote-Name Remote-Email + } } auth.64815139.xyz { - reverse_proxy authelia:9091 + route { + crowdsec + reverse_proxy authelia:9091 + } } www.64815139.xyz { - import secure * + route { + crowdsec + import secure * - root * /var/www/dashboard - encode gzip - file_server + root * /var/www/dashboard + encode gzip + file_server + } - log { - output file /var/log/caddy/dashboard.log - } + log { + output file /var/log/caddy/dashboard.log + } } 64815139.xyz { - redir https://www.{host}{uri} + redir https://www.{host}{uri} } search.64815139.xyz { @@ -45,109 +55,120 @@ search.64815139.xyz { output discard } - import secure * + import secure * - @api { - path /config - path /healthz - path /stats/errors - path /stats/checker - } + @api { + path /config + path /healthz + path /stats/errors + path /stats/checker + } - @static { - path /static/* - } + @static { + path /static/* + } - @notstatic { - not path /static/* - } + @notstatic { + not path /static/* + } - @imageproxy { - path /image_proxy - } + @imageproxy { + path /image_proxy + } - @notimageproxy { - not path /image_proxy - } + @notimageproxy { + not path /image_proxy + } - header { - # Enable HTTP Strict Transport Security (HSTS) to force clients to always connect via HTTPS - Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" + 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" + # 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" + # Prevent some browsers from MIME-sniffing a response away from the declared Content-Type + X-Content-Type-Options "nosniff" - # 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=()" + # 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=()" - # Disable some features (legacy) - Feature-Policy "accelerometer 'none';ambient-light-sensor 'none'; autoplay 'none';camera 'none';encrypted-media 'none';focus-without-user-activation 'none'; geolocation 'none';gyroscope 'none';magnetometer 'none';microphone 'none';midi 'none';payment 'none';picture-in-picture 'none'; speaker 'none';sync-xhr 'none';usb 'none';vr 'none'" + # Disable some features (legacy) + Feature-Policy "accelerometer 'none';ambient-light-sensor 'none'; autoplay 'none';camera 'none';encrypted-media 'none';focus-without-user-activation 'none'; geolocation 'none';gyroscope 'none';magnetometer 'none';microphone 'none';midi 'none';payment 'none';picture-in-picture 'none'; speaker 'none';sync-xhr 'none';usb 'none';vr 'none'" - # Referer - Referrer-Policy "no-referrer" + # Referer + Referrer-Policy "no-referrer" - # X-Robots-Tag - X-Robots-Tag "noindex, noarchive, nofollow" + # X-Robots-Tag + X-Robots-Tag "noindex, noarchive, nofollow" - # Remove Server header - -Server - } + # Remove Server header + -Server + } - header @api { - Access-Control-Allow-Methods "GET, OPTIONS" - Access-Control-Allow-Origin "*" - } + header @api { + Access-Control-Allow-Methods "GET, OPTIONS" + Access-Control-Allow-Origin "*" + } - # Cache - header @static { - # Cache - Cache-Control "public, max-age=31536000" - defer - } + # Cache + header @static { + # Cache + Cache-Control "public, max-age=31536000" + defer + } - header @notstatic { - # No Cache - Cache-Control "no-cache, no-store" - Pragma "no-cache" - } + header @notstatic { + # No Cache + Cache-Control "no-cache, no-store" + Pragma "no-cache" + } - # CSP (see http://content-security-policy.com/ ) - header @imageproxy { - Content-Security-Policy "default-src 'none'; img-src 'self' data:" - } + # CSP (see http://content-security-policy.com/ ) + header @imageproxy { + Content-Security-Policy "default-src 'none'; img-src 'self' data:" + } - header @notimageproxy { - Content-Security-Policy "upgrade-insecure-requests; default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; form-action 'self' https://github.com/searxng/searxng/issues/new; 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" - } + header @notimageproxy { + Content-Security-Policy "upgrade-insecure-requests; default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; form-action 'self' https://github.com/searxng/searxng/issues/new; 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" + } - - handle { + handle { encode zstd gzip - reverse_proxy 192.168.0.210:8080 { - header_up X-Forwarded-Port {http.request.port} - header_up X-Forwarded-Proto {http.request.scheme} - header_up X-Real-IP {remote_host} - } - } + reverse_proxy 192.168.0.210:8080 { + header_up X-Forwarded-Port {http.request.port} + header_up X-Forwarded-Proto {http.request.scheme} + header_up X-Real-IP {remote_host} + } + } } gitea.64815139.xyz { - rewrite /user/login /user/oauth2/Authelia - reverse_proxy 192.168.0.210:3000 + route { + crowdsec + rewrite /user/login /user/oauth2/Authelia + reverse_proxy 192.168.0.210:3000 + } } immich.64815139.xyz { - reverse_proxy 192.168.0.210:2283 + route { + crowdsec + reverse_proxy 192.168.0.210:2283 + } } uptime.64815139.xyz { - reverse_proxy 192.168.0.210:4393 + route { + crowdsec + reverse_proxy 192.168.0.210:4393 + } } oaT3cqYuCAegcoM4Xc4Pun1BUMOschxR.64815139.xyz { - reverse_proxy 192.168.0.210:4449 + route { + crowdsec + reverse_proxy 192.168.0.210:4449 + } } diff --git a/gateway/caddy/Dockerfile b/gateway/caddy/Dockerfile new file mode 100644 index 0000000..7020cb7 --- /dev/null +++ b/gateway/caddy/Dockerfile @@ -0,0 +1,15 @@ +ARG CADDY_VERSION=2 + +FROM caddy:${CADDY_VERSION}-builder-alpine AS builder + +RUN xcaddy build \ + --with github.com/mholt/caddy-l4 \ + --with github.com/caddyserver/transform-encoder \ + --with github.com/hslatman/caddy-crowdsec-bouncer/http@main \ + --with github.com/hslatman/caddy-crowdsec-bouncer/layer4@main + +FROM caddy:${CADDY_VERSION} AS caddy + +WORKDIR / + +COPY --from=builder /usr/bin/caddy /usr/bin/caddy diff --git a/gateway/caddy/crowdsec/acquis.yaml b/gateway/caddy/crowdsec/acquis.yaml new file mode 100644 index 0000000..91c9d1d --- /dev/null +++ b/gateway/caddy/crowdsec/acquis.yaml @@ -0,0 +1,4 @@ +filenames: + - /var/log/caddy/*.log +labels: + type: caddy diff --git a/gateway/docker-compose.yml b/gateway/docker-compose.yml index 84dc60a..5368aac 100644 --- a/gateway/docker-compose.yml +++ b/gateway/docker-compose.yml @@ -80,18 +80,45 @@ services: volumes: - ./data/redis:/data caddy: - image: caddy:2.8.4-alpine + build: + context: ./caddy + target: caddy container_name: gateway_caddy + depends_on: + - crowdsec restart: unless-stopped ports: - "80:80" - "443:443" - "443:443/udp" + env_file: + - ./secrets/caddy/.env volumes: - ./caddy/Caddyfile:/etc/caddy/Caddyfile - ./dashboard:/var/www/dashboard - caddy_data:/data - caddy_config:/config + networks: + crowdsec: + security_opt: + - no-new-privileges=true + crowdsec: + image: docker.io/crowdsecurity/crowdsec:latest + container_name: gateway_crowdsec + environment: + - GID=1000 + - COLLECTIONS=crowdsecurity/caddy crowdsecurity/http-cve crowdsecurity/whitelist-good-actors + env_file: + - ./secrets/crowdsec/.env + volumes: + - ./crowdsec/data:/var/lib/crowdsec/data/ + - ./caddy/crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml + - caddy_logs:/var/log/caddy:ro + networks: + crowdsec: + restart: unless-stopped + security_opt: + - no-new-privileges=true ddns: image: timothyjmiller/cloudflare-ddns:latest container_name: gateway_cloudflare_ddns @@ -121,5 +148,9 @@ services: volumes: - /var/run/docker.sock:/var/run/docker.sock volumes: + caddy_logs: caddy_data: - caddy_config: \ No newline at end of file + caddy_config: +networks: + crowdsec: + driver: bridge \ No newline at end of file