Deploy a Docker app to a DigitalOcean Droplet
Create a Droplet, lock it down with a Cloud Firewall, install Docker from Docker's own repository, and run your app with Compose and automatic HTTPS. Every command tested; prices checked on 11 November 2026.
TL;DR
- Create an Ubuntu 24.04 Droplet with SSH-key login; a Basic Droplet with 2 GiB costs $12 a month and one with 4 GiB costs $24 (prices of 11 November 2026).
- Attach a Cloud Firewall that allows only SSH, HTTP and HTTPS; it is free and blocks everything a rule does not allow.
- Install Docker (opens in a new tab) with the commands from Docker's documentation, create a deploy user, and run the app, PostgreSQL (opens in a new tab) and Caddy (opens in a new tab) with Docker Compose.
- Point your domain at the Droplet so Caddy gets the certificate, and automate later with the same GitHub Actions (opens in a new tab) workflow used for any VPS.
On this page
To deploy a Docker app to DigitalOcean (opens in a new tab), create an Ubuntu Droplet with SSH-key login, attach a Cloud Firewall that allows only SSH, HTTP and HTTPS, install Docker from Docker's own apt repository, and run your app with Docker Compose behind Caddy, which gets the HTTPS certificate once your domain points at the Droplet. A Droplet with 2 GiB of memory, enough for a small app with a database, cost $12 a month on 11 November 2026.
This is the DigitalOcean part of our complete guide to deploying a web app to a VPS, which explains the choices behind each step; here the server is set up by hand over SSH, so you see every command. If you prefer the server to set itself up on first boot, the cloud-init file in the Hetzner tutorial works on a Droplet too: DigitalOcean's create page takes a cloud-config file as user data.
What was tested. We ran the Docker installation and the user setup commands in an Ubuntu 24.04 container on 11 November 2026 (Docker 29.9.3 and Compose 5.7 installed), and ran the Compose stack with the app, PostgreSQL 18.6 and Caddy 2.11.9 locally. We did not create a Droplet: the console steps and every price come from DigitalOcean's documentation and pricing page, checked the same day.
1. Create the Droplet
In the DigitalOcean control panel, choose Create → Droplets. The page asks, in this order:
- Region. The one closest to your users. DigitalOcean's regional availability page listed 16 datacenters where you can create new resources, among them New York, San Francisco, Toronto, Amsterdam, London, Frankfurt, Singapore, Bangalore and Sydney. In Atlanta, Richmond and Kansas City it listed Basic Droplets with Premium CPUs only, so the Regular plans below were not offered there.
- Image. Ubuntu 24.04 (LTS). Docker supports it, and 26.04 LTS too.
- Size. Bundled Basic plans with Regular CPUs are enough for a small app. In some datacenters the page also offers v5 Droplets, where you set vCPUs, memory and disk separately and the public IPv4 address is a separate line on the bill; you cannot switch between the two types later. For an app with PostgreSQL, take at least 2 GiB (table below).
| Memory | vCPU | SSD | Transfer per month | Price per month |
|---|---|---|---|---|
| 1 GiB | 1 | 25 GiB | 1,000 GiB | $6 |
| 2 GiB | 1 | 50 GiB | 2,000 GiB | $12 |
| 2 GiB | 2 | 60 GiB | 3,000 GiB | $18 |
| 4 GiB | 2 | 80 GiB | 4,000 GiB | $24 |
| 8 GiB | 4 | 160 GiB | 5,000 GiB | $48 |
Bundled plans include a public IPv4 address. Since 1 January 2026, Droplets are billed per second (with a minimum charge of 60 seconds or $0.01, whichever is higher), capped at the monthly price.
Then, further down the same page:
- Backups. Optional; see below.
- Authentication. Choose SSH Key and add your public key.
- Networking and Monitoring. Tick Public IPv6 address if you want an AAAA record (only IPv4 is selected by default), and turn on Improved Metrics and monitoring, which is free and installs DigitalOcean's metrics agent.
- Hostname and tags. Give the Droplet a tag such as
web; the firewall in the next step can apply itself to every Droplet with that tag.
2. Add a Cloud Firewall
Under Networking → Firewalls, create a firewall with these inbound rules:
| Type | Protocol | Port | Sources |
|---|---|---|---|
| SSH | TCP | 22 | All IPv4, all IPv6 (or your own addresses) |
| HTTP | TCP | 80 | All IPv4, all IPv6 |
| HTTPS | TCP | 443 | All IPv4, all IPv6 |
| Custom | UDP | 443 | All IPv4, all IPv6 (HTTP/3, optional) |
Apply it to the Droplet by name or by its tag. DigitalOcean describes Cloud Firewalls as a network-based, stateful service that blocks all traffic a rule does not expressly allow, at no additional cost.
Why not just ufw on the Droplet? Docker's documentation warns that ports you publish with Docker bypass ufw and firewalld rules, while a firewall in DigitalOcean's network is configured outside the Droplet, so nothing Docker does on the Droplet changes it.
3. Create a deploy user
Log in as root with the key you added (ssh root@DROPLET_IP), then create a user for the app and give it your key and a folder:
useradd --create-home --shell /bin/bash deploy
install -d -m 700 -o deploy -g deploy /home/deploy/.ssh
install -m 600 -o deploy -g deploy /root/.ssh/authorized_keys /home/deploy/.ssh/authorized_keys
install -d -o deploy -g deploy /srv/myappSSH checks the ownership and permissions of these files before it accepts a key, so they belong to deploy, with 700 for the folder and 600 for the file.
4. Install Docker
These are the commands from Docker's documentation for Ubuntu, which we ran unchanged on Ubuntu 24.04 (with -y added so they run without questions):
sudo apt update
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugindocker --version then printed Docker version 29.9.3 and docker compose version printed Compose v5.7.1. Docker's packages come from Docker's repository, so apt upgrade keeps them current along with the rest of the system.
Let the deploy user run Docker:
sudo usermod -aG docker deployDocker's documentation warns that the docker group grants root-level privileges. Only the deploy user gets it, and only your key (and later your CI's key) can log in as that user.
5. Run the Docker app with Compose
From here the Droplet is a plain Docker host, so the files are the ones we tested in Deploy Next.js to a VPS with Docker and HTTPS: a compose.yaml with the app, postgres:18 and caddy:2, a Caddyfile with your domain, and a .env file with the database password and the image tag. Only Caddy publishes ports; PostgreSQL is reachable only from the app.
Copy them to the Droplet as the deploy user and protect the secrets file:
scp compose.yaml Caddyfile .env deploy@DROPLET_IP:/srv/myapp/
ssh deploy@DROPLET_IP 'chmod 600 /srv/myapp/.env'If your image is private in GitHub (opens in a new tab) Container Registry, log in once on the Droplet with a personal access token (classic) that has only the read:packages scope.
Before you start the stack, create the DNS records (next step), because Caddy requests the certificate as soon as it starts. Then:
ssh deploy@DROPLET_IP
cd /srv/myapp
docker compose up -d
docker compose logs -f caddyWhen Caddy logs that it obtained the certificate, open https://example.com. Caddy redirects plain HTTP to HTTPS and renews the certificate in the background.
6. Point your domain at the Droplet
At your DNS provider, create an A record for example.com with the Droplet's IPv4 address, an AAAA record with its IPv6 address if you enabled it, and the same for www. Check with dig +short example.com. Caddy's documentation lists the three requirements for automatic HTTPS: DNS records pointing at the server, ports 80 and 443 reachable from outside, and a data folder that persists (the caddy-data volume).
7. Automate deploys
After the first deploy, let GitHub Actions do it: build the image, push it to a registry tagged with the commit, and run a deploy script on the Droplet over SSH. The workflow and script in Deploy a Docker Compose app to Hetzner with GitHub Actions contain nothing specific to Hetzner (opens in a new tab). For a Droplet, give the workflow its own SSH key (add its public half to /home/deploy/.ssh/authorized_keys), pin the Droplet's host key in a secret, and set SERVER_HOST to the Droplet's address.
Each deploy recreates the app container, which means a few seconds without answers. To avoid that, run two copies of the app as in zero-downtime deployments with Docker Compose; on a 2 GiB Droplet, check that two copies and PostgreSQL fit in memory first (docker stats).
Backups and snapshots
DigitalOcean offers two kinds of copies, priced on its Droplet pricing page:
- Backups run automatically. The percentage-based plans cost 20% of the Droplet's price for weekly backups or 30% for daily ones; usage-based plans start at $0.01 per GiB per month, with backups as often as every 4 hours and retention from 3 days to 6 months.
- Snapshots are copies you take on demand, for example before an upgrade, at $0.06 per GB per month.
Both copy the whole disk. For the database, add a nightly pg_dump copied off the Droplet: a dump is consistent and small, and you can restore one table from it. The pillar guide shows the dump and restore commands we tested.
DigitalOcean's documentation says a powered-off Droplet on a Bundled plan is still billed: to stop paying for one you no longer need, destroy it, after a snapshot if you may want it back.
Transfer and other costs
Each plan includes outbound transfer (2,000 GiB a month for the $12 Droplet), pooled across all the Droplets in your team. Inbound transfer is free, and outbound beyond the pool costs $0.01 per GiB. The firewall and the monitoring agent cost nothing. With weekly backups, the 2 GiB Droplet comes to $14.40 a month.
Doing this with OpsCrew
OpsCrew is an open-source tool that does these steps on DigitalOcean with your approval at each one. It proposes Droplet sizes with their monthly cost, shows the exact infrastructure plan, and creates nothing until you approve that plan by its hash (how it works). It then hardens the server, runs your database next to the app (databases), puts Caddy in front with HTTPS (the reverse proxy), opens a pull request with the deploy workflow, and deploys without downtime. Its snapshots copy the app's data, not only the disk, and can keep an encrypted copy off the server.
Not sure DigitalOcean is the right provider? Hetzner vs DigitalOcean for a small production app compares them on price, traffic, regions and features. For everything else around the server, from logs to hardening, see the complete guide to deploying an app to a VPS.
Key facts
| Fact | Value | Source |
|---|---|---|
| Basic Droplet, Regular CPU, 1 vCPU, 2 GiB, 50 GiB SSD, 2,000 GiB transfer | 12 USD per month | DigitalOcean Droplet pricing (opens in a new tab)Verified on |
| Basic Droplet, Regular CPU, 2 vCPUs, 4 GiB, 80 GiB SSD, 4,000 GiB transfer | 24 USD per month | DigitalOcean Droplet pricing (opens in a new tab)Verified on |
| Outbound transfer beyond the pooled allowance | 0.01 USD per GiBThe allowance is pooled across a team's Droplets; inbound transfer is free. | DigitalOcean bandwidth billing (opens in a new tab)Verified on |
| Droplet backups | 20% of the Droplet price (weekly) or 30% (daily); usage-based plans from $0.01 per GiB-month | DigitalOcean Droplet pricing (opens in a new tab)Verified on |
| Droplet snapshots | 0.06 USD per GB per month | DigitalOcean Droplet pricing (opens in a new tab)Verified on |
| Cloud Firewalls | Available at no additional cost | DigitalOcean Cloud Firewalls pricing (opens in a new tab)Verified on |
Frequently asked questions
Should I use the Docker 1-Click app or install Docker myself?
Both give you a Droplet with Docker. Installing it yourself from Docker's apt repository, as in this article, means you know exactly what is on the server and update it the same way as any Ubuntu package, with commands that work the same on any provider.
Is DigitalOcean App Platform easier than a Droplet?
App Platform builds and runs your app from its repository, with no server for you to manage. A Droplet is a plain virtual server: the operating system, Docker, the proxy and backups are yours to run. Compare the two on DigitalOcean's pricing pages for your app's size, and choose App Platform if you never want to see a server.
Sources
- Droplet pricing (opens in a new tab)
- How to create a Droplet (opens in a new tab)
- Droplet pricing details (opens in a new tab)
- Bandwidth billing (opens in a new tab)
- Cloud Firewalls (opens in a new tab)
- Cloud Firewalls pricing (opens in a new tab)
- Regional availability (opens in a new tab)
- Install Docker Engine on Ubuntu (opens in a new tab)
- Linux post-installation steps for Docker Engine (opens in a new tab)
- Automatic HTTPS (opens in a new tab)
Related articles
- Deploying
How to deploy a web app to a VPS: the complete guide
From an empty server to a production app: server size, Docker, a reverse proxy with HTTPS, DNS, CI/CD, secrets, backups, zero-downtime updates, previews, logs and hardening.
- Deploying
Deploy Next.js to a VPS with Docker and HTTPS
A tested setup for Next.js 16 on your own server: standalone output, a small multi-stage Docker image, PostgreSQL and Caddy with automatic HTTPS, and the build-time traps that break apps after the first deploy.
- Deploying
Zero-downtime deployments with Docker Compose
Two app replicas behind Caddy, health checks, retries and a 25-line script: a zero-downtime rollout with plain Docker Compose, tested under constant load, including a broken release and a rollback.