A lightweight, containerized reverse proxy service built with Caddy that allows you to access multiple remote services through localhost on different ports.
Goal: Set up Caddy in Docker as a lightweight reverse proxy to access multiple remote services through localhost.
Use Case: You have several services running on different IPs/domains (e.g., 192.168.1.100:8000, https://httpbin.org) and want to access them all through your local machine on different ports (e.g., localhost:8000, localhost:8001).
Why Caddy: Simpler configuration than nginx with beginner-friendly syntax, making it perfect for quick proxy setups.
This project provides a clean, easy-to-maintain proxy configuration where you can add/remove services by simply editing the Caddyfile and restarting the container.
- Simple Configuration: Beginner-friendly Caddyfile syntax (much simpler than nginx)
- Localhost Access: Access multiple remote services through localhost on different ports
- Containerized: Runs in Docker for easy deployment and management
- Host Network Mode: Uses host networking for direct localhost access
- Smart Header Handling: Automatically adds Host headers only when needed for external HTTPS domains
- Easy Maintenance: Add/remove services by simply editing the Caddyfile and restarting
- Persistent Storage: Volumes for Caddy data and configuration persistence
- Auto-restart: Container automatically restarts unless manually stopped
┌─────────────────┐ ┌──────────────┐ ┌─────────────────────┐
│ localhost:8000 │───▶│ Caddy │───▶│ https://httpbin.org │
├─────────────────┤ │ (Docker) │ ├─────────────────────┤
│ localhost:8001 │───▶│ │───▶│ 192.168.1.101:3000 │
├─────────────────┤ │ │ ├─────────────────────┤
│ localhost:8002 │───▶│ │───▶│ some.domain.com:9000│
└─────────────────┘ └──────────────┘ └─────────────────────┘
Result: Clean, easy-to-maintain proxy configuration accessible through your local machine.
ProxyService/
├── Caddyfile # Caddy server configuration
├── docker-compose.yml # Docker Compose service definition
├── caddy_data/ # Caddy persistent data (ignored by git)
├── caddy_config/ # Caddy configuration cache (ignored by git)
├── .gitignore # Git ignore rules
└── README.md # This documentation
The service allows you to access remote services through localhost:
| Local Access | Remote Service | Description |
|---|---|---|
localhost:8000 |
https://httpbin.org |
External HTTPS service (Host header added automatically) |
localhost:8001 |
192.168.1.101:3000 |
Internal service by IP address |
localhost:8002 |
some.other.domain.com:9000 |
External domain service (Host header added automatically) |
Key Rule: Add header_up Host {upstream_hostport} only when proxying to external HTTPS domains.
# Global options
{
auto_https off # Disable automatic HTTPS
admin off # Disable admin API
}
# External HTTPS service - needs Host header
:8000 {
reverse_proxy https://httpbin.org {
header_up Host {upstream_hostport}
}
}
# Internal service by IP - no Host header needed
:8001 {
reverse_proxy 192.168.1.101:3000
}
# External domain with HTTPS - needs Host header
:8002 {
reverse_proxy some.other.domain.com:9000 {
header_up Host {upstream_hostport}
}
}git clone <repository-url>
cd ProxyServiceEdit the Caddyfile to configure your specific backend services:
# Add your own proxy configurations
:PORT {
reverse_proxy YOUR_BACKEND_SERVICE {
# Add Host header for external services
header_up Host {upstream_hostport}
}
}docker-compose up -dNow you can access all your remote services through localhost:
# Access external HTTPS service
curl http://localhost:8000/get
# Access internal service (if available)
curl http://localhost:8001
# Access external domain service (if available)
curl http://localhost:8002That's it! All your remote services are now accessible through your local machine on different ports.
docker-compose down# View all logs
docker-compose logs
# Follow logs in real-time
docker-compose logs -f
# View logs for specific timeframe
docker-compose logs --since 30mdocker-compose restart- Edit the
Caddyfile - Restart the service:
docker-compose restart
Remove all containers, networks, and volumes:
docker-compose down -vThe beauty of this setup is its simplicity. To add a new remote service, just add a new server block to the Caddyfile:
# Add your new service
:NEW_PORT {
reverse_proxy YOUR_REMOTE_SERVICE {
# Only add this line for external HTTPS domains
header_up Host {upstream_hostport}
}
}Examples:
# Access a remote API through localhost:8003
:8003 {
reverse_proxy https://api.example.com {
header_up Host {upstream_hostport}
}
}
# Access an internal server through localhost:8004
:8004 {
reverse_proxy 10.0.0.50:5000
}
# Access a remote web app through localhost:8005
:8005 {
reverse_proxy https://myapp.herokuapp.com {
header_up Host {upstream_hostport}
}
}Then simply restart the container:
docker-compose restartUnderstanding when to add the header_up Host {upstream_hostport} directive:
- ✅ ADD for external HTTPS domains:
https://api.example.com,https://httpbin.org - ❌ DON'T ADD for IP addresses:
192.168.1.100:8000,10.0.0.5:3000 - ❌ DON'T ADD for internal services:
internal-server:9000(unless specifically required)
Why? External HTTPS services often use virtual hosting and need the correct Host header to route requests properly.
-
Port already in use
# Check what's using the port netstat -ano | findstr :8000 # Change the port in Caddyfile if needed
-
Backend service unreachable
# Test backend connectivity curl -I http://BACKEND_ADDRESS # Check Docker logs docker-compose logs caddy
-
Container won't start
# Check container status docker-compose ps # View detailed logs docker-compose logs caddy
To enable verbose logging, modify the Caddyfile:
{
log {
level DEBUG
}
}- The service runs with
network_mode: host, which provides full network access - Consider using specific port bindings instead of host mode for production
- Implement proper authentication/authorization for backend services
- Monitor logs for suspicious activity
- Keep Caddy image updated for security patches
Add custom headers to requests:
:8000 {
reverse_proxy https://httpbin.org {
header_up Host {upstream_hostport}
header_up X-Custom-Header "custom-value"
header_up Authorization "Bearer {env.API_TOKEN}"
}
}Configure multiple backend servers:
:8000 {
reverse_proxy {
to backend1.example.com:8080
to backend2.example.com:8080
lb_policy round_robin
health_uri /health
}
}Enable HTTPS with automatic certificates:
{
auto_https on
}
yourdomain.com {
reverse_proxy localhost:8080
}- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
This project is provided as-is for educational and development purposes.
For issues and questions:
- Check the Caddy documentation
- Review Docker Compose logs
- Open an issue in this repository
Note: Remember to update the backend service addresses in the Caddyfile to match your actual services before deployment.