The Blog of Charles Daniels

# Running a Headless Factorio Server on FreeBSD

Posted 2017-07-24

Running a Headless Factorio Server on FreeBSD

# Introduction

In this guide, I will discuss how you can go about running a headless factorio 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:

• Installing and running the Factorio standalone server.
• Writing a FreeBSD rc.d script to run the Factorio server as a system service.
• Configuring the Factorio standalone server.
• Managing the Factorio standalone servier via RCON.

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.

## What is Factorio

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.

source

# Software Versions

• FreeBSD 11.0-RELEASE
• Factorio 0.15.30 (experimental release)
• RCON 1.0.2

Last updated: 2017-07-24

# Installing Factorio

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 on your server. To get the Linux libraries needed to run the server, you should install linux_base-c7 (CentOS 7.X compatibility).

First, we will setup the Factorio user account:

 1 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:

 1 zfs create -o mountpoint=/opt/factorio zroot/factorio 

OR (don't do both!)

To make /opt/factorio as a normal directory:

 1 mkdir -p /opt/factorio 

Set this directory to be owned by the factorio user:

 1 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 this page. 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:

 1 2 3 4 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:

 1 bin/x64/factorio --version 

 1 2 3 4 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 

# Running Factorio as a Service

While reading this section, you may find the document Practical rc.d scripting in BSD helpful as reference material.

Note: in 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.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 #!/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:

• Run factorio as a background daemon, rather than leaving it attached to a console session.
• Start and stop the factorio daemon.
• Check if Factorio is running or not.
• All of this via the standard rc componant of FreeBSD.

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!

# Configuring the Factorio Server

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, however, I have found the following modifications are particularly convienient:

• autosave_interval - should be set to a fairly low number (I suggest 3 minutes); raise it if it causes performance issues.
• autosave_slots - I prefer to set this to a high number. Combined with a short autosave interval, this will give you a highly granular, but also long-lived backup history (if you have the disk space to space!)

# Using the Factorio Server

The first time you start the server via service factorio onestart, you will probably get a nasty error like this:

 1 2 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:

 1 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:

 1 /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:

 1 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.

# Managing the Factorio Server with RCON

RCON is an extremely helpful tool for managing Factorio servers which run headlessly. It can be downloaded from a forum post. 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.

# Conclusion

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.