1) latest cmd running, it will update the latest domain info. to owerwrite the old one, 2) Check if traefik or *-frpc container is running to know which mode even no .env, 3) Automatically processes multiple .env-<domain> files in a single run

This commit is contained in:
chungyan5 2026-03-07 03:12:55 +00:00
parent ced4f6d900
commit 6d7f9a06f6
6 changed files with 697 additions and 150 deletions

View File

@ -1,72 +0,0 @@
# Sample Environment Configuration for Reverse Proxy Architecture
# Copy this file to .env, .env.development or .env.production and fill in your values
# Common
# =========================================
# === Instance Configuration ===
INSTANCE_NAME=myapp-3000 # Unique identifier for the service instance (alphanumeric, hyphens, underscores only)
# The container and volume name will be {INSTANCE_NAME}-frpc
# Target server information for proxy connection
TARGET_SERVER=WW.XX.YY.ZZ # Target Proxy Server IP/hostname
TARGET_USER=your_user_name # Username for SSH access to target server
SSH_PORT=22 # SSH port for target server (default 22)
# SSH key file name (must be in $HOME/.ssh/)
SSH_KEY_FILE_NAME=your_key # SSH private key file name in $HOME/.ssh/
# === Domain Configuration ===
DOMAIN_NAME=myapp.example.com # Public domain for Traefik routing
# Debug flag
DEBUG=false # Set to true for additional debug output
# FRP
# =========================================
# === FRP vs Traefik Mode Configuration ===
FRP=true # Set to 'true' to use FRP mode, 'false' to use Traefik-only mode
# === Internal Service Container Configuration (FRP Mode) ===
INTERNAL_SERVICE_PORT=3000 # Port exposed by the target Docker container (e.g., 3000)
DOCKER_NETWORK=app-network # Docker network for connecting to internal service container
# === FRP Server Configuration (FRP Mode) ===
FRP_SERVER_ADDR=192.168.1.100 # Public IP address of the FRP server
FRP_SERVER_USER=myuser # Username for FRP server (defaults to 'teenfuture')
FRP_SERVER_PORT=16999 # Port for FRP communication (default 16999)
# === Service Configuration ===
SERVICE_DOCKER_CONTAINER_NAME=your-app-docker-container # Docker container name for internal service connection
# === FRP Remote Ports Configuration (FRP Mode) ===
PROXY_WEB_PORT=11077 # Remote port for web proxy
PROXY_RAD_PORT=8779 # Remote port for rad proxy (default 8779, use 8776 if following standard)
PROXY_SSH_PORT=13076 # Remote port for SSH proxy (default 13076)
# Dynamic Proxy Configuration - Use PROXY_*_PORT format for additional proxies
# Examples:
# PROXY_API_PORT=8080 # Creates an 'api' proxy to port 8080
# PROXY_API_LOCAL_PORT=8000 # Optional local port for the API proxy (defaults to service port)
# PROXY_DATABASE_PORT=5432 # Creates a 'database' proxy to port 5432
# PROXY_DATABASE_LOCAL_PORT=5433 # Optional local port for database proxy
# PROXY_CUSTOM_PORT=9000 # Creates a 'custom' proxy to port 9000
# Traefik
# =========================================
# === Target Proxy Server Configuration (Traefik Mode) ===
# This section is used when FRP=false
# Destination path for host or docker volume folder deployment
DEST_PATH=/ # Destination path on target server
# Target Application Service information (on the target server)
TARGET_SERVICE_NAME=your-app-service # Name of the Docker container running the application service
TARGET_SERVICE_PORT=3000 # Port the application service is listening on
# Traefik configuration
TRAEFIK_VER=v3.5.4 # Traefik Docker image version to use
LETSENCRYPT_EMAIL=admin@yourdomain.com # Email for Let's Encrypt certificate registration
RESTART_TRAEFIK=false # Set to 'true' to restart Traefik after configuration (default: false for dynamic loading)

View File

@ -74,10 +74,47 @@ Each domain gets its own `.env-<domain>` file.
2. Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash` 2. Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash`
**For New Domain Setup:** **For New Domain Setup:**
1. Create `.env-<domain>` file with domain configuration
2. Ensure `.env` exists and reverse proxy is running The script supports flexible domain setup with automatic proxy mode detection:
3. Ensure your application service is running
4. Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash` 1. **With `.env-<domain>` file (recommended):**
- Create `.env-<domain>` file with domain configuration
- Ensure reverse proxy is running (Traefik or FRP)
- Ensure your application service is running
- Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash`
2. **Without `.env` file (auto-detection):**
- Create `.env-<domain>` file with domain configuration
- Ensure reverse proxy is running (script will auto-detect mode)
- Ensure your application service is running
- Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash`
- Script automatically detects running proxy (Traefik or FRP) and configures accordingly
3. **Without any config files (interactive wizard):**
- Ensure reverse proxy is running
- Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash`
- Script detects running proxy and starts wizard for domain settings
4. **Batch processing (multiple domains):**
- Create multiple `.env-<domain>` files in the same directory
- Ensure reverse proxy is running
- Ensure all application services are running
- Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash`
- Script automatically processes all `.env-<domain>` files in batch mode
- Example output:
```
[INFO] Found 3 domain config files, will process all in batch mode
[INFO] =========================================
[INFO] Processing domain 1 of 3: .env-domain1-com
[INFO] =========================================
[INFO] Setting up new domain: domain1.com
...
[INFO] =========================================
[INFO] Processing domain 2 of 3: .env-domain2-com
[INFO] =========================================
...
[INFO] Batch processing completed: 3 domain(s) processed
```
## Run this System ## Run this System
@ -104,26 +141,21 @@ curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
If you run the script for a domain that has already been added to the reverse proxy: If you run the script for a domain that has already been added to the reverse proxy:
1. **Detection**: The script checks if a configuration file already exists for the domain and service combination 1. **Detection**: The script detects the running proxy mode (Traefik or FRP) automatically
2. **Warning**: Displays a warning message: 2. **Warning**: Displays a warning message that configuration will be overwritten
``` 3. **Update**: The existing configuration is updated with the new settings
[WARN] Configuration file app-service-domain-service.yml already exists, it will be overwritten
[INFO] This will update the existing domain configuration for my.domain.com
```
- Configuration File Naming:
- Format: app-service-{domain}-{service}.yml
- Example: app-service-my-domain-com-myapp.yml
- Unique per domain+service combination
3. **Update**: The existing configuration is overwritten with the new settings
4. **Result**: The domain configuration is updated (not duplicated) 4. **Result**: The domain configuration is updated (not duplicated)
**Key Points:** **Key Points:**
- **Safe to re-run**: Running the script multiple times for the same domain is safe - **Safe to re-run**: Running the script multiple times for the same domain is safe
- **Configuration is updated, not duplicated**: Each domain+service combination has a unique configuration file - **No .env required**: Script auto-detects running proxy mode (Traefik or FRP)
- **No service interruption**: Traefik dynamically loads the updated configuration (no restart needed by default) - **Configuration is updated, not duplicated**: Each domain+service combination has a unique configuration
- **No service interruption**:
- Traefik: Dynamically loads updated configuration (no restart needed by default)
- FRP: Restarts FRP client container to apply new configuration
- **Use case**: Useful for updating application port changes or domain routing modifications - **Use case**: Useful for updating application port changes or domain routing modifications
**Example Scenario:** **Example Scenario (Traefik Mode):**
```bash ```bash
# First run - adds my.domain.com # First run - adds my.domain.com
curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
@ -131,24 +163,52 @@ curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
# Second run - updates my.domain.com (e.g., after port change) # Second run - updates my.domain.com (e.g., after port change)
curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
# [WARN] Configuration file ... already exists, it will be overwritten # [INFO] Detected running Traefik reverse proxy
# [INFO] This will update the existing domain configuration for my.domain.com # [INFO] Setting up new domain: my.domain.com
# [INFO] New domain my.domain.com has been configured in Traefik
```
**Example Scenario (FRP Mode):**
```bash
# First run - adds my.domain.com
curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
# [INFO] Creating new configuration for domain my.domain.com
# Second run - updates my.domain.com (e.g., after port change)
curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
# [INFO] Detected running FRP client container: my-instance-frpc
# [INFO] Setting up new domain: my.domain.com
# [INFO] Generated remote port 12001 for domain my.domain.com
# [INFO] New domain my.domain.com has been configured in FRP tunnel
``` ```
### Script Behavior ### Script Behavior
### Mode Selection ### Mode Selection
Set the `FRP` environment variable to control the deployment mode: The script automatically detects the proxy mode from running containers:
```bash ```bash
# Traefik Mode (local reverse proxy on same server) # Auto-detects running proxy (Traefik or FRP)
FRP=false ./deploy-traefik.sh setup-rvs-prxy curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
# FRP Mode (remote proxy via FRP tunnel)
FRP=true ./deploy-traefik.sh setup-rvs-prxy
``` ```
**Manual override (optional):** Set the `FRP` environment variable to force a specific mode:
```bash
# Force Traefik Mode (local reverse proxy on same server)
FRP=false ./deploy-rvs-prxy.sh
# Force FRP Mode (remote proxy via FRP tunnel)
FRP=true ./deploy-rvs-prxy.sh
```
**Auto-detection behavior:**
- If `traefik` container is running → Traefik mode (`FRP=false`)
- If `*-frpc` container is running → FRP mode (`FRP=true`)
- If both are running → Traefik mode takes precedence
- If neither is running → Interactive wizard
### Traefik Mode Operations (FRP=false) ### Traefik Mode Operations (FRP=false)
#### Setup #### Setup
@ -192,6 +252,36 @@ FRP=true ./deploy-traefik.sh setup-rvs-prxy
6. Update proxy server configuration 6. Update proxy server configuration
7. Display container operation commands 7. Display container operation commands
#### Setup New Domain (FRP Mode)
When the FRP reverse proxy is already running, you can add new domains:
- **Prerequisites:**
- FRP client container must be running (`${INSTANCE_NAME}-frpc`)
- Application service must be running locally
- `.env` file with reverse proxy configuration must exist
- `.env-<domain>` file with domain configuration (or use interactive wizard)
- **Process:**
1. Run the script: `curl -s "<url>/deploy-rvs-prxy.sh" | bash`
2. Script detects existing FRP proxy and domain config
3. Validates FRP client container is running
4. Validates application service is running
5. Generates a new remote port for the domain
6. Updates frpc.toml with new proxy configuration
7. Restarts FRP client container to apply changes
8. Updates proxy server configuration with domain routing
9. Domain is now accessible via HTTPS
- **Configuration Files:**
- `.env` - Reverse proxy instance configuration (contains `INSTANCE_NAME`, `FRP_SERVER_ADDR`, etc.)
- `.env-<domain>` - Domain-specific configuration (contains `DOMAIN_NAME`, `LOCAL_SERVICE_NAME`, `LOCAL_SERVICE_PORT`)
- **What Happens:**
- A new TCP proxy is added to frpc.toml for the domain's service
- A unique remote port is allocated for this domain
- Proxy server (FRPS) is updated to route the domain to the new tunnel port
- FRP client container is restarted to apply the new configuration
### Environment Variable Priority ### Environment Variable Priority
Configuration files are loaded in the following priority order: Configuration files are loaded in the following priority order:

View File

@ -15,9 +15,11 @@
- **Automatic Mode Detection**: Automatically detects whether to setup reverse proxy or add new domain - **Automatic Mode Detection**: Automatically detects whether to setup reverse proxy or add new domain
- **Two Deployment Modes**: - **Two Deployment Modes**:
- **Setup Reverse Proxy**: Deploys Traefik or FRP Tunnel with Traefik - **Setup Reverse Proxy**: Deploys Traefik or FRP Tunnel with Traefik
- **Setup New Domain**: Adds new domain to existing reverse proxy - **Setup New Domain**: Adds new domain to existing reverse proxy (supports both Traefik and FRP modes)
- **Batch Processing**: Automatically processes multiple `.env-<domain>` files in a single run
- **Traefik Mode**: Deploy and configure Traefik reverse proxy on the same server as your application - **Traefik Mode**: Deploy and configure Traefik reverse proxy on the same server as your application
- **FRP Mode**: Optional Fast Reverse Proxy support for tunneling connections to a remote proxy server - **FRP Mode**: Optional Fast Reverse Proxy support for tunneling connections to a remote proxy server
- **FRP Domain Setup**: Add new domains to existing FRP tunnel by allocating new remote ports and updating proxy server configuration
- **Automated Configuration**: Dynamic generation of reverse proxy configurations based on `.env` files - **Automated Configuration**: Dynamic generation of reverse proxy configurations based on `.env` files
- **Docker Integration**: Seamless integration with Docker containers and networks - **Docker Integration**: Seamless integration with Docker containers and networks
- **HTTPS/TLS Support**: Automatic SSL certificate management via Let's Encrypt - **HTTPS/TLS Support**: Automatic SSL certificate management via Let's Encrypt
@ -32,12 +34,19 @@
- **No application service check** (application not needed at this stage) - **No application service check** (application not needed at this stage)
- No domain configuration at this stage - No domain configuration at this stage
2. **Add domain (`.env` exists, proxy running)**: Setup New Domain 2. **Add domain (proxy running)**: Setup New Domain
- Interactive wizard asks for domain configuration - Script auto-detects running proxy mode (Traefik or FRP)
- Interactive wizard asks for domain configuration (if no `.env-<domain>` exists)
- Creates `.env-<domain>` with application settings - Creates `.env-<domain>` with application settings
- **Checks if application service is running** - **Checks if application service is running**
- Configures domain in existing reverse proxy - Configures domain in existing reverse proxy
**Proxy Mode Detection:**
- Script automatically detects running proxy from Docker containers
- Traefik mode: detects `traefik` container
- FRP mode: detects `*-frpc` containers
- Works with or without `.env` file
``` ```
┌────────────┬─────────────────────────────────────┬────────────────────────────────────────────────────────┬────────────────┐ ┌────────────┬─────────────────────────────────────┬────────────────────────────────────────────────────────┬────────────────┐
│ Scenario │ Configuration │ Wizard Asks For │ Creates │ │ Scenario │ Configuration │ Wizard Asks For │ Creates │
@ -52,7 +61,7 @@
- Detect the existing of reverse proxy instance -- this script and reverse proxy instance at same computer. - Detect the existing of reverse proxy instance -- this script and reverse proxy instance at same computer.
- if non-existing of reverse proxy instance: look for the existing of `.env` -- the configuration of reverse proxy instance, create a reverse proxy instance only. - if non-existing of reverse proxy instance: look for the existing of `.env` -- the configuration of reverse proxy instance, create a reverse proxy instance only.
- if missing `.env`, start interactive wizard to take all configuration for reverse proxy instance only. - if missing `.env`, start interactive wizard to take all configuration for reverse proxy instance only.
- if existing of reverse proxy instance: look for the existing of `.env-<domain>` -- not touch the reverse proxy instance, just insert this domain configuration into the existing reverse proxy instance. - if existing of reverse proxy instance: look for the existing of `.env-<domain>` -- not touch the reverse proxy instance, just insert this domain configuration into the existing reverse proxy instance.
- if missing `.env-<domain>`, start interactive wizard to take all configuration for the domain, then insert into existing reverse proxy instance. - if missing `.env-<domain>`, start interactive wizard to take all configuration for the domain, then insert into existing reverse proxy instance.
- one of example of domain configuration: application's internal service port - one of example of domain configuration: application's internal service port
@ -68,6 +77,7 @@
│ .env-<domain> exists │ Setup New Domain │ Add domain to existing proxy │ │ .env-<domain> exists │ Setup New Domain │ Add domain to existing proxy │
│ No .env-<domain> + Proxy running │ Setup New Domain │ Interactive wizard → Create │ │ No .env-<domain> + Proxy running │ Setup New Domain │ Interactive wizard → Create │
│ │ │ Check app service → Configure │ │ │ │ Check app service → Configure │
│ No .env + Proxy running │ Setup New Domain │ Auto-detect mode → Wizard/Config│
└────────────────────────────────────────┴─────────────────────┴─────────────────────────────────┘ └────────────────────────────────────────┴─────────────────────┴─────────────────────────────────┘
``` ```
@ -79,6 +89,7 @@
- Contains reverse proxy instance settings (FRP mode, Traefik version, etc.) - Contains reverse proxy instance settings (FRP mode, Traefik version, etc.)
- Created during first-time setup - Created during first-time setup
- One file per reverse proxy instance - One file per reverse proxy instance
- **Note:** This file is optional for domain setup if proxy is already running (mode auto-detected)
**Domain-Specific Configuration (`.env-<domain>`):** **Domain-Specific Configuration (`.env-<domain>`):**
- Pattern: `.env-<domain-with-dashes>` (e.g., `.env-example-com`, `.env-sub-domain-net`, `.env-app-org-hk`) - Pattern: `.env-<domain-with-dashes>` (e.g., `.env-example-com`, `.env-sub-domain-net`, `.env-app-org-hk`)
@ -86,9 +97,24 @@
- One file per domain - One file per domain
- Multiple domain files can coexist - Multiple domain files can coexist
- Accepts any domain format: `.com`, `.net`, `.org`, `.org.hk`, `.com.hk`, subdomains, etc. - Accepts any domain format: `.com`, `.net`, `.org`, `.org.hk`, `.com.hk`, subdomains, etc.
- **Simplified format:** Only requires 3 variables (see below)
#### Key Environment Variables #### Key Environment Variables
**Domain-Specific Configuration (`.env-<domain>`):**
**Required Variables (only 3):**
- `DOMAIN_NAME` - Domain name for reverse proxy routing (e.g., `app.example.com`)
- `LOCAL_SERVICE_NAME` - Name of the local Docker application container
- `LOCAL_SERVICE_PORT` - Port number of the local application service
**Example `.env-app-example-com`:**
```bash
DOMAIN_NAME="app.example.com"
LOCAL_SERVICE_NAME="my-app-container"
LOCAL_SERVICE_PORT="3000"
```
**Reverse Proxy Instance Configuration (`.env`):** **Reverse Proxy Instance Configuration (`.env`):**
**Mode Selection:** **Mode Selection:**

View File

@ -265,6 +265,190 @@ The `deploy` command syncs files from local folder to target server:
## Workflow ## Workflow
- i have multiple of `.env-domain` as one folder, like below: ls -al /tmp/domain
```
total 16
drwxrwxr-x 2 teenfuture teenfuture 4096 Mar 7 02:12 .
drwxrwxrwt 15 root root 4096 Mar 7 02:11 ..
-rw-rw-r-- 1 teenfuture teenfuture 206 Mar 7 02:12 .env-event-cgu-org-hk
-rw-rw-r-- 1 teenfuture teenfuture 209 Mar 5 07:12 .env-www2-ivantito-com
```
- i ran cmd: teenfuture@ssdnodes-69008e84ae541:/tmp/domain$ curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
```
[INFO] Loading domain config from .env-event-cgu-org-hk
[INFO] Detected running Traefik reverse proxy
[INFO] Auto-detected FRP mode: false (from running container)
[INFO] Deployment mode: Setup New Domain (found domain config: .env-event-cgu-org-hk)
[INFO] Setting up new domain in existing reverse proxy...
[INFO] Setting up new domain: event.cgu.org.hk
[INFO] Domain configuration loaded from: .env-event-cgu-org-hk
[INFO] Checking if Application Service is running locally...
[INFO] Application Service is running locally
[INFO] Configuring Traefik locally to connect to Application Service...
[INFO] Creating new configuration for domain event.cgu.org.hk
[INFO] Added configuration for service cgu-react-client on domain event.cgu.org.hk to Traefik (file: app-service-event.cgu.org.hk-cgu-react-client.yml)
[INFO] Traefik dynamic configuration added (restart not performed, Traefik should auto-load the configuration)
[INFO] If needed, you can manually restart Traefik with: docker restart traefik
[INFO] Traefik configured to route traffic to Application Service
[INFO] Service will be accessible at: https://event.cgu.org.hk
[INFO] New domain event.cgu.org.hk has been configured in Traefik
[INFO] Service will be accessible at: https://event.cgu.org.hk
```
- it handles one `.env-domain`, modify the code which can loop to handle all `.env-domain` setup.
- Result
Code Changes (deploy-rvs-prxy.sh)
1. Added global array for domain files:
1 declare -a DOMAIN_ENV_FILES=()
2. Modified `load_env()` function:
- Collects all .env-<domain> files into DOMAIN_ENV_FILES array
- Loads first file for backward compatibility
- Reports number of domain files found for batch processing
3. Modified `main()` function:
- Loops through all domain config files in DOMAIN_ENV_FILES array
- Processes each domain sequentially with progress indicator
- Validates each domain config before processing
- Shows batch processing summary at the end
- Currently situation as: the reverse proxy -> traefik instance is running, and i setup the domain www2.ivantito.com and they both working with `.env` as:
```
cat .env-www2-ivantito-com
# Domain configuration for www2.ivantito.com
# Generated by deploy-rvs-prxy.sh on Thu Mar 5 07:12:35 UTC 2026
DOMAIN_NAME="www2.ivantito.com"
LOCAL_SERVICE_NAME="itl-www2-nginx_cntr"
LOCAL_SERVICE_PORT="80"
```
- However, i have a cmd: curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
- it showed:
```
[INFO] Loading domain config from .env-www2-ivantito-com
[INFO] Deployment mode: Setup New Domain (found domain config: .env-www2-ivantito-com)
[INFO] Setting up new domain in existing reverse proxy...
[INFO] Setting up new domain: www2.ivantito.com
[INFO] Domain configuration loaded from: .env-www2-ivantito-com
[ERROR] Domain setup for FRP mode is not yet implemented
```
- Resolve this issue. I assume the latest cmd running, it will update the latest domain info. to owerwrite the old one, finally success to setup, should not like currently as coming out Err.
- Result
- deploy-rvs-prxy.sh - Implemented FRP Domain Setup
Modified `setup_new_domain()` function (around line 2194):
- Added FRP mode domain setup logic that:
- Validates INSTANCE_NAME is set from .env
- Checks if FRP client container is running
- Validates application service is running locally
- Generates a new remote port for the domain
- Updates frpc.toml with new proxy configuration
- Updates proxy server configuration with domain routing
Added helper functions (around line 1086):
- generate_remote_port() - Generates a unique remote port by checking existing ports
- update_frpc_config_for_domain() - Updates frpc.toml with new domain proxy config and restarts FRP container
How It Works Now
When running curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash in FRP mode with a domain config:
1. Script loads .env (reverse proxy config) and .env-<domain> (domain config)
2. Detects FRP mode and domain setup mode
3. Validates FRP client container is running
4. Validates application service is running
5. Generates unique remote port (e.g., 12000, 12001, etc.)
6. Adds new proxy entry to frpc.toml for the domain
7. Restarts FRP client container
8. Updates proxy server (FRPS) configuration with domain routing
9. Domain becomes accessible via HTTPS
- I read your previous result, you mentioned the FRP mode, however, currently, my reverse proxy is running traefik instance, not FRP. I am confused as my current case as same to following `Design_Doc/Operations.md` -> Section "Run this System" -> Section "Re-running for Existing Domain", it does not mentioned FRP mode or traefik mode. For my original design, i aim to have first time setting to design as traefik or frp mode, which should be indicated at `.env`. Then any setting of domain with or without `.env-<domain>`, does not force to have previous instance `.env` at there, but this script can detect the current running instance mode as FRP mode or traefik mode, then setup domain. For the case of "Re-running for Existing Domain", but reverse proxy FRP mode or traefik mode is running, can absent of `.env`, when go with or without `.env-<domain>`, update domain overwrite the old domain setting.
- Result
- Code Changes (deploy-rvs-prxy.sh)
1. Enhanced `load_env()` function - Added automatic proxy mode detection:
- Detects running traefik container → sets FRP=false
- Detects running *-frpc containers → sets FRP=true, extracts INSTANCE_NAME
- Loads FRP configuration from volume if .env is missing
- Determines deployment mode based on running containers, not just config files
2. Added `load_frp_config_from_volume()` function:
- Extracts FRP_SERVER_ADDR and FRP_SERVER_PORT from frpc.toml in Docker volume
- Allows FRP domain setup without .env file
3. Updated `setup_new_domain()` function - Enhanced FRP mode:
- Detects INSTANCE_NAME from running FRP containers if not set
- Generates unique remote port for new domain
- Updates frpc.toml with new proxy configuration
- Restarts FRP client container to apply changes
- Updates proxy server configuration with domain routing
- My current reverse proxy instance as: docker ps -a
```
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
23082fb71d18 traefik:v3.6.9 "/entrypoint.sh --ap…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcp, 127.0.0.1:8080->8080/tcp traefik
```
- the container name is traefik.
- I ran the cmd with following outcome as: curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
```
[INFO] Loading domain config from .env-www2-ivantito-com
[INFO] Detected running Traefik reverse proxy
[INFO] Deployment mode: Setup New Domain (found domain config: .env-www2-ivantito-com)
[INFO] Setting up new domain in existing reverse proxy...
[INFO] Setting up new domain: www2.ivantito.com
[INFO] Domain configuration loaded from: .env-www2-ivantito-com
[INFO] Setting up new domain in FRP mode...
[ERROR] INSTANCE_NAME is not set and no FRP container detected.
[ERROR] Please ensure your .env file contains the reverse proxy configuration.
```
- i find out it goes into the FRP again, since not detected as traefik mode. What is your algorithm to detect the FRP or traefik mode at a current reverse proxy instance? How to improve? and resolve the above issue.
- Result
1. Fixed FRP Mode Detection Algorithm (deploy-rvs-prxy.sh)
Problem: The script was using FRP value from config files instead of detecting from running containers.
Solution:
- Running container detection now always takes precedence over .env settings
- Traefik container takes precedence over FRP containers
- When a proxy is detected running, FRP variable is always updated based on actual running containers
New Detection Logic:
1 1. Check if traefik container is running → FRP=false (Traefik mode)
2 2. Check if *-frpc container is running (and no Traefik) → FRP=true (FRP mode)
3 3. Always override FRP variable when proxy is detected running
2. Updated Configuration File Format
Domain config files (`.env-<domain>`) - Simplified format:
1 DOMAIN_NAME="event.cgu.org.hk"
2 LOCAL_SERVICE_NAME="cgu-react-client"
3 LOCAL_SERVICE_PORT="3000"
Reverse proxy instance config (`.env`) - Full format:
- Contains FRP/Traefik instance settings
- Used for initial proxy setup
- Optional for domain setup (mode auto-detected from running containers)
3. Created New Files
- `.env.domain-sample` - Template for domain configuration files
4. Updated Documentation
- `Design_Doc/Spec.md` - Added simplified domain config format with example
- `.env.sample` - Added note clarifying it's for proxy instance setup
How It Works Now
When you run with Traefik container running:
1 [INFO] Loading domain config from .env-event-cgu-org-hk
2 [INFO] Detected running Traefik reverse proxy
3 [INFO] Auto-detected FRP mode: false (from running container)
4 [INFO] Setting up new domain in Traefik mode...
- in scenario of proxy running, no matter have or not have `.env-<domain>`, it will execute the "Add domain" task. However, one of domain, eg. my.domain.com, has already added into reverse proxy instance, this command `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash` is executed again, does it re-insert the same command into reverse proxy instance? Let me the current logic, and update into the `Design_Doc/Operation.md` if does not has this description before. - in scenario of proxy running, no matter have or not have `.env-<domain>`, it will execute the "Add domain" task. However, one of domain, eg. my.domain.com, has already added into reverse proxy instance, this command `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash` is executed again, does it re-insert the same command into reverse proxy instance? Let me the current logic, and update into the `Design_Doc/Operation.md` if does not has this description before.
- Result -- Design_Doc/Operations.md -> section: "Re-running for Existing Domain" - Result -- Design_Doc/Operations.md -> section: "Re-running for Existing Domain"

View File

@ -1,5 +1,62 @@
- Before Starting Any Work, Please read the following documents carefully **before taking any actions** on this project: `Readme.md`, `Design_Doc/Spec.md`, `Design_Doc/Operation.md` and `Design_Doc/Tech_Desc.md` **Exception:** You may skip the "AI Prompt" section. These files provide essential background information and project understanding. Only after reviewing them should you proceed with the following tasks. # Before Starting Any Work
- Please read the following documents carefully **before taking any actions** on this project: `README.md`, `Design_Doc/Spec.md`, `Design_Doc/Operations.md` and `Design_Doc/Tech_Desc.md`. You may skip the `Design_Doc/Tech_Desc.md` -> "AI Prompt" section and its sub-sections when reading. These files provide essential background information and project understanding. Only after reviewing them should you proceed with the following tasks.
- <any your prompt msg> # Your Current Tasks
- Listing the specific tasks for this session.
- Upon completion of the code changes specified above, you MUST update all affected documentation to reflect the modifications. This includes, where applicable: `Readme.md`, `Design_Doc/Spec.md`, `Design_Doc/Operation.md` and `Design_Doc/Tech_Desc.md` except the "AI Prompt" section and its child sections, that means skip and untouch this "AI Prompt" section including all its child sections. Each file MUST be updated in accordance with its designated purpose and content guidelines. These guidelines are defined in the "Documentation Overview" section of `Readme.md`. # Quick Reminder: Update the Documents After You Change the Code
Whenever you finish making code changes, please take a few minutes to update the related documents.
This keeps everything clear and up-to-date for everyone on the team.
## Which files might need an update?
Only touch the files that your changes actually affect. The most common ones are:
- `README.md`
- `Design_Doc/Spec.md`
- `Design_Doc/Operations.md`
- `Design_Doc/Tech_Desc.md`
## How should you update them?
Just follow the style and purpose each file already has.
(You can check the "Documentation Overview" part in `README.md` if you're not sure.)
---
## ⚠️ CRITICAL RULE for `Design_Doc/Tech_Desc.md` - The "AI Prompt" Section
**The "AI Prompt" section at the end of `Design_Doc/Tech_Desc.md` must NEVER be modified, deleted, or rewritten by you.**
### What is the "AI Prompt" section?
- It is the section that starts with `# AI Prompt` (level-1 heading)
- It is always located at the **very end** of `Design_Doc/Tech_Desc.md`
- It contains sub-sections like `## AI Prompt habit as a reminder`, `## Script Code`, `## Doc.`
- It contains **task history and instructions from previous sessions** written by the user
### Why must you NOT touch it?
- This section is **written and maintained by the user only**
- It contains **accumulated task history** that the user wants to preserve
- It is **not documentation** about the project - it is a **working log of tasks**
- Other team members (including the user) will update this section manually when needed
### What you MUST do:
✅ **Leave the "AI Prompt" section completely unchanged**
✅ **Keep the exact content** that is currently there (do not revert, do not update, do not clean up)
✅ **Only edit the technical documentation sections** that come BEFORE the "AI Prompt" section
✅ **Ensure "AI Prompt" stays at the end** of the file (do not move it)
### What you MUST NOT do:
❌ **Do NOT delete** the "AI Prompt" section
❌ **Do NOT modify** any words, sentences, or formatting inside "AI Prompt"
❌ **Do NOT revert** it to an older version
❌ **Do NOT clean up** or reorganize its content
❌ **Do NOT add** new task results to it (the user does this manually)
❌ **Do NOT remove** task history from it
### Simple rule to remember:
> **Everything before `# AI Prompt` = Your responsibility to update**
> **Everything from `# AI Prompt` to the end = User's responsibility, DO NOT TOUCH**
---
Thank you so much for helping keep the documents accurate and the task history preserved — it makes a big difference to the whole team!

View File

@ -40,11 +40,14 @@ DEPLOY_MODE=""
# Domain configuration file pattern: .env-your-domain-com # Domain configuration file pattern: .env-your-domain-com
DOMAIN_ENV_FILE="" DOMAIN_ENV_FILE=""
# Array to store all domain configuration files for batch processing
declare -a DOMAIN_ENV_FILES=()
# Function to load environment variables from .env files # Function to load environment variables from .env files
load_env() { load_env() {
local proxy_env_loaded=false local proxy_env_loaded=false
local domain_env_loaded=false local domain_env_loaded=false
# Step 1: Load reverse proxy instance configuration from .env # Step 1: Load reverse proxy instance configuration from .env
# Check for .env files in priority order: .env.development, .env.production, .env # Check for .env files in priority order: .env.development, .env.production, .env
if [ -f ".env.development" ]; then if [ -f ".env.development" ]; then
@ -72,58 +75,87 @@ load_env() {
source "$(dirname "$0")/.env" source "$(dirname "$0")/.env"
proxy_env_loaded=true proxy_env_loaded=true
fi fi
# Step 2: Look for domain-specific configuration files (.env-* pattern) # Step 2: Collect all domain-specific configuration files (.env-* pattern)
# These files contain domain-specific settings like DOMAIN_NAME, LOCAL_SERVICE_NAME, LOCAL_SERVICE_PORT # These files contain domain-specific settings like DOMAIN_NAME, LOCAL_SERVICE_NAME, LOCAL_SERVICE_PORT
# Pattern matches any domain format: .env-example-com, .env-sub-domain-org-hk, etc. # Pattern matches any domain format: .env-example-com, .env-sub-domain-org-hk, etc.
# All found files will be processed in batch mode
for env_file in .env-*; do for env_file in .env-*; do
# Skip .env.development and .env.production # Skip .env.development and .env.production
if [ "$env_file" = ".env.development" ] || [ "$env_file" = ".env.production" ]; then if [ "$env_file" = ".env.development" ] || [ "$env_file" = ".env.production" ]; then
continue continue
fi fi
if [ -f "$env_file" ]; then if [ -f "$env_file" ]; then
echo -e "${BLUE}[INFO]${NC} Loading domain config from $env_file" >&2 DOMAIN_ENV_FILES+=("$env_file")
source "$env_file"
domain_env_loaded=true
DOMAIN_ENV_FILE="$env_file"
break # Load only the first domain file found
fi fi
done done
# Determine deployment mode based on what configuration files exist # Load the first domain file for initial variable setup (backward compatibility)
if [ ${#DOMAIN_ENV_FILES[@]} -gt 0 ]; then
echo -e "${BLUE}[INFO]${NC} Loading domain config from ${DOMAIN_ENV_FILES[0]}" >&2
source "${DOMAIN_ENV_FILES[0]}"
domain_env_loaded=true
DOMAIN_ENV_FILE="${DOMAIN_ENV_FILES[0]}"
if [ ${#DOMAIN_ENV_FILES[@]} -gt 1 ]; then
log_info "Found ${#DOMAIN_ENV_FILES[@]} domain config files, will process all in batch mode"
fi
fi
# Step 3: Detect proxy mode from running containers
# This allows domain setup even without .env file, by detecting running proxy
# IMPORTANT: Running container detection takes precedence over .env settings
local proxy_running=false
local detected_frp_mode=""
# Check if Traefik is running (takes precedence)
if docker ps --filter name=^traefik$ --format '{{.Names}}' | grep -q "^traefik$"; then
proxy_running=true
detected_frp_mode="false"
log_info "Detected running Traefik reverse proxy"
fi
# Check if FRP client is running (look for any *-frpc container)
local frpc_containers=$(docker ps --filter name="-frpc$" --format '{{.Names}}' 2>/dev/null || true)
if [ -n "$frpc_containers" ]; then
# FRP container found, extract instance name from first container
local first_frpc=$(echo "$frpc_containers" | head -1)
INSTANCE_NAME="${first_frpc%-frpc}"
proxy_running=true
# Only set FRP mode if Traefik is not detected (Traefik takes precedence)
if [ -z "$detected_frp_mode" ]; then
detected_frp_mode="true"
log_info "Detected running FRP client container: ${first_frpc} (instance: ${INSTANCE_NAME})"
# Load FRP configuration from volume if .env not loaded
if [ "$proxy_env_loaded" = false ]; then
load_frp_config_from_volume "$INSTANCE_NAME"
fi
fi
fi
# ALWAYS use detected FRP mode when proxy is running (override .env settings)
# This ensures the script uses the actual running proxy mode, not stale config
if [ "$proxy_running" = true ] && [ -n "$detected_frp_mode" ]; then
FRP="$detected_frp_mode"
log_info "Auto-detected FRP mode: $FRP (from running container)"
fi
# Determine deployment mode based on what configuration files exist and running proxy
if [ "$domain_env_loaded" = true ]; then if [ "$domain_env_loaded" = true ]; then
# Domain config exists - setup new domain # Domain config exists - setup new domain
DEPLOY_MODE="domain" DEPLOY_MODE="domain"
log_info "Deployment mode: Setup New Domain (found domain config: ${DOMAIN_ENV_FILE})" log_info "Deployment mode: Setup New Domain (found domain config: ${DOMAIN_ENV_FILE})"
elif [ "$proxy_running" = true ]; then
# Proxy is running (detected from containers) - setup new domain via wizard if no domain config
DEPLOY_MODE="domain_wizard"
log_info "Deployment mode: Setup New Domain (proxy running, no domain config)"
elif [ "$proxy_env_loaded" = true ]; then elif [ "$proxy_env_loaded" = true ]; then
# Only proxy config exists - check if proxy is already running # Proxy config exists but proxy not running - setup proxy
local proxy_exists=false DEPLOY_MODE="proxy"
if [ "$FRP" = "false" ] || [ "$FRP" = "False" ] || [ "$FRP" = "FALSE" ]; then log_info "Deployment mode: Setup Reverse Proxy (config exists, proxy not running)"
FRP=false
if docker ps -a --filter name=^traefik$ --format '{{.Names}}' | grep -q "^traefik$"; then
proxy_exists=true
fi
else
FRP=true
if [ -n "$INSTANCE_NAME" ]; then
local frpc_container="${INSTANCE_NAME}-frpc"
if docker ps -a --filter name=^${frpc_container}$ --format '{{.Names}}' | grep -q "^${frpc_container}$"; then
proxy_exists=true
fi
fi
fi
if [ "$proxy_exists" = true ]; then
# Proxy exists but no domain config - need domain setup via wizard
DEPLOY_MODE="domain_wizard"
log_info "Deployment mode: Setup New Domain (proxy running, no domain config)"
else
# Proxy config exists but proxy not running - setup proxy
DEPLOY_MODE="proxy"
log_info "Deployment mode: Setup Reverse Proxy (config exists, proxy not running)"
fi
else else
# No configuration files found - run interactive wizard # No configuration files found and no proxy running - run interactive wizard
echo -e "${YELLOW}[INFO]${NC} No configuration file found." >&2 echo -e "${YELLOW}[INFO]${NC} No configuration file found." >&2
interactive_setup_wizard interactive_setup_wizard
# Source the newly created files # Source the newly created files
@ -1082,7 +1114,138 @@ extract_all_remote_ports() {
echo "${ports[@]}" echo "${ports[@]}"
} }
# Function to execute Docker commands locally (Traefik Mode - runs on same server) # Function to load FRP configuration from volume (when .env is missing)
load_frp_config_from_volume() {
local instance_name="$1"
local volume_name="${instance_name}-frpc"
local temp_container="temp-load-config-$(date +%s)"
log_info "Loading FRP configuration from volume: $volume_name"
# Create a temporary container to check for existing config
if docker volume inspect "$volume_name" >/dev/null 2>&1; then
if docker run --rm -d --name "$temp_container" -v "$volume_name:/etc/frp" alpine:latest sleep 10 >/dev/null 2>&1; then
if docker exec "$temp_container" test -f /etc/frp/frpc.toml >/dev/null 2>&1; then
# Extract server address and port from frpc.toml
local server_addr=$(docker exec "$temp_container" grep "^serverAddr" /etc/frp/frpc.toml | cut -d'"' -f2 || true)
local server_port=$(docker exec "$temp_container" grep "^serverPort" /etc/frp/frpc.toml | cut -d'=' -f2 | tr -d ' ' || true)
if [ -n "$server_addr" ]; then
FRP_SERVER_ADDR="$server_addr"
log_info "Loaded FRP_SERVER_ADDR from volume: $FRP_SERVER_ADDR"
fi
if [ -n "$server_port" ]; then
FRP_SERVER_PORT="$server_port"
log_info "Loaded FRP_SERVER_PORT from volume: $FRP_SERVER_PORT"
fi
fi
docker stop "$temp_container" >/dev/null 2>&1
fi
fi
}
# Function to generate a new remote port for domain setup (FRP Mode)
generate_remote_port() {
if [ "$FRP" = false ]; then
log_info "Skipping remote port generation as FRP=false"
return 0
fi
# Get existing remote ports to avoid conflicts
local existing_ports
existing_ports=$(extract_all_remote_ports)
# Start from a base port (e.g., 12000) and find an available port
local base_port=12000
local new_port=$base_port
# Check if any existing ports conflict
while echo "$existing_ports" | grep -qw "$new_port"; do
new_port=$((new_port + 1))
done
echo "$new_port"
}
# Function to update frpc.toml with new domain proxy configuration (FRP Mode)
update_frpc_config_for_domain() {
local new_remote_port="$1"
if [ "$FRP" = false ]; then
log_info "Skipping frpc.toml update as FRP=false"
return 0
fi
log_info "Updating frpc.toml with new domain proxy configuration..."
local volume_name="${THIS_INSTANCE}-frpc"
local temp_container="temp-update-config-$(date +%s)"
local temp_dir="/tmp/frpc-update-${THIS_INSTANCE}"
# Create temporary directory
mkdir -p "$temp_dir"
# Get existing configuration
local existing_config=""
if docker volume inspect "$volume_name" >/dev/null 2>&1; then
if docker run --rm -d --name "$temp_container" -v "$volume_name:/etc/frp" alpine:latest sleep 10 >/dev/null 2>&1; then
if docker exec "$temp_container" test -f /etc/frp/frpc.toml >/dev/null 2>&1; then
existing_config=$(docker exec "$temp_container" cat /etc/frp/frpc.toml)
fi
docker stop "$temp_container" >/dev/null 2>&1
fi
fi
# Get server address and port from existing config or environment
local server_addr="${FRP_SERVER_ADDR}"
local server_port="${FRP_SERVER_PORT:-16999}"
if [ -z "$existing_config" ]; then
# No existing config, create new one
log_info "Creating new frpc.toml configuration"
existing_config="serverAddr = \"${server_addr}\"\nserverPort = ${server_port}\n\n"
fi
# Generate proxy name from domain
local proxy_name
proxy_name=$(echo "$DOMAIN_NAME" | sed 's/\./-/g' | tr '[:upper:]' '[:lower:]')
# Add new proxy configuration for this domain
local new_proxy_config
new_proxy_config="[[proxies]]\n"
new_proxy_config+="name = \"${proxy_name}-${THIS_INSTANCE}\"\n"
new_proxy_config+="type = \"tcp\"\n"
new_proxy_config+="localPort = ${LOCAL_SERVICE_PORT}\n"
if [ -n "$SERVICE_DOCKER_CONTAINER_NAME" ]; then
new_proxy_config+="localIP = \"${SERVICE_DOCKER_CONTAINER_NAME}\"\n"
else
new_proxy_config+="localIP = \"${THIS_INSTANCE}-app\"\n"
fi
new_proxy_config+="remotePort = ${new_remote_port}\n\n"
# Append new proxy config to existing config
local full_config="${existing_config}${new_proxy_config}"
# Write the config to a temporary file
echo -e "$full_config" > "${temp_dir}/frpc.toml"
# Create the volume if it doesn't exist
docker volume create "$volume_name" >/dev/null 2>&1 || true
# Copy the config file to the volume
docker run --rm -v "$volume_name:/etc/frp" -v "${temp_dir}:/tmp/source:ro" alpine:latest cp /tmp/source/frpc.toml /etc/frp/frpc.toml
# Clean up
rm -rf "$temp_dir"
# Restart the FRP client container to apply new configuration
log_info "Restarting FRP client container to apply new configuration..."
docker restart "${THIS_INSTANCE}-frpc" >/dev/null 2>&1
log_info "frpc.toml configuration updated successfully"
}
# Function to execute Docker commands locally (Traefik Mode)
local_docker_exec() { local_docker_exec() {
local command="$1" local command="$1"
log_debug "Executing local Docker command: $command" log_debug "Executing local Docker command: $command"
@ -2071,7 +2234,7 @@ setup_reverse_proxy() {
setup_new_domain() { setup_new_domain() {
log_info "Setting up new domain: ${DOMAIN_NAME}" log_info "Setting up new domain: ${DOMAIN_NAME}"
log_info "Domain configuration loaded from: ${DOMAIN_ENV_FILE:-.env}" log_info "Domain configuration loaded from: ${DOMAIN_ENV_FILE:-.env}"
if [ "$FRP" = false ]; then if [ "$FRP" = false ]; then
# Check if Traefik is running # Check if Traefik is running
if ! docker ps --filter name=^traefik$ --format '{{.Names}}' | grep -q "^traefik$"; then if ! docker ps --filter name=^traefik$ --format '{{.Names}}' | grep -q "^traefik$"; then
@ -2079,20 +2242,74 @@ setup_new_domain() {
log_error "Please ensure the reverse proxy is setup first" log_error "Please ensure the reverse proxy is setup first"
exit 1 exit 1
fi fi
# Check if Application Service exists locally # Check if Application Service exists locally
if ! check_app_service_local; then if ! check_app_service_local; then
log_error "Application Service not found locally. Please ensure the service '$LOCAL_SERVICE_NAME' is running." log_error "Application Service not found locally. Please ensure the service '$LOCAL_SERVICE_NAME' is running."
exit 1 exit 1
fi fi
# Configure the new domain in Traefik # Configure the new domain in Traefik
configure_traefik_local configure_traefik_local
log_info "New domain ${DOMAIN_NAME} has been configured in Traefik" log_info "New domain ${DOMAIN_NAME} has been configured in Traefik"
log_info "Service will be accessible at: https://${DOMAIN_NAME}" log_info "Service will be accessible at: https://${DOMAIN_NAME}"
else else
log_error "Domain setup for FRP mode is not yet implemented" # FRP Mode domain setup
exit 1 log_info "Setting up new domain in FRP mode..."
# Ensure INSTANCE_NAME is set (from .env or detected from running container)
if [ -z "$INSTANCE_NAME" ]; then
# Try to detect from running FRP containers
local frpc_containers=$(docker ps --filter name="-frpc$" --format '{{.Names}}' 2>/dev/null || true)
if [ -n "$frpc_containers" ]; then
local first_frpc=$(echo "$frpc_containers" | head -1)
INSTANCE_NAME="${first_frpc%-frpc}"
log_info "Detected instance name from running container: ${INSTANCE_NAME}"
else
log_error "INSTANCE_NAME is not set and no FRP container detected."
log_error "Please ensure your .env file contains the reverse proxy configuration."
exit 1
fi
fi
THIS_INSTANCE="$INSTANCE_NAME"
log_info "Using instance name: ${THIS_INSTANCE}"
# Check if FRP client container is running
local frpc_container="${THIS_INSTANCE}-frpc"
if ! docker ps --filter name=^${frpc_container}$ --format '{{.Names}}' | grep -q "^${frpc_container}$"; then
log_error "FRP client container '${frpc_container}' is not running!"
log_error "Please ensure the reverse proxy is setup first"
exit 1
fi
# Check if Application Service exists locally
if ! check_app_service_local; then
log_error "Application Service not found locally. Please ensure the service '$LOCAL_SERVICE_NAME' is running."
exit 1
fi
# Generate a new remote port for this domain
local new_remote_port
new_remote_port=$(generate_remote_port)
log_info "Generated remote port ${new_remote_port} for domain ${DOMAIN_NAME}"
# Update frpc.toml with the new proxy configuration
update_frpc_config_for_domain "$new_remote_port"
# Update proxy server configuration
local server_addr
server_addr=$(extract_frp_server_address)
if [ -z "$server_addr" ]; then
log_error "Failed to extract FRP server address from configuration"
exit 1
fi
log_info "Updating proxy server configuration at ${server_addr}..."
update_proxy_server_config "$server_addr" "true" "$new_remote_port"
log_info "New domain ${DOMAIN_NAME} has been configured in FRP tunnel"
log_info "Service will be accessible at: https://${DOMAIN_NAME}"
fi fi
} }
@ -2325,14 +2542,59 @@ main() {
usage usage
exit 0 exit 0
fi fi
# Load environment variables from .env files (or trigger interactive wizard) # Load environment variables from .env files (or trigger interactive wizard)
load_env load_env
# Execute based on detected deployment mode # Execute based on detected deployment mode
if [ "$DEPLOY_MODE" = "domain" ]; then if [ "$DEPLOY_MODE" = "domain" ]; then
log_info "Setting up new domain in existing reverse proxy..." log_info "Setting up new domain in existing reverse proxy..."
setup_new_domain
# Process all domain config files in batch mode
if [ ${#DOMAIN_ENV_FILES[@]} -gt 0 ]; then
local total=${#DOMAIN_ENV_FILES[@]}
local count=0
for env_file in "${DOMAIN_ENV_FILES[@]}"; do
count=$((count + 1))
# Skip .env.development and .env.production
if [ "$env_file" = ".env.development" ] || [ "$env_file" = ".env.production" ]; then
continue
fi
echo "" >&2
log_info "========================================="
log_info "Processing domain $count of $total: $env_file"
log_info "========================================="
echo "" >&2
# Source the domain config file
source "$env_file"
DOMAIN_ENV_FILE="$env_file"
# Validate domain config
if [ -z "$DOMAIN_NAME" ]; then
log_error "DOMAIN_NAME is required in $env_file"
continue
fi
if [ -z "$LOCAL_SERVICE_NAME" ] || [ -z "$LOCAL_SERVICE_PORT" ]; then
log_error "LOCAL_SERVICE_NAME and LOCAL_SERVICE_PORT are required in $env_file"
continue
fi
# Setup the domain
setup_new_domain
done
echo "" >&2
log_info "========================================="
log_info "Batch processing completed: $count domain(s) processed"
log_info "========================================="
else
# Fallback for backward compatibility
setup_new_domain
fi
elif [ "$DEPLOY_MODE" = "domain_wizard" ]; then elif [ "$DEPLOY_MODE" = "domain_wizard" ]; then
log_info "Starting interactive wizard for domain setup..." log_info "Starting interactive wizard for domain setup..."
interactive_setup_wizard interactive_setup_wizard