$linuxjunkies
>

Set Up a DigitalOcean Droplet for Production

Create a hardened, production-ready DigitalOcean Droplet: SSH keys, doctl, cloud and host firewalls, monitoring agents, backups, and Reserved IPs explained step by step.

BeginnerUbuntuDebianFedoraArch10 min readUpdated June 7, 2026

Before you start

  • A DigitalOcean account with billing configured
  • doctl installed and authenticated with an API token
  • A local SSH client and ability to generate key pairs
  • A domain name or subdomain to point at the Reserved IP

Spinning up a DigitalOcean Droplet takes about two minutes. Getting it production-ready takes a bit more: hardened SSH, a firewall, monitoring, automated backups, and a Floating IP so you can failover without changing DNS. This guide walks every step from the initial Droplet creation through a live verification checklist.

Prerequisites and Tools

You need a DigitalOcean account with a payment method attached and a local machine running Linux, macOS, or WSL. Install doctl, DigitalOcean's CLI, so you can automate or script anything shown here.

Install doctl

# Debian / Ubuntu
sudo snap install doctl
# or via apt on Ubuntu 22.04+
sudo apt install doctl
# Fedora / RHEL family
sudo dnf install doctl
# Arch
pacman -S doctl
# Authenticate with your API token (generate one at cloud.digitalocean.com > API)
doctl auth init

Step 1 — Generate and Upload an SSH Key

Password authentication on a production server is a liability. Create an Ed25519 key pair before you create the Droplet — it is faster and more secure than RSA.

ssh-keygen -t ed25519 -C "prod-droplet" -f ~/.ssh/do_prod
# Upload the public key to DigitalOcean
doctl compute ssh-key import prod-key --public-key-file ~/.ssh/do_prod.pub
# Note the numeric key ID returned — you need it in the next step
doctl compute ssh-key list

Step 2 — Choose a Region and Droplet Size

Pick a region close to your users. For general web workloads a Basic Shared CPU Droplet at the 2 vCPU / 2 GB tier (s-2vcpu-2gb) is a solid starting point. Use a Dedicated CPU slug (c-2) for sustained compute work.

# List regions
doctl compute region list

# List available sizes (output is long; grep for what you need)
doctl compute size list | grep "s-2vcpu"

For the OS, Ubuntu 24.04 LTS (ubuntu-24-04-x64) gives you five years of standard support. Rocky Linux 9 (rockylinux-9-x64) is the right call when you need RHEL-compatible tooling.

Create the Droplet

doctl compute droplet create prod-web-01 \
  --region nyc3 \
  --size s-2vcpu-2gb \
  --image ubuntu-24-04-x64 \
  --ssh-keys YOUR_KEY_ID \
  --enable-monitoring \
  --enable-backups \
  --tag-names "production,web" \
  --wait

The --wait flag blocks until the Droplet is fully active. Record the public IPv4 address from the output.

Step 3 — Initial Server Hardening

Log in as root the first time, create a non-root sudo user, then lock down SSH.

ssh -i ~/.ssh/do_prod root@YOUR_DROPLET_IP
# Create a deploy user
useradd -m -s /bin/bash deploy
usermod -aG sudo deploy   # Ubuntu/Debian
# usermod -aG wheel deploy  # Fedora/RHEL/Rocky

# Copy root's authorized_keys to the new user
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
# Harden sshd — edit /etc/ssh/sshd_config
sed -i 's/^#\?PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sed -i 's/^#\?X11Forwarding.*/X11Forwarding no/' /etc/ssh/sshd_config

systemctl restart ssh   # Ubuntu/Debian (service is named 'ssh')
# systemctl restart sshd  # Fedora/Rocky

Open a second terminal and verify you can log in as deploy before you close the root session.

Step 4 — Configure the Firewall

DigitalOcean offers a cloud-level firewall (no performance cost on the Droplet) and you should also run a host-level firewall. Use both in production.

Cloud Firewall via doctl

doctl compute firewall create \
  --name prod-firewall \
  --inbound-rules "protocol:tcp,ports:22,address:0.0.0.0/0,address:::/0 protocol:tcp,ports:80,address:0.0.0.0/0,address:::/0 protocol:tcp,ports:443,address:0.0.0.0/0,address:::/0" \
  --outbound-rules "protocol:tcp,ports:all,address:0.0.0.0/0,address:::/0 protocol:udp,ports:all,address:0.0.0.0/0,address:::/0 protocol:icmp,address:0.0.0.0/0,address:::/0"
# Attach the firewall to your Droplet
FW_ID=$(doctl compute firewall list --format ID --no-header | head -1)
DROPLET_ID=$(doctl compute droplet list --format ID,Name --no-header | grep prod-web-01 | awk '{print $1}')
doctl compute firewall add-droplets $FW_ID --droplet-ids $DROPLET_ID

Host-level Firewall with ufw (Ubuntu/Debian)

ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
ufw status verbose
# Fedora / Rocky — use firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

Step 5 — Enable Monitoring and Set Up Alerts

Passing --enable-monitoring at creation installs the DigitalOcean Metrics Agent automatically. Confirm it is running:

systemctl status do-agent

If the Droplet was created without the flag, install the agent manually:

curl -sSL https://repos.insights.digitalocean.com/install.sh | sudo bash

Back in the control panel (or via API), create alert policies for CPU > 80 % sustained for 5 minutes, memory > 90 %, and disk utilization > 80 %. These are the three metrics that actually page you for actionable issues without alert fatigue.

Step 6 — Enable and Verify Backups

Backups passed via --enable-backups cost 20 % of the Droplet's hourly price and retain four weekly snapshots. Check they are scheduled:

doctl compute droplet get $DROPLET_ID --format BackupIDs,Features

For point-in-time snapshots before risky changes, trigger a manual snapshot:

doctl compute droplet-action snapshot $DROPLET_ID --snapshot-name "pre-deploy-$(date +%F)" --wait

Snapshots cost $0.06 per GB per month. List and prune old ones to control costs:

doctl compute snapshot list --resource-type droplet

Step 7 — Assign a Reserved (Floating) IP

A Reserved IP (formerly Floating IP) is a static public address you can instantly remap to any Droplet in the same region. This lets you push a new Droplet live or roll back without a DNS TTL wait.

# Reserve an IP in the same region as your Droplet
doctl compute reserved-ip create --region nyc3
# Assign it to your Droplet
RESERVED_IP=YOUR_RESERVED_IP
doctl compute reserved-ip-action assign $RESERVED_IP $DROPLET_ID

Point your DNS A record to the Reserved IP, not the Droplet's ephemeral IP. When you eventually replace the Droplet, reassign the Reserved IP to the new one — traffic switches in seconds.

Verification Checklist

  • SSH as deploy using the key: ssh -i ~/.ssh/do_prod deploy@RESERVED_IP
  • Confirm root login is blocked: ssh -i ~/.ssh/do_prod root@RESERVED_IP should be refused.
  • Check firewall drops unexpected ports: nmap -Pn RESERVED_IP from an external host should show only 22, 80, 443.
  • Verify the Metrics Agent: systemctl is-active do-agent returns active.
  • Confirm backups are listed in the Droplet's detail page in the control panel.

Troubleshooting

Locked out after SSH changes

Use the DigitalOcean web console (Droplet > Access > Launch Droplet Console) to log in without SSH. Re-check /etc/ssh/sshd_config for typos and run sshd -t to validate the config before restarting.

do-agent not starting

The agent requires outbound HTTPS to agent.digitalocean.com. Verify your outbound firewall rules allow port 443 and that the host's DNS is working: curl -I https://agent.digitalocean.com.

Reserved IP not routing

A Reserved IP unassigned to any Droplet simply drops traffic — it is not a NAT address. Confirm it is assigned: doctl compute reserved-ip get RESERVED_IP and check the droplet field is populated.

tested on:Ubuntu 24.04Rocky 9Debian 12

Frequently asked questions

What is the difference between a DigitalOcean Backup and a Snapshot?
Backups are automated weekly images retained for four weeks, costing 20% of the Droplet price. Snapshots are manual, on-demand images you take yourself; they persist until deleted and cost $0.06 per GB per month.
Can I resize my Droplet later without losing data?
Yes. You can do a CPU/RAM-only resize (reversible) or a full resize that also expands the disk (irreversible). Both require powering down the Droplet first. Take a snapshot before resizing.
Is the cloud firewall sufficient, or do I need ufw as well?
The cloud firewall filters traffic before it reaches the Droplet's NIC, so it has no CPU cost. The host firewall (ufw/firewalld) adds a second layer that also protects against traffic from other Droplets in the same private network. Running both is best practice for production.
What happens to a Reserved IP if I destroy the Droplet it is assigned to?
The Reserved IP is released back to your account unassigned and continues to be billed at the idle rate ($4/month as of 2024). Assign it to a replacement Droplet or explicitly delete it to stop charges.
How do I move a Reserved IP to a different Droplet during a deployment?
Run 'doctl compute reserved-ip-action assign YOUR_IP NEW_DROPLET_ID'. The reassignment takes effect in seconds at the network level, making it suitable for blue-green deployments without DNS propagation delays.

Related guides