NAS Upgrade - Synology or Freenas?
30 Jan 2015In order to replace my old Netgear Readynas DUO v1, I spent a lot of time to choose the right NAS for home purpose. Synology NAS are great products but expensive if you need more than two disks. Few month ago I made a great deal buying a HP n54l gen7 on amazon for less than ~$200. This is where the story began.
The beast
This little homeserver has 4 disk trays (said as non hotplug but if you flash it with an unlocked feature bios you can make them hotplug - aka esata) and two pci-express expansion slots.
I added to this little boy 16GB of ECC RAM and 4x1TB drives and it is good to go !
The interresting point is that there is a usb port on the mother board to if you need to boot from USB, this will be very usefull for what we want to achieve later.
Give me a NAS OS
Synology port / hack / whatever
In the first stages, I tried to use the Synology OS (DSM) on it, I finaly manage to fake some contros calls in kernel and create my own DSM 4.3 booting system. This was fun and I'm one of the first guy able to bypass their new protections. It was working quite good but updating is a pain as it could break my customs hooks. DSM sounds pretty secure for an embeded OS as it checks if the hardware it's running on match the hardware it's suppose to run into. If it fails, you can't use it as it will degrade your volume (basicaly delete /dev/sdx devices entries). The check is done by several parts in the system, mainly on cgi scripts. Hacking in the cgi scripts is a pain as everything is offuscated and protected against disassembly/tracing by detecting debuggers:
Trying to attach a strace on a process gives you this:
20954 19:03:31 [f6bf4c08] ptrace(PTRACE_TRACEME, 0, 0, 0) = -1 EPERM (Operation not permitted)
20989 19:03:38 [f6c06c08] ptrace(PTRACE_TRACEME, 0, 0, 0) = -1 EPERM (Operation not permitted)
And nothing else interresting.
This is well known trick to defeat debugging/tracing. A reduction could be:
#include <stdio.h>
#include <sys/ptrace.h>
int main()
{
if (ptrace(PTRACE_TRACEME, 0, 0, 0) == -1)
{
printf("don't trace me !!\n");
return 1;
}
// normal execution
return 0;
}
Compile this using gcc -o ptrace ptrace.c
then try to strace it:
strace -e ptrace ./ptrace
ptrace(PTRACE_TRACEME, 0, 0, 0) = -1 EPERM (Operation not permitted)
don't trace me !!
+++ exited with 1 +++
The trick here is to override using LD_PRELOAD
the ptrace function:
#include <stdio.h>
long ptrace(int x, int y, int z)
{
printf("--this is the ptrace clone block--\n"); return 0;
}
Compile it as a library gcc -shared -o faketrace.so -fPIC faketrace.c
, then
strace -e ptrace -E LD_PRELOAD=/root/faketrace2.so ./ptrace
--this is the ptrace clone block--
+++ exited with 0 +++
Using this method I found that these files are signed using Synology certificates and each file (process) is checking others, but the most interresting part is that it's also checking /proc/bus/pci/devices
and comparing the output to a list defined in the binary itself.
The trick was to customize the kernel to return fake read entries when a particular process tried to read certains files related to devices installed. Basically it involves kernel hooking and seq files (kernel proc.c to dispatch certains call from processes to a hand crafted seq_file).
To find process accessing this /proc/devices
I had to create a kooking module printing every process name trying to access this file.
I also had to disassemble and edit a proprietary module and change some others things in the kernel tree. I will not provide all the details and the methodology here but it worked. Synology provides the kernel source code (with lot of ifdef/ndef stripped away to male it almost impossible to compile).
DSM is quite a great system, the UI is really fancy and they are plenty of features and addons you can install. But I was not really confortable with running a hacked system in home production and beside that, running other applications directly next to the NAS services may not be a good idea and hardware support for a non genuine Synology is a pain (example: I can't use usb port as it leads to kernel panic).
And at this time, I had to pack everything, because we were moving to California... so after almost one year, it's time to respin everything!
Freenas
Based on FreeBSD, Freenas looks quite good for a DIY NAS. The UI is quite simple but ugly when you have tasted Synology DSM, but it's a NAS and you don't spend your life in the UI. It's pretty well documented and quite open to customisations.
ZFS
FreeNAS like freebsd uses ZFS as file system and seams quite robust and provides a lot of features like:
- Self healing architecture
- Snapshots / Clones
- Compression
- Deduplication (but really RAM-hungry)
- Encryption
- Thin provisioning
- Copy on write
It also uses a smart caching system (using RAM and even SSD):
As I had a previous good experience with FreeBSD system using pfSense, this let me think that this solution will be more robust than using a hacked synology firmware...
Jails
The most interresting thing about FreeBSD is the concept of Jails, this is like chroot on steroids (like LXC for linux) and combined with ZFS, it sounds like docker. Its main goals are:
- Virtualization: Each jail is a virtual environment running on the host machine with its own files, processes, user and superuser accounts. From within a jailed process, the environment is (almost) indistinguishable from a real system.
- Security: Each jail is sealed from the others, thus providing an additional level of security.
- Ease of delegation: The limited scope of a jail allows system administrators to delegate several tasks which require superuser access without handing out complete control over the system.
With latest FreeBSD release, a network virtualization layer as been added vImage, basically it lets you have in your jails a full instance of the host’s networking stack, including loopback interface, routing tables...
In order give network to your jail, you will use epair as a L2 back to back connected ethernet interfaces. One interface will be in your jail, the other one on your host (idealy member of a bridge if you plan to set several jails).
Jails and plugins in Freenas
Plugins
In Freenas you have the choice between plugins and jails. Plugins is the easy way using PBI - Push Button Installer in order to simplify the installation of plugins. Basically it will create a jails for you and install the prepackaged software in it. You can find actual supported plugins here.
Plugins are great if you don't want to deal with your jails by hand but the caveat is that you will have one jail per plugin and you can't really hack them as you want. And it you will miss all the fun :)
Jails
This is where the fun is :)
Jails are using templates, actually there is only two templates (before linux was a template but the support has been deprecated due to bugs and 32 bits limitation):
- Freebsd Jail - Basic FreeBSD jail
- VirtualBox Jail - VirtualBox with phpVirtualBox frontend to virtualize linux/windows! Cool :)
The jails documentation is a good starting point.
Another cool thing is a tool called Warden to manage and deal with your jails. It makes setting up jails easier !
Cli usage:
Warden version 1.3
---------------------------------
Available commands
Type in help <command> for information and usage about that command
help - This help file
gui - Launch the GUI menu
auto - Toggles the autostart flag for a jail
bspkgng - BootStrap pkgng and setup TrueOS repo
checkup - Check for updates to a jail
chroot - Launches chroot into a jail
create - Creates a new jail
details - Display usage details about a jail
delete - Deletes a jail
export - Exports a jail to a .wdn file
fstab - Start users $EDITOR on jails custom fstab
get - Gets options list for a jail
import - Imports a jail from a .wdn file
list - Lists the installed jails
pkgs - Lists the installed packages in a jail
pbis - Lists the installed pbi's in a jail
set - Sets options for a jail
start - Start a jail
stop - Stops a jail
type - Set the jail type (pbibox|pluginjail|portjail|standard)
template - Manage jail templates
zfsmksnap - Create a ZFS snapshot of a jail
zfslistclone - List clones of jail snapshots
zfslistsnap - List snapshots of a jail
zfsclonesnap - Clone a jail snapshot
zfscronsnap - Schedule snapshot creation via cron
zfsrevertsnap - Revert jail to a snapshot
zfsrmclone - Remove a clone directory
The interresting feature is import/export that lets you create your jail on another system and lets you deploy it to your freenas when ready. Unfortunately on Freenas 9.3 this feature is broken and should not be used anyway (explaination below).
Freenas Installation
Quite easy even for a headless system, you just have to grab the iso installation, boot it for example on your desktop using virtualbox with a usb key attached, perform the installation and... plug the key to your target system and let it boot ! By default it will grab an IP through DHCP and let you configure everything.
Creating your zpool and datasets
I let you read the documentation, you can next tweak your system for powersaving, email alerts, services...
Creating our First Jail
The idea behing that is to host some services (SABnzbd,CouchPotatoe,Sonarr) inside the same jail and mount the proper dataset to the jail using nullfs this allow you to mount one part of the file system in a different location (like bind option for mount under linux systems).
You MUST use the Freenas UI do create your own jail! Under the hood it will use a slightly customised version of Warden. I will detail in the next chapters what's going on when you create a jail.
As everything is managed through the UI dealing with warden directly could be a bad idea and lead to weird behavior or worse.
By default creating a new jail will create a new dataset in the jail root directory.
You can change this path in the UI it will update the path in /etc/local/warden.conf
.
All the jails creation parameters are documentent on the freenas doc.
Under the hood,
This is how it works when you push the create button in the UI (more or less).
The first time warden will download a template for the jail we want to create, this is done once. Afterwards, and this is were it's clever, when you create a new jail., Warden does a snapshot of the plugin template dataset and then creates an individual plugin jail as ZFS clone of the template snapshot. When creating a new jail the UI will use warden with all paramters you set.
For entertainement purpose I split the creation step below:
Creating a new jail from template:
[root@freenas] ~# warden create myjail --vanilla --startauto
Building new Jail... Please wait...
zfs clone test/jails/.warden-template-9.1-RELEASE-amd64@clean test/jails/myjail
Added new repo: "Official PC-BSD Repository" to the database.
Mounting user-supplied file-systems
jail -c path=/mnt/test/jails/myjail host.hostname=myjail allow.raw_sockets=true persist
Starting jail with: /etc/rc
Success!
Jail created at /mnt/test/jails/myjail
Bring up the network
Activate ipv4 dhcp on the jail and vimage
warden set ipv4 myjail DHCP
warden set vnet-enable myjail
Start your jail again
[root@freenas] ~# warden start myjail
Mounting user-supplied file-systems
jail -c path=/mnt/test/jails/myjail name=myjail host.hostname=myjail allow.raw_sockets=true persist vnet=new
Getting IPv4 address from DHCP
DHCPDISCOVER on epair0b to 255.255.255.255 port 67 interval 7
DHCPOFFER from 10.0.0.1
DHCPREQUEST on epair0b to 255.255.255.255 port 67
DHCPACK from 10.0.0.1
bound to 10.0.0.5 -- renewal in 1800 seconds.
inet6_enable: -> YES
ip6addrctl_enable: YES -> YES
route: writing to routing socket: File exists
add net default: gateway 10.0.0.1: route already in table
Starting jail with: /etc/rc
Adding some storage
It will edit your jail fstab, you can use the warden fstab myjail
, to see for example
/mnt/test/mydataset /mnt/test/jails/myjail/data nullfs rw 0 0
Note: the edited fstab is not the fstab file located in the jail, but is located under medata directory of you jail.
This part if done by hand using warden is overwritten by the UI when you will start the jail as the storage options are not in the UI configuraiton database
This is why you need to use the UI to add storage to your jails...
zfs PoV for jails
As I explained before new jails are based on clone of snaptshot of the template jail:
[root@freenas] ~# zfs list -o origin,name,used,avail,refer,mountpoint
ORIGIN NAME USED AVAIL REFER
- test/jails/.warden-template-9.1-RELEASE-amd64 205M 5.89G 205M
- test/jails/.warden-template-pluginjail 719M 5.89G 719M
test/jails/.warden-template-9.1-RELEASE-amd64@clean test/jails/myjail 2.55M 5.89G 207M
test/jails/.warden-template-pluginjail@clean test/jails/sabnzbd_1 122M 5.89G 840M
test/jails/.warden-template-pluginjail@clean test/jails/sabnzbd_2 96K 5.89G 719M
You can easily see the origin for each jails and the most import part, the USED size. That a clever use of zfs with jails (somehow docker is doing the same thing using AUFS)
Hacking on your fresh jail
SSH to your jail
It is useful to enable ssh on your jail by editing the /etc/rc.conf
and editing the ssh line to set to YES and change the hostname:
sshd_enable="YES"
hostname="media_grabbers"
Edit the /etc/ssh/sshd_config
and add the line
PermitRootLogin Yes
Create a root password using passwd
and then service sshd start
, this will create the keys.
Install your first packages
Packagement management could done through pkg or port
- pkg is for binary grab and install (deb/rpm like)
- port tree if for building the package from source (gentoo/archlinux like)
First update your jail using pkg upgrade
and update the port tree portsnap fetch extract update
then you can install some packages:
pkg install zsh tmux py27-virtualenv py27-virtualenvwrapper py27-pip
curl -L http://install.ohmyz.sh | sh
chsh -s /usr/local/bin/zsh
Now I feel at home :)
How to export/import my jails between systems
That's a good point... but we can't use warden to do that because it's broken and doing things in the UI's back is not a good idea... but we can find two other ways:
Export the jail dataset using
zfs send / reveive
if you need to transfer existing jails. (warning if you transfer jails from clones you will have to transfer the origin snapshot as well)Use the builtin template system (this is smarter especially if you need to deploy several jails afterward)
Make your jail a template
My up to date and custom jail is now ready, it could be great to use it as a base for other jails comming and use the clone of snaptshot zfs clever trick for this.
Create a snaptshot of your current jail:
warden zfsmksnap myjail
orzfs snapshot test/jails/myjail@my_snap
This will allow you to keep a versioning from your base jail or templating from a running jail. Snapshots are accessibles from an hidden directory .zfs/snapshot.Package you jail for transport
cd /mnt/test/jails/myjail/.zfs/snapshot/my_snap/ tar czf /mnt/test/mydataset/base.tgz .
It's important to create the tgz outside of the jail (here I create the tgz from freenas), you can use the
--exclude
tar parameter if you want to do this from the jail.zfs send
is here not usable because this command is meant to send a full dataset (not only the content) targeted to a zpool.Deploy
For this you will have two choices to import your template:
Deploy the tgz to a ftp or http server and add a new template (using the UI) (this is the supported way) Note: For an unknow nreason this doesn't work using
python -m SimpleHTTPServer
, see Bug #7811Create a new template from your tar with
warden template create -tar base.tgz -nick custom_template
- The trick to make it appear in the UI is to create a fake template entry using the same name as you set as nick (url could be wrong but not empty)
You're done! Create a new jail from your custom template (should be fast) and you can chack that your new jail is using the template.
[root@freenas] /mnt/test/jails# zfs list -o origin,name,used,avail,refer,mountpoint
ORIGIN NAME USED AVAIL REFER
- test/jails 2.34G 5.22G 788M
- test/jails/.warden-template-custom_template 207M 5.22G 207M
test/jails/.warden-template-custom_template@clean test/jails/new_jail_from_custom_template 2.44M 5.22G 207M
(I stripped the other entries for better readability)
Media grabber installation
In the previous chapter we saw how to deploy a custom jail and how to mount (bind) a dataset to it. Now it's time for us to install every piece of software needed in order to grab our favorite media.
Users and permissions
One fondamental thing is to be consistent between the permissions on your dataset and the permissions your process will run as in your jail.
- Freenas side:
Create a new user on freenas (using UI or cmd line as you like), let's say something like this user:
media:*:1001:1001:Media user:/nonexistent:/sbin/nologin
and for group
media:*:1001:
No shell, no home and login is better for security.
On your dataset be sure that this user a the permissions deal with your files. For this you can use the UI or a chmod -R media.media /mnt/test/mydataset
Note: as every media files belong to media, I also make the AFP/NFS guest account media in order to access to the share from my mac as a guest with full privileges. (I trust my own network).
- Jail side:
Same thing as before:
➜ ~ adduser
Username: media
Full name: Media
Uid (Leave empty for default): 1001
Login group [media]:
Login group is media. Invite media into other groups? []:
Login class [default]:
Shell (sh csh tcsh zsh rzsh git-shell nologin) [sh]: nologin
Home directory [/home/media]: /nonexistent
Home directory permissions (Leave empty for default):
Use password-based authentication? [yes]: no
Lock out the account after creation? [no]: no
From there you can mount your dataset using the UI to the folder of your choice and check if everything is fine using
➜ ~ sudo -u media ls -al /media
total 419
drwxrwxr-x 12 media media 13 Feb 1 22:26 .
drwxr-xr-x 17 root wheel 21 Feb 1 13:19 ..
drwxrwxr-x 3 media media 6 Feb 17 2014 Test
Software installation
For git clone sotware we will install them in
mkdir /grabbers
chown media:media /grabbers
cd /usr/ports/news/sabnzbdplus && make config-recursive && make install clean
chown media:media /usr/local/sabnzbd
# make listen to 0.0.0.0 (needed for first configuration)
sed -i.ori 's/host = localhost/host = 0.0.0.0/g' /usr/local/sabnzbd/sabnzbd.ini
sysrc sabnzbd_enable="YES"
sysrc sabnzbd_user="media"
sysrc sabnzbd_group="media"
pkg install mono mediainfo sqlite wget
cd /grabbers
fetch http://download.sonarr.tv/v2/master/mono/NzbDrone.master.tar.gz
tar -xzvf NzbDrone.master.tar.gz
chown -R media:media NzbDrone
Then you need to create a /usr/local/etc/rc.d/sonarr
service script in order to make it run.
#!/bin/sh
# $FreeBSD$
#
# PROVIDE: sonarr
# REQUIRE: LOGIN
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# sonarr_enable: Set to YES to enable sonarr
# Default: NO
# sonarr_user: The user account used to run the sonarr daemon.
# This is optional, however do not specifically set this to an
# empty string as this will cause the daemon to run as root.
# Default: sonarr
# sonarr_group: The group account used to run the sonarr daemon.
# This is optional, however do not specifically set this to an
# empty string as this will cause the daemon to run with group wheel.
# Default: sonarr
# sonarr_data_dir: Directory where sonarr configuration
# data is stored.
# Default: /var/db/sonarr
. /etc/rc.subr
name=sonarr
rcvar=${name}_enable
load_rc_config $name
: ${sonarr_enable:="NO"}
: ${sonarr_user:="sonarr"}
: ${sonarr_group:="sonarr"}
: ${sonarr_data_dir:="/var/db/sonarr"}
pidfile="${sonarr_data_dir}/nzbdrone.pid"
command="/usr/sbin/daemon"
procname="/usr/local/bin/mono"
command_args="-f ${procname} /grabbers/NzbDrone/NzbDrone.exe --data=${sonarr_data_dir} --nobrowser"
start_precmd=sonarr_precmd
sonarr_precmd() {
if [ ! -d ${sonarr_data_dir} ]; then
install -d -o ${sonarr_user} -g ${sonarr_group} ${sonarr_data_dir}
fi
}
run_rc_command "$1"
Note: Don't forget to set the execution attributes (555).
And finally append the followin to your /etc/rc.conf
sysrc sonarr_enable="YES"
sysrc sonarr_user="media"
sysrc sonarr_group="media"
cd /grabbers && git clone git://github.com/RuudBurger/CouchPotatoServer.git
chown -R media:media CouchPotatoServer
cp /grabbers/CouchPotatoServer/init/freebsd /usr/local/etc/rc.d/couchpotato
# fix the path
sed -i.ori 's/\/usr\/local\/CouchPotatoServer/\/grabbers\/CouchPotatoServer/g' /usr/local/etc/rc.d/couchpotato
chmod +x /usr/local/etc/rc.d/couchpotato
# fix python path
ln -sf /usr/local/bin/python2.7 /usr/bin/python
sysrc couchpotato_enable="YES"
sysrc couchpotato_user="media"
Maraschino is a HTPC frontend written in python and it can integrate SabNzbd, Xbmc, CouchPotatoe and let you search for content in a nice frontend.
cd /grabbers && git clone https://github.com/mrkipling/maraschino.git
chown -R media:media /grabbers/maraschino
sysrc maraschino_enable="YES"
sysrc maraschino_user="media"
sysrc maraschino_dir="/grabbers/maraschino"
sysrc maraschino_host="127.0.0.1"
Create a /usr/local/etc/rc.d/maraschino
script as follow:
#!/bin/sh
#
# PROVIDE: maraschino
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf.local or /etc/rc.conf
# to enable this service:
#
# maraschino_enable (bool): Set to NO by default.
# Set it to YES to enable it.
# maraschino_user: The user account maraschino daemon runs as what
# you want it to be.
# maraschino_dir: Directory where maraschino lives.
# Default: /usr/local/maraschino
# maraschino_chdir: Change to this directory before running maraschino.
# Default is same as maraschino_dir.
# maraschino_pid: The name of the pidfile to create.
# Default is maraschino.pid in maraschino_dir.
# maraschino_port (int): The port where maraschino will listen to
# Default is 7000
# maraschino_host (host): The ip/host where maraschino will listen to
# Default is 0.0.0.0
. /etc/rc.subr
name="maraschino"
rcvar=${name}_enable
PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
load_rc_config ${name}
: ${maraschino_enable:="NO"}
: ${maraschino_user:="USERNAME"}
: ${maraschino_dir:="/usr/local/maraschino"}
: ${maraschino_chdir:="${maraschino_dir}"}
: ${maraschino_pid:="${maraschino_dir}/maraschino.pid"}
: ${maraschino_port:="7000"}
: ${maraschino_host:="0.0.0.0"}
pidfile="${maraschino_dir}/maraschino.pid"
status_cmd="${name}_status"
stop_cmd="${name}_stop"
command="/usr/sbin/daemon"
# extra args
if [ -n "${maraschino_port}" ]; then
maraschino_args="${maraschino_args} --port=${maraschino_port}"
fi
if [ -n "${maraschino_host}" ]; then
maraschino_args="${maraschino_args} --host=${maraschino_host}"
fi
command_args="-f -p ${maraschino_pid} python ${maraschino_dir}/Maraschino.py ${maraschino_args}"
# Ensure user is root when running this script.
if [ `id -u` != "0" ]; then
echo "Oops, you should be root before running this!"
exit 1
fi
verify_maraschino_pid() {
# Make sure the pid corresponds to the Maraschino process.
pid=`cat ${maraschino_pid} 2>/dev/null`
ps -p ${pid} | grep -q "python ${maraschino_dir}/Maraschino.py"
return $?
}
maraschino_stop() {
echo "Stopping $name"
verify_maraschino_pid
maraschino_pid=`ps -U ${maraschino_user} | grep "python.*Maraschino.py.*--daemon" | grep -v 'grep' | awk '{print $1}'`
if [ -n "${pid}" ]; then
kill ${pid}
fi
}
maraschino_status() {
verify_maraschino_pid && echo "$name is running as ${pid}" || echo "$name is not running"
}
run_rc_command "$1"
Check if everything is running fine
To see if everything is running fine you can use the sockstat
command
sockstat -4
USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
media python2.7 9221 7 tcp4 *:8080 *:*
media python2.7 6044 50 tcp4 *:5050 *:*
media mono-sgen 3921 12 tcp4 *:8989 *:*
media python2.7 6044 50 tcp4 *:7000 *:*
Access to our grabbers
Accessing each grabber using ip:port is a pain, we will create a small reverse proxy on top of then, this way you can access them using url/service scheme. For this will use nginx.
Install nginx
pkg install nginx
sysrc nginx_enable=YES
sysrc nginx_profiles="grabber"
sysrc nginx_grabber_configfile="/usr/local/etc/nginx/grabber.conf"
- Create your certificates for ssl
For testing purposes we can deal with autosigned certs
mkdir -p /etc/ssl/{private,certs}
openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
openssl rsa -passin pass:x -in server.pass.key -out /etc/ssl/private/server-key.pem
rm server.pass.key
openssl req -new -key /etc/ssl/private/server-key.pem -out server.csr -subj "/C=US/ST=Somewhere/L=Somewhere/O=MyHome/OU=Home/CN=grabber.home.local"
openssl x509 -req -days 365 -in server.csr -signkey /etc/ssl/private/server-key.pem -out /etc/ssl/certs/server-cert.pem
#secure our private key
chown www /etc/ssl/private/server-key.pem
chmod 600 /etc/ssl/private/server-key.pem
In /usr/local/etc/nginx/
, create:
- grabber.conf
user www;
worker_processes 1;
error_log /var/log/nginx-grabber-error.log;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx-grabber-access.log main;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_http_version 1.0;
gzip_min_length 1024;
gzip_proxied any;
gzip_buffers 16 8k;
gzip_types text/plain text/css application/x-javascript text/xml
application/xml application/xml+rss text/javascript;
gzip_vary on;
client_max_body_size 4G;
server_tokens off;
ssl_ciphers ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!aNULL:!MD5:!EDH;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_session_cache shared:SSL:10m;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
# Allow only local ip to 80
server {
listen 80;
# allow localnetwork and localhost
allow 192.168.0.0/24;
allow 127.0.0.1/32;
deny all;
include proxy.conf;
}
server {
listen 443 ssl;
satisfy any;
ssl_certificate /etc/ssl/certs/server-cert.pem;
ssl_certificate_key /etc/ssl/private/server-key.pem;
ssl_client_certificate /etc/ssl/certs/server-cert.pem;
ssl_verify_client on;
include proxy.conf;
}
}
- proxy.conf
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
# Maraschino
location / {
proxy_pass http://127.0.0.1:7000/;
proxy_redirect default;
}
# sabnzbd
location /sab {
proxy_pass http://127.0.0.1:8080/sabnzbd;
proxy_redirect default;
}
# sonarr
location /tv {
proxy_pass http://127.0.0.1:8989;
proxy_redirect default;
}
#couchpotato
location /movies {
proxy_pass http://127.0.0.1:5050;
proxy_redirect default;
}
Note 1: If you are using a certificate chain be careful to append the server cert first in the concatenated certs (cert, intermediate ca, ca). Don't forget to set ssl_verify_depth x;
with x according to your certification chain depth.
Note 2: SSL CA are not provided by default by freebsd they can be install with the package ca_root_nss
, don't forget to symlink it ln -sf /usr/local/etc/ssl/cert.pem /etc/ssl/cert.pem
(could cause issue with python apps)
So basically the http traffic is only allowed from local network, ssl with client cert for 443 (used to publish over internet).
We can't use both ssl_verify_client
and allow x.x.x.x/x
with satisfy any
directive (nginx limitation). So we need to split them.
For some services (like sonarr,couchpotato) you will have to set URL Base (in settings) in order to make it work with the reverse proxy.
Once everything respond using the reverse proxy, you can change every service to listen only on localhost (using UI of services or manualy).
- sabnzbd: Using UI in wizard
- CouchPotatoe: Adding
host = 127.0.0.1
in/grabbers/CouchPotatoServer/data/settings.conf
- Sonarr: Using UI to change both base url / listening IP
Say Bonjour to your jails
One usefull thing is to be able to resolve your jails using their hostname and the .local
suffix. In order to do so you just need ton install the mDNSResponder
package and activate it.
pkg install mDNSResponder mDNSResponder_nss
sysrc mdnsd_enable="YES"
service mdnsd start
And edit your /etc/nsswitch.conf
to add mdns
entry between files
and dns
for hosts
entry.
You should be able to acces your jail using HOSTNAME.local
but also access other devices from your jail like openelec.local
TODO: dns update custom alerts