Skip to content
 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2,040 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Uberserver Deployment Guide

A start-to-finish guide for running uberserver on Ubuntu Server 24.04 LTS using Docker and MariaDB.

Repository: https://github.com/ScarylePoo/uberserver


Prerequisites

  • Ubuntu Server 24.04 LTS
  • A non-root user with sudo privileges
  • Ports 8200 (TCP) and 8201 (UDP) available

1. Install Docker

curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER

Log out and back in after this, then verify it worked:

docker run hello-world

2. Clone the Repository

git clone https://github.com/ScarylePoo/uberserver.git
cd uberserver

3. Configure the Environment

cp .env.example .env
nano .env

Fill in your values:

Setting Description
DB_ROOT_PASSWORD MariaDB root password. Set something strong.
DB_PASSWORD MariaDB password for the uberserver user. Set something strong.
DB_NAME Database name. Default: uberserver
DB_USER Database username. Default: uberserver
LOBBY_PORT Port clients connect to. Default: 8200
NAT_PORT Port for NAT hole-punching. Default: 8201
MAXMIND_LICENSE_KEY Optional. Free key from maxmind.com for country flags. Leave blank to skip.
ONLINE_IP Optional. The server's own public IP. Leave blank to auto-detect. Affects battles hosted on the same LAN as the server, and identifies the server's own traffic. See Host IP Detection.
EXTRA_ARGS Optional extra arguments passed to server.py.

Never commit your .env file to source control — it contains passwords.


4. Build and Start

docker compose build
docker compose up -d

The build takes a few minutes the first time. Check it started successfully:

docker compose logs -f uberserver

You should see:

MariaDB is up.
Starting uberserver...
Started lobby server!

Press Ctrl+C to stop watching logs. The server keeps running in the background.


5. Open Firewall Ports

sudo ufw allow 8200/tcp
sudo ufw allow 8201/udp

If you're on a cloud VPS (AWS, Hetzner, DigitalOcean etc.), also open these ports in your cloud provider's firewall or security group.


6. Create an Admin User

Connect to the database:

docker compose exec db mariadb -u uberserver -p uberserver

Enter your DB_PASSWORD when prompted. Then generate a password hash — open another terminal and run:

docker compose exec uberserver /app/venv/bin/python3 -c "
import hashlib, base64
pw = 'your_chosen_password'
print(base64.b64encode(hashlib.md5(pw.encode()).digest()).decode())
"

Then back in the MariaDB shell, insert your admin user:

INSERT INTO users (username, password, access, register_date, last_login, last_ip, last_agent, last_sys_id, last_mac_id, ingame_time, bot)
VALUES ('yourusername', 'PASTE_HASH_HERE', 'admin', NOW(), NOW(), '127.0.0.1', '', '', '', 0, 0);

Verify it was created:

SELECT id, username, access FROM users;

Type exit to leave the MariaDB shell.


7. Connect with a Lobby Client

Use any Spring lobby client (e.g. SkyLobby or SpringLobby) and add a custom server pointing to your server's IP on port 8200. Make sure TLS/SSL is disabled when connecting to a private server with a self-signed certificate.


Day-to-Day Management

Command What it does
docker compose up -d Start everything
docker compose down Stop everything
docker compose restart uberserver Restart just the lobby server
docker compose logs -f uberserver Watch live logs (Ctrl+C to stop)
docker compose ps Check container status
docker compose build --no-cache Rebuild from scratch (e.g. after pulling updates)

Accessing the Container Shell

To open a bash shell inside the running uberserver container:

docker compose exec uberserver bash

To exit the shell and return to the host:

exit

Monitoring the Server Log

Watch live output from the server (Ctrl+C to stop):

docker compose logs -f uberserver

Read the persistent log file inside the container:

docker compose exec uberserver cat /app/server.log

Tail the last 50 lines of the log file:

docker compose exec uberserver tail -50 /app/server.log

Updating

git pull
docker compose build --no-cache
docker compose up -d

Auto-start on Reboot

Docker's restart: unless-stopped policy means containers restart automatically after a reboot, as long as the Docker daemon starts on boot:

sudo systemctl enable docker

ChanServ Admin Commands

Once logged in as an admin, you manage the server through the ChanServ bot. Commands are prefixed with : and can be sent as a PM to ChanServ, or typed inside a channel (omitting the channel name).

Channel Management

Command Who can use it
:register chanName [founder] Moderators
:unregister chanName Moderators
:op chanName username Moderators, channel founder
:deop chanName username Moderators, channel founder
:history chanName on|off Moderators, channel founder
:antispam chanName on|off Moderators, channel founder

User Management

Command Who can use it
:topic chanName topic text Ops, moderators, founder
:kick chanName username Ops, moderators, founder
:mute chanName username 2d reason Ops, moderators, founder
:unmute chanName username Ops, moderators, founder
:ban chanName username 7d reason Ops, moderators, founder
:unban chanName username Ops, moderators, founder
:listbans Ops, moderators, founder
:listmutes Ops, moderators, founder
:setbot username Moderators, admins
:unsetbot username Moderators, admins

Duration format: 1h = one hour, 2d = two days.

:setbot and :unsetbot must be sent as a PM to ChanServ — they cannot be used inside a channel since they require a username argument.

Server Management

Command Who can use it
:showip Moderators, admins
:refreship Admins

:showip reports the server's current online and local IP, and whether either is pinned by an override.

:refreship re-runs IP detection without restarting the container. Use it if the server's WAN IP changes while it is running — see Host IP Detection. It replies immediately and PMs the result once detection finishes. Battles already open keep their old advertised address and must be rehosted; new battles pick up the refreshed value.

Both must be sent as a PM to ChanServ, or typed in a channel without a channel argument.

Access Levels

Every user account has an access level that controls what they can do on the server.

Level Description Inherits from
fresh Newly registered, has not accepted the agreement yet
agreement Has accepted the agreement, pending email verification
user Normal fully verified user
mod Moderator user
admin Administrator mod, user
bot Bot account with higher flood/bandwidth limits

fresh and agreement are transitional states that users pass through automatically during registration. You should not need to set these manually.

Moderators inherit all user permissions plus moderator-only actions. Admins inherit all moderator and user permissions plus admin-only actions.

Changing a User's Access Level

Via the database (recommended for fresh, agreement):

docker compose exec db mariadb -u uberserver -p uberserver
UPDATE users SET access = 'mod' WHERE username = 'someuser';

Via the lobby (admins only, works for user, mod, admin):

Send this command in the lobby server window or as a lobby client admin:

SETACCESS username user|mod|admin

Note: SETACCESS only accepts user, mod, or admin. Use the database directly to set fresh or agreement.

Bot Accounts

Bot accounts are regular user accounts with a bot flag set. They get significantly higher flood and bandwidth limits, and are shown as bots to connecting clients. The access field should be user — do not set it to bot.

Creating a bot account via the database:

docker compose exec db mariadb -u uberserver -p uberserver
INSERT INTO users (username, password, access, register_date, last_login, last_ip, last_agent, last_sys_id, last_mac_id, ingame_time, bot)
VALUES ('botusername', 'HASH_HERE', 'user', NOW(), NOW(), '127.0.0.1', '', '', '', 0, 1);

Note the bot = 1 at the end. The access field must be user, not bot.

Managing bot flags via ChanServ (mods and admins):

PM ChanServ or type in a registered channel:

:setbot username
:unsetbot username

:setbot sets bot = 1 on the account. :unsetbot removes the bot flag. Both commands work on online and offline users.


Optional Config Files

These files live in the root of the repository alongside server.py. After creating or editing any of them, copy them into the running container and restart:

docker compose cp filename.txt uberserver:/app/filename.txt
docker compose restart uberserver

server_motd.txt — Message of the Day

Displayed to every user when they log in. One line per message. Plain text.

Welcome to My Uberserver!
Visit our Discord at discord.gg/example

server_agreement.txt — Terms of Service

Shown to new users on registration. They must accept it before their account is activated. One line per paragraph.

Welcome to My Uberserver.

By registering you agree to behave respectfully towards other players.
No cheating, hacking, or abusive behaviour is permitted.

The server administrators reserve the right to ban any user at any time.

If no agreement file is present the server uses a default warning message and does not block registration.


server_email_account.txt — Email / SMTP Configuration

Required if you want email verification on registration and password reset emails. If this file does not exist, email verification is disabled and users can register without providing an email address.

The file has up to 5 lines:

line 1: from address        (required)
line 2: SMTP host           (required for external relay)
line 3: SMTP port           (optional, default 587)
line 4: SMTP username       (optional)
line 5: SMTP password       (optional)

Example using AuthSMTP:

no-reply@yourdomain.com
mail.authsmtp.com
587
your_authsmtp_username
your_authsmtp_password

Example using Gmail:

no-reply@yourdomain.com
smtp.gmail.com
587
your.email@gmail.com
your_app_password

For Gmail you must use an App Password, not your regular password. Two-factor authentication must be enabled first.


server_verification_message.txt — Verification Email Template

Customises the email sent to users when they register or request a password reset. If this file does not exist, a default Recoil Engine-branded email is sent.

The file has 4 header lines followed by the email body template:

line 1: server/community name
line 2: contact URL
line 3: email subject line
line 4: timezone label
line 5+: email body template (can be as many lines as you like)

Example:

Recoil Engine
https://recoilengine.org
Recoil Engine - Email Verification
UTC
You are receiving this email because you recently {reason}.
Your email verification code is: {code}

This code will expire on {expiry_date} at {expiry_time} {tz}.

If you received this message in error, please contact us at {contact}.
Direct replies to this message will be automatically deleted.

Available placeholders for the body template:

Placeholder Value
{name} Server/community name (line 1)
{contact} Contact URL (line 2)
{reason} Why the email was sent (e.g. "registered an account on the X lobbyserver")
{username} The username of the registering user
{code} The verification code
{expiry_date} Date the code expires (YYYY-MM-DD)
{expiry_time} Time the code expires (HH:MM)
{tz} Timezone label (line 4)

server_iphub_xkey.txt — VPN/Proxy Detection

Contains a single API key from iphub.info. When present, the server checks each registering user's IP against the IPHub API. Users connecting from VPNs, datacenters, or non-residential IPs will have their account activation delayed by 24 hours.

your_iphub_api_key_here

Get a free API key at https://iphub.info — the free tier allows 1,000 checks per day.

If this file is not present, IP checking is disabled and all registrations are processed immediately.


bad_words.txt — Profanity Filter

A list of words to censor in chat. One word per line. The server replaces matched words with *** in channels where censoring is enabled.

You can optionally provide a replacement word by putting it after a space:

badword
anotherbadword replacement

If this file is not present, no word censoring is applied.


bad_sites.txt — URL/Site Blacklist

A list of domain names or URL fragments to block from chat. One entry per line, lowercase. If a message contains any of these strings it is silently dropped.

badsite.com
anotherbadsite.net

If this file is not present, no URL filtering is applied.


bad_nicks.txt — Username Blacklist

A list of usernames or username fragments that are not allowed to be registered. One entry per line, lowercase.

badusername
admin
moderator

If this file is not present, no username blacklisting is applied beyond the server's built-in character validation.


args.txt — Server Arguments File

An alternative to passing arguments via EXTRA_ARGS in .env. Put server startup arguments in this file, one per line.

--no-censor
--min_spring_version 105.1.1

To use it, set in your .env:

EXTRA_ARGS=--loadargs /app/args.txt

Then copy it into the container:

docker compose cp args.txt uberserver:/app/args.txt
docker compose restart uberserver

proxies.txt — Trusted Proxy List

A list of trusted proxy IP addresses, one per line. When a connection comes from a trusted proxy, the server uses the client's real IP instead of the proxy's IP for ban checks, country detection, and rate limiting.

192.168.1.100
10.0.0.1

To enable it, set in your .env:

EXTRA_ARGS=--proxies /app/proxies.txt

Then copy it into the container:

docker compose cp proxies.txt uberserver:/app/proxies.txt
docker compose restart uberserver

Host IP Detection

When a player opens a battle, the server decides which IP address to advertise to everyone else as the game host address. That address ends up in the game's start script as HostIP. The logic lives in client_AddBattle in protocol/Protocol.py and picks one of three values per receiving client:

Situation Address sent
Joining client has the same WAN IP as the host The host's own LAN IP (both are behind the same router)
Host is on a private IP, joining client is on WAN The server's public IP (online_ip)
Otherwise The host's WAN IP as seen by the server

The second case is what makes LAN-hosted battles reachable from the internet — it assumes the relevant port is forwarded to the host. If your SPADS node and your own machine sit on the same LAN as the lobby server, every battle you host takes this path and is advertised using online_ip.

Note the scope: online_ip is consulted only in that second case. A host connecting from elsewhere on the internet has a public address, falls through to the third case, and has its own WAN IP passed through untouched. Those hosts are unaffected by online_ip entirely.

Other uses of online_ip

Besides battle addressing, the server uses online_ip to recognise its own traffic. Loopback connections (127.*) are rewritten to it in Client.py, and connections whose address matches it are exempted from two protections:

  • the per-IP registration rate limit (Protocol.py, in_REGISTER)
  • the IPHub VPN/proxy check, which is skipped outright

This matters if you pin ONLINE_IP manually. A stale value mainly breaks LAN-hosted battles; a wrong value additionally grants unlimited registrations and a VPN-check bypass to whoever actually occupies that address. Verify the value with curl -s https://api.ipify.org before pinning it.

How online_ip is determined

At startup the server queries a series of public IP-echo services (ipify, ifconfig.me, checkip.amazonaws.com, icanhazip, ipecho) and takes the first valid answer. It falls back to the local IP if all of them fail.

This runs once, at process start, and is never repeated on its own. If the server's WAN IP changes while the container is running — an ISP lease renewal, a router or firewall reconfiguration — the server keeps advertising the old address indefinitely, and external players get an unroutable HostIP for every battle. Nothing in the logs will flag this after the fact.

Three ways to fix or avoid it:

  • Restartdocker compose restart uberserver re-runs detection.
  • :refreship — re-runs detection live, no restart, no dropped clients.
  • ONLINE_IP — pins the value permanently. Appropriate only for a static WAN IP, or where outbound HTTPS from the container is blocked. A pin never self-corrects, so on a dynamic address it is worse than leaving detection on.

Diagnosing a wrong host IP

Check what the server currently believes, via :showip or the startup log:

docker compose logs uberserver | grep -iE "detecting|overridden|IP detected|falling back"

Compare against reality:

curl -s https://api.ipify.org

What you see tells you which value broke:

Symptom Cause
An address you used to have Stale online_ip — WAN IP changed since startup
A 172.x address All detection services failed and it fell back to the container's bridge address. Logged at error level
A 192.168.x reaching external players The private-IP branch didn't trigger; check what the host reported at login
Every host shows the same wrong IP A server-side value (online_ip), not a per-host misconfiguration

That last row is the useful discriminator: if only one host is affected it's that host's config, and the logins table records what each client reported:

SELECT u.username, l.ip_address, l.local_ip, l.agent, l.time
FROM logins l JOIN users u ON u.id = l.user_id
ORDER BY l.time DESC LIMIT 20;

Note that local_ip is supplied by the client in its LOGIN command and is only sanity-checked, not verified.


Troubleshooting

Container keeps restarting

docker compose exec uberserver cat /app/server.log

Can't connect on port 8200

  • Check containers are running: docker compose ps
  • Check firewall: sudo ufw status
  • Test locally: telnet localhost 8200

Players can't connect to hosted battles / wrong host IP in the start script

  • Check the advertised address: PM ChanServ :showip
  • If it's stale, PM ChanServ :refreship (admin) or docker compose restart uberserver
  • Full explanation: Host IP Detection

Need to wipe and start fresh (deletes all data)

docker compose down -v
docker compose up -d

Wipe everything including built images

docker compose down -v
docker rmi $(docker images -q)
docker builder prune -af

About

Uberserver, a matchmaking/chat lobby server for Recoil Engine.

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages