FreeBSD: Services in jails
(modified )This uses my jail
setup from previous post.
Nginx web proxy
SSL
Using Letsencrypt, install the certbot “standalone” client:
# pkg install py36-certbot
Close down nginx, so certbot can bind to 80/443 for obtaining the certs:
# service nginx stop
Get your certificates:
# certbot-3.6 certonly --standalone -d example.org [-d www.example.org]
# certbot-3.6 certonly --standalone -d another.com [-d www.another.com]
Certs and keys are stored in /usr/local/etc/letsencrypt/live/example.org
.
Edit nginx config (/usr/local/etc/nginx/nginx.conf
) to use the certs for your new domains:
server {
listen 80;
listen 443 ssl;
server_name www.example.org example.org;
ssl_certificate /usr/local/etc/letsencrypt/live/example.org/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/example.org/privkey.pem;
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
location / {
root /mnt/example.org;
index index.html index.htm;
}
}
Start nginx and browse securely:
# service nginx start
To renew all certs automatically and non-interactive, quietly run certbot renew
every night
with hooks for shutting down the http server (and let certbot bind to the ports) and starting
it once finished. The hooks will not run, unless there is a need for renewal.
# crontab -e
0 0 * * * /usr/local/bin/certbot-3.6 renew --quiet --pre-hook 'service nginx stop' --post-hook 'service nginx start'
SSL Client side
In case you have some cool scripts or web apps running, performing client requests by themselves, you probably need to install root certificates for that chain of trust to work:
# pkg install ca_root_nss
Proxy
I use the nginx server to proxy requests to some services in other jails, instead of exposing more ports in my firewall.
This is a typical proxy in /usr/local/etc/nginx/nginx.conf
:
server {
listen 80;
server_name service.example.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://10.0.1.94:3000/;
}
}
See nginx documentation for fine tuning.
CGI
To have CGI enabled in nginx, install fcgiwrap:
# pkg install fcgiwrap
Configure fcgiwrap to run as www
user, so nginx can communicate via UNIX sockets.
# vi /etc/rc.conf
fcgiwrap_enable=YES
fcgiwrap_user=www
fcgiwrap_group=www
fcgiwrap_socket_owner=www
fcgiwrap_socket_group=www
Start the service:
# service fcgiwrap start
cgit
I install this in the same jail as my nginx web service, since it is a CGI script. This requires the fcgiwrap part from the nginx installation.
# pkg install cgit
cgit
gets installed into /usr/local/www/cgit
.
The file /usr/local/etc/cgitrc
is read by cgit before handling a request
(documentation).
Create it if it does not exist already, /usr/local/etc/cgitrc
:
virtual-root=/
root-title=vty.se
root-desc=git repos from prd
css=/cgit.css
logo=
clone-url=https://git.vty.se/$CGIT_REPO_URL
snapshots=tar.gz tar.bz2 zip
enable-log-filecount=1
enable-log-linecount=1
mimetype.gif=image/gif
mimetype.html=text/html
mimetype.jpg=image/jpeg
mimetype.jpeg=image/jpeg
mimetype.pdf=application/pdf
mimetype.png=image/png
mimetype.svg=image/svg+xml
about-filter=/usr/local/bin/cgit-about.sh
readme=:README.md
readme=:readme.md
readme=:README.txt
readme=:readme.txt
readme=:README
readme=:readme
readme=:INSTALL.md
readme=:install.md
readme=:INSTALL.txt
readme=:install.txt
readme=:INSTALL
readme=:install
scan-path=/var/git
Create the about-filter script, /usr/local/bin/cgit-about.sh
. This will wrap every readme above
in a <pre>
tag for proper white-space rendering and replace every <
with its HTML entity to avoid
breaking the page.
#!/bin/sh
echo "<pre>"
cat $- | sed 's/</\</g'
echo "</pre>"
Make the script executable:
# chmod +x /usr/local/bin/cgit-about.sh
Create the git repos folder. The repos will be mounted from outside the jail in my case:
# mkdir /var/git
Because of how I have the jails setup, the actual directory will be stored in the
thinjail, which gets mounted in /skeleton
from the jail’s point of view. And since
var
is one of those symlinked folders to keep it away from the base, the actual dir
will be found in /skeleton/var/git
from within the jail.
Edit and add in /usr/local/jails/httpd.fstab
(outside the jail):
/data/git/pub /usr/local/jails/httpd/skeleton/var/git nullfs ro 0 0
Finally, edit and update the http
section in /usr/local/etc/nginx/nginx.conf
:
server {
listen 80;
listen 443 ssl;
server_name git.vty.se;
ssl_certificate /usr/local/etc/letsencrypt/live/vty.se/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/vty.se/privkey.pem;
if ($scheme != "https") {
return 301 https://$host$request_uri;
}
root /usr/local/www/cgit;
try_files $uri @cgit;
location @cgit {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/local/www/cgit/cgit.cgi;
fastcgi_param PATH_INFO $uri;
fastcgi_param QUERY_STRING $args;
fastcgi_param HTTP_HOST $server_name;
fastcgi_pass unix:/var/run/fcgiwrap/fcgiwrap.sock;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/www/nginx-dist;
}
}
Plex media server
Kudos to https://nbari.com/post/plex-jail/.
For downloading metadata, Plex uses 127.0.0.1. Therefore the jail needs to have a loopback interface.
Create a lo1 interface. Add to rc.conf
:
cloned_interfaces="lo1"
Add a made-up loopback IP in /etc/jail.conf
for the appropriate jail:
plex {
ip4.addr = lo1|127.0.92.1;
ip4.addr += em0|10.0.1.92;
}
This will add 127.0.92.1 as the main IP. This works as a specific setting for this jail, even though there is a lot of global stuff for the other jails.
Inside a jail, access to the loopback address 127.0.0.1 is redirected to the first IP address assigned to the jail. To make the jail loopback correspond with the new lo1 interface, that interface must be specified first in the list of interfaces and IP addresses given when creating a new jail.
Finally, edit /etc/hosts
inside the jail so that localhost is mapped correctly:
127.0.92.1 localhost localhost.your.domain
Profit.
Transmission torrent server
Create a new jail as described in previous post.
Mount external folder into the jail by appending to /usr/local/jails/transmission.fstab
:
/data/torrents /usr/local/jails/transmission/mnt nullfs rw 0 0
Install transmission:
# pkg install transmission-daemon transmission-web
Take note of the group ID given to the group name transmission
by the installation. In my case, it was 921.
Add the same group name with the same ID in the host machine for managing your data:
# pw groupadd transmission -g 921
# chgrp -R transmission /data/torrents
Start the transmission daemon upon jail startup (back inside the jail):
# echo 'transmission_enable="YES"' >> /etc/rc.conf
# service transmission start
Shut it down and configure transmission-daemon to allow incoming connections from other than localhost, by requiring RPC authentication and disable RPC whitelist. Change the umask from 18 to 2 (which will give rw to owner and group).
# service transmission stop
/usr/local/etc/transmission/home/settings.json
:
"download-dir": "/mnt",
"rpc-authentication-required": true,
"rpc-bind-address": "0.0.0.0",
"rpc-password": "XXXXXXXXXXXXXXXXXXX",
"rpc-port": 9091,
"rpc-url": "/",
"rpc-username": "prd",
"rpc-whitelist-enabled": false,
"umask": 2,
To properly set the download-dir, add it as a flag to the transmission-daemon:
/etc/rc.conf
:
transmission_download_dir="/mnt"
Start:
# service transmission start
Browse to http://a.b.c.d/web/
(remember the trailing slash) and start downloading/seeding!
mstream music server
A streaming music player written in node, https://mstream.io.
Create a new jail. Mount any music directories you would like inside, by editing /usr/local/jails/<jail>.fstab
. Start the jail and enter it.
Install mstream using git and node package manager:
# pkg install git npm
# cd /usr/local/
# git clone https://github.com/IrosTheBeggar/mStream.git
# cd mStream
# npm install
# npm link
Run the setup wizard:
# mstream --wizard
Start the server and try it out:
# mstream -j /usr/local/mStream/save/default.json
Move the config file to /usr/local/etc/
for consistency:
# mv /usr/local/mStream/save/default.json /usr/local/etc/mstream.conf
Create a new service shell script, pointing to your configuration.
/usr/local/etc/rc.d/mstream
:
#!/bin/sh
#
# PROVIDE: mstream
# REQUIRE: LOGIN FILESYSTEMS
# KEYWORD: shutdown
. /etc/rc.subr
name=mstream
rcvar=mstream_enable
command="/usr/local/bin/mstream"
load_rc_config $name
# Set PATH so mstream can find node
PATH=$PATH:/usr/local/bin
#
# DO NOT CHANGE THESE DEFAULT VALUES HERE
# SET THEM IN THE /etc/rc.conf FILE
#
mstream_enable=${mstream_enable-"NO"}
pidfile=${mstream_pidfile-"/var/run/mstream.pid"}
run_rc_command "$1"
Make executable:
# chmod +x /usr/local/etc/rc.d/mstream
Enable in /etc/rc.conf
and set the configuration flag:
mstream_enable="YES"
mstream_flags="-j /usr/local/etc/mstream.conf"
Reboot the jail. Since mstream doesn’t seem to have a real background daemon setting,
it will eat your terminal if you service start mstream
. Do it to verify that everything
is working, but reboot if you would like it running in the background. It will eat your
terminal if you jail -c mstream
as well. I just close my tmux pane and carry on with
my life…
This is something of an ugly hack, but it works for now…