July 9, 2025 These are my personal notes for running Foundry VTT version 13 behind Caddy 2 on a Debian 12 server in the cloud. I'm using OliveTin as a web interface to restart Foundry VTT, Caddy 2, or just reboot the server. I also use Restic for backups. I'm sure I've made some mistakes, errors, and omissions.
I attempted to use LLMs to help create these notes. I tried ChatGPT, Gemini, and Claude. They were all dog shit. They consistently confused software versions and gave incorrect instructions. Their output of configuration files were needlessly verbose to the point of literally making up parameters and breaking syntax. The generated config files for Caddy 2 were particularly insane, with it often mixing totally different config formats in the same file. All in all, the LLMs only served to waste my time. LLMs: Overrated, unreliable. Would not recommend. Just RFTM
ssh <user>@<your-server-ip>
sudo apt update
sudo apt upgrade
sudo apt install curl htop unzip nano build-essential git
sudo adduser frank
sudo usermod -aG sudo frank
ssh frank@<server-ip>
mkdir -p /home/frank/foundry/rigden/{core,data}
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt update
sudo apt install nodejs
sudo apt install debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy
sudo systemctl enable caddy
sudo npm install -g pm2
cd /home/frank/foundry/rigden/core
wget -O foundry.zip <timed link>
unzip foundry.zip
rm foundry.zip
I'm using --max-old-space-size=4096 to give node more memory.
node --max-old-space-size=4096 /home/frank/foundry/rigden/core/main.js --name foundry --dataPath=/home/frank/foundry/rigden/data
pm2 start "node --max-old-space-size=4096 /home/frank/foundry/rigden/core/main.js --name foundry --dataPath=/home/frank/foundry/rigden/data" --name rigden-foundry
pm2 save
pm2 startup
Run provided by PM2 command in the output.
sudo nano /etc/caddy/Caddyfile
Then edit:
<your-domain> {
reverse_proxy localhost:30000
}
Restart Caddy with the new Config
sudo service caddy restart
nano /home/frank/foundry/rigden/data/Config/options.json
"hostname": " <FoundryInstanceDomainName>
Restart Foundry
pm2 restart rigden-foundry
wget https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin_linux_amd64.deb
sudo dpkg -i OliveTin_linux_amd64.deb
rm OliveTin_linux_amd64.deb
sudo nano /etc/OliveTin/config.yaml
Edit:
listenAddressSingleHTTPFrontend: 0.0.0.0:7331
# Choose from INFO (default), WARN and DEBUG
logLevel: "DEBUG"
# Checking for updates https://docs.olivetin.app/reference/updateChecks.html
checkForUpdates: true
actions:
- title: Restart Rigden Foundry
icon: disk
shell: su - frank -c "pm2 restart rigden-foundry"
popupOnStart: execution-dialog-stdout-only
- title: Caddy 2 Web Server
icon: disk
shell: sudo service caddy restart
popupOnStart: execution-dialog-stdout-only
- title: Reboot Server
icon: disk
shell: reboot
popupOnStart: execution-dialog-stdout-only
Then:
sudo systemctl enable --now OliveTin
We will be using BasicAuth to protect OliveTin. So need to hash a password.
caddy hash-password --plaintext <your-password>
Copy the output for later. Now let Caddy proxy OliveTin.
sudo nano /etc/caddy/Caddyfile
Add:
<your-control-domain> {
basicauth {
frank <hashed-password>
}
reverse_proxy localhost:7331
}
Now restart Caddy.
sudo service caddy restart
ssh-keygen -t ed25519 -b 4096 -C "your_email@example.com"
ssh-copy-id -i ~/.ssh/id_ed25519.pub <user>@<your-server-ip>
sudo nano /etc/ssh/sshd_config
Change:
PermitRootLogin no
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no
The restart the SSH service.
sudo systemctl restart ssh
sudo apt install ufw
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo apt install fail2ban python3-systemd
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Edit to tell Fail2Ban to use Systemd
sshd_backend = systemd
And then Enable for SSH.
[sshd]
backend=systemd
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
Then reload and restart the Fail2Ban Service.
sudo systemctl enable fail2ban
sudo systemctl reload fail2ban
sudo systemctl restart fail2ban
You can check on your jails.
sudo fail2ban-client status sshd
To backup our Foundry games, I've chosen Restic and Backblaze 2. Don't use default distro version of restic. It is old. Download current version and make and alias.
Data Needed: Backblaze B2 Bucket Name='' AWS_ACCESS_KEY_ID='' AWS_SECRET_ACCESS_KEY='' RESTIC_PASSWORD=''
sudo apt install restic
mkdir /home/frank/config
nano /home/frank/config/backup.env
Edit:
AWS_ACCESS_KEY_ID=<AWS_ACCESS_KEY_ID> AWS_SECRET_ACCESS_KEY=<AWS_SECRET_ACCESS_KEY> RESTIC_PASSWORD=<RESTIC_PASSWORD>
Initialize first backup:
source /home/$FoundryUser/backup/backup.env
restic -r s3:https://s3.us-west-004.backblazeb2.com/<bucket-name> init
And now we preform our first backup.
source /home/frank/config/backup.env
pm2 stop rigden-foundry
restic -r s3:https://s3.us-west-004.backblazeb2.com/<bucket-name> --verbose backup /home/frank/foundry
pm2 start rigden-foundry
sudo apt install unattended-upgrades apt-listchanges
sudo nano /etc/apt/apt.conf.d/50unattended-upgrades
hostnamectl set-hostname <server-name>
timedatectl list-timezones
sudo timedatectl set-timezone America/Los_Angeles
timedatectl set-ntp true
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
sudo nano /etc/security/limits.conf
Add:
* soft nofile 65536
* hard nofile 65536
sudo nano /etc/sysctl.conf
Add these lines at the end:
# TCP optimizations for slow boys
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_slow_start_after_idle = 0
net.core.netdev_max_backlog = 2500
net.ipv4.tcp_congestion_control = bbr
Reload settings.
sudo sysctl -p
sudo reboot
While initially convenient, we don't want to run a program like Foundry with sudo permissions.
sudo deluser frank sudo
IP
Default User's Name
Foundry Instance Name
Default User's Password
Frank's Password
Backblaze B2 Bucket Name
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
RESTIC_PASSWORD