Without FastDL, custom content downloads through the game server at a crawl — a few KB/s over the old UDP transfer, so a 20 MB map map-change empties the server. FastDL moves those transfers to a normal HTTP server via sv_downloadurl. The setup is not hard, but one detail — where exactly the URL points relative to the cstrike folder — accounts for the overwhelming majority of "FastDL not working" reports.
1. How it works
When a client joins and is missing a file the server references (a map, model, sound, sprite), it fetches that file over HTTP from sv_downloadurl instead of the game channel. Your web server just serves static files; the client reconstructs the path from the game-relative filename.
2. Set the server cvars
// server.cfg sv_allowdownload 1 sv_allowupload 1 sv_downloadurl "http://dl.example.com/cs"
sv_allowdownload 1 lets clients download at all; without it they join with missing textures and errors. Clients also need cl_allowdownload 1 on their end (the default), so you cannot fix a client that disabled it.
3. Get the path right (the part everyone breaks)
The engine builds the download URL as sv_downloadurl + the game-relative path, and that path includes the cstrike/ folder. So if a client needs cstrike/maps/de_rats.bsp and your sv_downloadurl is http://dl.example.com/cs, it will request:
http://dl.example.com/cs/cstrike/maps/de_rats.bsp
Therefore your web root must contain a cstrike/ directory that mirrors the server's, not the contents of cstrike/ dumped loose. The correct layout on the web host:
/var/www/fastdl/ <- sv_downloadurl points here (http://dl.example.com/cs)
cstrike/
maps/
de_rats.bsp
sound/
models/
sprites/
gfx/
overviews/
If you point the URL inside cstrike you get a doubled or missing segment and every download 404s. This is the single most common mistake; see FastDL not working for the diagnostic version.
4. Add bzip2 compression
The engine can fetch a bzip2-compressed copy and decompress it client-side, which roughly halves map transfer size. For each file, place a .bz2 alongside it:
cd /var/www/fastdl/cstrike/maps bzip2 -k de_rats.bsp # produces de_rats.bsp.bz2, keeps the original
The client requests de_rats.bsp.bz2 first and falls back to the plain file if it is absent. Compress the big content — maps, models, sounds. Keep the uncompressed files too; some clients still ask for them.
5. Nginx configuration
server {
listen 80;
server_name dl.example.com;
root /var/www/fastdl;
location / {
autoindex off;
# serve unknown types as raw bytes so .bsp/.bz2 download cleanly
default_type application/octet-stream;
types {
application/octet-stream bsp bz2 mdl spr wav;
}
}
}
Turn autoindex off so the mirror is not browsable, and make sure the server sends the files rather than trying to interpret them.
6. Apache configuration
<VirtualHost *:80>
ServerName dl.example.com
DocumentRoot /var/www/fastdl
<Directory /var/www/fastdl>
Options -Indexes
Require all granted
AddType application/octet-stream .bsp .bz2 .mdl .spr .wav
</Directory>
</VirtualHost>
HTTPS works fine for sv_downloadurl and is worth it; just make sure the certificate is valid, because a TLS error makes the client silently fall back to the slow in-game transfer.
7. Keep the mirror in sync
The web mirror is a separate copy of your content, and it drifts. Every time you add a map to the rotation or install a new model pack, the same files must land on the FastDL host, or clients download everything except the new content and join with missing textures. The lowest-friction fix is to make the mirror the same filesystem — bind-mount or symlink cstrike/maps, cstrike/sound and the rest into the web root — so there is only one copy to maintain. If the mirror is a different machine, script an rsync after every content change and re-run bzip2 -k on new files. A stale mirror is the second most common FastDL failure after the path mistake, and it is entirely self-inflicted.
Common errors
- Every download 404s — the
cstrike/level is missing or doubled in your web root. The client requests<url>/cstrike/maps/...; that exact path must resolve. - Downloads are still slow —
sv_downloadurlis empty or unreachable and the server fell back to the UDP transfer. Test the URL in a browser. - Files download but are corrupt — the web server rewrote or compressed them (gzip on the fly, an HTML error page served with a 200). Serve as
application/octet-streamand confirm the byte size matches. - .bz2 ignored — wrong filename (
de_rats.bz2instead ofde_rats.bsp.bz2) or the web server refuses the extension. The compressed name is the full original name plus.bz2. - Client gets missing textures anyway —
sv_allowdownload 0on the server, or the file is not actually on the mirror.
Verification
Open the exact URL of one map in a browser and confirm it downloads with the right size:
http://dl.example.com/cs/cstrike/maps/de_rats.bsp
Then join the server from a client that does not have that map and watch it pull over HTTP in seconds rather than minutes. A clean test is to delete a map locally, connect, and confirm it re-downloads fast. Pair this with a well-ordered mapcycle so the mirror always holds every map you rotate.









