DEV Community

peaceful-octopus
peaceful-octopus

Posted on • Updated on

Self-Hosting Multiple Worlds on Foundry VTT

Introduction

I received several requests on the Foundry VTT Facebook group to document my self-hosting setup for Foundry on Windows that allows me to host multiple worlds simultaneously. With the license terms as of version 0.8.0 of Foundry, you will need a separate key for each instance. This is not a highly scalable approach, but if you're like me and you just want to have several games up at the same time because you want the convenience of being able to switch between them without starting them up and shutting them down, this is the way to go.

What this guide covers

I'm going to go over the minimal setup for this approach. I won't be covering SSL certificates or custom dynamic DNS at this point. I will assume you already have a custom or dynamic domain pointing at your IP address and port 80 (or 443 for HTTPS) forwarded through your router. If you're not there yet you can find other guides that will get you that far. If you have a custom domain and SSL certificate, there are only a few minor changes to enable HTTPS instead, which I will link to at the end.

Downloads

If you don't have Node installed on your host machine, go to the Node website and download the current LTS release.

We're using the Node version of Foundry, not the Windows wrapper, so go to Foundry, log in to your account, and download the Node.js version from the Licenses tab.

We'll also be making a lot of use of NSSM to create easy to manage Windows Services for nginx and Foundry, so download the latest version and unzip it somewhere convenient.

Last, you need nginx to act as your reverse proxy. Go to the downloads page and download the current mainline version.

Structure

Organization will be helpful here, so make a folder somewhere on your computer (ideally with a short path, like at a drive root) for Foundry. We'll assume it's at C:\FoundryVTT. Create a folder inside called Foundry and unzip the Node.js version of Foundry there.

Back at C:\FoundryVTT create another folder called shareddata. This folder will hold the shared data between all the instances - this means that if you install a module or update a system version on one instance, it will be installed or updated on all of them. If you don't want to use a shared data folder you can skip this step, but I highly recommend it as keeping everything in sync becomes very tiresome with as few as 3 instances.

Last, create a folder for each instance of Foundry you want to run. I just call them foundrydata1, foundrydata2, etc. When you're done your folder structure should look like this:

C:\FoundryVTT
   Foundry
   shareddata
   foundrydata1
   foundrydata2
   ...
Enter fullscreen mode Exit fullscreen mode

Installation and Configuration

nginx

Put the contents of the nginx zip file somewhere convenient like C:\nginx. In C:\nginx, create a folder called sites-enabled and inside that create a text file called https.conf. Next, go to the main nginx configuration file, C:\nginx\conf\nginx.conf and open it. The default setup has a lot of things we don't need, so replace the entire body with this:

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;
    include "../sites-enabled/*.conf";

    sendfile        on;
    keepalive_timeout  65;
}
Enter fullscreen mode Exit fullscreen mode

This configures just the HTTP service, and references the sites-enabled folder we created before for additional configuration.

Now go back to the sites-enabled folder and open https.conf. Fill it with the following configuration, slightly modified from Foundry's nginx directions page. Supply your domain name for server_name, and for each game you want to run, duplicate the location block with a different url (so /game2 or /dnd2 or anything you want) and increment the port number on proxy_pass by 1. So the first game is at the default 30000, then the next is 30001, etc.

server {

    # Enter your fully qualified domain name or leave blank
    server_name             your.hostname.com;

    # Listen on port 80 without SSL certificates
    listen                  80;

    # Sets the Max Upload size to 300 MB
    client_max_body_size 300M;

    location /game1 {

        # Set proxy headers
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # These are important to support WebSockets
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";

        # Make sure to set your Foundry VTT port number
        proxy_pass http://localhost:30000;
    }

     location /game2 {

        # Set proxy headers
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # These are important to support WebSockets
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";

        # Make sure to set your Foundry VTT port number
        proxy_pass http://localhost:30001;
    }
}
Enter fullscreen mode Exit fullscreen mode

Last, we need to make nginx a service so it can run on startup in the background. Go to the folder where you unzipped NSSM, then Win64, open a command prompt and run:

nssm install nginx
Enter fullscreen mode Exit fullscreen mode

This will bring up the NSSM GUI. Set the Path to nginx.exe in your nginx folder (C:\nginx\nginx.exe in our example) and set the Startup Directory to the nginx folder (C:\nginx). Click Install Service and your service will be created. You can go to the Windows Service panel to start it, and by default it will always start at boot.

Foundry

Before we create our instances, let's set up our shared data folder. Go back to your Foundry folder, and in each one of the foundrydata folders, open a Administrator command prompt and enter:

mklink /d Data ..\shareddata
Enter fullscreen mode Exit fullscreen mode

This will create a directory link in that instance that points back to the shared data folder.

Next we're going to create our Foundry instances. Go back to NSSM\Win64 and open another command prompt and run

nssm install Foundry1
Enter fullscreen mode Exit fullscreen mode

This time for the Path, find node.exe from your Node installation (probably in C:\Program Files\nodejs). For the Startup Directory, supply the resources\app folder inside your Foundry folder (in our example, C:\FoundryVTT\Foundry\resources\app). For Arguments, enter main.js --dataPath=C:\Foundry\foundrydata1 --port=30000. Click Install Service, then repeat that process for each instance you want to run, changing the dataPath and the port each time. The port numbers need to correspond to the ports you mapped in your nginx config earlier.

Now start all those instances in the Windows Service panel, which will create the config files we need in the right places, then stop the services again so we can modify their configs. In each of your foundrydata folders, open Config\options.json. Add or edit the following values:

"hostname": "your.hostname.com",
"routePrefix": "/game1 (or whatever you specified)"
"proxyPort": 80
Enter fullscreen mode Exit fullscreen mode

Done!

Now fire all your services back up and if all went well, you should be able to reach your Foundry instance at [your-domain.xyz]/game1. Keep in mind that if you don't have a router that supports loopback (most home routers don't), your external URL will not work inside your network. Edit your Windows hostfile to remap your custom domain to the correct internal IP. You can test the external URL by using a VPN.

Considerations

Remember that any changes made to shared components (modules, systems, or the Foundry engine itself) will propagate to all your instances. So if you do an upgrade on one of them, make sure you restart your other instances so they catch up.

When I set this up, I purchased a custom domain for a few dollars because I wanted to share the Foundry URLs in Facebook events (that's how most of my games are organized), and Facebook bans links from most dynamic DNS providers. I use dynv6 as my dynamic DNS provider with a Windows Task that runs every 5 minutes to keep the IP updated.

I didn't cover SSL certificates or HTTPS, but if you do obtain a certificate, the aforementioned Foundry nginx document contains the changes you need to make for SSL. Essentially just change your "listen" port in nginx to 443 ssl, add your ssl certificates, and optionally redirect non-HTTPS traffic to HTTPS. Then in your Foundry config, just change the proxyPort to 443 and set proxySSL to true.

If you want to use subdomains instead of paths for your different games, you can do that too by setting up different "servers" in nginx, and using those hostnames in the Foundry config without a routePrefix specified. I haven't tried it but I don't see why it wouldn't work.

Lastly, while this is obviously a supported configuration for Foundry, it's pretty niche so if things go wrong you're a bit on your own. I haven't had any trouble yet (aside from a single path resolving incorrectly in the PF1e system), but YMMV.

Good luck!

Discussion (4)

Collapse
kawasintel profile image
Izak Nash

So I'm just trying to run two separate foundry's so that I can host it from my house or my girlfriends house. When I try though it won't let me use the same port (atleast I think thats the problem, I'm not technical at all) is there a way I can use this without a domain and just off of my routers?

Collapse
jbowensii profile image
jbowensii

HI, just to start I have multiple foundry licenses. I now have thanks to your article one virtual server on AWS running with those instances and a landing page served by node that allows my players to goto thier game. but my question is this, certain modules with certain settings no not seem to stick... from the base framerate of the game setting to shared compendiums. I think i have a open database collision (locking) problem. Any suggestions on how I can fix that??

Collapse
pinja profile image
Pinja Jäkkö

The routePrefix shouldn't have a slash at the beginning, or at least for me it didn't work for me. Spent an hour or so wondering why it wouldn't work 😅

Collapse
tonyeltigre profile image
Anthony Varin

Took me far longer to realize this and now realize I could've read it in the comments!