DEV Community

Vishvajeet Shukla
Vishvajeet Shukla

Posted on

Deploy Any Web App on a DigitalOcean Droplet: Node, Static or Docker (2026)

Most deploy tutorials cover one kind of app. Real servers rarely stay that tidy. A single DigitalOcean Droplet often ends up hosting a Node API, a static marketing site and a container or two.

This guide shows how to deploy all three on one Droplet, each on its own domain with HTTPS. Then we'll look at how ShipOwn handles the same mix from a desktop app.

Step 1: Create the Droplet

  1. Create → Droplets, choose a region near your users.
  2. Image: Ubuntu LTS.
  3. Size: a basic plan is enough to start; you can resize later.
  4. Authentication: SSH key (not a password).
  5. Optional: enable the free Cloud Firewall with inbound 22, 80 and 443.

Point three DNS records at the Droplet's IP, for example:

  • api.example.com for the Node API
  • www.example.com for the static site
  • tools.example.com for the Docker app

Step 2: Base setup

ssh root@DROPLET_IP
adduser deploy && usermod -aG sudo deploy
rsync --archive --chown=deploy:deploy ~/.ssh /home/deploy
apt update && apt install -y nginx git certbot python3-certbot-nginx
ufw allow OpenSSH && ufw allow 'Nginx Full' && ufw enable
Enter fullscreen mode Exit fullscreen mode

App 1: Node API under PM2

su - deploy
git clone https://github.com/you/api.git && cd api
npm ci && npm run build
PORT=3001 pm2 start npm --name api -- start
pm2 save && pm2 startup
Enter fullscreen mode Exit fullscreen mode

Nginx (/etc/nginx/sites-available/api):

server {
  server_name api.example.com;
  location / { proxy_pass http://127.0.0.1:3001; proxy_set_header Host $host; }
}
Enter fullscreen mode Exit fullscreen mode

App 2: Static site on Nginx

A Vite, Astro or plain HTML site doesn't need a running process at all. Build it and let Nginx serve the files:

git clone https://github.com/you/site.git && cd site
npm ci && npm run build          # outputs dist/
sudo mkdir -p /var/www/site && sudo cp -r dist/* /var/www/site/
Enter fullscreen mode Exit fullscreen mode
server {
  server_name www.example.com;
  root /var/www/site;
  index index.html;
  location / { try_files $uri $uri/ /index.html; }
}
Enter fullscreen mode Exit fullscreen mode

No port, nothing to restart.

App 3: A Docker app

For anything not built on Node (a Python, Go or PHP service, for example), a container is the cleanest route.

curl -fsSL https://get.docker.com | sh
git clone https://github.com/you/tool.git && cd tool
docker compose up -d --build
Enter fullscreen mode Exit fullscreen mode

Bind the container to localhost only, so it isn't exposed directly:

ports:
  - "127.0.0.1:8080:8080"
Enter fullscreen mode Exit fullscreen mode
server {
  server_name tools.example.com;
  location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Enable sites and HTTPS

sudo ln -s /etc/nginx/sites-available/{api,site,tools} /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d api.example.com -d www.example.com -d tools.example.com
Enter fullscreen mode Exit fullscreen mode

That's three apps, three runtimes, three Nginx files and one certificate run. Now imagine updating each of them every week and rolling back when one breaks.

The same Droplet with ShipOwn

ShipOwn is a desktop app for Windows, macOS and Linux that deploys to Linux servers over SSH. It installs no deployment agent on your Droplet, and it supports exactly these three targets:

  • Node apps run by PM2: Next.js, Nuxt, Remix, SvelteKit, NestJS, Fastify and plain Express, with port, health check and restart policy set.
  • Static sites served by Nginx: Vite with React or Vue, Astro, or plain HTML, published to a release directory. No process, no port.
  • Docker apps: a Dockerfile or Compose file built on the server and published behind Nginx. Images are labelled with the commit they came from, and the previous container is kept until the health check passes.

For each app you go through the same five steps: connect server, pick source, review the editable plan, watch the build, operate. Domains and HTTPS work the same way for all three. ShipOwn writes the virtual host, tests it before reloading, restores it if Nginx rejects it, and requests a Certbot certificate.

Managing existing containers

If the Droplet already runs containers you started by hand, ShipOwn can still help. It inspects each container, maps published and internal ports, shows CPU and memory, flags crash loops, and lets you start, stop or restart a container, open a shell inside it and read its logs.

Keeping a mixed server healthy

  • Watch disk. Docker images and old builds add up. docker system df and du -sh are your friends. ShipOwn's server view shows disk usage at a glance.
  • One Nginx mistake affects everything. Always nginx -t before reload. ShipOwn does this automatically.
  • Know what's deployed. ShipOwn shows which commit each app runs and how far behind its branch it is.

Rolling back on a mixed server

Each app type rolls back differently when you do it by hand:

  • Node app: check out the previous commit, rebuild and pm2 reload. That takes minutes, and the app is in a half-built state while it runs.
  • Static site: keep the previous dist/ folder around and copy it back.
  • Docker app: keep the previous image tag and run it again.

ShipOwn gives all three the same model. Every deploy goes into its own release directory (or an image labelled with its commit, for Docker). The live pointer only moves after the build and health check pass. A deploy that fails restores the previous release by itself, and you can go back to a retained release later with one click. Database migrations and persistent data still need their own backup and recovery plan, whichever tool you use.

FAQ

Can ShipOwn deploy a Python or Go app? Through Docker, yes. There's no native Python or Go runtime; ship it in a container.

Does ShipOwn need Docker on the server? Only for Docker apps. Node and static apps run without it, and ShipOwn can install Docker for you if you need it.

Is there a free trial? Yes, 30 days, no card required.

Conclusion

One Droplet can comfortably host an API, a static site and a container. Doing it by hand teaches you how the pieces fit. Doing it every week is where ShipOwn saves time and mistakes.


Written by Vishvajeet Shukla, full stack developer and creator of ShipOwn.

Top comments (0)