Self-hosted lab server
One Debian server running my apps in Docker, with automatic HTTPS, a deployment panel and this website.
I run my own projects on a single Debian 13 virtual server with 6 cores and 8 GB of RAM. It started as a home for PIR-ELN, which had outgrown shared hosting, and has become the place where I test and host everything else, including the site you are reading.
What was interesting to solve
- From shared hosting to containers. The lab notebook used to run on a cPanel host, where a file upload did not restart the app and a restart meant clicking a button in the panel. Now it runs as a Docker container behind Caddy, which handles Let's Encrypt certificates on its own. The database and attachments live on a volume, so rebuilding the image never touches data.
- A port that stayed open. My first compose override used
ports: []to hide the app port behind the proxy. Compose merges lists instead of replacing them, so the port was still reachable from outside. The fix was a standalone production compose file where the app only usesexpose, checked with a curl from outside that has to time out. - Two proxies on one machine. Coolify (with its own Traefik proxy) now deploys this site and future demos. The server has several IP addresses, so Caddy is pinned to one and Traefik to another, and both can own ports 80 and 443 without clashing.
- Basic hardening. A firewall that only opens SSH, HTTP and HTTPS, fail2ban on SSH, and automatic security updates.
This portfolio is a Next.js app in Docker, built by Coolify on every push to main. A Homarr dashboard behind a login gives an overview of the sites and containers.
Stack
Debian 13, Docker and Compose, Caddy, Coolify, Traefik, ufw, fail2ban, unattended-upgrades, systemd timers.