- External SSD with USB 3.0 cable (I used this 120 GB SSD and this case)
- Raspberry Pi 4
- Install Pi OS on the external SSD. I downloaded Raspberry Pi Imager on my adjacent Mac and used that to install the latest Raspbery Pi OS.
-
Once the install finishes, unplug the SSD, remove the SD card from your raspberry pi (if it has one), plug in the SSD, and boot it up from the SSD.
Note: if you have trouble getting your Raspberry Pi 4 to boot from one of the blue USB 3.0 ports, boot it from a black USB 2.0 port, then run
sudo nano /boot/cmdline.txt
and add the following to the beginning of the line in /boot/cmdline.txt:usb-storage.quirks=152d:0578:u
Follow the instructions here to setup ssh, including passwordless ssh access.
Follow this guide to setup an AFP server so you can access your Pi's files remotely.
PiTunnel makes it easy to ssh into your raspberry pi when you're outside of your local network.
-
Follow the steps here to install Docker using the convenience script.
-
Run
systemctl start docker
-
Install docker-compose using
sudo apt install docker-compose
. -
Add a Non-Root User to the Docker Group By default, only users who have administrative privileges (root users) can run containers. If you are not logged in as the root, one option is to use the sudo prefix. However, you could also add your non-root user to the Docker group which will allow it to execute docker commands. The syntax for adding users to the Docker group is:
sudo usermod -aG docker [user_name]
To add the Pi user (the default user in Raspbian), use the command:
sudo usermod -aG docker pi
You can check the version of Docker using
docker version
. For system-wide information (including the kernel version, number of containers and images, and more extended description) rundocker info
.
Basically just follow the steps as indicated on the FoundryVTT installation instructions for Node.js, Nginx, and foundryvtt-docker. You can get 5 free subdomains from DuckDNS.
- Go to www.duckdns.org, sign in, and create a subdomain of your choice.
Then go here and follow the installation instructions.
- Install Node.js
sudo apt install -y libssl-dev curl -sL https://deb.nodesource.com/setup_12.x | sudo bash - sudo apt install -y nodejs
- Create a directory for the application data
cd $HOME mkdir foundrydata
- Install nginx:
sudo apt-get update sudo apt-get install nginx
- Create an Nginx configuration file for your domain. Make sure to update the references to
your.hostname.com
in the configuration file:sudo nano /etc/nginx/sites-available/your.hostname.com
and make sure the proxy_pass port number matches the published port in your docker-compose file.# the filename should be "your.hostname.com" # Define Server 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; # Proxy Requests to Foundry VTT location / { # 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 # This should match the published port in your docker-compose file proxy_pass http://localhost:30000; } }
Save and exit nano with ctrl + x, press Y, then Enter
- Use the
service
utility to manage your Nginx server. Enable the site, test your configuration, fix any errors, and start the service. Don't forget to replaceyour.hostname.com
!# Enable new site sudo ln -s /etc/nginx/sites-available/your.hostname.com /etc/nginx/sites-enabled/ # Test your configuration file sudo service nginx configtest # View configuration errors (if the configtest was not OK) sudo nginx -t # Start Nginx sudo service nginx start # Stop Nginx sudo service nginx stop # Restart Nginx sudo service nginx restart
- Next, create a docker-compose file to run foundryvtt-docker:
nano $HOME/docker-compose.yml
. See the foundryvtt-docker for instructions on using secrets, a temporary foundryvtt download url, and other options. Make sure to replaceYOUR_FOUNDRY_LICENSE
,YOUR_ADMIN_KEY
,YOUR_FOUNDRY_USERNAME
, andYOUR_FOUNDRY_PASSWORD
before saving the file.version: "3.3" services: foundry_1: container_name: foundry image: felddy/foundryvtt:release hostname: my_foundry_host_1 restart: "unless-stopped" volumes: - type: bind source: ./foundrydata target: /data environment: - CONTAINER_CACHE=/data/container_cache - FOUNDRY_USERNAME=YOUR_FOUNDRY_USERNAME - FOUNDRY_PASSWORD=YOUR_FOUNDRY_PASSWORD - FOUNDRY_LICENSE_KEY=YOUR_FOUNDRY_LICENSE - FOUNDRY_ADMIN_KEY=YOUR_ADMIN_KEY ports: - target: "30000" published: "30000" protocol: tcp
Note: if you need to run FoundryVTT on a different port, change the published port to the desired port. No need to change the target port. The target
is the port inside the container, the published
is the publicly exposed port.
- Now you should be able to start the container and see FoundryVTT running at
http://localhost:30000
and athttp://your.hostname.com
:docker-compose up -d
Check that your container is running using docker container ls
, view the container logs using docker logs foundry
. If needed you can stop the container docker stop foundry
, remove it docker rm foundry
, and run it again after making any necessary changes to your docker compose file docker-compose up -d
. Alternately, docker-compose down
will stop all containers and removes containers, networks, volumes, and images created by the previous docker-compose up
in a single command.
- Now it's time to setup HTTPS for your domain. Create SSL certificates using Certbot. Follow the instructions here.
NOTE: certbot seems to now automatically do step 11 for you
- Update the nginx config file to use port 443 and the SSL certificates you created. Again, make sure to replace
your.hostname.com
:sudo nano /etc/nginx/sites-available/your.hostname.com
and make sure the proxy_pass port number matches the published port in your docker-compose file.# the filename should be "your.hostname.com" # Define Server server { # Enter your fully qualified domain name or leave blank server_name your.hostname.com; # Listen on port 443 using SSL certificates listen 443 ssl; ssl_certificate "/etc/letsencrypt/live/your.hostname.com/fullchain.pem"; ssl_certificate_key "/etc/letsencrypt/live/your.hostname.com/privkey.pem"; # Sets the Max Upload size to 300 MB client_max_body_size 300M; # Proxy Requests to Foundry VTT location / { # 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 # This should match the published port in your docker-compose file proxy_pass http://localhost:30000; } } # Optional, but recommend. Redirects all HTTP requests to HTTPS for you server { if ($host = your.hostname.com) { return 301 https://$host$request_uri; } listen 80; listen [::]:80; server_name your.hostname.com; return 404; }
Save and exit nano with ctrl + x, press Y, then Enter
- Don't forget to setup Port Forwarding on your router. You'll need to forward ports 80 and 443 to your raspberry pi. Every router is different, but you can find specific instructions here.
Now your site should be accessible at https://your.hostname.com
!
Be aware that you shouldn't have your foundry instance referencing data in a cloud sync/backup service as it could cause data corruption. What you can do is create a tar archive of your foundry data, compress it with gzip and move it to your cloud sync/backup folder on a regular basis.
- Follow this guide to mount google drive using
rclone
.
Note: install the latest version of rclone using curl https://rclone.org/install.sh | sudo bash
a. I recommend modifying your [email protected] file so it auto-restarts: nano ~/.config/systemd/user/[email protected]
. Add the Restart
and RestartSec
options to the [Service] and StartLimitIntervalSec
and StartLimitBurst
in the [Unit] section prevent a failing service from being restarted every 5 seconds. This will give it 5 attempts, if it still fails, systemd will stop trying to start the service.
[Unit]
Description=rclone: Remote FUSE filesystem for cloud storage config %i
Documentation=man:rclone(1)
StartLimitIntervalSec=500
StartLimitBurst=5
[Service]
Type=notify
Restart=on-failure
RestartSec=5s
ExecStartPre=/bin/mkdir -p %h/mnt/%i
ExecStart= \
/usr/bin/rclone mount \
--fast-list \
--vfs-cache-mode writes \
--vfs-cache-max-size 100M \
%i: %h/mnt/%i
[Install]
WantedBy=default.target
- Follow this guide to schedule automatic backups of your foundrydata folder (Config, Data, and Logs folders).
a. I recommend creating a local /bin folder to store the backup script and add it to your PATH, instead of the /usr/bin folder which requires sudo access:
mkdir ~/bin
export PATH=home/pi/bin:$PATH
b. This is what my backup script looks like. I used rclone move
to copy files to google drive and rclone delete
to automatically delete older files.
#!/bin/bash
BACKUP_FOLDER='/home/pi/backups/'
BACKUP_CMD='/bin/tar -rvf'
counter=1
while [ $counter -le 4 ]
do
SECONDS=0
NOW=`date '+%F_%H%M'`
DEST_FILE="foundrydata$counter-backup-$NOW.tar"
DEST_FOLDER="/home/pi/mnt/gdrive/FoundryBackups/foundrydata$counter/"
echo deleting backups older than 56 days..
rclone delete --min-age 56d $DEST_FOLDER --progress
echo archiving..
$BACKUP_CMD $BACKUP_FOLDER/$DEST_FILE -P /home/pi/foundrydata$counter
echo compressing..
/bin/gzip $BACKUP_FOLDER/$DEST_FILE
echo copying..
rclone move --update --verbose --transfers 30 --checkers 8 --contimeout 60s --timeout 300s --retries 3 --drive-chunk-size 128M --low-level-retries 10 --fast-list --stats 1s $BACKUP_FOLDER/$DEST_FILE.gz gdrive:FoundryBackups/foundrydata$counter
echo foundrydata$counter backup completed in $SECONDS seconds
((counter++))
done
echo all backups complete
c. You can use Crontab Generator to find the syntax for whatever backup schedule you want in crontab. I used this to run backups each Wednesday at 2 am and output the log to a log file with the date (and the backup script above deletes backups after 8 weeks):
0 2 * * 3 ~/bin/backup.sh > ~/backups/backup__`date +\%y\%m\%d`.log
If you have multiple FoundryVTT licenses, it's easy to modify the docker-compose file to spin up multiple foundry instances and have each instance be accessible from its own URL. You'll need to:
- Create a directory for the application data.
cd $HOME
mkdir foundrydata2
- Create another subdomain on www.duckdns.org
- From Setup Step 5 above, follow the same process again but for your new URL. Create the Nginx config file.
- Add the additional service to your existing docker-compose file (rather than creating another docker-compose file) and start it up to ensure it’s setup correctly. Here I have it setup for 3 foundry instances:
---
version: "3.3"
services:
foundry_1:
container_name: foundry1
image: felddy/foundryvtt:release
hostname: my_foundry_host_1
restart: "unless-stopped"
volumes:
- type: bind
source: ./foundrydata1
target: /data
environment:
- FOUNDRY_USERNAME=YOUR_USERNAME
- FOUNDRY_PASSWORD=YOUR_PASSWORD
- CONTAINER_CACHE=/data/container_cache
- FOUNDRY_LICENSE_KEY=YOUR_LICENSE_KEY
- VIRTUAL_HOST=KEY=YOUR_URL.duckdns.org
- FOUNDRY_ADMIN_KEY=YOUR_ADMIN_KEY
ports:
- target: "30000"
published: "30000"
protocol: tcp
foundry_2:
container_name: foundry2
image: felddy/foundryvtt:release
hostname: my_foundry_host_2
restart: "unless-stopped"
volumes:
- type: bind
source: ./foundrydata2
target: /data
- '/home/pi/foundrydata1/Data/maps/:/home/pi/foundrydata1/Data/maps/'
- '/home/pi/foundrydata1/Data/modules/:/home/pi/foundrydata1/Data/modules/'
- '/home/pi/foundrydata1/Data/systems/:/home/pi/foundrydata1/Data/systems/'
- '/home/pi/foundrydata1/Data/audio/:/home/pi/foundrydata1/Data/audio/'
- '/home/pi/foundrydata1/Data/tokens/:/home/pi/foundrydata1/Data/tokens/'
- '/home/pi/foundrydata1/Data/dndbeyond/:/home/pi/foundrydata1/Data/dndbeyond/'
- '/home/pi/foundrydata1/Data/dragupload/:/home/pi/foundrydata1/Data/dragupload/'
- '/home/pi/foundrydata1/Data/uploaded-chat-images/:/home/pi/foundrydata1/Data/uploaded-chat-images/'
environment:
- FOUNDRY_USERNAME=YOUR_USERNAME
- FOUNDRY_PASSWORD=YOUR_PASSWORD
- CONTAINER_CACHE=/data/container_cache
- FOUNDRY_LICENSE_KEY=YOUR_LICENSE_KEY
- VIRTUAL_HOST=KEY=YOUR_URL.duckdns.org
- FOUNDRY_ADMIN_KEY=YOUR_ADMIN_KEY
ports:
- target: "30000"
published: "30001"
protocol: tcp
foundry_3:
container_name: foundry3
image: felddy/foundryvtt:release
hostname: my_foundry_host_2
restart: "unless-stopped"
volumes:
- type: bind
source: ./foundrydata3
target: /data
- '/home/pi/foundrydata1/Data/maps/:/home/pi/foundrydata1/Data/maps/'
- '/home/pi/foundrydata1/Data/modules/:/home/pi/foundrydata1/Data/modules/'
- '/home/pi/foundrydata1/Data/systems/:/home/pi/foundrydata1/Data/systems/'
- '/home/pi/foundrydata1/Data/audio/:/home/pi/foundrydata1/Data/audio/'
- '/home/pi/foundrydata1/Data/tokens/:/home/pi/foundrydata1/Data/tokens/'
- '/home/pi/foundrydata1/Data/dndbeyond/:/home/pi/foundrydata1/Data/dndbeyond/'
- '/home/pi/foundrydata1/Data/dragupload/:/home/pi/foundrydata1/Data/dragupload/'
- '/home/pi/foundrydata1/Data/uploaded-chat-images/:/home/pi/foundrydata1/Data/uploaded-chat-images/'
environment:
- FOUNDRY_USERNAME=YOUR_USERNAME
- FOUNDRY_PASSWORD=YOUR_PASSWORD
- CONTAINER_CACHE=/data/container_cache
- FOUNDRY_LICENSE_KEY=YOUR_LICENSE_KEY
- VIRTUAL_HOST=KEY=YOUR_URL.duckdns.org
- FOUNDRY_ADMIN_KEY=YOUR_ADMIN_KEY
ports:
- target: "30000"
published: "30002"
protocol: tcp
Some things to note:
- Make sure to replace
YOUR_USERNAME
,YOUR_PASSWORD
,YOUR_LICENSE_KEY
,YOUR_URL.duckdns.org
, andYOUR_ADMIN_KEY
for each service. - Each new Foundry instance will need its own published port number (but the target port will always be 30000)
- Foundry supports symbolic links (aka symlinks) as of v0.5.0: "The software can now support symbolic links inside the user data location which can point to art assets, module, systems, or worlds which are stored in other locations." I've added symlinks so that all foundry instances share a bunch of folders, including modules and systems, with the foundrydata1 folder. That way I don't have to backup, maintain and update duplicate modules, worlds, and other assets. In addition to including each volume in the volumes section of the docker-compose file, you'll need to run the command
ln -s /home/pi/foundrydata1/Data/modules /home/pi/foundrydata2/Data/modules
for each folder you want to link. This command creates a link to/home/pi/foundrydata1/Data/modules
in/home/pi/foundrydata2/Data/
. For example, if you wanted to have the modules and systems shared between all instances, you'd need to run these commands:ln -s /home/pi/foundrydata1/Data/modules /home/pi/foundrydata2/Data/modules ln -s /home/pi/foundrydata1/Data/modules /home/pi/foundrydata3/Data/modules ln -s /home/pi/foundrydata1/Data/systems /home/pi/foundrydata2/Data/systems ln -s /home/pi/foundrydata1/Data/systems /home/pi/foundrydata3/Data/systems
- Setup HTTPS using Certbot and Nginx per Setup Steps 9 and 10 above.