💾 Archived View for cdaniels.net › posts › factorio-freebsd.gmi captured on 2022-01-08 at 13:50:04. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2021-11-30)
-=-=-=-=-=-=-
published 2017-07-24
In this guide, I will discuss how you can go about running a headless Factorio[1] game server on your FreeBSD server. My server is an AMD64 system running FreeBSD 11-RELEASE, although to my knowledge nothing in this guide is specific to this version of FreeBSD. In particular, this guide will cover:
This guide assumes you are familiar with the basics of UNIX server administration, and the UNIX shell. You must own a legitimately licensed copy of Factorio to run the game server.
Note: except as noted, all commands should be run as root.
For the un-initiated:
Factorio is a game in which you build and maintain factories.
You will be mining resources, researching technologies, building infrastructure, automating production and fighting enemies. Use your imagination to design your factory, combine simple elements into ingenious structures, apply management skills to keep it working and finally protect it from the creatures who don't really like you.
The game is very stable and optimized for building massive factories. You can create your own maps, write mods in Lua or play with friends via Multiplayer.
Last updated: 2017-07-24
We will install Factorio under it's own prefix in /opt, which will run under it's own user account (for security). Before starting, you should enable Linux binary compatibility[2] on your server. To get the Linux libraries needed to run the server, you should install linux_base-c7 (CentOS 7.X compatibility).
[2] - FreeBSD Handbook: Linux Binary Compatibility
First, we will setup the Factorio user account:
pw useradd factorio
Now, we will create the required /opt folder. For convenience, and to make snapshots easy, you can optionally create /opt/factorio as a ZFS filesystem. if you don't know what that means, just make it as a folder.
To make /opt/factorio as a ZFS filesystem:
zfs create -o mountpoint=/opt/factorio zroot/factorio
OR (don't do both!)
To make /opt/factorio as a normal directory:
mkdir -p /opt/factorio
Set this directory to be owned by the factorio user:
chown -R factorio:factorio /opt/factorio
Henceforth, we will run as the factorio user account ("su factorio") - all commands should be run as the user factorio unless otherwise noted.
Download the Factorio headless server for Linux from [3]. The current version at the time this article was last updated is noted in the previous section. Save the current release tarball to /opt/factorio, and let's call it /opt/factorio/factorio-release.tar.gz. Extract it and move the content's to the current directory:
[3] - Factorio Headless Download
cd /opt/factorio tar xvf factorio-release.tar.gz mv factorio/* ./ rmdir factorio
Optionally, you can also remove the release tarball as well. We will not be using it again in this guide.
To test that you have installed Factorio correctly, and that Linux emulation is working as it should, you can run:
bin/x64/factorio --version
The output should reflect the version you downloaded. On my particular system at the time of this article's writing, the output was:
Version: 0.15.30 (build 30727, linux64, headless) Binary version: 64 Map input version: 0.12.0-0 Map output version: 0.15.30-1
While reading this section, you may find the document "Practical rc.d scripting in BSD"[4] helpful as reference material.
[4] - Practical rc.d scripting in BSD
Notein this section, we are running as root again.
Place the following script at /usr/local/etc/rc.d/factorio. Be sure to read through the script and configure it to your needs. Don't forget to mark the script executable with chmod +x.
#!/bin/sh # KEYWORD: shutdown . /etc/rc.subr # service name name=factorio # "on/off" variable for /etc/rc.conf rcvar=factorio_enable # handle loading RC variables load_rc_config $name : ${factorio_enable:=no} # default disabled # command to start the service start_cmd="${name}_start" # command to stop the service stop_cmd="${name}_stop" ### factorio-specific configuration ### # factorio installation dir (should contain bin/x64/factorio) FACTORIO_PREFIX=/opt/factorio # factorio binary path FACTORIO_BINARY="$FACTORIO_PREFIX/bin/x64/factorio" # factorio save file FACTORIO_SAVE_FILE="$FACTORIO_PREFIX/serversave.zip" # factorio server port (default is 34197) FACTORIO_PORT=34197 # bind IP (XXX.XXX.XXX.XXX:port) FACTORIO_IP="0.0.0.0:$FACTORIO_PORT" # RCON port FACTORIO_RCON_PORT=34198 # RCON password (CHANGE THIS!) FACTORIO_RCON_PASSWORD="default" # server server-settings.json FACTORIO_SETTINGS="$FACTORIO_PREFIX/data/server-settings.json" # path to write console logs to FACTORIO_LOGFILE="/var/log/factorio.log" # path for the pidfile FACTORIO_PIDFILE="/var/run/factorio.pid" # user to run the server as FACTORIO_USER="factorio" # build up the factorio arguments list FACTORIO_ARGS=" --bind $FACTORIO_IP --rcon-port $FACTORIO_RCON_PORT --rcon-password $FACTORIO_RCON_PASSWORD --server-settings $FACTORIO_SETTINGS --start-server $FACTORIO_SAVE_FILE" ####### factorio_get_running_pid() { # get the PIDfile stored on disk. If the PID is current running, echo it, else # return 1 if [ -e "$FACTORIO_PIDFILE" ] ; then PID=$(cat "$FACTORIO_PIDFILE") fi N=$(ps aux | grep "$PID" | grep -v "grep" | wc -l) if [ $N == 1 ] ; then echo "$PID" else return 1 fi } factorio_start() { # check if there is already a copy of this service running if [ -e "$FACTORIO_PIDFILE" ] ; then RUNNING_PID=$(factorio_get_running_pid) if [ $? -ne 0 ] ; then # there is a stale pidfile rm "$FACTORIO_PIDFILE" else echo "factorio is already running with PID $RUNNING_PID" exit 1 fi fi # back up the old log file if [ -e "$FACTORIO_LOGFILE" ] ; then mv "$FACTORIO_LOGFILE" "$FACTORIO_LOGFILE.old" fi # we have to create the log file so we can chown it to the factorio user touch "$FACTORIO_LOGFILE" chown "$FACTORIO_USER" "$FACTORIO_LOGFILE" # launch the server /usr/local/bin/sudo -u $FACTORIO_USER sh -c "$FACTORIO_BINARY $FACTORIO_ARGS 2>&1 > $FACTORIO_LOGFILE" & PID=$! echo "$PID" > "$FACTORIO_PIDFILE" echo "started $name, pidfile is: $FACTORIO_PIDFILE, PID is $(cat $FACTORIO_PIDFILE) " # make sure the server started correctly sleep 5 factorio_get_running_pid > /dev/null if [ $? -eq 0 ] ; then echo "factorio is running with PID $PID" else echo "factorio failed to start, check $FACTORIO_LOGFILE" exit 1 fi } factorio_stop() { # check to see if factorio is really running RUNNING_PID=$(factorio_get_running_pid) if [ $? -ne 0 ] ; then echo "factorio is not running." exit 0 fi # if so, shut it down gracefully echo "Killing PID $RUNNING_PID..." kill "$RUNNING_PID" sleep 10 # clean up the pidfile factorio_get_running_pid > /dev/null if [ $? -ne 0 ] ; then # the server has closed echo "cleaning pidfile..." rm "$FACTORIO_PIDFILE" else # the server is still running, try again echo "waiting for factorio server to stop..." factorio_stop fi echo "factorio has stopped." } # implement "status" command if [ "$1" == "status" ] ; then RUNNING_PID=$(factorio_get_running_pid) if [ $? -ne 0 ] ; then echo "factorio is not running." else echo "factorio is running with pid $RUNNING_PID" fi exit 0 fi run_rc_command "$1"
This script will allow us to:
Further, thanks to the line "# KEYWORD: shutdown", the Factorio service should be shutdown safely if the system is powered off through normal means (/sbin/shutdown).
Note that this script isn't perfect by any means - this is my first BSD rc.d script, so I've probably missed some things. If you have a suggestion for how to improve this script, please send me an email!
You can edit the file /opt/factorio/data/server-settings.json to configure Factorio. You can find some relevant information on this subject on the Factorio wiki[5], however, I have found the following modifications are particularly convienient:
[5] - Factorio Wiki: Multiplayer
The first time you start the server via "service factorio onestart", you will probably get a nasty error like this:
started factorio, pidfile is: /var/run/factorio.pid, PID is 1234 factorio failed to start, check /var/log/factorio.log
If you consult the logfile, you will see that this error is caused by the server's world save file not existing:
0.504 Error ServerMultiplayerManager.cpp:94: MultiplayerManager failed: "File /opt/factorio/serversave.zip does not exist."
Fortunately, this is very easy to rectify, simply run as the factorio user:
/opt/factorio/bin/x64/factorio --create /opt/factorio/serversave
Now you should be able to launch the server with "service factorio onestart"
You may have noticed that simply running "service factorio start" makes rc yell at you with an error like this:
Cannot 'start' factorio. Set factorio_enable to YES in /etc/rc.conf or use 'onestart' instead of 'start'.
This is because the service has not been enabled. To enable the service (which will also cause your factorio server to boot when your turn on your FreeBSD server), add the line "factorio_enable=YES" to /etc/rc.conf.
RCON is an extremely helpful tool for managing Factorio servers which run headlessly. It can be downloaded from a [forum post](https://forums.factorio.com/viewtopic.php?f=133&t=27540). You can connect to your Factorio server with RCON via the information you configured in the rc script above.
Disappointingly, this tool does not run on UNIX systems, nor could I get it to run under WINE. However, running RCON via Parallels on my MacBook worked quite well.
For now, the main uses of RCON are to create additional saves on the server, send messages to and amdinistrate the connected players, and to terminate the server safely. This is valuable if you want to give operators access to administrate your Factorio server, but without giving them access to start and stop services on your FreeBSD host. Likewise, RCON is also useful for sending messages or otherwise interacting with players without launching the Factorio client first.
Thus, with a little know how and some shell scripts, it is quite straightforward to run Factorio on FreeBSD thanks to FreeBSD's excellent Linux emulation. Using the method outlined above, it can even be run as a background daemon, without requiring one to leave a console session attached. Furthermore, the RCON administration tool allows one to perform common administrative tasks on the Factorio server without requiring a Factorio game client to be running, or shell access on the FreeBSD host running the game server.
Copyright 2017 Charles Daniels.