Server Administration

This page covers how to set up and run a dedicated Quetoo server on Debian or Fedora Linux.

Installation

Download quetoo and quetoo-data packages from their respective Releases pages and install them together:

# Debian / Ubuntu
sudo apt install ./quetoo-x86_64-pc-linux.deb ./quetoo-data_*.deb

# Fedora / RHEL
sudo dnf install quetoo-x86_64-pc-linux.rpm quetoo-data-*.rpm

quetoo and quetoo-data have independent release cycles — install the latest of each.


Service Management

The quetoo package installs a systemd template unit quetoo-dedicated@.service and a default instance configuration at /etc/quetoo-dedicated/default.cfg.

Each .cfg file in /etc/quetoo-dedicated/ represents one server instance. Lines are in Quake console format and are passed directly as +set key value arguments to quetoo-dedicated. Blank lines and lines beginning with // or # are ignored.

Edit the default instance configuration to suit your server:

// /etc/quetoo-dedicated/default.cfg
set net_port 1998
set sv_hostname "My Quetoo Server"
set sv_public 1
set rcon_password "secret"

Enable and start the default instance:

sudo systemctl enable --now quetoo-dedicated@default

Manage the service:

sudo systemctl start   quetoo-dedicated@default
sudo systemctl stop    quetoo-dedicated@default
sudo systemctl restart quetoo-dedicated@default
sudo systemctl status  quetoo-dedicated@default

Multiple Instances

To run multiple server instances, create a .cfg file per instance and enable each one:

# Create a CTF instance on port 1999
sudo cp /etc/quetoo-dedicated/default.cfg /etc/quetoo-dedicated/ctf.cfg
# Edit /etc/quetoo-dedicated/ctf.cfg: set net_port 1999, and add the line: game ctf
sudo systemctl enable --now quetoo-dedicated@ctf

The game is a command, so the line MUST be game ctf, not set game ctf. With set game ctf, the server crashes when it starts.

Each instance is managed independently. A typical three-server VPS might have default.cfg (FFA, port 1998), ctf.cfg (CTF, port 1999), and instagib.cfg (Instagib, port 2000).

Attaching to the Console

Each dedicated server instance runs inside a named screen session. The quetoo-attach command lets any sudo-capable user attach to the live server console:

quetoo-attach           # attaches to the "default" instance
quetoo-attach ctf       # attaches to the "ctf" instance

Detach with Ctrl-A D without stopping the server.

Logs and Crashes

Each instance writes its log to /var/lib/quetoo/.local/share/WickedOldGames/Quetoo/logs/<instance>.log, for example logs/default.log. A server that stops is restarted by systemd after five seconds, and each start keeps the logs of the previous ten runs as <instance>.log.1 (the newest) to <instance>.log.10.

If a server crashes, it writes a crash report with a backtrace to the end of its log, and also to <instance>-crash.log in the same directory. The crash log is never truncated or rotated, so it holds every crash of the instance. To see why a server restarted:

sudo tail -n 60 /var/lib/quetoo/.local/share/WickedOldGames/Quetoo/logs/default-crash.log

When you report a crash, you SHOULD include the crash report and the end of the log of the run that crashed (<instance>.log.1 if the server has restarted since).

To give a server that you start by hand its own log, pass -l <path> (or --logFile <path>). A relative name goes in the default directory of the user directory, and an absolute path is used as given. The crash log takes the same name with -crash added.


Updates

quetoo-update fetches the latest release versions of quetoo and quetoo-data from GitHub independently, installs any that are out of date, and restarts all running instances.

Run it manually to update immediately:

sudo quetoo-update

For automatic updates, add it to root’s crontab with --wait-for-empty. The server will update within 15 minutes of a new release, but only once all human players have disconnected:

sudo crontab -e
*/15 * * * * /usr/bin/quetoo-update --wait-for-empty >> /var/log/quetoo-update.log 2>&1

Running a Dedicated Server

Quetoo ships with a quetoo-dedicated binary for headless server operation. You can also launch it directly from the command line:

quetoo-dedicated +set sv_hostname "My Server" +map edge

You can pass any cvar as a +set key value argument at startup, and any command (like map) with +command.

Minimal Startup Example

quetoo-dedicated \
  +set sv_hostname "Fragfest" \
  +set sv_maxClients 16 \
  +set sv_public 1 \
  +map edge

Key Server Cvars

Network

CvarDefaultDescription
net_port1998UDP port the server listens on
sv_hostnameQuetooServer name shown in the browser
sv_public0Set to 1 to advertise on the master server

Capacity

CvarDefaultDescription
sv_maxClients64Maximum simultaneous players
sv_minClients0Number of clients (human + bot) the game fills to; default lets each map decide; see Bots
sv_maxEntities1024Maximum entities; rarely needs changing
sv_timeout20Client connection timeout in seconds

Security

CvarDefaultDescription
rcon_password(empty)Password for remote console access (rcon). Set this to allow trusted admins to run server commands remotely.
g_adminPassword(empty)In-game admin password (set with admin <password>)

Game Modules

Some modes are a separate game module rather than a cvar. A module is selected with a game line in the instance .cfg, which the wrapper passes as +game <name>:

game ctf

Quetoo ships default, ctf, lithium and race. A module brings its own maps, rules and cvars, so g_captureLimit below only applies under ctf.

Game Rules

CvarDefaultDescription
g_fragLimitdefaultFrags needed to win the level
g_timeLimitdefaultMinutes per level
g_captureLimitdefaultFlag captures to win (CTF)
g_gravitydefaultWorld gravity
g_gameplaydefaultGame variant: default, deathmatch, instagib or arena. Prefix with team_ for team play, e.g. team_deathmatch. default defers to whatever the level asks for
g_numTeamsdefaultNumber of teams (auto-detected by default)
g_autoJoin1Automatically assign players to teams
g_weaponStay0Weapons stay after pickup instead of respawning
g_spawnProtection0Spawn protection duration in seconds; it ends when the player fires
g_spawnFarthest1Spawn players as far as possible from enemies
g_ammoRespawnTime20.0Ammo respawn interval in seconds
g_weaponRespawnTime5Weapon respawn interval in seconds

Level Settings

sv_minClients, g_fragLimit, g_timeLimit, g_captureLimit, g_gravity, g_gameplay and g_movement are level settings. Each level resolves them in this order:

  1. The cvar, if it is set to anything but default. This applies to every map.
  2. The map’s entry in the map rotation.
  3. The map’s own worldspawn keys, which the mapper sets.
  4. Quetoo’s built-in value: 0 clients, 30 frags, 20 minutes, 8 captures, and the movement’s gravity.

Leave a cvar at default to let each map decide. Set it only to force one value on every map. Every level setting defaults to default except sv_minClients, which defaults to 0. Set it to default to let each map’s min_clients decide. The server log shows each value in effect and where it came from when a level starts, for example frag_limit: 30 (worldspawn).


Bots

Quetoo has a built-in bot system that provides real opposition when human players aren’t around. Bots are especially useful for server seeding — an empty server rarely attracts players, but a server with a few active bots is much more likely to draw people in.

sv_minClients

sv_minClients sets the total number of clients (human + bot) the game fills to. The game adds bots to reach it, and removes them one by one as real players join, until all bots are gone.

// Keep 4 clients in the game at all times, on every map
set sv_minClients 4

sv_minClients defaults to 0. Set it to default, and each map decides with its min_clients key, from the map rotation or from the map itself. A small duel map can ask for 2 clients and a large map for 8. A map that sets nothing gets no bots.

When the last human disconnects, bots fill back up within a few seconds. The count is capped by sv_maxClients, so you never need to worry about them conflicting.

Choosing the Bots

A map can name the bots that join first with its ai key, from the map rotation or from the map itself. The names are separated by spaces. The named bots always join, even beyond min_clients. If min_clients asks for more, the rest are picked at random. When players join, unnamed bots leave before named ones.

{
    name aerowalk
    min_clients 2
    ai Bastard
}

The bots themselves are defined in ai.lst, in the default/ game directory, in the same format as the map rotation. Each entry has a name, a skin and a guid, three traits from 0 to 1 (skill, aggression and awareness), and optional color, helmet, shirt and pants values. The file’s header comment describes each key. To change the roster, copy ai.lst to the server’s user data directory, as for the map rotation, and edit the copy.

Players can vote on the number of bots with vote ai <count>. The vote applies to the current map only.

A typical seeding configuration for a public server:

// /etc/quetoo-dedicated/default.cfg
set sv_hostname "My Quetoo Server"
set sv_public 1
set sv_maxClients 16
set sv_minClients 4   // always 4 players in the game

Map Rotation

The server cycles through maps in rotation order when the frag limit or time limit is reached. The rotation is defined by a map list file — by default maps.lst from the game data.

Copying the Default maps.lst

The installed game data includes a default maps.lst at:

/usr/lib/quetoo/share/quetoo/default/maps.lst

To customize the rotation, copy it to the server’s user data directory and edit it there:

sudo -u quetoo mkdir -p /var/lib/quetoo/.local/share/WickedOldGames/Quetoo/default
sudo -u quetoo cp /usr/lib/quetoo/share/quetoo/default/maps.lst \
    /var/lib/quetoo/.local/share/WickedOldGames/Quetoo/default/my-rotation.lst

The user data directory takes precedence over the installed data, so your copy will be used without modifying the system files.

Pointing the Server at Your Custom List

In /etc/quetoo-dedicated/default.cfg, add:

set sv_mapList my-rotation.lst

The filename is resolved from the default/ game directory — no path prefix needed.

maps.lst Format

Each map is an entry enclosed in { }. Only name is required. The other fields are optional, and set that level setting for that map only. A cvar that is set to anything but default still wins over them.

{
    name edge
}
{
    name aerowalk
    gameplay instagib
}
{
    name lavatomb
    min_clients 4
    frag_limit 20
}
{
    name pits
    gravity 600
    music quetoo/the_pits
}

Supported fields:

FieldTypeDescription
namestringMap filename (required)
gameplaystringThe gameplay mode, as for g_gameplay, e.g. instagib
movementstringThe player movement: quetoo, race, quake, quake2 or quake3
min_clientsintThe number of clients (human + bot) the game fills to
aistringThe bots that join first, by name, separated by spaces
frag_limitintFrags needed to win
time_limitfloatMinutes per level
capture_limitintFlag captures to win (CTF)
gravityfloatWorld gravity
musicstringMusic track to play on this map

Advancing the Map Manually

From the server console or via rcon:

map edge

Remote Console (rcon)

If rcon_password is set, admins can run commands remotely from a Quetoo client:

rcon_password mypassword
rcon map edge
rcon status

Firewall / Port Forwarding

Quetoo uses UDP port 1998 by default. Open this port in your firewall and forward it on your router if hosting from a home network.

To list your server on the public master server, set:

+set sv_public 1

Getting Help

Join the Discord #development channel for help running a server.