Link to English podcast

Self Hosted Applications: Security Habits Teams Should Adopt Early

When you self-host applications, your early security decisions tend to stick, for better or worse. It’s easy to spin up containers with latest tags, skip HTTPS, or run everything on one box “just for now.” Those shortcuts quietly become your default operating model. If you want a stack that doesn’t break on updates or expose more than it should, you need a few habits in place from day one starting with how you treat your infrastructure.

Essential Security Checklist for Self-Hosted Apps

When you self-host applications, a simple, repeatable security checklist helps prevent small configuration errors from becoming serious issues.

Pin container image versions instead of using latest, so you don't automatically pull new images that could introduce regressions or compromised releases.

Prefer Docker-based or other containerized deployments over direct host installs to limit the impact of supply-chain problems and to make environments easier to compare and reproduce.

Place every service behind a reverse proxy such as Nginx, enforcing HTTPS redirects, handling TLS termination, and supporting WebSockets while forwarding traffic to internal container ports.

Harden the runtime by using unprivileged LXCs on Proxmox or equivalent isolation mechanisms to reduce the potential impact of container escape vulnerabilities and keep services compartmentalized.

These habits are easier to absorb from a worked example than from a checklist. The DotRoll guide to self-hosting Supabase follows exactly this pattern on a real stack Docker deployment, a reverse proxy handling HTTPS in front of it, environment variables and credentials managed properly, persistent storage and automated backups and ends on the mistakes that recur most often, weak authentication and misconfigured storage among them. Worth reading alongside the list above if you're standing up your first production service.

Safer Updates: Version Pinning and Rollbacks

A safer update process starts by preventing upstream releases from automatically deploying into your environment. Pin exact Docker image tags or digests such as postgres:16.3 or a specific SHA instead of using moving tags like latest. This reduces the risk that a compromised or faulty release will be pulled into production without review.

Historical incidents have shown that malicious or broken versions can be published, detected within minutes, and removed within a few hours. By updating only through an intentional process, you limit the time window in which such versions could affect your systems. Treat each update as a controlled change: review the release notes and changes, deploy to a test or staging environment where possible, then roll out to production and monitor the service for a defined period (for example, one to two hours) for anomalies in logs, metrics, and error rates.

Maintain clear rollback paths by retaining previous configuration artifacts, including earlier Compose files, pinned image versions, and environment variables. This allows you to revert quickly and predictably if an update introduces regressions or security issues.

Limiting Blast Radius in Your Self-Hosted Stack

Careful updates reduce how often systems fail; limiting blast radius reduces the impact when failures or compromises occur. This is achieved by isolating services. Run each service in its own virtual machine (VM), LXC container, or other container technology, rather than concentrating all services on a single host or monolithic Docker stack.

Unprivileged LXCs or containers are generally preferable, because the root user inside the container is mapped to a non-root user on the host. This reduces the risk that a container escape will lead to full host compromise. Privileged LXCs should be used only when there's a clear, documented requirement.

Review your stack for any privileged containers that aren't strictly necessary. When you identify one, create a new unprivileged container and migrate data and configuration into it, instead of attempting to retrofit stronger isolation into the existing privileged container. This approach provides a clearer security boundary and makes it easier to reason about the container’s permissions and behavior.

The OWASP Docker Security Cheat Sheet is a good companion here: it works through capability restriction, preventing privilege escalation, read-only filesystems and rootless mode as separate controls, so you can audit your stack against each one rather than treating isolation as a single switch.

Fixing Privileged Containers and LXCs Safely

Privileged containers can simplify certain tasks, but they significantly weaken the isolation you normally expect from a self‑hosted environment. In Proxmox, review each LXC and verify whether it's configured as privileged.

A privileged LXC maps the container’s root user directly to the host’s root user, while an unprivileged LXC maps the container’s root user to an unprivileged user on the host through user namespaces.

If you identify a privileged LXC, it's generally safer to replace it rather than attempting ad‑hoc fixes.

Create a new unprivileged LXC with appropriate user ID (UID/GID) mappings, then migrate application data, permissions, and configuration files to the new container. During this process, review file ownership and access control to ensure the new mappings are correct.

Consider this part of limiting potential impact (blast radius). Where feasible, run separate services in their own unprivileged LXCs or virtual machines, and perform periodic audits of container privileges especially after troubleshooting steps or changes that might've altered container settings.

Ongoing Security Habits for Self-Hosted Teams

Ongoing security requires consistent, repeatable practices rather than one-time hardening efforts. Make version pinning a standard: specify exact Docker image tags in docker-compose instead of relying on latest, so a brief malicious or faulty release isn't deployed automatically.

Treat updates as a core security control by patching on a defined schedule, testing changes in a controlled environment, and maintaining a documented rollback plan.

Audit Proxmox LXCs regularly. Use unprivileged containers by default, record any cases where privileged containers are required, and review that list after infrastructure or configuration changes.

After each security-relevant change, confirm that logs are being collected as expected and that runtime behavior matches your intended configuration.

Harden access around your reverse proxy. Enforce HTTPS with modern TLS settings, ensure correct handling of WebSockets, and limit exposed DNS records to only what's necessary.

Where appropriate, use a service such as Cloudflare to front origins and reduce direct exposure of your server’s IP address.

Conclusion

When you treat your self‑hosted stack like production from day one, you avoid painful surprises later. Pin versions, test updates in staging, and always know how you’ll roll back. Keep services isolated, avoid unnecessary privileges, and harden access to everything. Add monitoring and regular reviews so security becomes routine, not reactive. If you build these habits early, you’ll ship faster, sleep better, and keep your users’ data safer as you grow.