This repository allows you to create a Quake 3 DeFrag server with minimal efforts, with the help of Docker, or natively if you're brave enough.
Due to very strict foldernames required for this project, please clone this repository using this command:
git clone https://github.com/Defrag-racing/defrag-server-bundle.git ./dfsv- A 64 bit Debian-based Linux system
- 150MB of RAM per server
- Around 2GB of free storage (about 15 GB more with
MAPS_MODE=sync, which keeps the whole map pool locally) - NFS client support (
nfs-commonpackage) - not needed withMAPS_MODE=sync - The current oDFe build for the default
MAPS_MODE=nfspk3-download_defrag.shinstalls it automatically (dfsv-core) - For Docker installs: Docker Compose v2 (
docker compose version). The legacydocker-compose1.x cannot parse the compose files in this repo - see Troubleshooting.
- Make sure Docker is installed and
docker compose versionreports v2. - As root, create a regular user called
q3df(very important) and let it use Docker:useradd -m -s /bin/bash q3df usermod -aG docker q3df
- Log in as
q3dfandgit clonethis repository (see above). - Inside the folder, run
./download_defrag.shto download all required files for defrag (engine + mod + baseq3 paks, ~500 MB). - Configure
sv.confto your likings (see Customization below). For MDD/recordsystem servers also drop yourmysqlconnection.infointogame/defrag/. - Build the docker image:
docker build -t q3df . - Run
./generate_docker_service.shto generate adocker-compose.override.ymlfile. Review the data if necessary. - Run
docker compose up -dto run everything in the background. - Open the game ports in your firewall. The containers use host networking, which does NOT bypass ufw the way port-published containers do:
sudo ufw allow 27960:27969/udp comment 'defrag servers' - Test by connecting to your server from a defrag client (
/connect ip:port).
After every sv.conf change, re-run ./generate_docker_service.sh && docker compose up -d to apply it.
See NATIVE-SETUP.md for the full walkthrough (systemd units for the servers, the NFS mount or map-sync timer, and manual start-servers.sh / stop-servers.sh usage). Short version:
- Create the
q3dfuser and clone this repo to/home/q3df/dfsv(the systemd units hardcode that path). - As root:
sudo .localinstall/install.sh(packages + 32-bit libraries). - As
q3df:./download_defrag.sh, then fill insv.conf. - Enable the mount/timer unit for your
MAPS_MODEand thedfsv.serviceunit - exact commands in NATIVE-SETUP.md.
- ssh into your instance
- run
cd ~/dfsv - run
nano sv.conf- To set a permanent hostname, rcon, admin, and location, fill in the information in the first block
- To make your server private, modify the "Server privacy" block. Set SV_PRIVATE to 1 and replace the default password with the desired one
- To control how many and what types of servers to deploy, modify the "Server counts" block. (e.g set
mixed_count=3for 3 mixed servers) - To modify the suffixes (- mixed 1, mixed 2, teamruns 1, etc.), modify the
Server suffixesblock.
- Save (Ctrl+O, Enter) and exit (Ctrl+X)
- Apply the changes:
- Docker:
./generate_docker_service.sh && docker compose up -d - Native:
./stop-servers.sh && ./start-servers.sh
- Docker:
- run
ps aux | grep oDFe.dedto see your running servers and their ports
nfspk3 (default) - the bsp-only pk3 pool (one pk3 per map, ~19 000 maps) is mounted over NFS at game/nfs/pk3bsp and the engine loads each map's pk3 on demand via fs_mapPakDir - no local pool, no scanning of thousands of pk3s, maps load instantly on callvote. Requires the current oDFe build, which download_defrag.sh installs automatically. Native: enable the home-q3df-dfsv-game-nfs-pk3bsp.mount unit; Docker: generate_docker_service.sh sets the volume up for you.
sync - keep a full local copy instead (no NFS dependency, keeps working during storage-server downtime):
./sync-maps.shdownloads the pool as bsp-only pk3s intogame/baseq3- one pk3 per map with just the.bspinside (no textures, the server does not need them), into the same place custom maps go.- The first run downloads the WHOLE pool (~15 GB - the script prints the exact size before it starts, check your disk space).
- Every later run only fetches maps that appeared or changed since, so new maps land on your server within minutes.
- Nothing is ever deleted locally, and interrupted downloads are redone safely (
.partfiles).
For Docker, re-run generate_docker_service.sh (it switches the maps volume to a local bind so the container no longer depends on NFS; the pk3s flow through the existing baseq3 bind), docker compose up -d, and add this to crontab -e as q3df:
*/10 * * * * cd ~/dfsv && bash ./sync-maps.sh
Native/systemd: enable the dfsv-mapsync.timer unit instead of the NFS mount unit - see NATIVE-SETUP.md.
Removed:
nfs(legacy loose.bspover NFS). The storage stopped exporting/maps/bspon 2026-07-31 - the tree was 79 GB of pure duplication (every.bspis re-extractable from the original pk3) and the pk3 pool replaced it everywhere.generate_docker_service.shnow refusesMAPS_MODE=nfsinstead of generating a mount that hangs. Switch tonfspk3(run./download_defrag.shfirst, it installs the oDFe build that supports it) or tosync, and disable thehome-q3df-dfsv-game-nfs-maps.mountunit.
After following the previous steps, you will have all current maps from ws.q3df.org on-demand. However, if you'd like to upload custom maps or maps not present in worldspawn, either upload pk3 files directly to baseq3, or:
From your local PC:
- from the machine that contains the desired map, run (from a powershell window or command line):
scp path/to/your/map q3df@ipofyourinstance:~/dfsv/game/baseq3
- Enter your instance's password.
- Restart your server from the game by callvoting the current map.
- Callvote your map
From the instance OS, as user q3df:
- run
cd ~/dfsv/game/baseq3 - run
wget link-to-map - Restart your server from the game by callvoting the current map.
- Callvote your map.
If you were provided a RSID (more information at https://defrag.racing), this step is REQUIRED for proving runs made online. Request your SFTP credentials on the defrag.racing server hosting page at https://defrag.racing/server-hosting (log in first) - after approval it shows the host, port, username, remote path and a one-time password.
Fill them into the DEMO_SFTP_* block of sv.conf and set DEMO_SFTP_ENABLED=1.
Docker: re-run the generator and bring the stack up with a build:
./generate_docker_service.sh
docker compose up -d --buildThis adds a q3df-demoupload container (shows up as dfsv-q3df-demoupload-1). It uploads all pending demos once at start and then every 30 minutes; each demo is deleted locally after a successful upload. Watch it with docker logs -f dfsv-q3df-demoupload-1.
Dockerless: as q3df, add this to crontab -e:
*/30 * * * * cd ~/dfsv && bash ./.docker-demoupload/upload_demos.sh
You are running legacy docker-compose 1.x. Install the Compose v2 plugin (docker-compose-plugin package), or drop the standalone binary in place:
sudo curl -SL https://github.com/docker/compose/releases/latest/download/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-composeThe containers use host networking, so your firewall applies to them directly (unlike port-published containers, which bypass ufw via NAT). Allow the UDP game ports:
sudo ufw allow 27960:27969/udpDocker volumes survive docker compose down and are NOT updated when their definition changes. If this machine ran an older dfsv install, the stale dfsv_maps volume keeps its old NFS settings. Recreate it:
docker compose down
docker volume rm dfsv_maps
docker compose up -dVerify with docker volume inspect dfsv_maps - the device should be :/maps/pk3bsp for MAPS_MODE=nfspk3.
You need to actually do a few more steps in order to use this feature, such as having unique rs_IDs (rs<PORT>=<id> entries in sv.conf) and a mysqlconnection.info file in game/defrag/, otherwise the server won't run.
Please go to the defrag.racing community for more information.
You might have libraries missing, but most likely libmysqlclient.so.20 on your system. To verify what libraries you might not have, type this:
ldd ./game/defrag/qagamei386.soIf it wasn't installed, a .deb package is available inside the .install subdirectory.
If you are running Docker, simply recreate a folder named .q3a within the game folder.
If you are not running Docker, create a folder named .q3a within your $HOME directory.
If you do not have a server ready, you can rent a VPS:
Options:
- https://www.vultr.com/ < cheap and good quality
- https://aws.amazon.com/
- https://azure.microsoft.com/en-us/
- https://www.digitalocean.com/
- https://www.linode.com/
I will show the steps for vultr, as it is the easiest to set up.
- Sign up
- Click on the big '+' sign or find "Deploy New Server"
- Choose "Cloud Compute"
- Choose desired location
- Choose 64 Bit Ubuntu (latest version)
- Choose the $5/mo option (1 CPU 1 Mb RAM). (Billed per hour of usage)
- Click on "Deploy Now". Wait for server to finish installing
- Once finished, click on the instance to see the details. You will see ip, username, and password.
- From a Powershell window (should be installed in your windows already) or command line, execute the following command:
ssh root@ipofyourinstance- Enter the password, proceed to next section.
- Once you have all your desired settings, you can create a snapshot for free (at the time of this writeup) on vultr.
- Click on the instance with all your settings
- Go to the 'snapshots' tab
- Create snapshot, enter whatever name suitable.
- Re-do the deployment steps from the beginning of this readme, this time choosing "Snapshot" instead of "64 Bit OS"
- Choose the snapshot with the name you chose in step 4.
- Deploy. Once done installing, everything will be up but in your new location. Try connecting via defrag.
- Destroy unused instances to avoid unecessary billing.
- frog for his original work.
- Ch0wW for rewriting parts of the project for defrag.racing.