Hosting a Searx instance on OpenBSD

2021.2.4-2021.2.6

!!!: This post comes from my personal notes archive, so it may be confusional and/or not structured as a lesson.

Env

🐡 Installation went smooth as always…

I’ve edited the default disk layout like this:

# df -h
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/sd0a      565M   85.0M    452M    16%    /
/dev/sd0k      986M    2.0K    937M     0%    /home
/dev/sd0d      782M   10.0K    743M     0%    /tmp
/dev/sd0f      2.9G    1.0G    1.7G    38%    /usr
/dev/sd0g      619M    234M    354M    40%    /usr/X11R6
/dev/sd0h      6.9G    218K    6.5G     0%    /usr/local
/dev/sd0e      4.8G    6.9M    4.6G     0%    /var

It’s considered bad to delete some of the proposed partitions but this is an experimental install.

NOTE: I’m following https://searx.github.io/searx/admin/installation-searx.html.

Searx & gunicorn

The Searx installation guide employs uWSGI. I don’t wanna compile uWSGI plugins for OpenBSD at the moment, so to avoid errors like !!! UNABLE to load uWSGI plugin: File not found !!! I’ll install gunicorn instead and improvise.

pkg_add python py3-pip git

ln -s /usr/local/bin/python3.8 /usr/local/bin/python

ln -s /usr/local/bin/pip3.8 /usr/local/bin/pip

pip install gunicorn

Create user _searx that is going to own the gunicorn process.

mkdir /usr/local/searx
useradd -d /usr/local/searx/ -s /sbin/nologin -u 10000 _searx
chown -R _searx:_searx /usr/local/searx/

NOTE: I don’t want to use a Python virtual env for now.

cat /etc/doas.conf
permit setenv { -ENV PS1=$DOAS_PS1 SSH_AUTH_SOCK } :wheel
doas -u _searx git clone "https://github.com/searx/searx.git" \
"/usr/local/searx/searx-src"

pip install -r /usr/local/searx/searx-src/requirements.txt

if

Error: Please make sure the libxml2 and libxslt development packages are installed.

then

pkg_add py3-lxml

fi

Follow the guide for the /etc/searx/settings.yml stuff.

Ok. Try.

cd /usr/local/searx/
doas -u _searx gunicorn -b 127.0.0.1:8001 --chdir /usr/local/searx/searx-src/searx --pythonpath /usr/local/searx/searx-src searx.webapp
[INFO] Listening at: http://127.0.0.1:8001 (93345)

Nice. Daemonize gunicorn. Create /etc/rc.d/gunisearx.

#!/bin/ksh

RUN_DIR="/var/run/gunisearx"
daemon="/usr/local/bin/gunicorn"
gunisearx_flags="-b 127.0.0.1:8001 --chdir /usr/local/searx/searx-src/searx --pythonpath /usr/local/searx/searx-src -p /var/run/gunisearx/gunisearx.pid -D searx.webapp"
gunisearx_user="_searx"

. /etc/rc.d/rc.subr

pexp="/usr/local/bin/python.*${pexp}"

# For the PID file.
rc_pre() {
	if [[ ! -d /var/run/gunisearx ]]; then
		mkdir $RUN_DIR
		chown -R _searx:_searx $RUN_DIR
	fi
}

rc_stop() {
	if [[ -f $RUN_DIR/gunisearx.pid ]]; then
		kill $(cat $RUN_DIR/gunisearx.pid)
		rm $RUN_DIR/gunisearx.pid
	fi
}

rc_cmd $1

Filtron

Compiled filtron on a build VM and copied to the server.

Create user _filtron that is going to own the filtron process. useradd -s /sbin/nologin -u 10001 _filtron

Daemonize filtron. Create /etc/rc.d/filtron.

#!/bin/ksh

daemon="/usr/local/bin/filtron"
filtron_flags="-api '127.0.0.1:4005' -listen '127.0.0.1:4004' -rules '/etc/filtron/rules.json' -target '127.0.0.1:8001'"
filtron_user="_filtron"

rc_bg=YES

. /etc/rc.d/rc.subr

rc_cmd $1

morty

Compiled morty on a build VM and copied to the server.

Create user _morty that is going to own the morty process. useradd -s /sbin/nologin -u 10002 _morty

Daemonize morty. Create /etc/rc.d/morty.

#!/bin/ksh

daemon="/usr/local/bin/morty"
morty_user="_morty"

rc_bg=YES

. /etc/rc.d/rc.subr

rc_cmd $1

Create a login class in /etc/login.conf to set some environment variables:

...other things...

morty:\
	:setenv=DEBUG=false,MORTY_ADDRESS=127.0.0.1\c3000,MORTY_KEY=<key generated with `openssl rand -base64 33`>:\
	:tc=daemon:

Bonus - nginx config

Nginx as reverse proxy and scores A+ at SSL Labs and observatory.mozilla.org. /etc/nginx/nginx.conf

http {

...lots of things...

server {
		listen		443 ssl;
		listen		[::]:443 ssl;
		server_name	searx.fmac.xyz;

		ssl_protocols	TLSv1.2 TLSv1.3;
		ssl_ciphers		ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
		ssl_prefer_server_ciphers	on;

		ssl_certificate		/etc/ssl/searx.fmac.xyz.fullchain.pem;
		ssl_certificate_key	/etc/ssl/private/searx.fmac.xyz.key;

		ssl_session_timeout	1d;
		ssl_session_cache	shared:MozSSL:10m;
		ssl_session_tickets	off;

		location / {
			proxy_pass http://127.0.0.1:4004/;

			include /etc/nginx/searx-proxy-headers.conf;
			include /etc/nginx/searx-default-headers.conf;
			add_header 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" always;
		}

		location /static/ {
			root /var/www/htdocs/searx/;

			include /etc/nginx/searx-default-headers.conf;
			add_header Cache-Control "public, max-age=31536000" always;
		}

		location /morty {
			proxy_pass http://127.0.0.1:3000/;

			include /etc/nginx/searx-proxy-headers.conf;
		}
	}
}

/etc/nginx/searx-default-headers.conf

add_header 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'" always;
add_header Referrer-Policy "no-referrer" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Robots-Tag "noindex, noarchive, nofollow" always;
add_header X-XSS-Protection "1" always;

/etc/nginx/searx-proxy-headers.conf

proxy_hide_header	Referrer-Policy;
proxy_hide_header	X-Content-Type-Options;
proxy_hide_header	X-Robots-Tag;
proxy_hide_header	X-Xss-Protection;
proxy_set_header	Host $host;
proxy_set_header	Connection $http_connection;
proxy_set_header	X-Real-IP $remote_addr;
proxy_set_header	X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header	X-Scheme $scheme;