Keeping the Website Running After a VPS Reboot
How to ensure your Podman-hosted website comes back automatically after a server restart.
Category: On-Premises & Private Cloud
The first time the VPS rebooted for a kernel update, the site stayed down until I SSH’d in and ran podman-compose up -d by hand. That’s the kind of thing you only accept once. A deployment that survives its own runtime but not the box underneath it isn’t really production.
This post is the minimal systemd wiring that makes reboot a non-event.
The setup
- VPS: Debian, Podman running rootful, compose stack under
/opt/website. - Reverse proxy: Caddy (from the earlier post in this series) in front of the app container.
- Goal: after
sudo reboot, everything — container, Caddy, TLS — is back on its own.
Restart policy in Compose
Inside compose.yml:
restart: unless-stopped
Problem: restart: unless-stopped is necessary but not sufficient. It tells Podman to restart the container if it crashes, but on a full reboot there’s nobody running podman-compose up in the first place — nothing tells Podman about this compose stack at all.
Implementation: A systemd unit that owns the compose lifecycle end-to-end.
A systemd service for the compose stack
/etc/systemd/system/website-compose.service:
[Unit]
Description=Website Podman Compose Stack
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/website
ExecStart=/usr/bin/podman-compose -f compose.yml up -d
ExecStop=/usr/bin/podman-compose -f compose.yml down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
Two details worth calling out:
Type=oneshotwithRemainAfterExit=yes—podman-compose up -dreturns immediately after starting the container, so systemd sees it exit;RemainAfterExittells systemd to still consider the unit “active” afterwards.After=network-online.target— without this, the compose stack can race the network on cold boot and fail to pull or resolve anything.
Enable and start it:
sudo systemctl daemon-reload
sudo systemctl enable website-compose.service
sudo systemctl start website-compose.service
sudo systemctl status website-compose.service --no-pager
Make sure Caddy also starts on boot
Caddy’s Debian package enables its unit by default — but it’s worth confirming rather than assuming:
sudo systemctl enable caddy
sudo systemctl status caddy --no-pager
The reboot test
The only way to know the wiring is right is to actually reboot the machine:
sudo reboot
After reconnecting over SSH:
systemctl status website-compose.service --no-pager
podman ps
curl -I http://127.0.0.1:4321
curl -I https://adrian-altner.de
What I expect to see:
website-compose.serviceactive.- The website container running.
- Both the local and public health checks return
200.
Troubleshooting after reboot
- Container not running. Logs first, always:
journalctl -u website-compose.service -n 100 --no-pager - Caddy up but site down. The app container is the usual suspect:
podman logs --tail=200 website - TLS or proxy issues. Caddy’s journal tells you which hostname failed and why:
journalctl -u caddy -n 100 --no-pager
What to take away
restart: unless-stoppedcovers crashes; systemd covers reboots — you need both.After=network-online.targetprevents cold-boot races that look random and are hard to debug later.Type=oneshot+RemainAfterExit=yesis the right shape for a unit that wraps a tool which detaches after starting.- Reboot the machine on purpose, once, before you ever need to trust the setup unattended.