rvs-prxy/Design_Doc/Tech_Desc.md

276 lines
11 KiB
Markdown

# Technical Architecture and Implementation Details
## Script Architecture
The `deploy-rvs-prxy.sh` script is an automated deployment tool supporting both FRP and Traefik modes.
**Key Architecture:** The script runs directly on the same server where the application is hosted (local deployment), eliminating the need for SSH-based remote operations in Traefik mode.
**Deployment Modes:**
1. **Setup Reverse Proxy**: Deploys new Traefik or FRP Tunnel with Traefik
2. **Setup New Domain**: Adds new domain configuration to existing reverse proxy
**Configuration File Structure:**
- `.env.rvs-prxy` - Reverse proxy instance configuration (FRP mode, Traefik version, etc.)
- `.env-<domain>` - Domain-specific configuration (DOMAIN_NAME, LOCAL_SERVICE_NAME, LOCAL_SERVICE_PORT)
- Domain format: Any domain format supported (`.com`, `.net`, `.org`, `.org.hk`, `.com.hk`, subdomains, etc.)
- Filename pattern: Dots replaced with dashes (e.g., `app.example.com` → `.env-app-example-com`)
- `.env-port-<port>` - Port-based routing configuration (HOST_PORT, CONTAINER_NAME, CONTAINER_PORT)
- Multiple domain and port files can coexist for multiple domains and ports
**Automatic Mode Detection:**
- No config files → Interactive wizard for proxy setup
- `.env.rvs-prxy` exists, proxy not running → Setup Reverse Proxy
- `.env.rvs-prxy` exists, proxy running, no domain/port file → Interactive wizard for domain/port setup
- `.env.rvs-prxy` + `.env-<domain>` exists → Setup New Domain
- `.env.rvs-prxy` + `.env-port-<port>` exists → Setup Port Exposure
**Validation:**
- **Proxy Setup Mode**: Validates proxy-specific settings (TRAEFIK_VER, LETSENCRYPT_EMAIL for Traefik; FRP_SERVER_ADDR for FRP)
- **Domain Setup Mode**: Validates domain-specific settings (DOMAIN_NAME, LOCAL_SERVICE_NAME, LOCAL_SERVICE_PORT)
**Workflow:**
First Run (No .env.rvs-prxy):
1. Interactive wizard asks for proxy instance settings
2. Creates .env.rvs-prxy with Traefik/FRP settings
3. Validation checks proxy settings (TRAEFIK_VER, LETSENCRYPT_EMAIL)
4. Deploys reverse proxy
5. Shows message: "Next: Run the script again to setup your first domain or port"
Second Run (.env.rvs-prxy exists, proxy running):
1. Detects running proxy
2. Interactive wizard asks for domain or port settings
3. Creates .env-<domain> or .env-port-<port> with settings
4. Validation checks domain/port settings
5. Checks if application service/container is running
6. Configures domain/port in existing reverse proxy
7. Shows: "Service will be accessible at: https://domain.name or http://host-ip:port"
Three Deployment Modes:
1. Setup Reverse Proxy - Deploys Traefik or FRP Tunnel
2. Setup New Domain - Adds domain-based routing
3. Setup Port Exposure - Adds port-based routing
### Core Components
**1. Environment Loading (`load_env`)**
- Loads configuration from `.env.rvs-prxy.development`, `.env.rvs-prxy.production`, or `.env.rvs-prxy`
- Supports files in current directory or script directory
- **Interactive Setup Wizard**: If no `.env.rvs-prxy` file is found, automatically launches a guided setup wizard
- Normalizes boolean values (FRP variable)
- Validates required parameters for each mode
- Supports three modes: proxy setup, domain setup, and port exposure
**Interactive Setup Wizard Features:**
- Step-by-step guided configuration
- Mode selection (Traefik or FRP) for proxy setup
- Choice between domain setup or port exposure when proxy exists
- Mode-specific configuration prompts
- Sensible defaults for all settings
- Automatic saving to `.env.rvs-prxy`, `.env-<domain>`, or `.env-port-<port>` files
**2. Instance Management (`prompt_instance_name`)**
- Auto-detects existing instances from Docker volumes (FRP mode)
- Supports instance name override via `INSTANCE_NAME` environment variable
- Generates timestamped default names
- Saves selections to `.env` for future runs
**3. Docker Network Selection (`select_docker_network`)**
- Lists available Docker networks
- Supports custom network names
- Remembers previous selections via `.para` file in volume (FRP mode)
**4. Configuration Generation**
- **FRP Mode**: Generates `frpc.toml` with dynamic proxy configurations
- **Traefik Mode**: Generates YAML configuration files for routing rules (local deployment)
**5. Container Management**
- Creates and manages Docker containers with persistent volumes
- Supports container restart and lifecycle operations
- Displays operation commands for user reference
## Traefik Mode Implementation (Local Deployment)
### Setup Flow (`setup_traefik_only`)
1. **Pre-request Checks**
- Verify Docker command permissions
2. **Application Service Verification** (`check_app_service_local`)
- Confirms target service is running locally
- Verifies connection to `traefik-public` network
3. **Traefik Container Creation** (`create_traefik_container_local`)
- Creates `traefik_data` volume for persistence
- Generates dynamic configuration with:
- Dashboard routing
- HTTP to HTTPS redirect
- Security headers
- Creates `traefik-public` Docker network
- Uses Docker Compose for container orchestration
- Detects Docker version for command compatibility (`docker compose` vs `docker-compose`)
4. **Service Configuration** (`configure_traefik_local`)
- Generates service-specific routing rules
- Supports sub-path routing (e.g., `example.com/api`)
- Creates unique configuration filenames to avoid conflicts
- Supports dynamic configuration loading (no restart required by default)
### Local Docker Operations
- `local_docker_exec()`: Executes Docker commands directly on the local server
- `local_volume_copy()`: Copies files to Docker volumes using temporary containers
### Configuration File Structure
**Traefik Main Config** (`traefik.yml`):
```yaml
http:
routers:
api:
rule: "PathPrefix(`/api`)"
service: api@internal
dashboard:
rule: "PathPrefix(`/dashboard`)"
service: api@internal
http-catchall:
rule: "PathRegexp(`{any:.*}`)"
entryPoints:
- "web"
service: "noop@internal"
middlewares:
- "redirect-to-https"
middlewares:
api-headers:
headers:
customFrameOptionsValue: SAMEORIGIN
contentTypeNosniff: true
browserXssFilter: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 15552000
redirect-to-https:
redirectScheme:
scheme: "https"
permanent: true
```
**Service Config** (dynamic, per-service):
```yaml
http:
routers:
<domain>-https:
rule: 'Host(`<domain>`)'
service: <domain>-service
tls:
certResolver: letsencrypt
entryPoints:
- websecure
<domain>-http:
rule: 'Host(`<domain>`)'
service: <domain>-service
entryPoints:
- web
middlewares:
- redirect-to-https
services:
<domain>-service:
loadBalancer:
servers:
- url: 'http://<container-name>:<port>'
passHostHeader: true
```
Router, service, and middleware names use the domain (or domain-without-sub-path) as the prefix instead of the container name. This ensures unique resource names when multiple domains share the same backend container. The backend URL still references the container hostname for Docker networking.
**Entrypoints Configuration:**
Default entrypoints (`web` on :80, `websecure` on :443) are defined in the docker-compose.yml command args. Additional entrypoints can be configured via the `EXTRA_ENTRYPOINTS` environment variable in `.env.rvs-prxy`:
- Format: `name=:port/protocol,name2=:port` (comma-separated)
- Example: `quic=:443/udp` enables HTTP/3 QUIC on UDP port 443
- These are injected into both the docker-compose.yml `command:` section and the `docker run` command
- Port mappings (TCP/UDP) are automatically added to the `ports:` section
- The `parse_extra_entrypoints()` function parses the variable and builds:
- `EXTRA_ENTRYPOINT_ARGS`: array of `--entrypoints.<name>.address=<address>` args
- `EXTRA_PORT_MAPPINGS`: array of port mappings in `host:container/protocol` format
- `EXTRA_COMPOSE_ENTRYPOINTS`: YAML lines for docker-compose.yml command section
- `EXTRA_COMPOSE_PORTS`: YAML lines for docker-compose.yml ports section
## FRP Mode Implementation
### Setup Flow
1. **Instance Setup**: Prompt for instance name
2. **Port Configuration**: Prompt for internal service port
3. **FRP Config Generation** (`generate_frpc_config`)
- Extracts existing configuration from volume
- Supports dynamic proxy configurations via `PROXY_*_PORT` variables
- Generates `frpc.toml` with TCP proxy rules
4. **Container Start** (`start_docker_container`)
- Creates volume if not exists
- Starts frpc container with configuration mounted
5. **Proxy Server Update** (`update_proxy_server_config`)
- Uploads dynamic configuration script to proxy server
- Updates `docker-compose.app.yml` with port mappings and labels
- Supports domain-based routing configuration
### Dynamic Proxy Configuration
The script supports dynamic proxy configurations through environment variables:
- `PROXY_<NAME>_PORT`: Defines remote port for proxy
- `PROXY_<NAME>_LOCAL_PORT`: Defines local port (defaults to `INTERNAL_SERVICE_PORT`)
Example:
```bash
PROXY_WEB_PORT=12077
PROXY_WEB_LOCAL_PORT=3000
PROXY_SSH_PORT=2222
PROXY_SSH_LOCAL_PORT=22
```
### Proxy Server Configuration Update
The script generates and executes a remote script on the proxy server that:
- Checks existing configuration status (not_found, up_to_date, outdated)
- Updates port mappings section in `docker-compose.app.yml`
- Updates labels section for Traefik routing
- Optionally restarts Docker Compose service
## File Deployment (Traefik Mode)
The `deploy` command syncs files from local folder to target server:
- Source: `LOCAL_FOLDER` (default: `../out/`)
- Destination: `DEST_PATH` on target server
- Uses rsync for efficient synchronization with `--delete` option
## Logging and Debugging
**Logging Functions:**
- `log_info()`: Green [INFO] messages
- `log_error()`: Red [ERROR] messages
- `log_warn()`: Yellow [WARN] messages
- `log_debug()`: Blue [DEBUG] messages (only when `DEBUG=true`)
**Status Commands:**
- `check_status_on_target()`: Shows Traefik and Application service status
- `view_traefik_logs()`: Displays last 50 lines of Traefik logs
## Error Handling
- Uses `set -e` for immediate exit on errors
- Validates required parameters before execution
- Provides detailed error messages with suggested fixes
- Graceful handling of missing configurations
## Version Compatibility
**Docker Version Detection:**
- Detects Docker version to determine command syntax
- Uses `docker compose` for Docker 20.10.0+
- Falls back to `docker-compose` for older versions
- Handles Compose file version field (deprecated in v2.0+)
**Traefik Version:**
- Default: `v3.6.9`
- Configurable via `TRAEFIK_VER` environment variable