How to Setup Jail with Iocage on FreeBSD
Jail is a term for OS-level virtualization on the FreeBSD. It was introduced by Poul-Henning Kamp in 1999 and adopted by FreeBSD since version 4.x.
The Jail allows the system administrator to create an isolated and independent mini system or 'jail' inside the FreeBSD system. The 'jail' has its root system and configuration, and it's helpful if you want to deploy an application in an isolated environment.
Iocage is a FreeBSD jail manager that is written in Python. It's simple and comes with an easy command syntax. The Iocage jail manager is dedicated to the ZFS dataset inside jails and allows you to create a jail based on the 'VNET' virtual networking stacks and/or the 'Shared IP' based jail. With the Iocage, you can create the jail template, base jail, and normal jail.
This tutorial will show you how to set up and configure FreeBSD jail using Iocage Jail Manager. We will install the Iocage on FreeBSD, set up a new jail using shared IP, set up the pf firewall, and then install the nginx web server inside the jail for testing.
Prerequisite
For this guide, you will be required to install and configure Iocage Jail Manager on the FreeBSD system that installed on the ZFS (Z File System). And make sure you have got the pf Firewall enabled on your FreeBSD system.
Below is the guide for FreeBSD installation on ZFS and the pf firewall configuration.
How to Install FreeBSD 12.0 on ZFS
How to Setup pf Firewall on FreeBSD
What we will do:
- Install Iocage Jail Manager
- Download FreeBSD Release
- Setup Shared IP and Pf Firewall
- Create New Jail with Iocage
- Testing
Step 1 - Install Iocage on FreeBSD
First, we will install and configure the Iocage Jail manager on the FreeBSD system. The Iocage is written in Python and is available in the FreeBSD binary package repository.
Install Iocage to the FreeBSD system using the pkg command below.
pkg install py36-iocage
Type 'y' to accept the Iocage python package installation, and the installation will begin.
Once the installation is complete, check available ZFS pool on the system using the zpool command below.
zpool list
Now choose the ZFS pool for the Iocage installation. For this guide, we will be using the default ZFS pool for the FreeBSD installed called 'zroot'.
Activate the 'zroot' pool for the Iocage usage using the command below.
iocage activate zroot
Now the Iocage installation on FreeBSD 12.0 has been completed, and you can use the iocage command-line to create and manage FreeBSD jail.
Additionally, you can enable the jail on system boot by adding the iocage service to the '/etc/rc.conf' file using the sysrc command below.
sysrc iocage_enable=yes
Step 2 - Download FreeBSD Release
To create a new jail, you will need to download the FreeBSD Release. And you can create a new jail which is a different version of your host FreeBSD version.
Check the available Release versions using the iocage command below.
iocage fetch
Now, you will get a different version of the Release. Select the version as you need and type the number. Choose the number '2' to download the latest Release version.
Wait for the FreeBSD release image being downloaded.
If you want to download a different image, you can use the following command.
iocage fetch 11.3-RELEASE
As a result, the FreeBSD release image for jail has been downloaded.
Step 3 - Setup Shared IP and Pf Firewall
After downloading the source images for jail, we will configure the networking and the pf firewall on the system. We will create a new network interface called 'bridge0' with network IP address '10.8.8.1/24', and it will be used by the jail.
Add new configuration to the '/etc/rc.conf' file by running the following command.
sysrc cloned_interfaces+="bridge0"
sysrc ifconfig_bridge0="10.8.8.1/24"
Create a new 'bridge0' interface with the network IP address '10.8.8.1/24'.
ifconfig bridge0 create
ifconfig bridge0 10.8.8.1/24 up
Now that the 'bridge0' interface has been created, check it using the following command.
ifconfig bridge0
And you will get the result as below.
Next, we will configure the pf firewall and add a new configuration for the jail environment. We're using the simply pf firewall configuration on this guide.
How to Setup Pf Firewall on FreeBSD 12.0
Goto the '/usr/local/etc' directory and edit the configuration file 'pf.conf'.
cd /usr/local/etc/
vim pf.conf
Add the internal network interface 'bridge0' and its Ip address as 'int_if' and 'localnet' variables.
# Internal interface
int_if = "bridge0"
localnet = $int_if:network
Now define the host jail IP address and ports that will be forwarded to the jail. We will forward the HTTP and HTTPS connections on the system external interface to the jail host IP address '10.8.8.5'.
# Port-Forward http and https to Jail '10.8.8.5'
ports_to_forward="{ 80, 443 }"
forward_host="10.8.8.5"
Enable nat on the 'ext_if' external interface for jail 'localnet' variable, and then enable the port redirection from the 'ports_to_forward' variable to the host 'forward_host'.
# nat jail to internet and internet to jail (http and https only)
nat on $ext_if inet from $localnet to any -> ($ext_if)
rdr on $ext_if proto tcp from any to any port $ports_to_forward -> $forward_host
Now pass all connection from the 'bridge0' interface and pass incoming connection on the external interface to the HTTP and HTTPS 'ports_to_forward'.
pass from { self, $localnet } to any keep state
pass in on $ext_if proto {udp, tcp} from any to any port $ports_to_forward keep state
Save and close.
Now test the pf firewall configuration and make sure there is no error, then reload the pf service.
service pf check
service pf reload
After that, check all rules on the pf firewall using the following command.
pfctl -s rules
And you will get the result as below.
Additionally, you can check the nat status on the pf firewall.
pfctl -v -s nat
As a result, the new interface 'bridge0' has been created, and the pf firewall has been configured. And we're ready to create new first jail.
Below is the complete pf firewall configuration.
cat /usr/local/etc/pf.conf
# Define External Interface and IP Address ext_if="vtnet0" ext_ip="198.13.39.207" # Define TCP and UDP Services ext_tcp_ports="{ ssh, smtp, smtps, imaps, http, https, domain }" ext_udp_ports="{ domain, ntp }" # Internal interface int_if = "bridge0" localnet = $int_if:network # Port-Forward http and https to Jail '10.8.8.5' ports_to_forward="{ 80, 443 }" forward_host="10.8.8.5" # Skip the localhost set skip on lo0 # Log interface set loginterface $ext_if # nat jail to internet and internet to jail (http and https only) nat on $ext_if inet from $localnet to any -> ($ext_if) rdr on $ext_if proto tcp from any to any port $ports_to_forward -> $forward_host # Default Policy block in all pass out all keep state # Allow Ping pass inet proto icmp icmp-type echoreq pass from { self, $localnet } to any keep state pass in on $ext_if proto {udp, tcp} from any to any port $ports_to_forward keep state # Allow Services pass in proto tcp from any to any port $ext_tcp_ports pass in proto tcp from any to any port $ext_udp_ports # Log access for ssh and http pass log quick proto tcp from any to any port { ssh,http }
Step 4 - Create a New Jail using Iocage
After configuring the network and pf firewall on the FreeBSD system, we're ready to create a new jail using iocage.
Create a new jail called 'jail01' with the FreeBSD release '12.0-RELEASE' using the iocage command below.
iocage create -n jail01 -r 12.0-RELEASE
Now add the IP address and default router gateway of the jail. We will give the 'jail01' an IP address 10.8.8.5' and the default router gateway is the 'bridge0' host IP address '10.8.8.1'.
iocage set ip4_addr="bridge0|10.8.8.5" jail01
iocage set defaultrouter="10.8.8.1" jail01
Enable the jail to start on boot.
iocage set boot=on jail01
Now check the jail list.
iocage list
And you will get the 'jail01' with IP address '10.8.8.5' and based the FreeBSD release '12.0'.
Next, start the 'jail01' using the command below.
iocage start jail01
Once the jail started, access the jail using the following command.
iocage console jail01
You will get a new shell inside jail01, as shown below.
Inside the jail, check the IP address of 'bridge0' interface on the 'jail01'.
ifconfig bridge0
And you will get the 'bridge0' interface has an IP address '10.8.8.5' as configured.
As a result, a new jail called 'jail01' has been created.
Step 5 - Testing
In this step, we will test the 'jail01' by installing the Nginx web server on it and then try to access the Nginx from the outside of the network, and the connection will be redirected to 'jail01'.
Firstly, update the binary packages on the jail using the pkg command below.
pkg update
After that, install the nginx web server inside the jail using the following pkg command.
pkg install nginx
Once the installation is complete, add the nginx service to the system boot and start the nginx service.
sysrc nginx_enable=yes
service nginx start
Now check the list open port on the 'jail01'.
sockstat -l4
And you will get the Nginx service is up and running in the HTTP port '80'.
Next, we will change the default index.html page on the 'jail01'.
Goto the '/usr/loca/www/' directory and edit the 'index.html' file.
cd /usr/local/www/
edit nginx-dist/index.html
Make some changes and exit.
cat nginx-dist/index.html
Now access the external IP address of the server from your web browser.
http://198.xx.xx.207/
And you will get the nginx index.html page inside the 'jail01'.
As a result, the 'jail01' is up and running with the Nginx installed on it. All HTTP and HTTPS connections to the server will be redirected to the 'jail01'.