Contrary to advertising pitches of many, hosting one's own Internet services has many advantages over using publicly available ones. Besides having the ability to preserve control over important aspects of our digital lives, it also make for great learning platform. In the following series, "Host Your Own Services With FreeBSD Jails", I will provide detailed information about setting various Internet services, such as DNS, email, web, LDAP, database and other services using FreeBSD jails.
I will be using "fat" jails, which include complete FreeBSD distribution. I won't be using any jail management tools such as iocage, CBSD or now obsolete, but still somewhat functional ezjail. Jails will be configured exclusively through
jail.conf. I will be using Jails with traditional networking, as opposed to newer VNET jails, which means their IP addresses will be aliases on host's physical network interface. Complete setup will be IPv4 only. Sorry, I know I am long overdue with at least testing IPv6 but my ISPs don't provide IPv6 addresses. Throughout the tutorials I will try to be as descriptive as I can, but don't expect me to teach you how to change file ownership or permissions, or how to edit config file in
vi - this series will require fairly advanced knowledge of FreeBSD and UNIX in general.
Taming Overreaching Services
Ok, let's start. Before we set up our first jail, we need to prepare host environment, as hinted in jail(8) manpage. It's mostly about networking: no services on the host should bind to all local IP addresses, as this could result in host answering requests sent to inexisting services on jails. On clean FreeBSD install these are
syslogd by default, and also
ntpd if we opted-in during install (which we should, as accurate timekeeping is essential for almost all Internet services). Let's check to be sure with
...which should show output similar to:
Active Internet connections (including servers) Proto Recv-Q Send-Q Local Address Foreign Address (state) (...some irrelevant lines skipped...) tcp4 0 0 *.22 *.* LISTEN tcp6 0 0 *.22 *.* LISTEN udp4 0 0 *.123 *.* udp6 0 0 *.123 *.* udp4 0 0 *.514 *.* udp6 0 0 *.514 *.*
All the services which listen on all local IP addresses are presented with asterisk followed with port number in "Local Address" column. You can check
/etc/services file if you are not familiar with services belonging to respective ports, however anyone who deals with FreeBSD jails probably knows them by now - as I said above, they are
ntp 123/udp and
syslogd, at least for now I won't be using its network features on the host, so I'll disable them completely:
sysrc syslogd_flags="-ss" service syslogd restart
netstat output shouldn't show port 514 anymore.
Make sure to always edit highlighted lines according to your environment.
You can safely use copy button in code blocks - it will copy only text and commands, not line numbers and terminal prompts.
sshd, I will replace content of its default config file,
/etc/ssh/sshd_config with one similar to this:
# jailhost.example.org:/etc/rc.conf ListenAddress 192.0.2.1 AuthorizedKeysFile .ssh/authorized_keys Subsystem sftp /usr/libexec/sftp-server
netstat output should show that
sshd now listens on specified IP address, and not on asterisk / wildcard, which means on all available IP addresses.
ntpd, I will replace its config file,
/etc/ntp.conf, with the following:
# jailhost.example.org:/etc/ntp.conf tos minclock 3 maxclock 6 pool 0.freebsd.pool.ntp.org iburst restrict default limited kod nomodify notrap noquery nopeer restrict source limited kod nomodify notrap noquery restrict 127.0.0.1 restrict 192.0.2.0 mask 255.255.255.0 nomodify notrap noquery nopeer leapfile "/var/db/ntpd.leap-seconds.list" interface ignore wildcard interface listen 192.0.2.1
I will also set
ntpd to listen on IPv4 only and restart the deamon:
sysrc ntpd_flags="-4" service ntpd restart
ntpd should now listen only on loopback interface (127.0.0.1) as well as on IP address of the host (192.0.2.1), serving ntp clients on local network only (192.0.2.0/24).
netstat output at this point shouldn't show any asterisks / wildcards in "Local Address" column, which means I have bound all host's services to specific IP addresses, as opposed to all available addresses on the host.
Creating Additional Loopback Interface
In order to keep jails' loopback traffic off the host's loopback network interface
lo0, we will configure and create additional loopback interface on host:
sysrc cloned_interfaces="lo1" service netif cloneup
Later on, when creating jails, I will assign jail's primary IP address to be from 127.0.1.0/24 address space, and bind it to
lo1 interface, whereas secondary IP address is going to be "real" IP address from 192.0.2.0/24 address space, bound to physical interface. This will prevent jails' communication over host's loopback interface, requiring all the jails to communicate with each other as though they were separate physical machines.
Editing hosts file
Long time ago I noticed that, after reboot, sshd would wait for DNS for some time in order to start accepting connections. It would eventually timeout after a minute or so, however adding local IP address to FQDN mappings to hosts file would speed things up (60 seconds may seem like a lifetime after reboot of remote production server while waiting for it to come up). I don't know if this is still relevant, but I got used to edit my hosts files so they contain local IP to FQDN mappings:
# jailhost.example.org:/etc/hosts ::1 localhost localhost.example.org 127.0.0.1 localhost localhost.example.org 192.0.2.1 jailhost jailhost.example.org
Tweaking Updates Config
Although freebsd-update.conf(5) lists
kernel as update components, freebsd-update(8) is mostly "smart" enough to figure out that system doesn't have sources installed and to skip updating them. However, I like to explicitly remove
src component from
freebsd-update.conf for jail host so it looks as follows:
# jailhost.example.org:/etc/freebsd-update.conf KeyPrint 800651ef4b4c71c27e60786d7b487188970f4b4169cc055784e21eb71d410cc5 ServerName update.FreeBSD.org Components world kernel IgnorePaths IDSIgnorePaths /usr/share/man/cat IDSIgnorePaths /usr/share/man/whatis IDSIgnorePaths /var/db/locate.database IDSIgnorePaths /var/log UpdateIfUnmodified /etc/ /var/ /root/ /.cshrc /.profile MergeChanges /etc/ /boot/device.hints
syslogd to bind to specific IP addresses, followed by creation of dedicated loopback interface for jails, I have prepared my host environment to be "jail-friendly". Before proceeding to installation of my first jail, I will apply binary patches by means of freebsd-update in order to hopefully increase host's security and reliability. I am not going to write exact procedure as it is really easy, and really well documented. However, the next chapter of this series will assume that my host runs with latest binary patches provided by