Docker is a great way to run applications. It will keep it separate from the rest of your system and you’re running in the same environment regardless of the system hosting the container.
Traefik is a Docker-aware reverse proxy with a monitoring dashboard. Traefik also handles setting up your SSL certificates using Let’s Encrypt allowing you to securely serve everything over HTTPS.
Portainer is a web interface for managing Docker. This allows you to easily start/stop/restart your docker containers, manage their settings, or add more containers in the future.
To follow along with this tutorial, you will need the following:
- A Debian based server - I recommend using Ubuntu 20.04.
- Check out the fvtt-docker/README.md if you need some server hosting recommendations.
- A non-root user, currently logged in, with sudo access
- Basic understanding of how to use the Linux command line
- A domain with three A records, each pointing to your servers IP address. I recommend, and for the tutorial will be using the following:
play. You’re free to use any A records you wish, just modify the steps below as appropriate.
Throughout the tutorial, I will use
nano as the text editor as I find it’s the most friendly to newer users. You’re welcome to use whatever editor you prefer.
Saving and Exiting with
Y- to save modifications
Step 1 - Setting up your server
Note: You should be connected to your server via SSH or PuTTY - not using a web console from your hosting provider as pasting content doesn’t work well through web-based consoles.
This section will assume you’re running as a non-root user, with
If you are running as root and do not have a regular user, run the follow commands to create one, replacing
USERNAME with your desired username:
adduser USERNAME usermod -aG sudo USERNAME su - USERNAME
The last command will have switched you to your newly created user. You’re now ready to continue with the tutorial.
Installing the required packages:
Use the following command to install all of the required packages:
sudo apt update && sudo apt install apache2-utils docker.io docker-compose
Start docker and enable it to start on reboot
sudo systemctl enable --now docker
Setup your firewall - we will only allow traffic to the server over SSH, HTTP and HTTPS.
sudo ufw allow 22 sudo ufw allow 80 sudo ufw allow 443 sudo ufw enable
When you enable ufw there will be a warning that your SSH connection may get closed. It shouldn’t actually get closed as we’ve left port 22 open.
Last up, we need to give your user access to the docker group, with these last 2 commands.
sudo usermod -aG docker $USER newgrp docker
Step 2 - Configuring and Running Traefik
Generating a secure password. In the command below, substitute
secure_password with the actual password that you want to use.
htpasswd -nb admin secure_password
The output will look something like this:
If your string has any
$ you will need to modify them to be
$$ - this is because docker-compose uses
$ to signify a variable. By adding
$$ we still docker-compose that it’s actually a
$ in the string and not a variable.
Take note of the output, we will need it near the end of this step.
Next up, we will start creating our config files. I recommend making a separate directory for each container. So, let’s make a folder and switch into it.
mkdir traefik && cd traefik
Now, let’s make our config file and start to edit it
Copy and paste the following into your editor.
api: dashboard: true entryPoints: http: address: ":80" https: address: ":443" providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false certificatesResolvers: http: acme: email: firstname.lastname@example.org storage: acme.json httpChallenge: entryPoint: http
Modify the email address from
email@example.com to a valid email address. This is used for generating your SSL certificates.
Save and exit your editor (for
nano check the Notes section above on how to Save & Exit)
On the topic of SSL, we’re going to need a file for our SSL information to be stored and persisted outside of the container. Let’s create that file now.
Let’s lock down the permissions on this file so other users can’t read it.
chmod 600 acme.json
Up next is the
Same as before, copy/paste the contents below into your editor and get ready to make a few modifications.
version: '3' services: traefik: image: traefik:v2.0 container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true networks: - proxy ports: - 80:80 - 443:443 volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - ./traefik.yml:/traefik.yml:ro - ./acme.json:/acme.json labels: - "traefik.enable=true" - "traefik.http.routers.traefik.entrypoints=http" - "traefik.http.routers.traefik.rule=Host(`monitor.yourdomain.com`)" - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$apr1$ruca84Hq$mbjdMZBAG.KWn7vfN/SNK/" - "traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https" - "traefik.http.routers.traefik.middlewares=traefik-https-redirect" - "traefik.http.routers.traefik-secure.entrypoints=https" - "traefik.http.routers.traefik-secure.rule=Host(`monitor.yourdomain.com`)" - "traefik.http.routers.traefik-secure.middlewares=traefik-auth" - "traefik.http.routers.traefik-secure.tls=true" - "traefik.http.routers.traefik-secure.tls.certresolver=http" - "traefik.http.routers.traefik-secure.service=api@internal" networks: proxy: external: true
monitor.yourdomain.com with your own domain on the following lines:
Replace the auth information from the first command we ran, in this Step, on this line:
Save and exit your editor.
We’re nearly there. Now we need to create the docker network with a quick command.
docker network create proxy
With that done, we’re ready to start our Traefik container.
Step 3 - Running the Traefik Container
Alright, we did all the heavy lifting for Traefik in Step 1. Time to start the container.
docker-compose up -d
This will build the docker container and start it up.
In your web browser, you should now be able to navigate to your Traefik monitoring page. You will be prompted to log in with the
secure_password you used at the start of Step 1. In your browser, replace
yourdomain.com with your domain to login.
Step 4 - Configuring and Running Portainer
Assuming you’re still where we left off, let’s go back up 1 level of our directory path, create a new directory for portainer, and switch into it.
cd .. && mkdir portainer && cd portainer
Portainer will create a fair number of files and directories that it needs to persist between runs. Let’s make a directory for all that.
Now, we’re going to create our
docker-compose config file.
Copy/paste the contents below. We have 2 lines to modify after.
version: '3' services: portainer: image: portainer/portainer:latest container_name: portainer restart: unless-stopped security_opt: - no-new-privileges:true networks: - proxy volumes: - /etc/localtime:/etc/localtime:ro - /var/run/docker.sock:/var/run/docker.sock:ro - ./data:/data labels: - "traefik.enable=true" - "traefik.http.routers.portainer.entrypoints=http" - "traefik.http.routers.portainer.rule=Host(`manage.yourdomain.com`)" - "traefik.http.middlewares.portainer-https-redirect.redirectscheme.scheme=https" - "traefik.http.routers.portainer.middlewares=portainer-https-redirect" - "traefik.http.routers.portainer-secure.entrypoints=https" - "traefik.http.routers.portainer-secure.rule=Host(`manage.yourdomain.com`)" - "traefik.http.routers.portainer-secure.tls=true" - "traefik.http.routers.portainer-secure.tls.certresolver=http" - "traefik.http.routers.portainer-secure.service=portainer" - "traefik.http.services.portainer.loadbalancer.server.port=9000" - "traefik.docker.network=proxy" networks: proxy: external: true
Modify the two lines below, replacing
yourdomain.com with your domain.
With that done, we’re ready to start the Portainer container.
Step 5 - Running the Portainer Container
Exactly the same as starting the Traefik container, we’re going to run:
docker-compose up -d
Now, if you browse to
https://manage.yourdomain.com (replacing yourdomain.com with your domain) you will be prompted to set up your login information.
On the screen asking you to
Connect Portainer to the Docker environment you want to manage, select
Local and press
We will use Portainer to set up and manage FoundryVTT
Step 6 - Configuring and Running FoundryVTT
Alright, we’re nearly there. For this next step, make sure you’ve downloaded the latest (linux) version of FoundryVTT zip file to your server. You don’t need to worry about unzipping it. I highly recommend storing it in its own directory, as the only file, and deleting it and replacing whenever a new version comes out.
If you have multiple FoundryVTT zip files in this directory, your docker deployment will break.
I will be storing mine in my users home directory in a folder called
foundrydl. Please take note of where you store yours as we will need the folder name later.
We have 1 more console command to run before we get into using Portainer. We’re going to create a data directory for Foundry to store it’s data. Go ahead and run this command:
Once you’ve logged into Portainer, you should see something that looks like the image below.
Go ahead and click on the only group on the page, called
local. Here’s the next screen you’ll see.
Next, you’ll want to click on where it says
2 Containers. This next page is where you’ll see all of your running containers. Go ahead and click the
Add Container button at the top of this page.
Go ahead and give your container a name. I will choose
fvtt but you’re welcome to call it anything you want.
Image field, enter
The top part of your settings should look like the image below. Don’t hit
Deploy the container just yet. We still have some more settings to add.
Scroll down to the
Advanced container settings at the bottom of the page.
Command & logging enter the following into
Next, click on the
Volumes tab. Currently, you won’t see any volumes mapped. Go ahead and hit the
map additional volume button.
container field, enter
/data/foundryvtt. Right next to where you entered that, change the toggle from
Bind. The next line should now say
The volume we’re currently adding is where Foundry will store all of your data, including your worlds, modules and uploaded images. At the start of this step we created this folder in our home directory. You’ll have to modify the path below to replace
username with your users’ actual username.
host field enter
/home/username/foundrydata. Don’t worry if the folder doesn’t exist - docker can handle that.
Next, we’re going to map our download directory (you’ll remember, above, that I’m using
foundrydl as my folder). You’ll have to modify your path to match where you’ve saved your zip file. Let’s go ahead and hit that
map additional volume button again.
For the newly created volume, enter the following in the
Just like before, hit the toggle to switch from
host filed, enter the path to where you’ve saved your zip file. For me, it will be
When you’re done, your volumes should look something like this image.
Next up is adding the container to the right network. If you haven’t already guessed, you’re going to want to go ahead and hit the
In the first field,
Network, expand the dropdown and select
proxy. You don’t need to change anything else on this tab. Here’s what your
Network tab should look like:
Next, we’re going to jump ahead a little bit. Go over and click on the
Restart policy tab. On this tab, change your
Restart policy to
Unless stopped. This will allow the container to automatically restart if it crashes.
Alright, one more tab to set up. I want to tell you that I saved the easiest for last. But, the reality is, I saved the longest one for last… Head on over the the
To add a label, you’re going to want to hit the
add label button. Below you’ll find the list of all the labels you want to add. Be sure to change
yourdomain.com to your actual domain.
Once you’re done, it should look something like this:
Now you can go ahead and hit the
Deploy the container button. Your container should now start up (it might take a minute) and you should be able to browse to
yourdomain.com with your domain) and find your freshly installed copy of Foundry VTT.
(Optional) Step 7 - Enabling Audio/Video Support
If you intend to use the built in audio/video support for Foundry and not another tool such as Discord, there’s one last step required.
First up, from the Portainer containers dashboard, select your Foundry container, and stop it.
Back in your SSH terminal, now that the container has been stopped, we’re going to edit one config file. Let’s use the following command to edit the config file in nano (as always, feel free to use your preferred editor):
sudo nano /home/$USER/foundrydata/Config/options.json
Look for the line that says
proxySSL and change the value from
null, depending on your version) to
true. Then you can save and exit nano.
Back in the Portainer containers dashboard, you can restart your Foundry container.
If you found this tutorial helpful and would like to show your appreciation, please consider becoming a Patron.