Searx - using my own Caddy

The Searx-docker quick start does a couple of things that I understand, but don't really like. One is cloning the repo to get things set up & the other is hard coding the reverse proxy into the docker-compose file (even if it is Caddy, which I use already).
It's not a great idea to expose a Searx installation to the outside without some of the protections that come baked into that hard coded setup though, so I did some searching.
Turns out that using Filtron to reach Searx (& using the filtering rules that are in that github repo) is a good idea, but there's no need for the Caddy proxy that they baked in.
So, the aim is to get a Caddy instance that's already running to kick off the Searx container, via Filtron's filtering, without running anything more than I need to.
Step 1 - (re)write the docker-compose file
version: "2"
services:
filtron:
container_name: filtron
image: dalf/filtron
restart: always
ports:
- 4040:4040
- 4041:4041
networks:
- searx
command: -listen 0.0.0.0:4040 -api 0.0.0.0:4041 -target searx:8080
volumes:
- ~/docker/searx/filtron/rules.json:/etc/filtron/rules.json:rw
read_only: true
cap_drop:
- ALL
searx:
container_name: searx
image: searx/searx:latest
restart: always
networks:
- searx
# command: ${SEARX_COMMAND:-} #comment this line if you made / will make some modifications to the settings
volumes:
- ~/docker/searx:/etc/searx:rw
environment:
- BIND_ADDRESS=0.0.0.0:8080 #10137
- BASE_URL=${MY_SEARX_URL}
- MORTY_URL=${MY_SEARX_URL}/morty/
- MORTY_KEY=${MORTY_KEY}
cap_drop:
- ALL
cap_add:
- CHOWN
- SETGID
- SETUID
- DAC_OVERRIDE
morty:
container_name: morty
image: dalf/morty
restart: always
ports:
- 3000:3000
networks:
- searx
command: -timeout 6 -ipv6
environment:
- MORTY_KEY=${MORTY_KEY}
- MORTY_ADDRESS=0.0.0.0:3000
logging:
driver: none
read_only: true
cap_drop:
- ALL
networks:
searx:
ipam:
driver: default
You'll note that there are a couple of places in there where you could either hard code or use an environment variable to set things up.
${MORTY_KEY} should be created as suggested in the github site (or do something yourself!)
${MY_SEARX_URL} would be something like https://searx/mydomain.com (& you'll need a https://searx/mydomain.com/morty too).
Step 2 - Get Filtron Ready
No point in having a filtering proxy if there are no rules to go with it.
You'll need to create the rules file at "~/docker/searx/filtron/rules.json" (Assuming that's the place that you specified in the docker-compose!)
nano ~/docker/searx/filtron/rules.json
Then just paste in the rules. (Be careful that you copy all of the brackets at the start & end (ask me how i know!)).
Step 3 - set up Caddy
Mainly this was a matter of adding the rules to the bottom of my Caddyfile & making them associate with the subdomain that I use for Searx (${MY_SEARX_URL} in the docker-compose file above). I've used that format for the reference in the snippet below, you'll need to do a search & replace in order to use it for your version. N.B. If you use an internal IP address then all of the ${MY_SEARX_URL} after that first one (on line 1) will need to be the IP address of the machine running your docker containers!
${MY_SEARX_URL} {
log {
output file /config/searx_${MY_SEARX_URL}.txt {
roll_size 10mb
roll_keep 3
roll_keep_for 2160h
}
}
@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 detec ted 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=(); au toplay=();camera=();encrypted-media=();focus-without-user-activation=(); geoloca tion=();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-activa tion '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 @morty {
Content-Security-Policy "default-src 'none'; style-src 'self' 'u nsafe-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' ht tps://overpass-api.de; img-src 'self' data: https://*.tile.openstreetmap.org; fr ame-src https://www.youtube-nocookie.com https://player.vimeo.com https://www.da ilymotion.com https://www.deezer.com https://www.mixcloud.com https://w.soundclo ud.com https://embed.spotify.com"
}
# Morty
handle @morty {
reverse_proxy ${MY_SEARX_URL}:3000
}
# Filtron
handle {
encode zstd gzip
reverse_proxy ${MY_SEARX_URL}: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}
}
}
Go Go Go
So, we've got the Caddy config set up, to point to the filtron instance, which was started with the docker-compose that we created in step 1. All we now need to do is create/update the CNAME for ${MY_SEARX_URL}, reload the Caddyfile (to update Caddy's instructions & to get the https certificate to go with ${MY_SEARX_URL} ) then run the docker-compose (or run it as a stack from portainer) & we're good to go!
You can test it from outside of your network, but don't forget to update your internal DNS settings if you want to use the ${MY_SEARX_URL} from inside your network (or just use the IP address & port of the server)