From 02deff01a03a37e66add533214bf69bc44372c88 Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Sun, 13 Nov 2022 23:57:21 +0100 Subject: Added factorio in a linux jail article --- .../freebsd/factorio-server-in-a-linux-jail.md | 163 +++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 content/blog/freebsd/factorio-server-in-a-linux-jail.md (limited to 'content/blog/freebsd/factorio-server-in-a-linux-jail.md') diff --git a/content/blog/freebsd/factorio-server-in-a-linux-jail.md b/content/blog/freebsd/factorio-server-in-a-linux-jail.md new file mode 100644 index 0000000..6dbd733 --- /dev/null +++ b/content/blog/freebsd/factorio-server-in-a-linux-jail.md @@ -0,0 +1,163 @@ +--- +title: Running a Factorio server in a linux jail, on FreeBSD +description: How to setup a linux jail on FreeBSD using vanilla tools +date: 2022-11-13 +--- + +## Introduction + +Two weeks ago I started playing [factorio](https://www.factorio.com/) again with a friend. Factorio packages a dedicated server build for linux, but none of my linux vps' could afford the GB of ram to run factorio along their existing workloads. Therefore I settled on trying to run it inside a linux jail. + +I had been meaning to test linux jails for quite some time but never had a good excuse to do it. This was the perfect opportunity! + +## Preparing FreeBSD + +### Linux subsystem + +Normally FreeBSD 13 has all you need from the get go, we just need to load a few kernel modules and prepare some mount points. All this as abstracted away with: +```sh +service linux enable +service linux start +``` + +### Jail loopback interface + +I strive for the simplest setup and this jail just needs the legacy loopback interface way of doing things: +```sh +echo "cloned_interfaces=\"lo1\"" >> /etc/rc.conf +service netif cloneup +``` + +Many jail tutorials will tell you to configure the jail ips in `/etc/rc.conf` too, this is not what I do. It is difficult to automate and I find that having those ips in the jails.conf file is a lot more useful, see bellow. + +### pf firewall + +Here is a template of my `/etc/pf.conf`: +```cfg +scrub in all + +table persist +table const { self } +table const { 10/8, 172.16/12, 192.168/16, fd00::/8 fe80::/10 } +table const { 0.0.0.0/0, !10/8, !172.16/12, !192.168/16, ::/0, fe80::/10, !fd00::/8 } + +##### Basic rules ##### +nat pass on egress from to -> (egress:0) +rdr-anchor "rdr/*" +set skip on lo +block return log + +##### This firewall ##### +block drop in on egress +pass inet proto icmp all icmp-type unreach code needfrag # MTU path discovery +pass inet proto icmp all icmp-type { echoreq, unreach } # echo reply +pass inet6 proto icmp6 all + +pass in on egress proto tcp from to port { ssh, http, https } +pass out from to any + +##### VPNs ##### +pass in on egress proto udp from to port 342 +pass in on wg0 from to +pass in on wg0 from to +pass out on wg0 from to +``` + +The important lines are the one about the persistent `jails` table and the first two basic rules to `nat` and process the `rdr-anchor`. + +## Bootstrapping the jail + +For some reason, the debootstrap program installs itself without exec permission, and does not list bash as one of its dependencies. +```sh +pkg install bash debootstrap +``` + +I keep my jails under `/jails` and choose debian 11 bullseye: +```sh +bash /usr/local/sbin/debootstrap + --include=openssh-server,locales,rsync,sharutils,psmisc,patch,less,apt \ + --components main,contrib bullseye /jails/factorio +``` + +We need to mount the linux filesystems inside the jail: +```sh +echo " +linprocfs /jails/factorio/proc linprocfs rw 0 0 +linsysfs /jails/factorio/sys linsysfs rw 0 0" >> /etc/fstab +mount -a +``` + +Setup a dedicated user to run factorio: +```sh +chroot /jails/factorio/ useradd -d /home/factorio -m -r factorio +``` + +Convert the linux password file into a bsd authentication database: +```sh +cat /jails/factorio/etc/passwd | sed -r 's/(:[x|*]:)([0-9]+:[0-9]+:)/:*:\2:0:0:/g' > /jails/factorio/etc/master.passwd +pwd_mkdb -p -d /jails/factorio/etc /jails/factorio/etc/master.passwd +``` + +## Installing factorio + +You will need to login to [factorio](https://www.factorio.com/) and download the headless serveur tar.gz. Scp it to the server and decompress it into `/jails/factorio/home/factorio` +```sh +wget https://dl.factorio.com/releases/factorio_headless_x64_1.1.70.tar.xz?secure=NmmeJ2O-iFtRuVc6c3aPzw,1668383018 +(cd /jails/factorio/home/factorio/; tar xf /root/factorio_headless_x64_1.1.70.tar.xz*) +mkdir /jails/factorio/home/factorio/factorio/saves/ +``` + +Upload your save file from the game (or create a new map for the occasion) and place it into `/jails/factorio/home/factorio/factorio/saves/`. + +If you want to use mods, now is the time to upload those into `/jails/factorio/home/factorio/factorio/mods`. A simple rsync of the mods folder from your game should do nicely. + +Edit `/jails/factorio/home/factorio/factorio/config/server-settings.json` to your liking. For example, my server is not publicly visible and has a game password. + +Let's not forget to assign the correct permissions after all this: +```sh +chroot /jails/factorio/ chown -R factorio:factorio /home/factorio +``` + +## Configuring the jail + +Here is my `/etc/jail.conf.d/factorio.conf`: +```cfg +factorio { + host.hostname = "factorio"; + path = /jails/$name; + ip4.addr = 127.0.1.1/32; + ip6 = "new"; + ip6.addr = fc00::1/128; + exec.system_user = "root"; + exec.jail_user = "root"; + exec.clean; + exec.prestart = "ifconfig lo1 alias ${ip4.addr}"; + exec.prestart += "ifconfig lo1 inet6 ${ip6.addr}"; + exec.prestart += "/sbin/pfctl -t jails -T add ${ip4.addr}"; + exec.prestart += "/sbin/pfctl -t jails -T add ${ip6.addr}"; + exec.prestart += "echo \"rdr pass on egress inet proto udp from any to port 34197 -> ${ip4.addr}\n rdr pass on egress inet6 proto udp from any to port 34197 -> ${ip6.addr}\" | pfctl -a rdr/jail-$name -f -"; + exec.poststop = "/sbin/pfctl -t jails -T del ${ip4.addr}"; + exec.poststop += "/sbin/pfctl -t jails -T del ${ip6.addr}"; + exec.poststop += "pfctl -a rdr/jail-$name -F nat"; + exec.poststop += "ifconfig lo1 inet ${ip4.addr} -alias"; + exec.poststop += "ifconfig lo1 inet6 ${ip6.addr} -alias"; + exec.start = "/bin/su - factorio -c 'factorio/bin/x64/factorio --start-server factorio/saves/mysave.zip' &"; + exec.stop = "pkill factorio ; sleep 15"; + mount.devfs; +} +``` + +Make sure you substitute `mysave.zip` with the name of your save file! + + +As you can see, I use the `prestart` and `poststop` steps to handle the network configuration using `ifconfig`, the jails' pf table and the rdr port forwarding. These are all setup when starting the jail and cleaned when stopping. + +Now if all went according to plan, the following should be enough to start your factorio server in the jail: +```sh +service jail enable +service jail start factorio +``` + +Check that factorio is running using `top -j factorio`. If something goes wrong, you should be able to check `/jails/factorio/home/factorio/factorio/factorio-current.log` for clues. + +If everything is running, you should be able to connect your dedicated server using the hostname of your server! -- cgit v1.2.3