← back
About this server
What this is
A self-hosted home server running my personal projects. Reachable at christiaanhub.com over HTTPS, with no router ports forwarded and my home IP address hidden from the public internet.
Hardware
- Machine: Dell Inc. PowerEdge R220 with Intel Xeon E3-1220 v3 x4
- OS: Ubuntu 26.04 LTS (Resolute Raccoon)
- Network interface: eno1, gigabit ethernet
- Connection: home internet via consumer ISP
Network architecture
Visitor's browser
|
| HTTPS (port 443)
v
Cloudflare edge network
|
| Cloudflare Tunnel (outbound from server)
v
cloudflared (Docker container)
|
| HTTP, internal Docker network
v
Caddy reverse proxy (Docker container)
|
| HTTP, internal Docker network
v
+-------------------+ +-------------------+
| nginx | | c2c marketpalce |
| static site | | coming soon |
+-------------------+ +-------------------+
Software stack
- Docker Engine + Docker Compose
- Caddy as reverse proxy, routes hostnames to containers
- nginx serving static HTML for the landing page
- Cloudflare Tunnel (cloudflared) for public exposure without port forwarding
- Tailscale for private SSH access from anywhere
How a request flows
- Browser resolves christiaanhub.com to a Cloudflare IP via DNS.
- Browser opens HTTPS connection to Cloudflare's nearest data centre.
- Cloudflare looks up the hostname, finds it routed to my tunnel.
- The cloudflared container in my home, which holds an outbound connection to Cloudflare, receives the request through that tunnel.
- cloudflared forwards the request to Caddy on the internal Docker network.
- Caddy reads the Host header, decides which container should handle it (nginx for the main site, project1-app for the subdomain), and proxies the request.
- The response flows back the same way.
Security choices
- No router ports are forwarded. The server is not publicly reachable on its own IP.
- The home IP is never exposed to visitors. They only see Cloudflare's IPs.
- Cloudflare provides DDoS protection and a WAF on the free tier.
- SSH is reachable through Tailscale's private network, not the public internet.
- Each project's database lives on a private Docker network, isolated from other services.
- Database credentials are loaded from .env files outside source control.
What's running
- caddy — reverse proxy, listens on the tunnel
- cloudflared — outbound tunnel to Cloudflare
- webserver — nginx, serves this static site
- PHP application and MySQL server soon
Domain
- christiaanhub.com — registered through Cloudflare
- DNS managed by Cloudflare, records auto-created by the tunnel
- HTTPS certificates issued and renewed by Cloudflare automatically