- Overview
- Basic installation
- Setting up a reverse proxy
- Public server setup
- Additional hardening (OS-level)
- Update and Maintain
This guide describes how to install searXNG on a private or public server running FreeBSD or HardenedBSD, whereby installing searXNG on HardenedBSD is no different than installing it on vanilla FreeBSD.
This guide is based on the official docs.
⚠️ Don't just copy-paste any of the configuration files that are provided here, make sure you understand what they are doing by yourself. No guarantee is given for their correctness.
Install the python runtime, uWSGI, git and other mandatory tools from the ports collection:
pkg install python311 py311-sqlite3 uwsgi-py311 git-tiny libxslt ca_root_nss
⚠️ This will force to install the Python 3.11.x series, which is EOL 2027-10. Make sure to upgrade before reaching that date.
Create a new unprivileged user to later run searXNG as:
pw useradd -n searx -m -M 750 -s csh -w no
Clone the git repository to the newly created users home directory:
su -l searx -c 'git clone "https://github.com/searxng/searxng" searxng'
Create a new virtual environment where we will install the required python modules into:
su -l searx -c 'python3.11 -m venv venv'
Make the virtual environment activates automatically as soon as the user is logging in:
su -l searx -c 'echo "source /home/searx/venv/bin/activate.csh" >>~/.cshrc'
ℹ️ To test if the virtual environment has been set up properly, execute the following command:
su -l searx -c 'pip -V'
Output should look like this:
pip 24.0 from /usr/home/searx/venv/lib/python3.11/site-packages/pip (python 3.11)
Update/Install some basic needed packages via pip:
su -l searx -c 'pip install -U pip setuptools wheel pyyaml pybind11'
Install searXNG itself:
su -l searx -c 'cd searxng && pip install --use-pep517 --no-build-isolation -e .'
Under FreeBSD, configuration files from third-party applications belong to /usr/local/etc/
, so
we change the environment variable read by searXNG for that file:
su -l searx -c 'echo "setenv SEARXNG_SETTINGS_PATH /usr/local/etc/searx.yml" >>~/.cshrc'
Create empty configuration file with appropriate permissions:
touch /usr/local/etc/searx.yml && chown root:searx /usr/local/etc/searx.yml && chmod 640 /usr/local/etc/searx.yml
Now edit the file /usr/local/etc/searx.yml
we just created and paste some basic sample configuration in there:
# SearXNG settings
# For further configuration, see https://docs.searxng.org/admin/installation-searxng.html#configuration
use_default_settings: true
general:
debug: false
instance_name: "change_me" # <<< CHANGE THIS
server:
secret_key: "ultrasecretkey" # <<< CHANGE THIS
public_instance: false
limiter: false
image_proxy: false # Change to true if you plan to create a public instance
redis:
url: false
Do not forget to create a new secret key, e.g. by running cat /dev/urandom | env LC_CTYPE=C tr -dc a-zA-Z0-9 | head -c 50 ; echo
⚠️ This will configure a basic searXNG setup, which is NOT intended to be used as a public instance. If you want to make your instance public, read the chapter Public server setup afterwards.
Create the directory that will contain the configuration file:
mkdir /usr/local/etc/uwsgi
Create the configuration file /usr/local/etc/uwsgi/searx.ini
and paste the following config in there:
# -*- mode: conf; coding: utf-8 -*-
[uwsgi]
pidfile = /var/run/searx/uwsgi/searx.pid
disable-logging = true
uid = searx
gid = searx
env = LANG=C.UTF-8
env = LANGUAGE=C.UTF-8
env = LC_ALL=C.UTF-8
chdir = /home/searx/searxng/searx
env = SEARXNG_SETTINGS_PATH=/usr/local/etc/searx.yml
chmod-socket = 660
single-interpreter = true
master = true
lazy-apps = true
enable-threads = true
module = searx.webapp
virtualenv = /home/searx/venv
pythonpath = /home/searx/searxng
socket = /var/run/searx/nginx/searx.socket
buffer-size = 8192
static-map = /static=/home/searx/searxng/searx/static
static-expires = /* 31557600
static-gzip-all = True
offload-threads = %k
SearXNG itself will be started using uWSGI which we just configured.
To start uWSGI, create the file /usr/local/etc/rc.d/searx
and paste the following content in there:
#!/bin/sh
# PROVIDE: searx
# REQUIRE: LOGIN FILESYSTEMS
# KEYWORD: shutdown
. /etc/rc.subr
name="searx"
rcvar="searx_enable"
: ${searx_enable:=NO}
pidfile="/var/run/searx/uwsgi/searx.pid"
procname="/usr/local/bin/uwsgi"
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
command="/usr/local/bin/uwsgi"
command_args="--ini /usr/local/etc/uwsgi/searx.ini --daemonize /dev/null"
stop_cmd="${name}_stop"
searx_stop()
{
/usr/local/bin/uwsgi --stop /var/run/searx/uwsgi/searx.pid
while [ "$(ps -x -U searx | grep $(cat /var/run/searx/uwsgi/searx.pid))" != "" ]; do
echo "Waiting for UWSGI to shut down..."
sleep 1
done
echo "Finished shutting UWSGI down."
}
start_precmd="${name}_prestart"
searx_prestart()
{
if [ -f /var/run/searx/uwsgi/searx.pid ] || [ -f /var/run/searx/nginx/searx.socket ]; then
echo "Warning: Service was not shut down properly!"
rm -f -- /var/run/searx/uwsgi/searx.pid /var/run/searx/nginx/searx.socket
fi
if ! [ -d /var/run/searx ]; then
mkdir -m 0775 /var/run/searx && chown root:wheel /var/run/searx
fi
if ! [ -d /var/run/searx/uwsgi ]; then
mkdir -m 0770 /var/run/searx/uwsgi && chown root:uwsgi /var/run/searx/uwsgi
fi
if ! [ -d /var/run/searx/redis ]; then
mkdir -m 0770 /var/run/searx/redis && chown searx:redis /var/run/searx/redis 2>/dev/null
fi
if ! [ -d /var/run/searx/nginx ]; then
mkdir -m 0770 /var/run/searx/nginx && chown searx:nobody /var/run/searx/nginx
fi
}
stop_postcmd="${name}_poststop"
searx_poststop()
{
rm -f -- /var/run/searx/uwsgi/searx.pid /var/run/searx/nginx/searx.socket
}
load_rc_config ${name}
run_rc_command "$1"
ℹ️ The reason we don't use the provided rc script by the package
uwsgi-py311
is for improving security by not making any UNIX socket accessible by a user not intended for accessing it and to make sure any runtime-related files are unified in the directory/var/run/searx
.
Now make the rc script executable:
chmod a+x /usr/local/etc/rc.d/searx
To start/stop searXNG use the well-known commands:
service searx onestart
service searx onestop
To confirm searXNG is running as intended, confirm the existance of the UNIX domain socket that will be used by a reverse proxy
that will be configured in Setting up a reverse proxy:
sockstat -lu | grep searx
Output should look like this:
searx uwsgi-3.11 2059 3 stream /var/run/searx/nginx/searx.socket
searx uwsgi-3.11 1676 3 stream /var/run/searx/nginx/searx.socket
ℹ️ In case searXNG is not working properly, enable debug mode in
/usr/local/etc/searx.yml
and run uWSGI manually via command line (/usr/local/bin/uwsgi --ini /usr/local/etc/uwsgi/searx.ini
) and observe its output.
We will use Nginx as our reverse proxy:
pkg install nginx
Edit /usr/local/etc/nginx/nginx.conf
by removing its existing configuration and replace it with the following, recommended one:
user nobody;
worker_processes auto;
events {
worker_connections 2048;
multi_accept off;
}
http {
sendfile on;
tcp_nopush on;
include /usr/local/etc/nginx/mime.types;
default_type application/octet-stream;
access_log /dev/null;
error_log /dev/null;
gzip on;
server_tokens off;
include /usr/local/etc/nginx/searx.vhost;
}
Also create the file /usr/local/etc/nginx/searx.vhost
with the following content:
server {
listen xxx.xxx.xxx.xxx:80; # <<< CHANGE THIS
server_name _;
root /dev/null/;
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 405;
}
add_header X-Frame-Options "SAMEORIGIN";
add_header X-DNS-Prefetch-Control "off";
add_header Content-Security-Policy "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";
add_header Permissions-Policy "accelerometer=(); ambient-light-sensor=(); autoplay=(); battery=(); camera=(); display-capture=(); encrypted-media=(); fullscreen=(); geolocation=(); gyroscope=(); idle-detection=(); magnetometer=(); microphone=(); midi=(); payment=(); picture-in-picture=(); screen-wake-lock=(); serial=(); usb=(); web-share=(); xr-spatial-tracking=(); clipboard-read=(); clipboard-write=(); gamepad=(); speaker-selection=()";
add_header Feature-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; battery 'none'; camera 'none'; display-capture 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; idle-detection 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; screen-wake-lock 'none'; serial 'none'; usb 'none'; web-share 'none'; xr-spatial-tracking 'none'; clipboard-read 'none'; clipboard-write 'none'; gamepad 'none'; speaker-selection 'none'";
location / {
include uwsgi_params;
uwsgi_pass unix:///var/run/searx/nginx/searx.socket;
uwsgi_param HTTP_HOST $host;
uwsgi_param HTTP_CONNECTION $http_connection;
uwsgi_param HTTP_X_SCHEME $scheme;
uwsgi_param HTTP_X_REAL_IP $remote_addr;
uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
}
}
Nginx can be simply started with the command service nginx onestart
.
After starting Nginx, searXNG should be accessible using your webbrowser by navigating to the address configured
in the server directive in /usr/local/etc/nginx/searx.vhost
.
Public instances should be using (and enforcing) modern TLS encryption. For your convenience, the relevant configuration files for Nginx are provided as a sample here:
nginx.conf
user nobody;
worker_processes auto;
events {
worker_connections 2048;
multi_accept off;
}
http {
sendfile on;
tcp_nopush on;
include /usr/local/etc/nginx/mime.types;
default_type application/octet-stream;
access_log /dev/null;
error_log /dev/null;
gzip on;
server_tokens off;
# Recommended TLS options disabling some weak ciphers
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_prefer_server_ciphers off;
# Uncomment the following limit_* options if you want to use rate limiting on all client queries
# (this is independent of the searXNG built-in rate limiter)
#limit_req_zone $binary_remote_addr zone=limitReq:10m rate=80r/s;
#limit_conn_zone $binary_remote_addr zone=limitConn:10m;
# Uncomment the following line only if you are using "Nginx ultimate bad bot blocker" (see chapter 4.3)
#include /usr/local/etc/nginx/conf.d/*.conf;
include /usr/local/etc/nginx/searx.vhost;
}
searx.vhost
server {
listen xxx.xxx.xxx.xxx:80; # <<< CHANGE THIS
server_name example.com; # <<< CHANGE THIS
root /dev/null/;
# Uncomment the following line only if you are using "Nginx ultimate bad bot blocker" (see chapter 4.3)
#include /usr/local/etc/nginx/bots.d/blockbots.conf;
return 301 https://$host$request_uri; # Redirect to https
}
server {
listen xxx.xxx.xxx.xxx:443 ssl http2; # <<< CHANGE THIS
server_name example.com; # <<< CHANGE THIS
root /dev/null/;
# Uncomment the following line only if you are using "Nginx ultimate bad bot blocker" (see chapter 4.3)
#include /usr/local/etc/nginx/bots.d/blockbots.conf;
ssl_certificate /path/to/certificate.crt; # <<< CHANGE THIS
ssl_certificate_key /path/to/private.key; # <<< CHANGE THIS
if ($request_method !~ ^(GET|HEAD|POST)$ ) {
return 405;
}
add_header Strict-Transport-Security "max-age=31536000; preload" always;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-DNS-Prefetch-Control "off";
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";
add_header Permissions-Policy "accelerometer=(); ambient-light-sensor=(); autoplay=(); battery=(); camera=(); display-capture=(); encrypted-media=(); fullscreen=(); geolocation=(); gyroscope=(); idle-detection=(); magnetometer=(); microphone=(); midi=(); payment=(); picture-in-picture=(); screen-wake-lock=(); serial=(); usb=(); web-share=(); xr-spatial-tracking=(); clipboard-read=(); clipboard-write=(); gamepad=(); speaker-selection=()";
add_header Feature-Policy "accelerometer 'none'; ambient-light-sensor 'none'; autoplay 'none'; battery 'none'; camera 'none'; display-capture 'none'; encrypted-media 'none'; fullscreen 'none'; geolocation 'none'; gyroscope 'none'; idle-detection 'none'; magnetometer 'none'; microphone 'none'; midi 'none'; payment 'none'; picture-in-picture 'none'; screen-wake-lock 'none'; serial 'none'; usb 'none'; web-share 'none'; xr-spatial-tracking 'none'; clipboard-read 'none'; clipboard-write 'none'; gamepad 'none'; speaker-selection 'none'";
# Uncomment to block additional robots from indexing / archiving your site
# Also comment the automatically set header by searXNG in its config file searx.yml, otherwise there will be two headers
#add_header X-Robots-Tag "noindex, noimageindex, nosnippet, notranslate, noarchive, nofollow";
location / {
# Uncomment the following limit_* options if you want to use rate limiting on all client queries (see nginx.conf)
# Don't forget to also uncomment the relevant options in nginx.conf
#limit_req zone=limitReq burst=80;
#limit_conn limitConn 80;
#limit_rate 2m;
#limit_rate_after 4m;
include uwsgi_params;
uwsgi_pass unix:///var/run/searx/nginx/searx.socket;
uwsgi_param HTTP_HOST $host;
uwsgi_param HTTP_CONNECTION $http_connection;
uwsgi_param HTTP_X_SCHEME $scheme;
uwsgi_param HTTP_X_REAL_IP $remote_addr;
uwsgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;
}
}
While being optional, it is highly recommended to enable the built-in rate limiting capability from searXNG.
The rate limiter requires a running redis instance, which will be installed like that:
pkg install redis62
⚠️ This will force to install the Redis 6.2.x series. Make sure to upgrade before this version reaches EOL.
Edit /usr/local/etc/redis.conf
by removing its existing configuration and replace it with the following, recommended one:
daemonize yes
pidfile /var/run/searx/redis/redis.pid
supervised no
cluster-enabled no
gopher-enabled no
latency-monitor-threshold 0
syslog-enabled no
crash-log-enabled no
loglevel warning
logfile /var/log/redis/redis.log
always-show-logo no
set-proc-title no
protected-mode yes
save ""
appendonly no
acllog-max-len 0
port 0
unixsocket /var/run/searx/redis/redis.socket
unixsocketperm 777
timeout 0
databases 1
maxmemory 20M
maxmemory-policy allkeys-lfu
maxmemory-samples 5
oom-score-adj no
Also create the rc script for our redis instance by creating the file /usr/local/etc/rc.d/redis_searx
with the following content:
#!/bin/sh
# PROVIDE: redis_searx
# REQUIRE: LOGIN FILESYSTEMS
# KEYWORD: shutdown
. /etc/rc.subr
name="redis_searx"
rcvar="redis_searx_enable"
: ${redis_searx_enable:=NO}
: ${redis_searx_user:=redis}
: ${redis_searx_group:=redis}
pidfile="/var/run/searx/redis/redis.pid"
procname="/usr/local/bin/redis-server"
command="/usr/local/bin/redis-server"
command_args="/usr/local/etc/redis.conf"
start_precmd="${name}_prestart"
redis_searx_prestart()
{
if [ -f /var/run/searx/redis/redis.pid ] || [ -f /var/run/searx/redis/redis.socket ]; then
echo "Warning: Service did not shut down properly!"
rm -f -- /var/run/searx/redis/redis.pid /var/run/searx/redis/redis.socket
fi
if ! [ -d /var/run/searx/redis ]; then
mkdir -p -m 0775 /var/run/searx && chown root:wheel /var/run/searx
mkdir -m 0770 /var/run/searx/redis
fi
chown searx:redis /var/run/searx/redis
}
stop_postcmd="${name}_poststop"
redis_searx_poststop()
{
rm -f -- /var/run/searx/redis/redis.pid /var/run/searx/redis/redis.socket
}
load_rc_config ${name}
run_rc_command "$1"
Make the rc script executable:
chmod a+x /usr/local/etc/rc.d/redis_searx
To start/stop the redis instance use the well-known commands:
service redis_searx onestart
service redis_searx onestop
⚠️ Make sure to start redis using our custom rc script, not the default one.
Now edit the searXNG configuration file and make sure the following options are set:
server:
limiter: true
public_instance: true
image_proxy: true # Recommended to prevent clients from connecting directly to third-party websites
redis:
url: unix:///var/run/searx/redis/redis.socket?db=0
If not done already, restart searXNG.
To confirm the limiter plugin is working properly, connect to the redis instance and output its current keys:
redis-cli -s /var/run/searx/redis/redis.socket
keys *
After performing a sample search query (in your browser), the output of keys *
should look roughly like this:
1) "SearXNG_limiter.token"
2) "SearXNG_ddg_AXjaR2HXxgpsli1AYtaXaR9CrsIUZFpKN0m640lv6Lqc0rugRUe0KDZa0TbyZnBXJKO"
To increase the efforts in blocking bots, one can use nginx-ultimate-bad-bot-blocker (for Nginx) or apache-ultimate-bad-bot-blocker (for Apache).
Follow the install instructions and, if wanted, block some additional bots which are only rate-limited by default by the
bot blocker by editing the file /usr/local/etc/nginx/bots.d/blacklist-user-agents.conf
and add the following lines under
the section "MY BLACKLIST":
# ------------
# MY BLACKLIST
# ------------
"~*(?:\b)AdsBot-Google(?:\b)" 3;
"~*(?:\b)Applebot(?:\b)" 3;
"~*(?:\b)DoCoMo(?:\b)" 3;
"~*(?:\b)Feedfetcher-Google(?:\b)" 3;
"~*(?:\b)Google-HTTP-Java-Client(?:\b)" 3;
"~*(?:\b)Googlebot(?:\b)" 3;
"~*(?:\b)Googlebot-Image(?:\b)" 3;
"~*(?:\b)Googlebot-Mobile(?:\b)" 3;
"~*(?:\b)Googlebot-News(?:\b)" 3;
"~*(?:\b)Googlebot-Video(?:\b)" 3;
"~*(?:\b)Googlebot/Test(?:\b)" 3;
"~*(?:\b)Gravityscan(?:\b)" 3;
"~*(?:\b)Jakarta\ Commons(?:\b)" 3;
"~*(?:\b)Kraken/0.1(?:\b)" 3;
"~*(?:\b)LinkedInBot(?:\b)" 3;
"~*(?:\b)Mediapartners-Google(?:\b)" 3;
"~*(?:\b)SAMSUNG(?:\b)" 3;
"~*(?:\b)Slackbot(?:\b)" 3;
"~*(?:\b)Slackbot-LinkExpanding(?:\b)" 3;
"~*(?:\b)TwitterBot(?:\b)" 3;
"~*(?:\b)Wordpress(?:\b)" 3;
"~*(?:\b)adidxbot(?:\b)" 3;
"~*(?:\b)aolbuild(?:\b)" 3;
"~*(?:\b)bing(?:\b)" 3;
"~*(?:\b)bingbot(?:\b)" 3;
"~*(?:\b)bingpreview(?:\b)" 3;
"~*(?:\b)developers.facebook.com(?:\b)" 3;
"~*(?:\b)duckduckgo(?:\b)" 3;
"~*(?:\b)facebookexternalhit(?:\b)" 3;
"~*(?:\b)facebookplatform(?:\b)" 3;
"~*(?:\b)gsa-crawler(?:\b)" 3;
"~*(?:\b)msnbot(?:\b)" 3;
"~*(?:\b)msnbot-media(?:\b)" 3;
"~*(?:\b)slurp(?:\b)" 3;
"~*(?:\b)teoma(?:\b)" 3;
"~*(?:\b)yahoo(?:\b)" 3;
"~*(?:\b)Presto(?:\b)" 3;
"~*(?:\b)Wget/1.15(?:\b)" 3;
"~*(?:\b)jetmon(?:\b)" 3;
"~*(?:\b)libwww-perl(?:\b)" 3;
"~*(?:\b)munin(?:\b)" 3;
"~*(?:\b)Alexa(?:\b)" 3;
"~*(?:\b)ArchiveTeam(?:\b)" 3;
"~*(?:\b)BUbiNG(?:\b)" 3;
"~*(?:\b)Baidu(?:\b)" 3;
"~*(?:\b)FlipboardProxy(?:\b)" 3;
"~*(?:\b)MSIE\ 7.0(?:\b)" 3;
"~*(?:\b)Proximic(?:\b)" 3;
"~*(?:\b)R6_CommentReader(?:\b)" 3;
"~*(?:\b)R6_FeedFetcher(?:\b)" 3;
"~*(?:\b)RED/1(?:\b)" 3;
"~*(?:\b)RPT-HTTPClient(?:\b)" 3;
"~*(?:\b)Spaidu(?:\b)" 3;
"~*(?:\b)UptimeRobot/2.0(?:\b)" 3;
"~*(?:\b)YandexBot(?:\b)" 3;
"~*(?:\b)YandexImages(?:\b)" 3;
"~*(?:\b)archive.org(?:\b)" 3;
"~*(?:\b)ia_archiver(?:\b)" 3;
"~*(?:\b)sfFeedReader/0.9(?:\b)" 3;
On public instances, especially when bots are targeting your instance, you may want to increase the default limit on FreeBSD regarding the maximum number of pending connections awaiting acception on a single socket:
sysctl kern.ipc.somaxconn=2048
It is highly recommended to also make this change persistent across reboots:
echo "kern.ipc.somaxconn=2048" >>/etc/sysctl.conf
Now make uWSGI use the new limit by inserting the following line in /usr/local/etc/uwsgi/searx.ini
:
[...]
listen = 2048
[...]
If it fits your threat model, searXNG (and redis and nginx) can be installed in a jail.
There are no specific installation steps required for that, the above guides do also apply for an installation inside a jail. If you are unsure about the configuration of the jail itself, use the following restrictive configuration, which has been proven working on HardenedBSD 13-STABLE:
/etc/jail.conf
allow.set_hostname = 0;
allow.chflags = 0;
allow.quotas = 0;
allow.read_msgbuf = 0;
allow.socket_af = 0;
allow.mlock = 0;
allow.unprivileged_proc_debug = 0;
allow.raw_sockets = 0;
allow.reserved_ports = 1;
allow.suser = 1;
allow.mount = 0;
allow.mount.devfs = 0;
allow.mount.fdescfs = 0;
# Kernel module disabled by default on HardenedBSD:
#allow.mount.fusefs = 0;
allow.mount.nullfs = 0;
allow.mount.procfs = 0;
# Kernel modules disabled by default on HardenedBSD:
#allow.mount.linprocfs = 0;
#allow.mount.linsysfs = 0;
allow.mount.tmpfs = 0;
allow.mount.zfs = 0;
# Kernel module disabled by default on HardenedBSD:
#linux = "new";
sysvmsg = "new";
sysvsem = "new";
sysvshm = "new";
enforce_statfs = 2;
# Also change /etc/devfs.rules
#devfs_ruleset 99;
mount.devfs;
nopersist;
securelevel = 3;
children.max = 0;
exec.clean;
exec.start = "/bin/sh /etc/rc";
exec.stop = "/bin/sh /etc/rc.shutdown";
host = "new";
ip4 = "new";
ip6 = "disable";
searx {
path = "change_me";
stop.timeout = 15;
host.hostname = "searx";
interface = "change_me";
ip4.addr = "change_me";
}
/etc/devfs.rules
[devfsrules_jail_hardened=99]
add hide
add path null unhide
add path zero unhide
add path crypto unhide
add path random unhide
add path urandom unhide
One can also apply some restrictions regarding system resource usage to the corresponding jail. Also useful if you want to prevent a buggy application from hogging your whole system in case of a memory leak for example.
/etc/rctl.conf
ℹ️ Sample values, change them as needed.
jail:searx:pcpu:deny=50
jail:searx:memoryuse:deny=4G
jail:searx:memorylocked:deny=0
jail:searx:maxproc:deny=32
jail:searx:openfiles:deny=25000
jail:searx:readbps:throttle=50M
jail:searx:writebps:throttle=15M
The resource usage of the searXNG executable (or all executables running under the "searx" user respectively) can be limited by
adding the following content to the file /etc/login.conf
:
searx:\
:coredumpsize=0:\
:filesize=8G:\
:maxproc=32:\
:memorylocked=0:\
:memoryuse=4G:\
:tc=default:
Rebuild the database after changing the configuration file:
cap_mkdb /etc/login.conf
To make the new changes apply to the user "searx", change its login class like that:
pw usermod -n searx -L searx
Updating searXNG is pretty straigthforward:
su -l searx -c 'cd searxng && git pull'
su -l searx -c 'cd searxng && pip install --use-pep517 --no-build-isolation -e .'
Don't forget to restart searXNG afterwards:
service searx onerestart
Thanks for figuring this out. Installing the package in the venv should be enough, I've updated the gist accordingly.