Practical Guide to Self-Hosted Security Architecture with Tailscale + Caddy + Authelia

Analyzing a Tailscale + Caddy + Authelia self-hosted architecture for security and best practices.
This article dissects a real-world self-hosted security architecture combining Tailscale for encrypted mesh networking, Caddy for reverse proxy with automatic HTTPS, and Authelia for centralized authentication. It examines the traffic flow, highlights the bastion host design pattern that minimizes attack surface, and identifies common pitfalls including inconsistent auth coverage, VPS hardening gaps, and secret management risks.
A Typical Self-Hosting Architecture Question
In the self-hosting community, more and more developers and enthusiasts are building their own service clusters — Gitea code repositories, Immich photo management, and various containerized applications. Self-hosting refers to individuals or organizations choosing to run software services on hardware they control or rented servers, rather than relying on third-party SaaS platforms. This movement has grown out of concerns about data privacy, resistance to vendor lock-in, and the maturity of the open-source software ecosystem. With the proliferation of Docker containerization technology, the barrier to deploying a complete service stack has dropped significantly, but operational challenges like network security, backup strategies, and high availability remain — work traditionally handled by professional operations teams now falls on individual enthusiasts.
However, as the number of services grows, so does the complexity of network security architecture. A Reddit user recently posted their multi-server architecture, candidly admitting: "I have several servers, but I'm not a network or security engineer, and I want to make sure I haven't left any security gaps."
This question is highly representative. It touches on the most popular technology combination in the self-hosting space today: Tailscale (mesh networking/tunnel) + Caddy (reverse proxy) + Authelia (identity authentication). This article will dissect the architectural design's strengths and potential risks based on this real-world case.

Architecture Breakdown: How Traffic Flows
The user's architecture consists of three machines with clearly defined roles:
Public VPS (Entry Layer)
- Tailscale: Forms an encrypted virtual LAN with private servers
- Caddy: Acts as the public-facing reverse proxy, handling HTTPS termination
- Authelia: Unified identity authentication gateway
About Tailscale: Tailscale is a zero-configuration VPN solution built on the WireGuard protocol. WireGuard itself is a modern kernel-level VPN protocol known for its minimal codebase (approximately 4,000 lines, compared to OpenVPN's hundreds of thousands) and high performance, using Curve25519 key exchange, ChaCha20 encryption, and Poly1305 message authentication. Tailscale adds identity management, NAT traversal (via DERP relay servers), automatic key rotation, and ACL access control on top of WireGuard, enabling devices across different network environments to communicate as if they were on the same LAN — without manual firewall rules or port forwarding.
About Caddy: Caddy is a modern web server written in Go, with its standout feature being automatic HTTPS — it can automatically request and renew TLS certificates from Let's Encrypt or ZeroSSL without any manual configuration. Compared to Nginx which requires tools like Certbot, Caddy has certificate management built in as a core feature. When used as a reverse proxy, Caddy receives external HTTPS requests, terminates TLS encryption, then forwards plaintext HTTP requests to backend services. Its configuration syntax (Caddyfile) is more concise and intuitive than Nginx's configuration files, reducing the likelihood of configuration errors.
About Authelia: Authelia is an open-source authentication and authorization server, typically deployed as authentication middleware for reverse proxies. It works as follows: when a user request reaches the reverse proxy, the proxy first sends a subrequest to Authelia to verify the user's identity; if the user is not authenticated, they're redirected to Authelia's login page. After successful authentication, Authelia records the state via a session cookie, and subsequent requests don't require repeated logins. It supports multi-factor authentication (TOTP, WebAuthn/FIDO2), single sign-on (SSO), and fine-grained access control policies based on domain names and paths — making it a popular choice for replacing enterprise IAM solutions in self-hosting scenarios.
Private Servers 1 and 2 (Application Layer)
- Server 1: Tailscale + Caddy + Gitea
- Server 2: Tailscale + Caddy + Immich
The complete request flow is as follows:
User requests https://foo.bar.com
→ DNS resolves to VPS public IP
→ VPS Caddy terminates HTTPS, authenticates via Authelia
→ Forwards through Tailscale to server1:80 (HTTP)
→ server1's local Caddy forwards to container foo:1234
The core design philosophy here is: only the public VPS is exposed to the internet, while the private servers running sensitive services are completely hidden behind the Tailscale network, with no public ports open. This is a robust "Bastion Host" pattern.
The bastion host is a classic concept in network security architecture, originating from DMZ (demilitarized zone) designs in enterprise data centers. The core idea is: concentrate the sole public access point on a specially hardened server, requiring all access to the internal network to pass through this machine for relay and auditing. Attackers can only see and attack this one machine, while internal servers are completely invisible to the internet. In traditional enterprise environments, bastion hosts typically run jump server functionality; in the self-hosting scenario discussed here, the VPS serves as the bastion host, connecting to backends via Tailscale tunnels, achieving similar security isolation.
Commendable Design Highlights
Zero Public Exposure for Private Servers
This is the architecture's greatest strength. Private servers communicate only through Tailscale's mesh network — even if an attacker scans the VPS, they cannot directly reach the machines running Gitea or Immich. The attack surface is dramatically narrowed to a single VPS.
Transport Encryption via Tailscale
Although the traffic between the VPS and private servers uses "internal HTTP" — seemingly plaintext — since the traffic is actually encapsulated within Tailscale's (WireGuard-based) encrypted tunnel, the physical link remains encrypted. WireGuard's ChaCha20-Poly1305 cipher suite provides security equivalent to AES-256-GCM, with better performance on devices lacking hardware acceleration. This addresses the common concern about "internal plaintext" — as long as you confirm traffic actually traverses the Tailscale interface (typically the tailscale0 or ts0 network interface), rather than a direct public connection.
Centralized Authentication Gateway
Placing Authelia at the VPS entry point enables single sign-on (SSO) and unified multi-factor authentication (MFA) capabilities. For services that lack their own authentication mechanisms (such as certain admin panels), this is an excellent supplement. This architectural pattern is a simplified version of what's called "Zero Trust Network Access" (ZTNA) in enterprise environments — every access requires identity verification, rather than relying solely on network perimeter isolation.
Common Pitfalls to Watch Out For
Inconsistent Authentication Coverage
The poster themselves mentioned a gray area: "VPS Caddy usually requires Authelia authentication (but I'm not sure about services with built-in auth)." This is precisely where problems most easily arise.
Recommendation — define clear policies: For services like Gitea that have their own robust authentication systems (supporting OAuth2, LDAP, 2FA, etc.), you might consider bypassing Authelia (to avoid the poor UX of double login), but you must ensure their internal authentication is sufficiently strong. For Immich or any admin interfaces, Authelia should be enforced by default. Never allow configuration blind spots where you "assume there's authentication but it's actually exposed." In Authelia's configuration, use policy: bypass, policy: one_factor, and policy: two_factor to explicitly label the protection level for each domain or path, avoiding ambiguous default policies.
The Necessity of Caddy on Private Servers
The architecture runs a Caddy instance on each private server to forward to Docker containers. This works functionally but increases maintenance costs. If private servers run few services, consider having the VPS Caddy point directly to container ports (via Tailscale), eliminating one proxy layer and reducing configuration complexity and error probability. However, legitimate scenarios for keeping a local Caddy include: needing local request rewriting, adding extra security headers, or still needing direct service access via Tailscale when the VPS is unavailable.
Security Hardening of the VPS Itself
Since the VPS is the sole public entry point, its security represents the ceiling for the entire system:
- Close all unnecessary ports, keeping only 443 (and SSH, which ideally should also be restricted to Tailscale access)
- Use SSH key authentication (Ed25519 algorithm preferred), disable password authentication, consider changing the default port
- Enable fail2ban or Caddy's rate-limiting plugin to prevent brute-force attacks
- Fine-tune Tailscale ACL configuration, restricting the VPS to only access necessary service ports, following the principle of least privilege
- Regularly update the system and packages, enable unattended security updates (unattended-upgrades)
About Tailscale ACL: Tailscale ACLs are JSON-format policy files defined in the Tailscale admin console, used for fine-grained control over which devices can access which ports in the network. By default, all devices in a Tailscale network can communicate with each other, which isn't optimal for security. ACLs enable the principle of least privilege: for example, restricting the VPS node to only access port 80 on server1 and port 80 on server2, without being able to SSH into those machines; or allowing an admin's laptop to SSH into all devices while preventing the VPS from initiating connections to admin devices. This policy ensures that even if the VPS is compromised, the scope an attacker can reach through the Tailscale network is strictly limited.
Certificate and Key Management
Caddy's automatic Let's Encrypt certificate provisioning is very convenient. Let's Encrypt is a free certificate authority operated by the Internet Security Research Group (ISRG), implementing automatic certificate application, validation, and renewal through the ACME protocol. Domain ownership verification methods include HTTP-01 challenge (placing a specific file on port 80), DNS-01 challenge (adding a specific DNS TXT record), and TLS-ALPN-01 challenge. Caddy has a built-in ACME client that automatically handles the entire process, with certificates valid for 90 days and auto-renewed.
Beyond certificates themselves, you must also ensure that Authelia's session secret, JWT signing key, and Tailscale's auth key are properly secured — never written in plaintext to public configuration repositories. Especially when Gitea is running on your own server, never commit configurations containing secrets to it. Use Docker Secrets, environment variable files (.env, added to .gitignore), or dedicated secret management tools like SOPS or age encryption for handling sensitive configurations.
Summary: An 8-out-of-10 Self-Hosted Security Architecture
Overall, this user's architecture has a clear design philosophy, correct direction, and qualifies as an "honor student" solution in the self-hosting space. It uses Tailscale to hide the backend, a single VPS to narrow the attack surface, and Authelia to provide unified authentication.
What truly needs polishing isn't the architecture itself, but consistency in configuration details: whether authentication policies leave no gaps, whether the VPS is sufficiently hardened, and whether secrets are securely stored. Security is never achieved by stacking tools — it comes from rigor at every configuration layer. For self-hosting enthusiasts who "aren't network security engineers," this combination is already a remarkably solid starting point.
Further improvement directions include: introducing intrusion detection systems (such as CrowdSec, a community-collaborative behavior analysis engine), setting up centralized log collection and alerting (such as Loki + Grafana), and conducting regular configuration audits. Security is a continuously evolving process, not a one-time deployment task.
Key Takeaways
Related articles

RunTrace: A Local-First CLI Tool for ML Experiment Reproducibility
RunTrace is a lightweight open-source CLI tool that saves reproducibility context for ML experiments by recording Git status, Python environment, GPU info, and config files. Local-first with zero server dependencies.

The AI Hallucination Problem: The Absurd Case of Escape Velocity Being Forcibly Linked to Autism
A Reddit post exposes AI absurdly linking escape velocity to autism. Explore the causes of AI hallucination, its technical roots, and strategies to combat it.

OpenAI Employee Reveals ChatGPT Speed Optimization Roadmap
OpenAI employee shares ChatGPT speed improvement roadmap on Reddit, covering inference optimization, model distillation, and infrastructure scaling to reduce response latency.