In this guide, I’ll walk you through deploying a secure virtual private server (VPS) on DigitalOcean using Terraform for infrastructure as code and Tailscale for private networking. This approach combines the convenience of cloud infrastructure with enhanced security through private networking.
Setting Up Terraform for DigitalOcean
First create a secrets.auto.tfvars
file securely store your DigitalOcean access token and SSH key path.
do_token = "digital_ocean_access_token"
pvt_key = "~/.ssh/your_private_key"
Next, create a provider.tf
file to configure the DigitalOcean provider in terraform.
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
}
}
variable "do_token" {
description = "DigitalOcean Personal Access Token"
sensitive = true
}
variable "pvt_key" {
description = "Path to your private SSH key"
}
provider "digitalocean" {
token = var.do_token
}
data "digitalocean_ssh_key" "terraform" {
name = "key_name_in_do" # Replace with SSH key name in DigitalOcean
}
Initialize your Terraform working directory:
terraform init
Creating the DigitalOcean Droplet
Create a droplet.tf
file to define your server configuration and provisioning. Add a SSH connection so that you’re able to provision, and add the path the scripts used for provisioning.
resource "digitalocean_droplet" "droplet" {
image = "ubuntu-20-04-x64"
name = "droplet-1"
region = "ams3"
size = "s-1vcpu-512mb-10gb"
backups = false
ssh_keys = [data.digitalocean_ssh_key.terraform.id]
# SSH connection for provisioning
connection {
host = self.ipv4_address
user = "root"
type = "ssh"
private_key = file(var.pvt_key)
timeout = "2m"
}
provisioner "remote-exec" {
scripts = [
"./scripts/update.sh",
"./scripts/tailscale.sh"
]
}
Setting Up Provisioning Scripts
Create a scripts
directory with the following two scripts files:
./scripts/update.sh
will update the system packages, without the need for user interaction.
#!/usr/bin/bash
sudo apt update
echo 'openssh-server openssh-server/sshd_config boolean true' | sudo debconf-set-selections
sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y
echo "System packages updated successfully."
./scripts/tailscale.sh
will install tailscale.
Note that
tailscale up
will request to authenticate and add the machine to your account by visiting and url.
#!/usr/bin/bash
sudo curl -fssl https://tailscale.com/install.sh | sh
echo "Starting Tailscale..."
sudo tailscale up
echo "Tailscale installed and running. Note the Tailscale IP from above."
Configuring Security with Tailscale and Firewall
Create a firewall.tf
to define your firewall rules. We want only allow the traffic from the tailscale network, and block all the other incoming traffic.
Read more about what ports ports tailscale uses here.
resource "digitalocean_firewall" "firewall" {
name = "tailscale"
droplet_ids = [digitalocean_droplet.droplet.id]
# Tailscale required ports
inbound_rule {
protocol = "udp"
port_range = "3478"
source_addresses = ["100.64.0.0/10"]
}
inbound_rule {
protocol = "udp"
port_range = "41641"
source_addresses = ["100.64.0.0/10"]
}
# Allow all outbound traffic
outbound_rule {
protocol = "tcp"
port_range = "1-65535"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
outbound_rule {
protocol = "udp"
port_range = "1-65535"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
}
Deploying Your Infrastructure
Run Terraform to create your infrastructure:
terraform plan # Preview the changes
terraform apply # Apply the changes
Connecting to Your Server
After deployment, you’ll need to connect to your server using its Tailscale IP rather than its public IP. This provides an additional layer of security, as your SSH port is only accessible through the private Tailscale network.
ssh -i ~/.ssh/your_private_key root@100.x.y.z # Replace with your Tailscale IP