With the world dealing with COVID-19 by social distancing many gaming groups are left looking for ways to game while keeping their distance. This post will provide an overview for installing Foundry Virtual Tabletop, a software specifically designed to support playing table top games remotely with a group. I found this overview helpful in comparing Virtual Table Top options. One unique feature of Foundry is it uses a self hosted one time purchase model. In this post I’ll be using the same tools I’ve used in previous posts to deploy local or to the cloud provider of your choice.
Since this post is targeted at people interested in Foundry I won’t make the assumption you are familiar with Juju, Charms, or LXD. If you are you can move onto the installation steps below. For this setup I’m going to start from a clean Ubuntu Bionic (18.04) machine, if you want to follow along.
While these tools have a lot of additional configuration options I will only go over what’s necessary to get started. You can dig into more advanced networks and configuration options when/if needed at a later time.
For this guide we’ll install the software into LXD containers locally. This will let us test out Foundry and the automation tools and remove the containers when we’re done. The deployment will utilize Juju to manage the software and can be used to deploy on different environments. While we’re going to deploy locally on LXD the same tools and process can be used to deploy to a variety of cloud providers.
Setup the local environment
We’ll need LXD and Juju both of which can be installed as snaps.
# Instal snaps sudo snap install lxd sudo snap install juju --classic # Setup lxd with defaults lxd init --auto # Verify LXD lxc launch ubuntu:18.04 lxc list
This should install the dependencies and launch a test container. The final command
should provide a table showing your new container.
+----------------+---------+------------------------+------+------------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +----------------+---------+------------------------+------+------------+-----------+ | capital-martin | RUNNING | 10.177.243.208 (eth0) | | PERSISTENT | 0 | +----------------+---------+------------------------+------+------------+-----------+
We don’t need that container it was just a test, remove it with
lxc delete --force
capital-martin, use the name that was generated for your container.
With LXD setup we’ll establish a local Juju environment, the processes of setting up a provider is known as bootstrapping.
juju bootstrap localhost lxd-controller
You can now check check the status of your juju environment with:
$ juju status Model Controller Cloud/Region Version SLA Timestamp default local-lxd localhost/localhost 2.7.5 unsupported 18:38:05-05:00 Model "admin/default" is empty.
You’re all set, if you have any issues more detailed instructions are available on the juju lxd documentation.
Let’s start by deploying a bundle which will get the install running and then review the
details of what it is doing. A bundle is simply a yaml file that completely defines a set of
applications and options in a single file. Create a file named
bundle.yaml with the
following contents in it.
series: bionic applications: foundry: charm: cs:~pirate-charmers/foundryvtt num_units: 1 options: proxy_port: 80 resources: foundryvtt: ./foundryvtt-0.5.5.zip haproxy: charm: cs:~pirate-charmers/haproxy num_units: 1 relations: - - haproxy:reverseproxy - foundry:reverseproxy
Foundry currently distributes the software via foundryvtt.com and requires a one time purchase. At the time of this writing it can be purchased as pre-release, with the full launch planned for 2020-05-22. You will need the Zip file for Linux be sure the file is in the same directory as the bundle.yaml and that the name of the file matches the filename shown above. If you have a newer version simply update the name for the .zip file in the bundle.yaml to match your file.
With the bundle.yaml and foundry.zip you can start the deploy:
juju deploy ./bundle.yaml
You can see the status of the install with
juju status --color. I prefer to watch it for a
watch -c juju status --color --relations.
When the deploy is finished you’ll see a status that looks like:
Model Controller Cloud/Region Version SLA Timestamp default local-lxd localhost/localhost 2.7.5 unsupported 19:36:38-05:00 App Version Status Scale Charm Store Rev OS Notes foundry active 1 foundryvtt jujucharms 4 ubuntu haproxy 0.1.8 active 1 haproxy jujucharms 8 ubuntu Unit Workload Agent Machine Public address Ports Message foundry/0* active idle 0 10.177.243.14 Unit is ready haproxy/0* active idle 1 10.177.243.63 80/tcp Machine State DNS Inst id Series AZ Message 0 started 10.177.243.14 juju-53a674-0 bionic Running 1 started 10.177.243.63 juju-53a674-1 bionic Running Relation provider Requirer Interface Type Message haproxy:reverseproxy foundry:reverseproxy reverseproxy regular
What was deployed
This bundle deploys two pieces of software.
- FoundryVTT - The virtual table top server
- Haproxy - Provides reverseproxy for FoundryVTT
This closely mirrors the configuration as described for setting up an Ubuntu VM on the community Wiki. Where the instructions on the Wiki use NGINX I’m using HAProxy both serve as a reverse proxy for Foundry.
Each software that Juju deploys is controlled via a piece of software known as a Charm. The HAProxy and FoundryVTT charms are publicly available and manage the installation and operation of each of those pieces of software. In this case they handle the setup much like the Wiki. Foundry installs Node, the provided Zip file, sets up a daemon to keep it running, and registers with HAProxy.
HAProxy has been installed and sets up the reverseproxy that is requested by Foundry.
This is done via a
relation which is shown at the bottom of the bundle. The relation is a
known connection point between charms, in this case it’s named
reverseproxy and we’ve
connected Foundry to HAProxy as they both support the relation type.
juju status output you’ll see a table with a section for App, Unit,
Machine, and Relation. Apps are the charms that are in the environment and tells you
where it was installed from (jujucharms) and the Revision. Units are an actual instance of the
application. In this case ‘foundry/0’ and ‘haproxy/0’. The Units tell you the IP address they
currently have, what machine they are on, and some status about the unit. Machines are a list
of all machines in an environment where machines can be bare metal, containers, virtual
machines, etc. Machines aren’t terribly interesting here, but on a cloud provider you might
install multiple units on a single virtual machine. Finally, a table of relations tells you
which relations currently exist, there is one as discussed above between haproxy and foundry.
With the deployment settled and all units showing active/idle we can access foundry. From the
status above we’ll use the IP Address for HAProxy and the subdomain ‘foundry’ which is the
default set on the foundry charm. Open a browser to
you should be greeted with the Activation Screen.
The use of xip.io is a convenience domain that lets us use an IP address like a domain name.
You can log into HAProxy or Foundry if you like with the
juju ssh command. Also of interest
juju scp which lets you copy files to/from machines. For example you might want to
copy a file to foundry to use as the background image for a world. You can do that with
scp ./my-awesome-background.png foundry/0 or access foundry to see logs
juju ssh foundry/0.
If you do put files on Foundry you’ll find the data path the charm uses is
As I continue to update the Foundry charm additional actions for operating the software may
become available. Charms can be upgraded with
juju upgrade-charm command allowing you to
pull in any fixes or changes. If you find bugs or features that should be part of the charm
you can file them on the github page for the charm. Additionally, I idle on
the Foundry Discord server with the user name Zarek if you want to ping me on the
When you’re done and want to remove the containers you can remove the model with all the
applications and machines and reset to a new clean default model with the command
juju destroy-model -y default && juju add-model default
From here you can redeploy with the same or new configurations if you like.
With Juju you can target several cloud providers to deploy your software onto. With the same charms shown here you can deploy to whichever provider you prefer. For self hosing in a lab environment the LXD or MAAS providers allow you to deploy to either containers or bare metal machines of your choosing. I’ve run labs hosted on a single machine as LXD containers as well as a multi-machine lab deployed with MAAS.
By default if the option
proxy_port is not set it will use 443 to provide a secure
connection. The details of setting up HAProxy with Letsencrypt are beyond the scope of this
post but it is supported by the charm and an example of setting it up can be seen in the
previous blog post about bundle weechat. In that post, HAProxy was also
used, and the section Accessing weechat via relay walks through the use of
HAProxy to setup a domain and Letsencrypt. As mentioned before feel free to ask questions
via Discord if you are ready to plan a roll out to a cloud provider or hardware in your lab.
Additionally, the weechat post demonstrates installing multiple charms on a single host with HAProxy
being deployed directly to the machine and other software in a LXD Container on the machine.
This same setup will let you run FoundryVTT and HAProxy on a single cloud machine.
In my experience if you deploy to a cloud provider the instance size needed to run the software is not very high. However, I’ve seen instances that die during installation due to lack of resource on small instances trying to install packages. One way to deal with that is to install with a default machine size and after it’s up and running shut the instance down and resize to a smaller instance.