Technology Stack
| Layer | Technology | Version/Details |
|---|---|---|
| Reverse Proxy | Traefik | v3.x (latest) |
| Container Runtime | Docker Engine | v29.2.1 |
| Orchestration | Docker Compose | v2.x |
| SSL/TLS | Let's Encrypt | HTTP-01 Challenge |
| DNS Provider | Cloudflare | Full/Strict mode |
| Operating System | Linux VPS | Ubuntu/Debian |
| Applications | Ghost, WordPress, Nginx | latest tags |
Purpose and Philosophy
The Server Manager project is a comprehensive infrastructure toolkit designed to simplify the deployment and management of containerized applications on a production server. The core philosophy centers on making server management boring to maintain and exciting to extend by eliminating manual certificate management, port configuration, and repetitive deployment tasks.
At its heart, this project embraces the infrastructure-as-code approach where all server configurations are version-controlled, documented, and reproducible. The system leverages Traefik v3 as an intelligent reverse proxy that automatically discovers Docker containers and configures routing based on container labels, eliminating the need for manual nginx configuration or complex load balancer setups.
Core Design Principles
The project follows several fundamental principles that ensure reliability, security, and maintainability:
- Zero-Touch SSL: All applications automatically receive SSL certificates through Let's Encrypt's HTTP-01 challenge without manual intervention. When a new container starts with proper Traefik labels, the proxy automatically requests and provisions certificates.
- Configuration-Driven Deployments: The project uses a template-based approach where deploying a new application requires only editing a
.envfile. Thedocker-compose.ymlfiles remain generic and reusable across different applications, reducing configuration drift and human error.
- Network Isolation: Applications run on isolated Docker networks. The
proxynetwork connects containers to Traefik for external access, while internal networks (likeinternalfor databases) ensure sensitive services remain inaccessible from the outside world.
- Secret Management: The project implements a two-branch Git strategy separating public code from secrets. The
mainbranch contains only configuration templates and application code, while theprivatebranch tracks actual environment variables and credentials. A pre-push hook prevents accidental secret leaks.
- Documentation-First: Every component, from the Traefik setup to individual application templates, includes comprehensive documentation explaining the what, why, and how. The documentation serves as both a user guide and a reference for future maintenance.
Architecture Deep Dive
The Traefik Foundation
Traefik serves as the centerpiece of the infrastructure, functioning as both a reverse proxy and a dynamic service discovery mechanism. Unlike traditional nginx configurations that require manual editing and service restarts, Traefik watches the Docker daemon for new containers and automatically configures routes based on labels.
# traefik-setup/traefik.yml - Core configuration
api:
dashboard: true
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
certificatesResolvers:
myresolver:
acme:
email: [email protected]
storage: acme.json
httpChallenge:
entryPoint: web
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: falseThe configuration defines two entry points: web for HTTP (which automatically redirects to HTTPS) and websecure for HTTPS. The exposedByDefault: false setting is a critical security feature that prevents containers from being accidentally exposed to the internet unless explicitly configured with traefik.enable=true.
Traffic Flow Architecture
The complete request flow demonstrates how requests traverse from end users to containerized applications:
User's Browser
│
▼
Cloudflare (DNS Resolution + SSL Termination)
│
▼
Server IP: 203.0.113.30
│
▼
Port 80 (HTTP) → Traefik → Auto-redirect to HTTPS
Port 443 (HTTPS) → Traefik → SSL Termination
│
▼
Traefik inspects Host header
│
├── tf.namani.in → Dashboard (api@internal)
├── blog.namani.in → Ghost Container (:2368)
├── c.aatmanova.in → WordPress Container (:80)
└── [any].namani.in → Respective ContainerThis architecture enables hosting multiple applications on a single server with different domains, each receiving automatic SSL without additional configuration. Cloudflare provides an additional layer of DDoS protection and CDN caching for static content.
Application Templates
The project provides reusable templates for common application types:
#### Single-Container Template (blog-example)
This template works with any single-container Docker application:
# applications/blog-example/docker-compose.yml
services:
app:
image: ${APP_IMAGE}
container_name: ${CONTAINER_NAME}
restart: always
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.http.routers.${ROUTER_NAME}.rule=Host(`${APP_DOMAIN}`)"
- "traefik.http.routers.${ROUTER_NAME}.entrypoints=websecure"
- "traefik.http.routers.${ROUTER_NAME}.tls.certresolver=myresolver"
- "traefik.http.services.${ROUTER_NAME}.loadbalancer.server.port=${APP_PORT}"
networks:
proxy:
external: trueUsers only edit the .env file to configure:
APP_DOMAIN: The domain for the applicationROUTER_NAME: Unique identifier for Traefik routingAPP_IMAGE: Docker image to runAPP_PORT: Internal container portCONTAINER_NAME: Friendly name for docker ps
#### Multi-Container Template (WordPress)
The WordPress template demonstrates handling database-backed applications:
# applications/wordpress/docker-compose.yml
services:
app:
image: ${WP_IMAGE}
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: ${DB_USER}
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
networks:
- proxy
- internal
labels:
- "traefik.enable=true"
# ... Traefik labels
db:
image: ${DB_IMAGE}
environment:
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
MYSQL_DATABASE: ${DB_NAME}
networks:
- internal # Only accessible internally
networks:
proxy:
external: true
internal:
name: ${INTERNAL_NETWORK_NAME}This architecture ensures the database container is completely isolated from external access while WordPress connects to both networks to serve traffic and communicate with the database.
Key Features and Functionality
1. Automatic SSL Certificate Management
The system uses Let's Encrypt's automated certificate authority to provision free SSL certificates:
- Container starts with
tls.certresolver=myresolverlabel - Traefik detects the new domain from
Host()rule - Let's Encrypt validates domain ownership via HTTP-01 challenge on port 80
- Certificate is issued and stored in
acme.json - HTTPS becomes available automatically
This happens entirely automatically with no manual intervention. Certificates are automatically renewed before expiration, and the system gracefully handles multiple domains.
2. Traefik Dashboard with Basic Auth
The Traefik dashboard provides real-time insights into routing, services, and middleware:
# Dashboard routing with Basic Auth
labels:
- "traefik.http.routers.dashboard.rule=Host(`tf.namani.in`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.routers.dashboard.tls.certresolver=myresolver"
- "traefik.http.middlewares.auth.basicauth.users=${DASHBOARD_AUTH}"The dashboard is protected by HTTP Basic Authentication using htpasswd-formatted credentials. The password hash is stored in .env with doubled dollar signs ($$) to escape Docker Compose's variable interpolation.
3. Network Architecture
The shared proxy network enables Traefik to communicate with all containers:
# Create the network once
docker network create proxyAll applications connect to this external network, allowing Traefik to discover and route to them. Internal networks like internal provide additional isolation for databases and backend services.
4. Environment-Driven Configuration
The entire setup is driven by environment variables:
# traefik-setup/.env
TRAEFIK_DOMAIN=tf.namani.in
[email protected]
DASHBOARD_AUTH=admin:$$apr1$$VDlqiA.Q$$HZsnUXm2oIU1ZXZQ8enzb0
DOCKER_API_VERSION=1.44This approach allows the same docker-compose.yml to be reused across different environments by simply changing the .env file.
5. Production Server Information
The project manages a live production server:
| Property | Value |
|---|---|
| Server IP | 203.0.113.30 |
| SSH Key | .ssh/aatmanova2 |
| Traefik Dashboard | https://tf.namani.in/dashboard/ |
| Docker API | v29.2.1 (requires API v1.44) |
| Traefik Version | v3.x (latest) |
| Config Location | /root/traefik/ on server |
6. Git-Based Secret Management
The project implements a sophisticated branching strategy for security:
- `main` branch (public): Contains only non-sensitive configuration templates and application code. Safe to push to GitHub.
- `private` branch (local): Tracks actual
.envfiles with real credentials. Never pushed to remote.
A pre-push Git hook provides automated protection:
- Blocks attempts to push the
privatebranch - Scans commits for forbidden file patterns (
.env,.key,.pem,id_rsa) - Provides manual verification step before any push
7. Troubleshooting Infrastructure
The documentation includes a comprehensive troubleshooting reference:
| Problem | Cause | Solution |
|---|---|---|
| Docker API version mismatch | Docker Engine v29+ requires explicit API version | Set DOCKER_API_VERSION=1.44 in .env |
| SSL not generating | DNS not pointing to server | Verify A record points to 203.0.113.30 |
| acme.json permission error | File too open | Run chmod 600 acme.json |
| $$ becoming garbage | Shell expanding $ during file creation | Use SCP or quoted heredoc |
| Container not discovered | Missing network or label | Ensure traefik.enable=true and proxy network |
| Dashboard 401 Unauthorized | Wrong password hash format | Regenerate with htpasswd -nb user pass, double $ to $$ |
8. Homelab Compatibility
The documentation thoroughly covers homelab scenarios:
VPS with Public IP: Works exactly as configured. Direct access to ports 80/443 enables Let's Encrypt HTTP-01 challenge.
Homelab with Port Forwarding: Works identically to VPS. Forward ports 80/443 from router to the server.
Homelab behind CGNAT: Does NOT work with standard setup. Let's Encrypt cannot reach the HTTP challenge endpoint.
Homelab with Cloudflare Tunnel: Works as an alternative. The tunnel creates an outbound connection to Cloudflare, bypassing the need for incoming port access.
The documentation provides a detailed comparison between Cloudflare Tunnel and Tailscale for homelab scenarios, concluding that both can run simultaneously with zero interference.
Security Implementation
Network Isolation
Applications follow the principle of least privilege:
- Web-facing containers connect to
proxynetwork - Databases connect only to isolated
internalnetworks - Traefik has read-only access to Docker socket (
/var/run/docker.sock:ro)
SSL/TLS Security
- All traffic automatically upgrades from HTTP to HTTPS
- Let's Encrypt certificates provide industry-standard encryption
- Cloudflare SSL mode set to "Full" or "Full (Strict)"
- Certificate storage file (
acme.json) has restrictive permissions (600)
Dashboard Protection
- Traefik dashboard hidden behind Basic Auth
- Credentials stored as htpasswd hash, not plaintext
- Separate user from application users
- Access limited to specific domain
Secret Handling
- No secrets in version control
- Environment-specific
.envfiles - Branch-based secret isolation
- Automated pre-push validation
Deployment and Operations
Quick Start Process
Deploying a new application follows a simple workflow:
# 1. Copy the template
cp -r applications/blog-example /opt/my-blog
# 2. Edit ONLY the .env file
nano /opt/my-blog/.env
# 3. Upload to server and start
scp -r /opt/my-blog [email protected]:/opt/
ssh [email protected] "cd /opt/my-blog && docker compose up -d"Traefik automatically discovers the new container within seconds and begins routing traffic.
Common Deployment Targets
The template supports numerous applications:
| Application | Image | Internal Port |
|---|---|---|
| Nginx | nginx:latest | 80 |
| Ghost Blog | ghost:latest | 2368 |
| WordPress | wordpress:latest | 80 |
| Node.js | node:latest | 3000 |
| Grafana | grafana/grafana | 3000 |
| Portainer | portainer/portainer-ce | 9000 |
| Uptime Kuma | louislam/uptime-kuma | 3001 |
| Jellyfin | jellyfin/jellyfin | 8096 |
| Gitea | gitea/gitea | 3000 |
| MinIO | minio/minio | 9001 |
Maintenance Operations
Regular server maintenance includes:
# View Traefik logs
docker logs -f traefik
# Restart after config changes
cd /opt/traefik
docker compose up -d --force-recreate
# Check container status
docker ps
# Inspect network
docker network inspect proxy
# View certificates
cat acme.json | python3 -m json.toolDocumentation Strategy
The project maintains comprehensive documentation across multiple files:
- `README.md`: Project overview, quick start guide, structure explanation
- `traefik-setup/Documentation.md`: Complete Traefik technical reference with 850+ lines
- `traefik-setup/info.md`: Server credentials and connection details
- `applications/*/README.md`: Per-application deployment instructions
- `ai-rules.md`: Guidelines for AI agents working on the repository
This documentation-first approach ensures the infrastructure remains maintainable over time, even as the original author returns after extended periods.
Lessons Learned and Best Practices
What Works Well
- Template-Driven Deployments: Editing only
.envfiles dramatically reduces configuration errors and deployment time.
- Comprehensive Documentation: The 850+ line Traefik documentation proves invaluable for troubleshooting and onboarding.
- Secret Branching Strategy: The two-branch approach provides strong protection against accidental secret exposure while maintaining version control benefits.
- Network Isolation: Separate
proxyandinternalnetworks provide defense-in-depth for database containers.
- Auto-Discovery: Traefik's container label-based discovery eliminates the need for manual routing configuration.
Areas for Enhancement
- Monitoring Integration: Could benefit from centralized logging (Loki/Graylog) and metrics (Prometheus/Grafana).
- Backup Automation: Database backups could be automated with scheduled jobs rather than manual intervention.
- Container Updates: No automated update mechanism for base images. Currently requires manual
docker compose pull.
- Multiple Environments: The system manages production directly. Development/staging environments would improve reliability.
- Load Balancing: Currently single-server. Could scale horizontally with Docker Swarm or Kubernetes.
Future Expansion
The infrastructure is designed to support growth in several directions:
- Orchestration: Could migrate to Docker Swarm or Kubernetes for multi-node clustering
- Service Mesh: Could add Istio or Linkerd for advanced traffic management
- GitOps: Could implement ArgoCD or Flux for declarative infrastructure
- Monitoring: Could deploy Prometheus stack for comprehensive observability
- Container Registry: Could set up private registry for custom images
Conclusion
The Server Manager project represents a mature, production-ready infrastructure approach that balances automation with control. By leveraging Traefik's dynamic configuration and Docker's containerization, it achieves the goal of making infrastructure boring to maintain and exciting to extend.
The comprehensive documentation, security-conscious branching strategy, and template-driven deployment model make this a robust foundation for any self-hosted application portfolio. Whether running a simple blog or complex multi-service architecture, this infrastructure toolkit provides the reliability and flexibility needed for modern production workloads.
The project demonstrates that effective server management doesn't require complex tooling—it requires thoughtful design, clear documentation, and consistent patterns that can be understood and maintained over time.
Operational Procedures and Best Practices
Adding New Applications to the Infrastructure
When deploying a new application to the server, follow this systematic approach to ensure consistency and maintainability:
- Select the appropriate template based on the application architecture. Use the single-container template for stateless applications like Nginx, Ghost, or Grafana. Use the multi-container template for applications requiring databases like WordPress or custom backends.
- Configure the environment file with all required variables including the domain name, router identifier, container name, image reference, and internal port. Ensure the router name is unique across all deployed applications to prevent routing conflicts.
- Verify network configuration by ensuring the application connects to the
proxynetwork for external access and any additional internal networks for service-to-service communication.
- Test locally if possible before deploying to production. Use
docker compose up -din development mode with verbose logging to verify the configuration.
- Deploy to production using SCP to transfer files to the server, then execute the container start command. Monitor Traefik logs to confirm successful discovery and routing configuration.
- Verify SSL certificate issuance by checking the acme.json file or observing the Traefik dashboard. SSL should provision automatically within seconds of container startup.
Monitoring and Alerting
The infrastructure provides several monitoring capabilities through the Traefik dashboard:
- Router Status: View all active routes and their health
- Service Metrics: Check load balancer distribution and response times
- Middleware Performance: Analyze rate limiting and authentication overhead
- Certificate Expiration: Monitor SSL certificate renewal status
For production deployments, consider integrating external monitoring solutions like Uptime Kuma (deployed via this very infrastructure) to provide external availability checks and notification mechanisms beyond the internal Traefik metrics.
Backup and Recovery
Database containers in this infrastructure use named Docker volumes:
volumes:
- db_data:/var/lib/mysqlTo back up database data, use Docker volume backup procedures:
# Create a backup container
docker run --rm -v mydb_data:/data -v $(pwd):/backup alpine tar czf /backup/backup.tar.gz -C /data .For the configuration itself, maintain regular Git commits with clear commit messages describing infrastructure changes. The branching strategy ensures production configurations are preserved in the private branch while development iterations remain in the main branch.
Performance Optimization
Several configuration options can improve application performance:
- Cloudflare Caching: Enable Cloudflare's CDN for static content by setting appropriate Page Rules
- Container Resource Limits: Add resource constraints to prevent any single container from consuming excessive CPU or memory
- Connection Pooling: For database-backed applications, configure appropriate connection pool sizes
- Static Asset Handling: Consider deploying dedicated static file servers or CDNs for high-traffic assets
Security Hardening Recommendations
While the current setup provides a solid security foundation, consider these enhancements for production environments:
- Rate Limiting: Implement Traefik middleware for rate limiting to prevent abuse
- IP Whitelisting: Add IP-based access control for administrative interfaces
- WAF Integration: Leverage Cloudflare's Web Application Firewall for additional protection
- Container Scanning: Implement regular security scanning for base images
- Intrusion Detection: Consider deploying container-level intrusion detection systems
The Server Manager infrastructure provides the flexibility to implement any of these enhancements while maintaining the simple, template-driven deployment model that makes this system approachable and maintainable.
Architecture Feedback
Spotted a potential optimization or antipattern? Let me know.