How to deploy an open source app on a VPS (Docker, Coolify, reverse proxy, backups)

7 minUpdated:
How to deploy an open source app on a VPS (Docker, Coolify, reverse proxy, backups)

Harden a fresh VPS (SSH keys, firewall, updates), install Docker, run the app with its official Docker Compose file, and put Caddy or Traefik in front for HTTPS. Or install Coolify to manage that for you. Then automate encrypted off-site backups, pin versions and test a restore.

What does deploying an open-source app on a VPS involve?

Most self-hostable projects today ship an official Docker image and a docker-compose.yml. Deploying them means five layers: a secure server, a container runtime, the app and its database, a reverse proxy that terminates HTTPS, and backups.

The first deploy is the easy part. The real work is keeping the app patched, backed up and restorable for years, so choose a setup you will still understand in six months.

A VPS gives you a full Linux machine at a predictable monthly cost, with root access and no platform limits on background jobs, websockets or custom ports. That flexibility is why many self-hosted projects assume one.

The flip side is that nobody patches, monitors or backs it up for you. Budget time for maintenance, not only for the initial install, and write down every decision in a README next to the compose files.

The steps below apply to most apps that publish Docker images, from analytics and automation tools to chat UIs and internal dashboards.

Which deployment approach should you choose?

Whichever option you choose, the underlying pieces are the same: containers, a proxy, volumes and backups. Learning them once with plain Compose makes any platform easier to debug later, because you know what it is doing on your behalf.

Avoid mixing approaches on one server, such as a platform’s built-in proxy and your own Nginx both trying to own ports 80 and 443. Pick one owner for incoming traffic.

ApproachLicenceBest forTrade-off
Plain Docker Compose + CaddyOpen source componentsOne to a few apps, full controlYou write and maintain config yourself
CoolifyApache 2.0Many apps, web UI, git deploys and one-click servicesAnother system to update; it needs server resources itself
DokkuMITHeroku-style git push deploysCLI-driven; buildpack or Dockerfile workflow
CapRoverCheck the licence fileWeb UI with one-click appsOpinionated setup around Docker Swarm
Bare metal install without containersVariesApps without Docker supportHarder upgrades and dependency conflicts

Step 1: How to prepare and harden the server

  • Create the VPS with a current Ubuntu LTS or Debian image and add your SSH public key during setup.
  • Log in, update packages: sudo apt update && sudo apt upgrade -y
  • Create a non-root user with sudo and use it from now on.
  • In /etc/ssh/sshd_config set PasswordAuthentication no and PermitRootLogin no, then restart the SSH service.
  • Enable a firewall: sudo ufw allow OpenSSH, sudo ufw allow 80, sudo ufw allow 443, sudo ufw enable
  • Install unattended-upgrades for automatic security patches, and optionally fail2ban.
  • Remember that Docker’s published ports can bypass ufw rules; bind internal services to 127.0.0.1 or keep them on internal Docker networks.

Step 2: How to deploy with Docker Compose and Caddy

  • Install Docker Engine and the Compose plugin following Docker’s official instructions for your distribution.
  • Create a folder per app, for example /opt/apps/myapp, and put the project’s official docker-compose.yml there.
  • Move secrets into an .env file next to it (restrict permissions with chmod 600) and never commit it.
  • Pin image versions to specific tags instead of latest so updates are deliberate.
  • Point a DNS A record (and AAAA if you use IPv6) for app.example.com at the server.
  • Run Caddy as the reverse proxy with a Caddyfile entry such as app.example.com { reverse_proxy localhost:3000 }; Caddy obtains and renews HTTPS certificates automatically.
  • Start the stack: docker compose up -d, then check docker compose ps and docker compose logs -f.
  • Visit the domain, finish the app’s setup wizard, and disable public sign-up if the app allows it.

Step 2 alternative: How to deploy with Coolify

  • On a fresh server, run the installer from Coolify’s documentation: curl -fsSL https://cdn.coollabs.io/coolify/install.sh | sudo bash
  • Open the dashboard on port 8000, create the admin account immediately, then put the dashboard behind your own domain with HTTPS.
  • Add a resource: a one-click service, a Docker Compose file, or a git repository with a Dockerfile.
  • Set the domain on the resource; Coolify’s built-in proxy handles certificates.
  • Configure scheduled database backups to S3-compatible storage in the resource settings.

Step 3: How to set up backups you can actually restore

Backups are the step most self-hosters skip and the one they regret. Follow the 3-2-1 idea: several copies, on different media, at least one off-site.

If you run a single app, plain Docker Compose is usually enough and keeps the setup transparent. If you expect to host several apps and prefer a dashboard, a platform like Coolify saves repetitive proxy and backup configuration.

Whatever you pick, keep the compose files and configuration in a private git repository, so you can rebuild the server from scratch when needed.

  • Dump databases with their native tools (pg_dump, mysqldump) rather than copying live database files.
  • Back up Docker volumes and the app’s .env and compose files.
  • Use an encrypting, deduplicating tool such as restic or BorgBackup to send backups to object storage or another server.
  • Schedule it with cron or a systemd timer, and alert when a backup run fails.
  • Test a full restore to a fresh server periodically; an untested backup is only a hope.

Common mistakes when self-hosting on a VPS

RepoLoot’s catalog tags self-hosted projects by difficulty, which is a sensible filter before committing to run something in production.

  • Using the latest image tag and getting a breaking major version during a routine restart.
  • Exposing databases or admin panels on public ports.
  • Leaving the default admin password or open registration enabled.
  • Keeping the only backup on the same server that might fail.
  • Running out of disk because of unrotated Docker logs and old images; configure log limits and prune periodically.
  • No monitoring: add an uptime checker such as Uptime Kuma, hosted elsewhere, so you learn about outages before users do.
  • Ignoring the licence: AGPL apps require sharing modifications if you offer them to users over a network.

Which apps are good first candidates to self-host?

Start with apps where downtime is annoying but not critical and where the data is easy to back up. That lets you learn the routine of updates and restores without pressure.

Good first candidates are an uptime monitor, a bookmarks or notes app, an analytics tool for a side project, or an automation tool like n8n. Save email servers and anything customer-facing with strict uptime needs for later.

For each candidate, check three things before installing: an official Docker image or compose file, clear upgrade notes between versions, and documented backup steps. Projects that lack all three will cost you far more time than the install suggests.

How do you monitor and update the server over time?

A deployed app needs routine care. Put a recurring reminder in your calendar to check updates, disk space and backup reports, even if everything looks fine.

Security updates for the operating system can be automatic, but application updates should stay manual because they can include database migrations.

  • Watch the project’s release page or subscribe to its security advisories.
  • Check disk usage with df -h and Docker usage with docker system df.
  • Rotate secrets when someone leaves the team or a key might have leaked.
  • Keep a short README in the app folder describing how it was deployed, where backups go and how to restore.

Frequently asked questions

How big a VPS do I need for a self-hosted app?
It depends on the app. Many lightweight apps run comfortably on one or two CPU cores with a couple of gigabytes of RAM, while apps bundling search engines, databases or AI models need much more. Check the project’s documented requirements, start small, and watch memory usage before resizing.
Is Coolify better than plain Docker Compose?
Coolify is more convenient when you run many apps, want git-based deploys, a web UI and built-in backups. Plain Docker Compose with Caddy is simpler, uses fewer resources and is easier to reason about for one or two apps. Both run the same containers underneath.
Do I need a reverse proxy?
For anything public, yes. A reverse proxy such as Caddy, Traefik or Nginx terminates HTTPS, routes several domains to different containers on one server and lets you keep app ports private. Caddy and Traefik can request and renew certificates automatically.
How do I update a self-hosted app safely?
Read the release notes, take a fresh backup, change the pinned image tag, then run docker compose pull and docker compose up -d. Check logs and the app itself afterwards. For major versions, test the upgrade on a copy first, because database migrations may not be reversible.
Free for builders

Get a hand-picked shortlist of repos for your project

Tell us what you are building. A person — not a bot — reviews it and replies within 48 hours with the catalog projects that fit, including licence and difficulty notes.

We use your email only for this request. Privacy policy

Related guides