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.

Instructions for your own dedicated OpenTTD server-heroimage

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.

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

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

New hostname

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.

Group management

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.

Access denied

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.

ZSH

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

Excerpt from the logs of the Openttd container

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.

Game is paused

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.

add server

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.

Game entry

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 🚈


This website uses cookies. These are necessary for the functionality of the website. You can find more information in the privacy policy