CS 1.6 FastDL setup using nginx to deliver maps, textures, models, and sounds over HTTP while the game server handles multiplayer traffic

How to Set Up FastDL for a CS 1.6 Server

Maps and sounds in seconds instead of minutes: nginx on the same VPS, game content only

When a player joins a CS 1.6 server with custom content, the client first downloads everything it is missing: maps, sounds, models, sprites. By default these files go through the game connection itself, and that is slow. On my DeathMatch server one sound plugin with 15 small .wav files took about three minutes to download. With FastDL the same 15 files came down in about a second.

FastDL is an ordinary web server running next to the game server and handing out the same files over http. The game server tells the client its address, and the client downloads everything from there instead of the game port. Here I set it up with nginx on the same VPS as the server from the base guide, so no extra hosting is needed. This is what the 2 GB of RAM from the requirements was for.

How FastDL Works

A few things to understand before setting it up. They save a lot of time later, when something does not work.

The address plus the file path

The client takes the address from the sv_downloadurl cvar and adds the file's path inside the cstrike folder to it. For sound/myplugin/hello.wav and the address http://fastdl.example.com/ it requests http://fastdl.example.com/sound/myplugin/hello.wav. That is why the web server simply points at the cstrike folder.

No error, just slow

If a file is missing on FastDL, or the web server refuses to give it, the client does not show an error. It quietly falls back to the slow download through the game connection. So a slow download almost always means FastDL is not being used at all.

Only http

The CS 1.6 client cannot download over https, so FastDL needs no SSL certificate and the address always starts with http://.

Only game files

The cstrike folder also holds server.cfg with the rcon password, reunion.cfg with the salt, plugin configs and logs. The web server must give out game content only and refuse everything else. The config below does exactly that.

Installing nginx

Connect to the server in PuTTY under the cs16 user and install nginx:

sudo apt install -y nginx

nginx starts on its own right after the install. Open http://your_server_ip/ in a browser and you should see the Welcome to nginx! page. That is the default site, I replace it with FastDL a bit later. If the page does not open, check the control panel of your hosting: some providers have their own firewall, and port 80 has to be allowed there.

One small thing that confuses people. Under an ordinary user the nginx command is not found:

-bash: nginx: command not found

nginx is installed, it just lives in /usr/sbin/, which the ordinary user does not have in its path. All nginx commands in this guide go with sudo in front, and then they work.

Giving nginx Access to the Server Folder

nginx runs under its own system user, www-data. The game files sit in the home folder of cs16, and a home folder can be closed to other users. If it is, nginx cannot even get to the cstrike folder and answers 403 to every request, including the maps. Check the whole path with one command:

namei -l /home/cs16/cs16srv/cstrike/maps

It prints every folder on the way and its permissions. Look at the line for cs16. If it looks like this, nginx will not get through:

drwx------ cs16 cs16 cs16

The fix is one command:

sudo chmod o+x /home/cs16

The x permission for other users lets them pass through the folder to a path they already know, but not see what is inside. Nobody can list your home folder, nginx just gets a way to the cstrike folder. After the fix the output looks like this:

f: /home/cs16/cs16srv/cstrike/maps
drwxr-xr-x root root /
drwxr-xr-x root root home
drwx-----x cs16 cs16 cs16
drwxrwxr-x cs16 cs16 cs16srv
drwxrwxr-x cs16 cs16 cstrike
drwxrwxr-x cs16 cs16 maps

The folders below cs16 end with r-x, so others can read them and nothing else needs changing. If one of them ends with ---, it needs sudo chmod o+rx with its full path.

Creating the FastDL Config

nginx keeps site configs in /etc/nginx/sites-available/. Create a new one there:

sudo nano /etc/nginx/sites-available/fastdl

Paste the config below (in PuTTY a right click pastes). If you have a domain for FastDL, put it into server_name. If not, leave the line as it is, nginx will answer by IP anyway.

# FastDL: game content only, straight from the server's cstrike folder.
# Plain http on purpose: the CS 1.6 client can't download over https.
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name fastdl.example.com;

    root /home/cs16/cs16srv/cstrike;
    autoindex off;
    access_log off;
    server_tokens off;

    # maps, sounds, models, sprites and their helpers
    location ~* ^/(maps|sound|models|sprites|gfx|overviews|resource)/[^/]+(/[^/]+)*\.(bsp|wad|res|txt|mdl|spr|wav|mp3|tga|bmp)$ {
        try_files $uri =404;
    }

    # texture files that live in the cstrike root
    location ~* ^/[^/]+\.wad$ {
        try_files $uri =404;
    }

    # configs, plugins, logs, everything else
    location / {
        return 403;
    }
}

Save with Ctrl+O and Enter, exit with Ctrl+X. What each part does:

listen 80 default_server
This site answers every request to port 80, including a request by plain IP.
root
The cstrike folder of the server. The client adds the file path to the address, nginx adds the same path to this folder.
autoindex off
No file lists. Opening a folder in a browser gives 403, nobody can browse what is on the server.
first location
The whitelist. A file is given out only if its path starts with one of the listed folders and ends with one of the listed extensions. sound/myplugin/hello.wav passes, addons/amxmodx/configs/users.ini does not.
second location
Lets through .wad files from the cstrike root. Custom maps often need them.
location / → 403
Catches everything else: server.cfg, addons, logs.

If a plugin uses a file type that is not in the list, add its extension to the first location, separated by |.

Enabling the FastDL Site and Checking It in the Browser

The config is written, now it has to be switched on and the default page switched off. Three commands one by one:

sudo ln -s /etc/nginx/sites-available/fastdl /etc/nginx/sites-enabled/fastdl
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
  1. ln -s creates a link to the config in the sites-enabled folder. nginx loads only what is linked there.
  2. rm removes the link of the default site. The file itself stays in sites-available , only the link goes. This is required: the default site is also default_server on port 80, and with two of them nginx refuses to start.
  3. nginx -t checks the config and does not restart anything.

The check should end with two lines:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If there is an error, it names the file and the line. Fix it and run sudo nginx -t again. When the test passes, apply the config:

sudo systemctl reload nginx

Checking FastDL in the Browser

No game and no domain are needed for this check, the server IP is enough. Open three addresses:

Address Expected result What it proves
http://your_server_ip/ 403 Forbidden The Welcome page is gone and folders are closed
http://your_server_ip/maps/de_dust2.bsp the browser starts downloading the map nginx reaches the game files
http://your_server_ip/server.cfg 403 Forbidden Configs are not given out

If the map also gives 403, nginx cannot get into the home folder. Go back to Giving nginx Access to the Server Folder and check namei -l again.

Pointing a Subdomain at FastDL

Cloudflare A record for CS 1.6 FastDL with proxy set to DNS only
A record for fastdl, proxy off (grey cloud, DNS only)

This step is optional. FastDL works by IP too, but an address like fastdl.example.com looks better, and if the server ever moves to another VPS you change one DNS record instead of the configs. My domain is on Cloudflare, so I show it there. Open your domain in Cloudflare, go to DNS → Records and press Add record:

  • Type - A
  • Name - fastdl
  • IPv4 address - your server IP
  • Proxy status - off, the cloud must be grey with the DNS only label
  • TTL - Auto

The proxy has to be off. With it on, requests go through Cloudflare servers instead of yours, and FastDL needs the client to talk to your VPS directly. Save the record and check it in Windows CMD:

ping fastdl.example.com

The reply should come from your server IP. If CMD says it could not find the host, wait a few minutes, a new record does not always work right away. Note that ping takes only the host name. With http:// or a path at the end, like ping http://fastdl.example.com/maps/, it always fails, even when everything is fine.

Adding FastDL to server.cfg and Checking It in the Game

nginx is ready, now the game server has to tell clients where to download from. Open /home/cs16/cs16srv/cstrike/server.cfg and add at the end:

// FastDL: players download maps and sounds over http instead of the game connection
sv_downloadurl "http://fastdl.example.com/"
sv_allowdownload 1
sv_send_resources 1
sv_downloadurl
The FastDL address. Without a domain, write the IP: "http://your_server_ip/". The address starts with http:// and ends with a slash.
sv_allowdownload 1
Lets players download missing files from the server at all.
sv_send_resources 1
Lets the server send custom resources to players.

server.cfg is read when a map starts, so the new lines work only after a map change or a server restart. Until then the old value stays in memory.

Checking FastDL in the Game

First make sure the server took the address. Type in the server console:

sv_downloadurl
"sv_downloadurl" is "http://fastdl.example.com/"

If it shows an empty value, "sv_downloadurl" is "", the map has not changed since you edited the file. Load the config by hand with exec server.cfg, type sv_downloadurl again and the address will be there. On the next map change the server reads server.cfg on its own.

Now the real test. Delete one of the custom files from your own game folder, for example a plugin sound, and connect to the server. On Steam, downloaded files usually land in the cstrike_downloads folder. If the file comes down in a second or two, FastDL works. If the download crawls file by file for minutes, the client is not using FastDL. Check sv_downloadurl in the console and open that file's address in a browser.

FastDL for Two Servers on One VPS

I run two servers on one of my machines, Dust2 and DeathMatch, each in its own folder:

  • /home/cs16/cs16srv/cstrike/ - Dust2
  • /home/cs16/cs16dmsrv/cstrike/ - DeathMatch

The config above has one root, one cstrike folder. For two servers I keep one nginx site and one domain, but give each server its own folder in the address:

  • http://fastdl.example.com/dust2/ → /home/cs16/cs16srv/cstrike/
  • http://fastdl.example.com/dm/ → /home/cs16/cs16dmsrv/cstrike/

The steps are the same as for one server: install nginx, open the home folder, create the config, enable it, check it. Only the config and the server.cfg lines are different.

# FastDL for Dust2 and DeathMatch: game content only, one folder per server.
# Plain http on purpose: the CS 1.6 client can't download over https.
server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name fastdl.example.com;

    autoindex off;
    access_log off;
    server_tokens off;

    # Dust2: /dust2/... -> /home/cs16/cs16srv/cstrike/...
    location ~* ^/dust2/((maps|sound|models|sprites|gfx|overviews|resource)/[^/]+(/[^/]+)*\.(bsp|wad|res|txt|mdl|spr|wav|mp3|tga|bmp))$ {
        alias /home/cs16/cs16srv/cstrike/$1;
    }
    location ~* ^/dust2/([^/]+\.wad)$ {
        alias /home/cs16/cs16srv/cstrike/$1;
    }

    # DeathMatch: /dm/... -> /home/cs16/cs16dmsrv/cstrike/...
    location ~* ^/dm/((maps|sound|models|sprites|gfx|overviews|resource)/[^/]+(/[^/]+)*\.(bsp|wad|res|txt|mdl|spr|wav|mp3|tga|bmp))$ {
        alias /home/cs16/cs16dmsrv/cstrike/$1;
    }
    location ~* ^/dm/([^/]+\.wad)$ {
        alias /home/cs16/cs16dmsrv/cstrike/$1;
    }

    # configs, plugins, logs, everything else
    location / {
        return 403;
    }
}

Why alias and not root. With root, nginx adds the whole requested path to the folder, /dust2/ included, and looks for a dust2 folder inside cstrike, which does not exist. alias throws away the /dust2/ part and puts only what is in brackets, the $1, after the folder path. The whitelist of folders and extensions stays the same.

Then each server gets its own address in its own server.cfg:

// FastDL: players download maps and sounds over http instead of the game connection
sv_downloadurl "http://fastdl.example.com/dust2/"
sv_allowdownload 1
sv_send_resources 1
// FastDL: players download maps and sounds over http instead of the game connection
sv_downloadurl "http://fastdl.example.com/dm/"
sv_allowdownload 1
sv_send_resources 1

The browser check is the same, only with the folder in the address: http://your_server_ip/dust2/maps/de_dust2.bsp and http://your_server_ip/dm/maps/de_dust2.bsp should download the map, http://your_server_ip/dm/server.cfg should give 403. And check sv_downloadurl in the console of each server. On my DeathMatch the address stayed empty because the map had not changed since I edited server.cfg. Dust2 already had it and downloaded in a second, DM was still pulling the same files for three minutes through the game port. One exec server.cfg fixed it.

A third server on the same VPS is one more pair of location blocks with its own folder name, the domain stays the same.

FastDL Problems and Fixes

Everything I ran into myself while setting up FastDL on three servers.

Problem Cause Fix
nginx: command not found The nginx command lives in /usr/sbin/, which an ordinary user does not have in its path Run nginx commands with sudo
nginx -t fails with a duplicate default server for 0.0.0.0:80 The default site is still enabled next to FastDL sudo rm /etc/nginx/sites-enabled/default, then sudo nginx -t again
The map in the browser gives 403 nginx cannot pass through the home folder sudo chmod o+x /home/cs16, check with namei -l
The browser downloads the file, the game downloads slowly The server does not know the address, sv_downloadurl is empty Check sv_downloadurl in the console, exec server.cfg or change the map
Everything downloads fast except one file The file is not on the server, or its name differs in letter case. Linux treats Sound.wav and sound.wav as two different files Open that file's address in a browser and compare the name with the file on the server
ping cannot find the host The address was typed with http:// or a path ping takes only the host name: ping fastdl.example.com
The domain does not open, the IP does The DNS record has not spread yet, or the Cloudflare proxy is on Wait a few minutes, check that the cloud is grey (DNS only)

The main rule for checks: if something downloads slowly in the game, open the same file's address in a browser. If the browser downloads it, the problem is in server.cfg. If the browser gives 403 or 404, the problem is in nginx or in the file itself.

FastDL FAQ

I set up FastDL, but players still download files slowly. Why?

The client is not using FastDL and has fallen back to the game connection. Type sv_downloadurl in the server console. If it is empty, the map has not changed since you edited server.cfg: run exec server.cfg or change the map. If the address is there, open the slow file's address in a browser. A 403 or 404 means nginx cannot reach the file, or its name differs in letter case from what the plugin asks for.

Do I need a separate hosting or a domain for FastDL?

No. nginx on the same VPS and the plain IP in sv_downloadurl work fine. A subdomain is a convenience: nicer address, one DNS record to change if the server moves.

Can FastDL use https?

No. The CS 1.6 client downloads over plain http only, so the address always starts with http:// and no certificate is needed. That is also why the Cloudflare proxy has to be off for the FastDL subdomain.

Is it safe to point a web server at the cstrike folder?

Only with a whitelist like the one in this guide. The folder holds server.cfg with the rcon password and reunion.cfg with the salt. The config gives out listed game folders and extensions only and answers 403 to everything else, and the browser check with /server.cfg proves it.

A map downloads from FastDL but the game says it is missing a .wad or .res file.

Those files must be on the server in the same place the map expects them: .wad in the cstrike root, .res next to the map in maps/. Both are in the whitelist. Check the file's address in a browser and the letter case of its name.

Can I put the FastDL files on another machine?

Yes, any web server that serves the same folder structure works. You then have to keep its copy of maps, sounds and models in sync with the game server by hand, which is why on a single VPS it is simpler to point nginx straight at the cstrike folder.

More CS 1.6 Guides

Leave a Reply

Your email address will not be published. Required fields are marked *