Skip to content
Go back

Deploying a static Astro web site on DigitalOcean with Tailscale, Docker, and Caddy.

| Last edited: Yesterday

This blog documents how I configured a new production-ready web server on DigitalOcean using their VPC and firewall tools, a custom Debian droplet, Caddy as a reverse proxy, and Tailscale for private access. I’ve done this setup a few times now, and this writeup is both a guide and a checklist for myself and others.

1. Create a new DigitalOcean project

Log in to DigitalOcean and create a new project for your site. This can help keep your account organized as you add more servers over time.

2. Configure a Firewall and tags

Go to Networking -> Firewalls. We’re going to create 2 firewalls:

  1. no-inbound: we’ll block everything except SSH from our IP addresses or an existing Droplet if you have one
  2. http-https: allow http/s through (e.g. for proxy servers)

Both firewalls will have these 2 allow rules:

and then the HTTP/S one will have this rule:

When you spin up new Droplets in the future, make sure you add them to at least 1 firewall.

2. Launch a Debian droplet in the VPC

Use the “Create Droplet” wizard:

Once it’s deployed, you’ll get a public IP and private VPC IP.

4. Install and configure Tailscale

SSH into the server and install Tailscale:

curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up

Use --advertise-tags=tag:prod or other tags if you plan to automate ACLs. Once connected, you can disable port 22 to the public entirely and only access via Tailscale IP.

To test, connect from your computer now:

hiro@Mac:~/git/edgar-test|main  ssh caddy-01
The authenticity of host 'caddy-01 (100.xx.xx.xx)' can't be established.
ED25519 key fingerprint is SHA256:Sx<redacted>.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'caddy-01' (ED25519) to the list of known hosts.
Linux caddy-01 6.1.0-26-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.112-1 (2024-09-30) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Jul 27 21:51:28 2025 from 10.xx.xx.xx
hiro@caddy-01:~$
logout
Connection to caddy-01 closed.

5. Install Caddy and enable HTTPS

Install Caddy with systemd support:

sudo apt install -y 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

Configure your site by editing /etc/caddy/Caddyfile:

yourdomain.com {
  reverse_proxy 127.0.0.1:3000
}

Reload the config:

sudo systemctl reload caddy

Caddy will automatically get a TLS cert from Let’s Encrypt.

6. Deploy your web app or static site

Place your app on the server and bind it to localhost:3000 (or any port you defined in the Caddyfile). Caddy will proxy incoming traffic securely and handle HTTPS for you.

7. Test and verify

Make sure the public IP only exposes 80/443 and that Tailscale is active.

8. Bonus: lock down or harden

If everything works:



Share this post on:

Previous Post
How I enabled native dictation on macOS and tested Perplexity
Next Post
Fixing MPRequestErrorDomain Error in Apple Music Shortcut