You've got a working docker-compose.yml
, and now you want to put it online.
Maybe it's a SaaS side project. A personal site. A dashboard for a client. Whatever it is – you're here because you want to host a Compose app, and you don't want to spend hours fiddling with YAML, CI pipelines, or Kubernetes manifests.
Let's walk through what it really takes to host a Docker Compose project on your own. And then I'll show you what I built to make this process go away – for myself and anyone else who's tired of copy-pasting configs.
Example: We'll use this project as our demo:
hostimdev/demo-django
(A simple Django app with MySQL and Redis)
🧱 The Hard Way: VPS + Docker + Compose
First, the classic method. Take your favorite VPS provider (we like Hetzner – in fact, Hostim.dev runs on their bare metal servers), and spin up a server.
Note: This guide assumes you're logged in as root.
If not, prefix commands withsudo
or usesudo -i
to switch to root.
1. Provision the VPS
Pick a Linux image (Ubuntu or Debian), log in via SSH, and update your system:
apt update && apt upgrade -y
Install Docker and docker-compose (we follow the official guide):
- Set up Docker's apt repository.
# Add Docker's official GPG key:
apt-get update
apt-get install ca-certificates curl
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc
# Add the repository to Apt sources:
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
- Install Docker packages:
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
2. Clone your project
We'll use a demo Django app
git clone https://github.com/hostimdev/demo-django.git
cd demo-django
💡 Private repo?
You can:
- Use a Personal Access Token (PAT) and clone via HTTPS, or
- Upload your VPS's public SSH key to GitHub and clone via SSH.
⚠️ If you go with the SSH method, make sure to secure the private key on the VPS and limit server access. It's secure if your system is.
3. Deploy your app
Assuming you have a docker-compose.yml
ready:
docker compose up -d
That runs the app. But there are some problems:
- It won't restart after reboot.
- There's no HTTPS.
- You're exposing raw ports to the world.
Security Note: To prevent exposing services to the public internet, modify your
docker-compose.yml
to bind ports only to localhost. For example:ports: - "127.0.0.1:8000:8000"
This ensures services are only accessible from the local machine, not directly from the internet.
4. Add HTTPS with nginx
Install nginx:
apt install nginx -y
Change the default config to proxy traffic to your app (assumes it runs on port 8000):
nano /etc/nginx/sites-available/default
Replace the location /
block inside the server {}
with:
location / {
proxy_pass http://localhost:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
Test and restart nginx:
nginx -t
systemctl restart nginx
Install Certbot and request an HTTPS certificate with automatic redirect:
apt install certbot python3-certbot-nginx -y
certbot --nginx # follow the instructions
It will configure the https for you
By default, if someone enters your server's IP address in a browser, nginx may respond with your app or a default welcome page. To prevent this and serve content only under your domain, block IP-based access. Install Edit your nginx config: Replace the topmost server block (usually the default one on port 80) with this: Then add this just below to block HTTPS access by IP: ⚠️ Replace the cert paths with your real SSL cert/key if you're not using the default snakeoil test cert. Restart nginx: From now on, only your domain name will serve content. Requests to the raw IP will be silently dropped (code 444 = connection closed with no response).🔒 Bonus: Block direct access to your server's IP
ssl-cert
package, we need it just for dummy certs:
app install ssl-cert -y
nano /etc/nginx/sites-available/default
# Block HTTP requests to IP (default server)
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}
# Block HTTPS requests to IP (default server)
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
server_name _;
ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
return 444;
}
nginx -t
systemctl restart nginx
5. Make it survive reboots
Stop the current stack before setting up systemd:
docker compose down
Then create a systemd unit:
# /etc/systemd/system/myapp.service
[Unit]
Description=My Docker Compose App
After=network.target
[Service]
Type=oneshot
WorkingDirectory=/root/demo-django
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Enable and start it:
systemctl enable myapp
systemctl start myapp
Your app will now automatically start after reboots.
6. Handle volumes, backups, logs…
If your Compose file uses volumes (e.g. MySQL, Redis), you now have to:
- Make sure volume paths are persisted and backed up
- Inspect logs manually or add a logging layer (e.g. Loki or Graylog)
- Possibly add monitoring for CPU, RAM, or disk usage
😮💨 It's a Lot
Even if you're comfortable with the CLI, this gets repetitive fast:
- Every project = new VPS
- Manual nginx tweaks
- No dashboard, no metrics
- No easy way to share access
After doing this too many times for clients, side projects, and demos, I decided to build something that just… does it for me.
🧃 The Easy Way: Paste & Deploy
I'm building Hostim.dev – a developer-first platform that lets you paste your docker-compose.yml
, click “Deploy”, and you're live.
Well, unless you
docker-compose.yml
is crazy big with tons of services, then it might take some manual configuration.
Here's what it takes:
- Sign up (no credit card required)
- Create a project and paste your Compose file
- We generate your stack – apps, databases, volumes
- Logs, metrics, and HTTPS just work
🎥 Here's a 27-second demo of deploying with Hostim.dev:
No nginx. No SSH. No firewalls. Just a real app online.
🧪 Try It Free
Every new user gets a 5-day trial project, plus always-free (albeit small) tiers for:
- MySQL and Postgres
- Redis
- Persistent volumes
If you're tired of fighting servers and YAML, check it out:
👉 Get started with Hostim.dev
🚀 Hostim.dev is currently in closed beta – if you want early access, join the waitlist or email me at pv@hostim.dev
P.S. If you do enjoy the ops side – I get it. I used to too. But these days, I just want to ship faster. That's what this is all about.
Top comments (0)