- Rootless Icarus Dedicated Server
- Preamble
- Building a container
- Running the rootless container
Because I hate running containers as root I created a rootless configuration. I was inspired on running steamcmd windows servers by the build of nerodon: https://gitlab.com/fred-beauch/icarus-dedicated-server
Building a contianer should preferable be done on a development system, this way you will not provide tools that can be exploited on the system that will be running the container.
Also build as a regular user, that way you ensure that the container accidently requires enhanced privileges.
If you must build on the system that is going to run the container, make sure that the account to run the container is a different account than the one used to build the container.
- podman latest
- enough space to build the container
For podman installation and usage visit https://podman.io/docs
For rootless containers you must ensure that subgid en subuid is configured.
For details on subuid and subgid visit https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md
We need --cap-add to build the container as a regular user, the container image will not use any caps when it's running.
Also required is --device /dev/fuse when building as a regular user.
To minimize the image size I add --squash-all to remove all the layers.
The -t example.registry.com:9999/library/icarus-dedicated-server:latest applies the tag to container when it is build.
On rocky/fedora --security-opt=label=type:container_runtime_t is also required to allow building.
As a regular user, to build issue the following command:
podman build -t example.registry.com:9999/library/icarus-dedicated-server:latest -f Dockerfile --cap-add=all --security-opt=label=type:container_runtime_t --device /dev/fuse --squash-allEnough space in the home directory of the user running the pod
On your linux system as root create a regular user.
The userid (UID) and the groupid (GID) are not important as we run a rootless container.
Make sure the subuid and subgid are configured for this user for details visit https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md
This tutorial will assume you are using fedora linux and the user will be called steam with a regular home and set a password on it
I choose to name the user on the container-host steam, this is a random name that just happens to be the same as the user in the container. Podman will assign an unique uid/gid when it starts the container and will try to do it's best to avoid conflicts with any uid specyfied in the /etc/passwd and /etc groups of the container host. So you might as well call it qwerty, just make sure you issue all the commands as the user qwerty after that.
useradd -m steam
passwd steamSince the container is ephemeral (ie all the savegame and server data in it will be gone when it shuts down) you must create persistent storage to be used as a savegame location and server data location.
The simplest way to do this is by creating 2 directories and mounting these as a volume in the container.
As the steam user create 2 directories, one for the server and one for savegames.
mkdir /path/to/steam /path/to/gameThese will be mounted as volumes when the container is started
Because rootless containers run in a different namespace the user in the container has no access to the host filesystem.
To enable access we must change the owner of the folders using 'podman unshare chown'.
That way the subuid/subgid will be made the owner of those folders.
To ensure the subuid/subgid matches the mapping to the uid/gid in the container this must be done using the user account on the container host
Here the UID and the GID MUST match the UID and GID used in the container.
I used UID 1001 and GID 1001 in the Dockerfile to create the container so I use them here as well.
podman unshare chown -R 1001:1001 /path/to/game
podman unshare chown -R 1001:1001 /path/to/steamThe uid/gid of the directories and subdirectories (if any) will now be changed to a random number from the subuid/subgid range. The user in the container is now owner of those directories and can read and write to them, the user on the host can now only read them.
Use the root account on the server host to edit or remove those directories. (or change the owner again)
When you manipulate the foldes make sure you:
- first as root recursivly change the owner back to the regular user
- then as the regular user unshare them again with the above commands
The best way to start the container is by using compose. That way the configuration is always the same and easy to check/debug.
To start issue the following command as the user on the container host.
To ensure the command runs in the background I add the option -d.
podman compose -f /path/to/compose.ymls up -dAs the steam user run the following command to stop the server.
podman compose -f /path/to/compose.ymls downThis requires the following steps.
- Add unit file to the steam user home dir
- Update systemd unit files as user
- Enable unit file as the user
- Enable linger for the user
- Start unit file as the steam user
Systemd needs a unit file to autostart a container.
The unit file for a container is called a quadlet, it has a lot of similarities with a docker-compose file.
For a regular user it needs to be located in the home directory of the user in the .config/container/systemd directory.
I've added a quadlet unit file that can be used for this: icarus.container
mkdir -p $HOME/.config/container/systemd
cp icarus.container $HOME/.config/container/systemdMake sure there is a game and steam folder in the user home dir
Systemd needs to be made aware of the new unit files. This can be done by issueing the following command as the steam user.
systemctl --user daemon-reloadThe container will be enabled automatically for the user by the systemctl --user daemon-reload command.
This section is here to make it clear that it's not longer needed to do this for container unit files for rootless containers.
To allow the container to run even when not logged in you must enable linger for the regular user account.
If you do not enable linger the container will be shut down as soon as you log out.
When linger is enabled for the user it will also ensure that all the containers who are specified in quadlet/unit files will be started on boot.
As root issue the following command:
loginctl enable-linger steamAfter issueing this command systemd will automatically start the container after a reboot if the unit file is in the ~/.config/container/systemd directory.
If you need to disable linger issue the following command as root.
loginctl disable-linger steamAs the steam user
systemctl --user start icarus.containerTo read the logs of the container is the following command as the user:
podman logs -f icarus-dedicated-serverThe -f causes the command to 'tail' the logs, use ctrl-c to stop tailing the logs.
To read all the ingame logs issue the following command as the regular user:
tail -f $HOME/game/drive_c/icarus/Saved/Logs/Icarus.logThis command assumes you have the $HOME/game on the container host mounted in the container on /home/steam/game.
To open the ports in firewalld during runtime:
firewall-cmd --add-port=17777/udp --add-port=27015/udpTo open the ports in firewalld on startup
firewall-cmd --add-port=17777/udp --add-port=27015/udp --permanentTo close the ports in firewalld during runtime:
firewall-cmd --remove-port=17777/udp --remove-port=27015/udpTo close the ports in firewalld on startup
firewall-cmd --remove-port=17777/udp --remove-port=27015/udp --permanentSome more commands that you might wish to use but that are no needed to get the container automatically started.
As steam user stop the container
systemctl --user stop icarus.containerThis is optional!!
You could make the steam user more secure if you do the following,
but this makes using the account a bit more difficult
Modify the user to use the nologin shell On the container host as root (replace steam with the regular user name you used)
usermod -s /sbin/nologin steamTo undo this:
usermod -s /bin/bash steamDo not set a password on the account when you create the user. If you did set a password you can remove it by issuing the following command.
passwd --delete steamAnd you can set the password back again with:
passwd steamIf you wish to access the account to modify the unit file. (which requires a login shell) Using another regular account on the container host that has sudo privileges.
sudo su --shell=/bin/bash - steam
export XDG_RUNTIME_DIR="/run/user/$UID"
export DBUS_SESSION_BUS_ADDRESS="unix:path=${XDG_RUNTIME_DIR}/bus"Now all the systemctl and podman commands will work.
Do NOT add sudo privileges to the account running the container !!!!
Every privilege that is added to the regular user account running the container is a privilege that can potentially be exploited. It is best to create a new account for each container so you can be sure it has no privileges that you might have forgotten.
For the regular user on the container host as root. Remove all the shell history files, and shell configuration files.
It's best to remove all the files that are not mentioned in this README.md
Files/dirs that are needed by the container:
- .local/share/containers
- .config/containers
- game # or whatever you set this to
- steam # or whatever you set this to
As root on the container host (replace steam with the regular user you created):
tar -cJvf /backup_folder/prospects.tar.xz /home/steam/game/drive_c/icarus/Saved/PlayerData/DedicatedServer/ProspectsAs root on the container host (replace steam with the regular user you created):
cd /
chown -R steam:steam /home/steam
tar -xvf /backup_folder/prospects.tar.xz
chown -R steam:steam /home/steamAs the regular user unshare the folders again:
podman unshare chown -R 1001:1001 game steamThe only option you realy need to set is the admin password.
Defaults will be applied where needed.
BRANCH=public
STEAM_USER=steam
STEAM_GROUP=steam
STEAM_USER_UID=1001
STEAM_USER_GID=1001
STEAM_CMD_DIR=/home/steam/Steam
STEAM_CMD=$STEAMDIR/steamcmd.sh
STEAM_CMD_URL=https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz
STEAM_GAME_DIR=/home/steam/game
WINEPREFIX=$STEAM_GAME_DIR
WINEARCH=win64
ADMIN_PASSWORD=""
ALLOW_NON_ADMINS_LAUNCH=""
ALLOW_NON_ADMINS_DELETE=""
CREATE_PROSPECT=""
GAMESAVEFREQUENCY=""
JOIN_PASSWORD=""
LOAD_PROSPECT=""
MAX_PLAYERS=""
SHUTDOWN_NOT_JOINED_FOR=""
SHUTDOWN_EMPTY_FOR=""
PORT=""
QUERYPORT=""
RESUME_PROSPECT=""
SAVEGAMEONEXIT=""
SERVERNAME=""
FIBERFOLIAGERESPAWN=""
LARGESTONERESPAWN=""
GAMESAVEFREQUENCY=""
SAVEGAMEONEXIT=""