Instructions for your own dedicated OpenTTD server
This guide is about the OpenTTD game. I will show you step-by-step how to set up a dedicated server for it.
Table of Contents
CAUTION
Please note that this blog post was originally written in German and has been translated for your convenience. Although every effort has been made to ensure accuracy, there may be translation errors. I apologize for any discrepancies or misunderstandings that may result from the translation and I am grateful for any corrections in the comments or via mail.
When the Corona pandemic started over a year ago, I was looking for games I could play with friends without being in one place. One of the games I came across was OpenTTD.
OpenTTD is an open-source simulation game based on Transport Tycoon Deluxe
This free game is now also available via Steam or the Play Store and has highly positive ratings (96%) and 4.1/5 stars respectively. The objective of the game is to run a transportation company by constructing and managing transportation routes and vehicles.
A dedicated server allows different players to log into a shared game at different times. I would like to set this up in this guide.
Install server
If you have already set up a server according to these instructions, you can skip this part, as the setup is repeated here in abbreviated form.
The first step is to get a server. In my opinion, the VPS and especially Root-Server (dedicated CPU) from Netcup are recommended. For a pure OpenTTD server, you don’t need high requirements, mainly if you don’t want to create huge maps and/or expect a high number of players. A smaller VPS should be sufficient.
New customers receive with these affiliate vouchers a discount on the first order (and I receive a commission for referred customers). The percentage discounts remain permanently active if the VPS is not canceled.
I choose Ubuntu 20.04 as the operating system for the new installation. Another would also be possible as long as Docker can be installed on it. Still, I have some experience with Ubuntu and see no reason to change. Furthermore, the end of standard support is in April 2025, so it will probably not be necessary to upgrade the operating system to the next version for the time being.
The connection to the server must be established as soon as the server has been reinstalled. This can be done under Windows with the Windows Terminal, PuTTY or a similar program. VSCode also has a built-in terminal and offers the advantage of easier editing, as described here. I use the Windows Terminal.
The server’s own IP address should of course be entered.
Then answer the question with “yes” if necessary and enter the password. The password is not displayed while it is being entered. First, we check whether there are any updates and install them if necessary:
apt update
apt upgrade
Confirm whether you want to update with Y.
The text editor Nano should already be installed by default, but you can install it like this to be on the safe side:
apt install nano
Next, we rename the server:
nano /etc/hostname
In Nano, exit the file with Ctrl + X. Nano will ask you if you want to save the changes (confirm with Y) and what you want to name the file. As we want to overwrite it, we do not change the name and simply confirm with Enter.
The new hostname is visible when you restart the server reboot
and then reconnect to it ssh admin@{ip-address}
.
Now, it makes sense to create a user who is not root.
useradd -m -G sudo namedesneuennutzers
passwd namednewuser
Useradd
is the command to create a new user. The -m
ensures that this user is assigned a home folder. The -G
puts the user into a group, and then the group is named. The sudo group can execute commands with sudo
. Finally, the name of the new user follows. A password for the user is created with passwd
.
If the sudo group does not exist, you must create a group.
groupadd namenewgroup
This group should have the right to execute sudo commands:
EDITOR=nano visudo
The new group must then be mentioned in the file.
Now, we set the correct time if required.
date
If the correct time is not displayed:
tzselect
The time zone can be selected using the numbers.
timedatectl set-timezone 'Europe/Berlin'
It is time to restart the server and log in as a newly created user.
reboot
Next, I install Htop (a monitoring program).
apt install htop
Now, the server should refuse to run the program and ask if you are root.
So again, with Superuser do.
sudo apt install htop
By entering htop
, you can now view the load on the server.
This makes it easy to see how much the server’s CPU and RAM are used. Press F10 or CTRL + C to exit the view.
I would like to have another shell.
sudo apt install git curl
sudo apt install zsh
Now I install zim and change the default shell to zsh.
curl -fsSL https://raw.githubusercontent.com/zimfw/install/master/install.zsh | zsh
chsh -s /bin/zsh
exec bash
Now the shell should (subjectively) look better.
The most important parts of the installation are Docker and Docker-Compose. Also optional is Lazydocker, a straightforward way to view your Docker containers and their current logs via SSH.
sudo apt install docker docker-compose
curl https://raw.githubusercontent.com/jesseduffield/lazydocker/master/scripts/install_update_linux.sh | bash
Docker must now be activated.
sudo systemctl enable --now docker
If the following line does not appear, use CTRL + C to help. Now assign the created user to the docker group for convenience. For security reasons, you should not do this and must always write sudo
before the commands with docker
.
sudo gpasswd -a namednewuser docker
Check whether the user has actually ended up in the group.
id namednewuser
Finally, we create a folder in the new user’s home directory.
cd ~
mkdir docker
With mkdir
(make directory), we created the folder docker in the home directory (~).
If Lazydocker can be opened, the setup is complete.
sudo lazydocker
With Q, ESC or CTRL + C Lazydocker can be closed again.
Docker-Compose with OpenTTD
The next step is to create a Docker-Compose file to start the container with OpenTTD. First, we need a folder in which the configuration file and the savegames can be saved as well as the Docker-Compose file.
mkdir ~/docker/appdata/openttd -p
touch ~/docker/docker-compose-openttd.yml
We check whether port 3979 is already in use.
sudo lsof -i -P -n | grep LISTEN
We now fill the Docker-Compose file.
nano ~/docker/docker-compose-openttd.yml
version: "3.7"
services:
openttd:
container_name: openttd
image: redditopenttd/openttd
ports:
- 3979:3979/tcp
- 3979:3979/udp
restart: unless-stopped
volumes:
- ./appdata/openttd:/config
environment:
- loadgame=false
If port 3979 is already in use, we select another port under which the Docker can be reached. For example 3969:3979/tcp
and 3969:3979/udp
. This is also necessary if several servers are to run simultaneously.
After we have saved the file, we start the container.
cd ~/docker
docker-compose -f docker-compose-openttd.yml up -d
And we look to see if there is anything unusual in the log.
lazydocker
First we stop our container again.
docker-compose -f docker-compose-openttd down
The container can also be stopped via Lazydocker.
Editing the configuration
Now the configuration should be customized to your liking. The configuration file should have been downloaded automatically when the container was started for the first time.
nano ~/docker/appdata/openttd/.config/openttd.cfg
There are many possibilities here, I change a few values of the default settings:
min_active_clients = 1
The game is paused if no player is connected to the server.
server_password = abc
It is possible to set a password so that new players must first enter the password to be able to play.
server_name = Unnamed Server
The server can be renamed.
autosave = quarterly
The game is saved four times per game year.
starting_year = 1920
This can be used to determine the year in which the game should start.
map_x = 9 map_y = 9
The size of the map can be changed. The larger the map, the more the server has to work.
infrastructure_maintenance = true
This causes an amount to be paid at regular intervals, calculated from the number of areas with rails, canals or locks.
forbid_90_deg = true
This prevents trains from making 90° turns.
max_aircraft = 100 max_ships = 200
This setting reduces the number of airplanes and ships a company may have.
town_name = german
This ensures German town names.
terrain_type = 2
This provides a slightly less flat landscape.
snow_line_height = 7
Snow starts lower.
town_layout = 4
More varied towns
industry_density = 4
Lower industrial density
station_noise_level = true
With this setting, the number of airports that can be placed near a city is no longer fixed. Instead, it depends on the airports’ noise level, distance from the city center and the city’s attitude.
I leave the rest as it is for now. Now I’ll delete the previous automatically created scores.
cd ~/docker/appdata/openttd/.local/share/save
sudo rm -r autosave
Starting the game
We adjust the configuration so that game saves are loaded.
cd ~/docker
nano docker-compose-openttd.yml
version: "3.7"
services:
openttd:
container_name: openttd
image: redditopenttd/openttd
restart: unless-stopped
ports:
- 3979:3979/tcp
- 3979:3979/udp
volumes:
- ./appdata/openttd:/config
environment:
- loadgame=exit
And a new game can be started.
cd ~/docker
docker-compose -f docker-compose-openttd.yml up -d
This time, the logs show that the game has been paused due to the changed settings.
Now, it is also possible to connect to the game. To do this, install the game and start it. You can add a server in the “Multiplayer” menu.
The IP address, including port, must be entered in the input field. For example 191.80.90.90:3979. You can then join the server.
Update the server
Of course, you should update the server occasionally; with Docker this is done with just a few lines of code.
cd ~/docker
docker-compose -f docker-compose-openttd.yml down
docker pull redditopenttd/openttd
docker-compose -f docker-compose-openttd.yml up -d
# Don't forget to update the host server as well
sudo apt update && sudo apt upgrade
With htop
you can see if the server has enough resources. At this point, I wish you lots of fun building 🚈