Set Up a CDN for Foundry VTT Using Backblaze and Cloudflare

Set Up a CDN for Foundry VTT Using Backblaze and Cloudflare

Set up Backblaze and Cloudflare to host your assets online, with caching.

Setting up Cloudflare to accelerate your VTT assets can help imrpvoe performance for your players, and reduce load on your server, without disrupting your existing workflow. The “downside” is that it really only works running on a server, where the server can also host nginx (a web server). I use Docker for all of my home apps, and so I use this container by felddy for Foundry, and SWAG as my nginx container, which reverse proxies & redirects things for me.

Setting those things up is beyond the scope of this tutorial, but if you’ve figured all that out, you can probably figure this out too.

Buy a Domain Name

Buy a domain name, even if you’re hosting on your laptop in your mom’s basement, everything will be a lot easier if you own your own domain. I use namecheap, but it doesn’t matter who your registrar is.

Set up Cloudflare DNS

Make a Cloudflare account, then “Add a site”. They’ll walk you through transferring your DNS to Cloudflare, from whoever you registered with.

Now make an “A Record” pointing at wherever your foundry server is. I’m going to assume you want to use foundry.yourdomain.com to point to your Foundry server, but you can also use yourdomain.com if you’d prefer, just replace “foundry” with “@” (meaning root). Also set up a second “A Record” pointing to the same address, but set the name to be “vttcdn”.

Instead of filling in your IP manually you can use dynamic DNS to keep this record updated for you - I use Docker, so it was easy to integrate Oznu’s Container for Cloudflare DDNS, but there are lots of programs out there to handle it for you.

Disable “Proxy status” for your “foundry” record, but enable it for your “vttcdn” record. This is essential.

Full-width image

Set up Backblaze Bucket

I find Backblaze B2 to be the most cost effective cloud storage provider. They have very cheap storage pricing, and a much simpler interface than something like Amazon’s S3.

After you’ve made a Backblaze account, you’re going to want to “Create a bucket”. These have to be uniquely named globally, so use something like foundry-cdn-yourdomain, make sure to set your files to “Public”. Your bucket should look something like this:

Full-width image

Once you’ve done that, make an assets subdirectory in the bucket; you can use the B2 website file browser for this.

Mount Backblaze Bucket

To make it so the Foundry media picker still works, you’re going to want to mount your bucket as assets in the directory with modules systems and worlds. I use s3fs, and my fstab entry looks like s3fs#assets /mnt/jensen-s3/assets fuse _netdev,allow_other,gid=1000,uid=1000,use_path_request_style,url=http://192.168.0.200:9000/ 0 0

Look up a guide for mounting B2. I actually use MinIO and self host my bucket, so my URL is a local IP address, but you can use B2, S3, or any other S3-compatible service with s3fs.

Once you’ve got that setup, and means you can browse the assets in your bucket with the Foundry image browser like so:

Full-width image

This is already useful, your files are safe and secure in your cloud storage, not taking up any local disk space, and are still accessible by Foundry. But the problem (that we will soon fix), is that everytime you want a file, you ask Foundry for it, Foundry downloads it from the bucket via s3fs, and then sends it to you itself. This process is extremely unperformant, and can crash s3fs during very heavy load. So we’re going to redirect all requests and make them never even hit Foundry.

Intercept & Redirect Requests for Assets

If you’ve set up a working Foundry installation, I assume you have a working nginx reverse proxy record, but here’s mine in its entirety. Credit to linuxserver.io for the original record shipped with SWAG.

## Version 2020/12/09
# make sure that your dns has a cname set for youtube-dl-server and that your youtube-dl-server container is not using a base url

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name foundry.*; # this record is for foundry.ANYDOMAIN.COM. if you're using the root for the foundry location, put YOURDOMAIN.COM here

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    location / {
        include /config/nginx/proxy.conf;
        resolver 127.0.0.11 valid=30s;
        set $upstream_app foundry; # address of the foundry server, i'm using docker, so this is a container name, but it could also be a local ip address
        set $upstream_port 30000; # port foundry runs on
        set $upstream_proto http;
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }

    location /assets/ {
        rewrite ^ https://vttcdn.tcj.one$request_uri? permanent;
    }

}

If you already have a working reverse proxy record, you just need to add this:

location /assets/ {
        rewrite ^ https://vttcdn.YOURDOMAIN.COM$request_uri? permanent;
}

This will rewrite any requests for https://foundry.yourdomain.com/assets to https://vttcdn.yourdomain.com/assets. If you restart nginx, and load Foundry in a browser, you can check in the devtools to see its working. If you see requests going to your cdn subdomain, things are working, requests for assets are being rewritten by nginx, and the clients turn around and request those assets directly from the cloud bucket instead.

Full-width image

This is already great, and will yield performance boons. Players won’t be constrained by your upload speed and your server won’t waste processing time on big files, but we can do better.

Enable Cloudflare Caching

Back on Cloudflare, go to Rules > Page Rules, and add a new page rule for your cdn subdomain. The URL should be for vttcdn.yourdomain.com/assets/*, and should look like this:

Full-width image

You can modify these settings how you want, but this setup:

  • The browser to cache assets for up to 12 hours - if a player refreshes the page, they (may) have a copy already stored locally
  • Even if Backblaze is down, your files will remain online, cached by Cloudflare and servable from them
  • Every single file is cached
  • Those files are all cached in Cloudflare’s servers for 6 days, which I find good for weekly play
  • If you update the same file frequently you may want to decrease this
  • I think there’s a good argument for 16 hours too

There’s lots of customization here, but the point is that all your assets are now being cached in Cloudflare endpoints close to where your players are.