Caching steam depots on your local server with nginx and dsniff
While I usually don’t advertise non libre software for obvious reasons (that’s a stupid way to think about computing), I admit, though, that the Steam platform goes toward what I’d like to see since many years. Proprietary software platform indeed – but the business is not made out of selling overly expensive DVD-Rom once in a while but cheap soft (downloadable) copies of games (often) maintained over years. They also seem about to base a future gaming console on some sort of GNU/Linux flavor, that’s not philanthropy, that’s just the only clever way to do a cool gaming based business without getting totally dependant on another software supplier that also brand his own gaming console. Latest South Park was about the fight beetween latest Xbox and Playstation. This issue only exists when you decide to make console non compatible with usual workstation, a shortcut with so many shortcomings. Making a GNU/Linux based console, because it is good business, is obviously going in the right direction.
So I’ll allow myself a little reminder here on how not to waste your bandwidth on a local network where you have several computers having copies of the same steam game. It’s merely a simplified version of the well thought Caching Steam Downloads @ LAN’s article. Obviously, to do this, you need to have your own home server. For instance, it should work out of the box with a setup like this (this is the setup mentioned before from now on in this article).
A) HTTP setup
We first create a directory to store steam depot. It will be served with http so you need to create something like (working with the setup mentioned before):
mkdir /srv/www/depot chown www-data:www-data /srv/www/depot
Next, you want to setup nginx, to be able to serve as a steam content provider. Everything is based on http -no proprietary non-standard crap- so it can only go smoothly.
If you have the setup mentioned before, then /etc/nginx/sites-available/default contains a server { } statement for general intranet. Add a new file called /etc/nginx/sites-available/steam with the following (watch out for the listen and allow statements, change it depending on your server intranet IP!):
# steam spoof/proxy server { # you want this line to be set to your server intranet IP listen 10.0.0.1; listen 127.0.0.1; server_name *.steampowered.com; access_log /var/log/nginx/steam.access.log; error_log /var/log/nginx/steam.error.log; root /var/www/; resolver 8.8.8.8; # restrict to local wired network allow 10.0.0.0/24; allow 127.0.0.1; deny all;
location /depot/ { try_files $uri @mirror; } location / { proxy_next_upstream error timeout http_404; proxy_pass http://$host$request_uri; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for; add_header X-Mirror-Upstream-Status $upstream_status; add_header X-Mirror-Upstream-Response-Time $upstream_response_time; add_header X-Mirror-Status $upstream_cache_status; } location @mirror { access_log /var/log/nginx/steam.remote.log; proxy_store on; proxy_store_access user:rw group:rw all:r; proxy_next_upstream error timeout http_404; proxy_pass http://$host$request_uri; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for; add_header X-Mirror-Upstream-Status $upstream_status; add_header X-Mirror-Upstream-Response-Time $upstream_response_time; add_header X-Mirror-Status $upstream_cache_status; } }
Make it live:
cd /etc/nginx/sites-enabled && ln -s ../sites-available/steam . invoke-rc.d nginx restart
Now nginx is able to fetch and serve steam depot files.
B) DNS setup
Now, you need your server to actually handle requests to steam content server, spoofing these servers IPs. It could be done by messing with the DNS cache server already up on the setup mentioned before but I actually find much more convenient to use dnsspoof from dsniff package with a two-line configuration than wasting time creating say bind9 unnecessarily complex db files.
So we first instead dnsspoof:
apt-get install dsniff
Here come’s the two line configuration, set in /etc/dnsspoof.conf. Obviously, here too you have to set the IP to be your server’s intranet one.
10.0.0.1 *.cs.steampowered.com 10.0.0.1 content*.steampowered.com
Then you want an init.d script. You can create an ugly /etc/init.d/dnspoof with the following (obviously, you want you ethernet ethX device to be properly set!):
/#! /bin/sh ### BEGIN INIT INFO # Provides: dnsspoof # Required-Start: bind9 # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start dnsspoof over bind9 # Description: Start dnsspoof over bind9 ### END INIT INFO # shitty version for testing purpose /usr/sbin/dnsspoof -i eth1 -f /etc/dnsspoof.conf 2> /dev/null > /dev/null & # EOF
Once ready, just start the spoofer:
chmod 755 /etc/init.d/dnsspoof invoke-rc.d dnsspoof start
Now you can restart steam on your clients computers. It should work properly. You can check whether new directories appear in /srv/www/depot and monitor /var/log/nginx/steam* logs.
I’ll soon add a small script to get more meaningful info about the depots available on your server, so you can know which are what in a jiffy and remove the no longer useful willy-nilly.