From 154c4212719edb8bcdc4ce57e76aba0fe167728b Mon Sep 17 00:00:00 2001 From: Ivan Gabaldon Date: Tue, 6 Aug 2024 12:50:09 +0200 Subject: [PATCH 1/4] rework Caddyfile --- Caddyfile | 171 ++++++++++++++++++++------------------------ docker-compose.yaml | 3 +- 2 files changed, 79 insertions(+), 95 deletions(-) diff --git a/Caddyfile b/Caddyfile index dea6806..83802cb 100644 --- a/Caddyfile +++ b/Caddyfile @@ -1,99 +1,84 @@ { - admin off + admin off + + log { + output stderr + format filter { + # Preserves fist 8 bits from IPv4 and 32 bits from IPv6 + request>remote_ip ip_mask 8 32 + request>client_ip ip_mask 8 32 + + # Remove identificable information + request>remote_port delete + request>headers delete + request>uri query { + delete url + delete h + delete q + } + } + } } -{$SEARXNG_HOSTNAME} { - log { - output discard - } +{$SEARXNG_HOSTNAME:http://localhost} - tls {$SEARXNG_TLS} - - @api { - path /config - path /healthz - path /stats/errors - path /stats/checker - } - - @static { - path /static/* - } - - @notstatic { - not path /static/* - } - - @imageproxy { - 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" - - # 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" - - # 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'" - - # Referer - Referrer-Policy "no-referrer" - - # X-Robots-Tag - X-Robots-Tag "noindex, noarchive, nofollow" - - # Remove Server header - -Server - } - - 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 @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" - } - - # SearXNG - handle { - encode zstd gzip - - reverse_proxy localhost:8080 { - header_up X-Forwarded-Port {http.request.port} - header_up X-Forwarded-Proto {http.request.scheme} - header_up X-Real-IP {remote_host} - } - } +tls {$SEARXNG_TLS:internal} +@api { + path /config + path /healthz + path /stats/errors + path /stats/checker +} + +@static { + path /static/* +} + +@imageproxy { + path /image_proxy +} + +header { + # Force clients to use HTTPS + Strict-Transport-Security "max-age=31536000" + + # Prevent MIME type sniffing from the declared Content-Type + X-Content-Type-Options "nosniff" + + # Disable some browser features + Permissions-Policy "accelerometer=(),ambient-light-sensor=(),autoplay=(),battery=(),camera=(),cross-origin-isolated=(),display-capture=(self),document-domain=(),encrypted-media=(),execution-while-not-rendered=(),execution-while-out-of-viewport=(),fullscreen=(self),geolocation=(),gyroscope=(),keyboard-map=(self),magnetometer=(),microphone=(),midi=(),navigation-override=(self),payment=(),picture-in-picture=(),publickey-credentials-get=(),screen-wake-lock=(),sync-xhr=(),usb=(),web-share=(),xr-spatial-tracking=()" + + # Set referrer policy + Referrer-Policy "no-referrer" + + # X-Robots-Tag (comment to allow site indexing) + X-Robots-Tag "noindex, noarchive, nofollow" + + # Remove "Server" header + -Server +} + +header @api { + Access-Control-Allow-Methods "GET, OPTIONS" + Access-Control-Allow-Origin "*" +} + +route { + # Caching + header Cache-Control "no-cache, no-store" + header @static Cache-Control "max-age=31536000" + + # CSP (https://content-security-policy.com) + header 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 @imageproxy Content-Security-Policy "default-src 'none'; img-src 'self' data:" +} + +# SearXNG (uWSGI) +reverse_proxy localhost:8080 { + header_up X-Forwarded-Port {http.request.port} + header_up X-Real-IP {http.request.remote.host} + + # https://github.com/searx/searx-docker/issues/24 + header_up Connection "close" } diff --git a/docker-compose.yaml b/docker-compose.yaml index bfd21fe..d8b4e17 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -11,8 +11,7 @@ services: - caddy-data:/data:rw - caddy-config:/config:rw environment: - - SEARXNG_HOSTNAME=${SEARXNG_HOSTNAME:-http://localhost:80} - - SEARXNG_TLS=${LETSENCRYPT_EMAIL:-internal} + - SEARXNG_TLS=${LETSENCRYPT_EMAIL} cap_drop: - ALL cap_add: From d8d9e0970586d5da0d999e3bdd8b6d6a66b9025b Mon Sep 17 00:00:00 2001 From: Ivan Gabaldon Date: Tue, 6 Aug 2024 13:12:30 +0200 Subject: [PATCH 2/4] fix missing "public" directive --- Caddyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Caddyfile b/Caddyfile index 83802cb..943063b 100644 --- a/Caddyfile +++ b/Caddyfile @@ -67,7 +67,7 @@ header @api { route { # Caching header Cache-Control "no-cache, no-store" - header @static Cache-Control "max-age=31536000" + header @static Cache-Control "public, max-age=31536000" # CSP (https://content-security-policy.com) header 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" From 5d066a4c63e102d4966e7baccc1072ffae732fa7 Mon Sep 17 00:00:00 2001 From: Ivan Gabaldon Date: Fri, 23 Aug 2024 22:12:45 +0200 Subject: [PATCH 3/4] features cleanup Since this header is attached to each outgoing request the overall size is slightly increased by 300 bytes, we don't care if the site is allowed to play media in the background, so with the vast majority of features that have been added (and those that were already present) --- Caddyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Caddyfile b/Caddyfile index 943063b..c567168 100644 --- a/Caddyfile +++ b/Caddyfile @@ -47,7 +47,7 @@ header { X-Content-Type-Options "nosniff" # Disable some browser features - Permissions-Policy "accelerometer=(),ambient-light-sensor=(),autoplay=(),battery=(),camera=(),cross-origin-isolated=(),display-capture=(self),document-domain=(),encrypted-media=(),execution-while-not-rendered=(),execution-while-out-of-viewport=(),fullscreen=(self),geolocation=(),gyroscope=(),keyboard-map=(self),magnetometer=(),microphone=(),midi=(),navigation-override=(self),payment=(),picture-in-picture=(),publickey-credentials-get=(),screen-wake-lock=(),sync-xhr=(),usb=(),web-share=(),xr-spatial-tracking=()" + Permissions-Policy "accelerometer=(),camera=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),payment=(),usb=()" # Set referrer policy Referrer-Policy "no-referrer" From a99c06801df3165534ff3a82f2d7996fa8f9c867 Mon Sep 17 00:00:00 2001 From: Ivan Gabaldon Date: Fri, 23 Aug 2024 22:19:39 +0200 Subject: [PATCH 4/4] restore encode directive Caddyserver actually did passthrough the precompressed resources served by uWSGI (Oops) --- Caddyfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Caddyfile b/Caddyfile index c567168..c415e3a 100644 --- a/Caddyfile +++ b/Caddyfile @@ -24,6 +24,8 @@ tls {$SEARXNG_TLS:internal} +encode zstd gzip + @api { path /config path /healthz