14 KiB
Generic Reverse Proxy Architecture
Overview
This document describes a generic reverse proxy architecture that enables internal services to be accessible via public domains. The architecture uses FRP (Fast Reverse Proxy) for tunneling and Traefik for HTTP/HTTPS routing with automatic certificate management.
Architecture Block Diagram
+-------------------+ SSH Commands +-------------------+
| Local Host | ------------------> | Proxy Server |
| | | |
| +-------------+ | FRP Tunnel | +-------------+ |
| | Application | | ------------------> | | FRPS | |
| | Service | | | | (Server) | |<--- Public IPs
| | | | | | | | Port: 16999
| +-------------+ | | +-------------+ |
| | | |
| +-------------+ | FRP Client | +-------------+ |
| | FRPC | | ------------------> | | Traefik | |<--- Domains
| | (Client) | | | | (Router) | | HTTPS/TLS
| | | | | | | |
| +-------------+ | | +-------------+ |
| | | |
| +-------------+ | | +-------------+ |
| | Docker | | | | Docker | |
| | Container | | | | Container | |
| +-------------+ | | +-------------+ |
+-------------------+ +-------------------+
| |
| |
+------------------ Volumes ------------------+
| rad-git-sshd-itl-frpc-<instance> |
+-------------------------------------------+
Architecture Components
Core Components
- FRP (Fast Reverse Proxy): Handles TCP/UDP tunneling between internal and external networks
- FRPS (FRP Server): Runs on the public-facing server
- FRPC (FRP Client): Runs on internal service hosts
- Traefik: HTTP/HTTPS router with automatic Let's Encrypt certificate management
- Docker & Docker Compose: Container orchestration and deployment
- SSH: Secure communication for remote configuration management
Supporting Elements
- Configuration Storage: Docker volumes for persistent configuration
- DNS Management: Domain-to-IP mapping for public access
- Certificate Management: Automatic SSL/TLS certificate provisioning and renewal
Prerequisites
- FRP (Fast Reverse Proxy) service with frpc and frps
- Traefik reverse proxy
- Docker and Docker Compose installed
- SSH key for remote server access
- SSH key at
~/.ssh/itl-devs1for proxy server access - User permissions for Docker commands
- Authentication keys for secure access
Parameters
Required Parameters
- Instance Name: Unique identifier for the service instance (alphanumeric, hyphens, underscores only)
- Internal Service Port: The port exposed by the target Docker container (e.g., 3000)
- Domain Name: Public domain for Traefik routing rules
- FRP Server Address: Public IP address of the FRP server
- FRP Server Port: Port for FRP communication (default 16999)
Optional Parameters
- Docker Network: Network for connecting to internal service container (default uses Docker bridge)
- Proxy Ports: Custom remote ports for external access (defaults: TCP ports matching internal ports)
- Service Type: Protocol specification (TCP/UDP/HTTP/HTTPS)
Environment Configuration
The architecture supports environment-based configuration using .env files to provide default values:
- Environment Files:
.env,.env.development,.env.production - Default Values: Parameters from environment files are used as defaults during script execution
- Interactive Fallback: If parameters are missing from environment files, scripts will prompt for input
- Auto-Persistence: Answered parameters are automatically saved to the appropriate
.envfile for future use - Supported Variables:
INSTANCE_NAME: Default instance nameINTERNAL_SERVICE_PORT: Port exposed by the target Docker container (e.g., 3000)DOCKER_NETWORK: Docker network for connecting to internal service containerFRP_SERVER_ADDR: FRP server addressFRP_SERVER_PORT: FRP server port (default 16999)DOMAIN_NAME: Default domain nameRAD_REMOTE_PORT: Remote port for rad proxy (default 8779)SSH_REMOTE_PORT: Remote port for SSH proxy (default 13076)WEB_REMOTE_PORT: Remote port for web proxy (default 13077)PROXY_*_PORT: Dynamic proxy configuration (e.g.,PROXY_API_PORT=8080)PROXY_*_LOCAL_PORT: Local port for the corresponding proxy (e.g.,PROXY_API_LOCAL_PORT=8000)
Dynamic Proxy Configuration
The system supports dynamic proxy configuration through environment variables:
- Format: Use
PROXY_*_PORTformat to define additional proxies - Examples:
PROXY_API_PORT=8080,PROXY_DATABASE_PORT=5432 - Local Port Override: Use
PROXY_*_LOCAL_PORTto specify a different local port - Flexibility: Allows configuration of any number of application-specific proxies
Internal Service Connection
The architecture connects to internal services on the same computer as the script execution:
- Connection Method: FRP client connects to target service on the same physical/virtual machine
- Local IP: Connection made via 127.0.0.1 (localhost) to the service port
- Port Configuration: Target service must be accessible on the specified port (e.g., 3000)
- Service Discovery: No container name resolution needed, connects directly to localhost
- Local IP Setting: FRP client configuration uses 127.0.0.1 as the local IP
- Naming Convention: Container and volume names follow the format
{INSTANCE_NAME}-frpc
Outcomes
- Public domain connectivity to internal service
- Secure encrypted tunnel between internal and external networks
- Automatic SSL/TLS certificates via Let's Encrypt
- Persistent configuration through Docker volumes
- Automated service discovery and routing
Architecture Flow
1. Configuration Phase
- User provides service parameters via interactive prompts or command-line
- System validates parameters and checks for existing configurations
- Generates appropriate FRP client configuration (frpc.toml)
- Persists configuration to Docker volumes for continuity
2. Deployment Phase
- Creates Docker container with FRP client
- Establishes connection to FRP server
- Sets up port forwarding rules
- Updates proxy server to recognize new instance
3. Routing Phase
- Traefik configuration updated with new routing rules
- Domain name routes to appropriate internal service
- Automatic SSL/TLS certificate provisioned
- Health checks and monitoring established
4. Management Phase
- Persistent configuration for service continuity
- Backup and recovery mechanisms
- Restart procedures for configuration changes
- Service status monitoring
Real-World Example: Using auto-sys-deploy.sh and update-compose-config.sh
Example: Deploying a New FRP Client Instance
Based on auto-sys-deploy.sh.md and update-compose-config.sh.md, here's a real-world example of the architecture in action:
Initial Setup
- Prerequisites: Docker, SSH key at
~/.ssh/itl-devs1 - Command:
./auto-sys-deploy.sh setup-rvs-prxy
Interactive Configuration (from auto-sys-deploy.sh)
-
Instance Name Selection:
- Default:
setup-rvs-prxy-$(date +%Y%m%d-%H%M%S) - User input:
my-app-instance-20231005-143000 - Validation: alphanumeric, hyphens, underscores only
- Default:
-
Docker Network Selection:
- Options: Select from existing networks, custom network, or default
- User input: Select network
bridgeor create custom - Outcome: Container runs on specific Docker network
-
FRP Server Configuration:
- Server Address:
192.168.1.100(example IP) - Server Port:
16999(default) - Validation: Ensure server is accessible
- Server Address:
-
Dynamic Proxy Configuration:
- Proxies are configured dynamically based on environment variables following the format
PROXY_*_PORT - Default rad proxy (if
RAD_REMOTE_PORTis set):- Local Port:
8776(default) - Remote Port: Value of
RAD_REMOTE_PORTenvironment variable - Name:
rad-my-app-instance-20231005-143000
- Local Port:
- Default SSH proxy (if
SSH_REMOTE_PORTis set):- Local Port:
22(default) - Remote Port: Value of
SSH_REMOTE_PORTenvironment variable - Name:
ssh-my-app-instance-20231005-143000
- Local Port:
- Default Web proxy (if
WEB_REMOTE_PORTis set):- Local Port: Service port or
80(default) - Remote Port: Value of
WEB_REMOTE_PORTenvironment variable - Name:
web-my-app-instance-20231005-143000
- Local Port: Service port or
- Additional proxies can be configured using
PROXY_*_PORTenvironment variables - Format:
PROXY_API_PORT=8080,PROXY_DATABASE_PORT=5432, etc. - The script will create as many proxies as defined by the environment variables
- Proxies are configured dynamically based on environment variables following the format
-
Domain Configuration:
- Input:
myapp.example.com - Used for Traefik routing rules
- Input:
Configuration Generation (from auto-sys-deploy.sh)
The script generates frpc.toml with:
serverAddr = "192.168.1.100"
serverPort = 16999
[[proxies]]
name = "rad-my-app-instance-20231005-143000"
type = "tcp"
localPort = 8776
localIP = "rad-git-sshd-my-app-instance-20231005-143000"
remotePort = 8779
[[proxies]]
name = "ssh-my-app-instance-20231005-143000"
type = "tcp"
localPort = 22
localIP = "rad-git-sshd-my-app-instance-20231005-143000"
remotePort = 13076
[[proxies]]
name = "web-my-app-instance-20231005-143000"
type = "tcp"
localPort = 80
localIP = "rad-git-sshd-my-app-instance-20231005-143000"
remotePort = 13077
Container Deployment (from auto-sys-deploy.sh)
- Creates Docker volume:
rad-git-sshd-itl-frpc-my-app-instance-20231005-143000 - Starts container:
rad-git-sshd-frpc-my-app-instance-20231005-143000 - Uses image:
snowdreamtech/frpc:0.62.0-alpine3.21 - Mounts config volume:
/etc/frp
Proxy Server Configuration (from update-compose-config.sh)
The script updates docker-compose.app.yml with:
Ports Section:
ports:
# ... other ports ...
# my-app-instance-20231005-143000 Self-hosting ports ====
- "8779:8779/tcp"
- "13076:13076/tcp"
- "13077:13077/tcp"
# =========================
# ... other ports ...
Labels Section:
labels:
# ... other labels ...
# my-app-instance-20231005-143000 Self-hosting labels ====
- "traefik.http.routers.frps-my-app-instance-20231005-143000-http.entrypoints=web"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-http.rule=Host(`myapp.example.com`)"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-http.service=frps-my-app-instance-20231005-143000"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-http.middlewares=http2https@file"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-https.entrypoints=websecure"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-https.rule=Host(`myapp.example.com`)"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-https.service=frps-my-app-instance-20231005-143000"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-https.tls=true"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-https.tls.certresolver=letsencrypt"
- "traefik.http.routers.frps-my-app-instance-20231005-143000-https.tls.domains[0].main=myapp.example.com"
- "traefik.http.services.frps-my-app-instance-20231005-143000.loadbalancer.server.port=13077"
# =========================
# ... other labels ...
Backup and Service Restart (from update-compose-config.sh)
- Creates backup:
docker-compose.app.yml.backup_YYYYMMDD_HHMMSS - Restarts service with:
./stop.sh && ./start.sh - Verifies deployment with:
docker logs --tail 50 frps_frps_1
Extensibility Points
Protocol Support
- TCP/UDP: Native FRP support for any TCP/UDP based service
- HTTP/HTTPS: Enhanced routing via Traefik with automatic certificates
- Custom Protocols: Extensible architecture for proprietary protocols
Service Types
- Web Applications: HTTP/HTTPS routing with domain-based access
- Database Services: Secure TCP tunneling for database connections
- SSH Services: Encrypted access to internal SSH servers
- API Services: Secure API endpoint exposure
Scaling Options
- Load Balancing: Multiple instances behind single domain
- Geographic Distribution: Multiple proxy servers in different regions
- Protocol Multiplexing: Multiple services through single tunnel
Security Considerations
- Encrypted tunnels between internal and external networks
- Access control through SSH keys and authentication
- Firewall isolation of internal services
- Automatic certificate management for HTTPS
- Docker container isolation
Maintenance Requirements
- Regular backup of configuration files
- Certificate renewal monitoring
- Connection health monitoring
- Log aggregation and analysis
- Docker image updates
Generic Application Examples
Web Application Deployment
- Parameters: Instance name, internal web port (80/443), domain name
- Outcome: Public website accessible via configured domain
Database Access
- Parameters: Instance name, internal database port, restricted domain
- Outcome: Secure external access to internal database
Custom Service Exposure
- Parameters: Instance name, custom application port, specific domain
- Outcome: External access to internal custom service