Hosting Foundry Virtual Tabletop in Azure
One of my favorite things to do is to combine my nerdy hobbies. I enjoy Azure and serverless, and I enjoy playing tabletop games like Dungeons & Dragons with my friends. We usually play online because of living far apart, which comes with the need for other things than just pen, paper and dice.
Last year, I decided that I wanted to change the platform for my regular game sessions, and thought that it would be a great opportunity to take a look at hosting it on my own using Azure to have more control, reduce costs and learn something new. The platform I chose is called Foundry Virtual Tabletop, a self-hosted one-time purchase with lots of built-in options, APIs for developers and open source community modules for extra functionality.
I found that other people had already made great guides for hosting it both in AWS and on simple virtual machines on various platforms, but since I wanted to use Azure and avoid managing another layer of infrastructure I decided to take a look at the container options instead.
Today we’ll go through the process of hosting Foundry VTT in Azure as an App Service, specifically a Web App for Container which is a perfect fit for the features we need.
To follow along you will need:
Just curious about the code? Check it out on GitHub!
The Container
The beautiful thing with open source is that sometimes you’re lucky and find that someone else out there has made exactly what you’re looking for. In this case there is already a fantastic Docker container that we can use.
Dockerfile
First of all I’d like for us to take a look at the Dockerfile
in the repository. This file is the blueprint to what will be run within the container.
We can see at the top that the container takes a few arguments for the configuration, such as username and password to retrieve the software license.
Don’t worry if you don’t understand the Dockerfile fully, it sets up an environment in which our dice can thrive.
I won’t pass the configuration as arguments here, instead I will utilize the feature called application settings for our app service in Azure, which exposes each setting as an environment variable inside our container. Environment variables is another way to set the configuration for our container.
Foundry is run on port 30000
by default, so we’ll need to take that into consideration when setting up our app service later.
docker-compose.yml
The second file to look at is docker-compose.yml
. It lets us specify configuration for the container itself, rather than for what is run within it.
First let’s take a look at the suggested file from the repository.
I’m not a fan of writing credentials in my configuration files, so I’m happy to say that we can skip the environment variables here as well since we will set them up as application settings for the app in Azure. We can also skip the port mapping, since our app service has functionality to handle the forwarding of data to Foundry’s port 30000
for us. That leaves us needing to specify:
- Image
- Hostname
- Persistent Storage
Image
Since I don’t want to maintain my own Dockerfile and container registry, I’m going to specify the public registry as listed on the GitHub repository.
A disclaimer here is that by not hosting our own image, we trust someone else to decide when we’re ready to update Foundry to a new version. In my experience it’s more convenient and cheaper, but I recommend that you enable regular backups in your web app after deploying it so that you’re safe if something breaks because of a version upgrade.
Hostname
For the hostname I will specify my own domain that I’ve pointed to my app, but if you haven’t gone all-in with a custom domain you will want to specify the URL to your app here, which looks something like <name>.azurewebsites.net
.
Persistent Storage
Foundry uses a directory called data
by default, but since we’re running our app in a container we don’t have persistent storage in the app’s environment. This means that any data created within Foundry is going to disappear when the app restarts, unless we mount a volume to our container that points to a location outside of it.
There are a few ways to manage persistent storage for our web app, but the easiest way for our scenario is by setting an environment variable called WEBSITES_ENABLE_APP_SERVICE_STORAGE
to true
, letting us use WEBAPP_STORAGE_HOME
which points to a persistent location within the app service root directory.
WEBSITES_ENABLE_APP_SERVICE_STORAGE
is actually enabled by default, by I like including it to make it easier to understand where the persistent storage comes from.
The File
Assembling the information we’ve found so far, we can create a very slim file to run our container with.
App Service
Lastly we need to set up our app service in Azure which will host our container. To do this, I wrote a deployment script and a template which we can find on GitHub. Here we will also set the application settings.
We can adjust the port that traffic is sent to inside the container, by setting the WEBSITES_PORT
application setting in our web app to 30000
. This ensures that people browsing to our web app will still be sent to Foundry inside the container.
For a list of the environment variables that can be used for Foundry configuration in the container, I recommend checking out the repository.
The final list of application settings used for our app service today looks like this.
The Template
The template for the deployment is written in Bicep, a language that makes it easier to write ARM templates used to deploy resources to Azure. It specifies the necessary components for the app service running Foundry, together with the application settings and service app plan determining the performance of the web app.
I’ve chosen to default to the standard S1 plan in the template, which is a dedicated cheap app service plan, but I’m actually using the premium P1v2 plan when I run Foundry myself to ensure good performance in the app.
Some of the input are defined as secrets, such as the credentials to Foundry, and we will be prompted to input them when running the deployment script.
Something to note is that we take the entire content of the docker-compose.yml
and convert it to Base64 in the template, to set it directly in the configuration of the app service.
The Deployment Script
The deployment script lets us get Foundry up and running very quickly in Azure, building on the container and settings previously discussed.
To run the script we first need to run the command Connect-AzAccount
to connect us to Azure with the right account and subscription. After doing so, changing line 2 and 3 in the script below to the name of the app and resource group is enough to then run it for a fresh installation of Foundry VTT for your own use!
You will be prompted for your Foundry username
and password
for license retrieval, as well as an adminKey
which is the admin password within the Foundry application.
Closing Thoughts
This post took me a year and a half to write, mainly because every time I wrote it I realized that I could make the solution I was using better, forcing me to rewrite most of the post again.
At first I was hosting my own container registry and keeping my own dockerfile and mapping ports within, then I tried mapping the ports within the compose file, and finally within the app settings.
I also ran into persistency issues with storage in several ways, first trying to use an Azure Files share, but the end result in this post is what I’m currently using for my own D&D campaigns.
The final code can be seen in my GitHub repository for this post.
I hope it’s as useful for you as writing and exploring the topic of this post has been for me. May your new digital dice roll well!