adding Setup External Service Domain

This commit is contained in:
chungyan5 2026-10-07 05:15:25 +08:00
parent 4cfd6443b9
commit ca25c9c850
6 changed files with 757 additions and 53 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
*.sh text eol=lf

View File

@ -1277,6 +1277,36 @@
## make a generic rvs-prxy system
- Using codebase `C:\Users\Yan\ws\cmptr-infra\traefik-mech-win11`; You evaluate this code; Currently, it has outcome like below:
```
curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
[INFO] Detected running Traefik reverse proxy
...
Select option [1-2] (default: 1 for Domain):
Selected: Setup New Domain
--- Setup New Domain ---
Let's configure a new domain for your existing reverse proxy.
Enter the domain name for this service:
Domain (e.g., app.example.com): www.sendbox.com.hk
Enter your Docker application container name:
Service name (e.g., my-app):
```
- the current operation as connecting a domain to local docker container (Service). You understand how it works. Then i aim to add a selection as current "Docker application container" or a new function as let traefik connect a domain, eg. app.example.com, to another web service, eg. https://cornersendbox-impact-vms.lovable.app/.
- I have these two .env files, how can i select .env-ext-sendbox-com-hk to run?
```
.env-ext-sendbox-com-hk
.env-ext-www-sendbox-com-hk
deploy-rvs-prxy.sh
---
cat .env-ext-sendbox-com-hk
DOMAIN_NAME="sendbox.com.hk"
EXTERNAL_URL="https://cornersendbox-impact-vms.lovable.app/"
```
- In a case, i have two domains name, that means two .env-www-domain-com and .env-domain-com, their service are same to one container, say web-fe-1, i find it has one domain work, another does not. I see the reason as: it has two dynamic configuration files inside /etc/traefik/config/, say app-service-www.domain.com-web-fe-1.yml, and app-service-domain.com-web-fe-1.yml, inside them, the routers are same names, say web-fe-1-https and web-fe-1-http, the services name are same too, say web-fe-1-service. By observation, the names format of routers and services is container-name-https, container-name-http and container-name-service. So i aim to improve this name format rule, do not use container-name, it may share to diff. domains, so should use domain name inside the rule, eg. domain-name-https, domain-name-http, domain-name-service, etc.
- Currently .env-p2prly1-ivantito-com as:

View File

@ -49,6 +49,8 @@ curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
2. Application service name (Docker container name)
3. Application service port
(Select `1) Setup New Domain` from the setup menu. Options `2) Setup Port Exposure` and `3) Setup External Service Domain` are covered in Step 4 and Step 5.)
**What Happens:**
- **Checks if your application service is running**
- Creates `.env-<domain>` with domain settings
@ -112,6 +114,58 @@ You can setup multiple port exposures at once by creating multiple `.env-port-*`
```
The script will process all port configuration files in batch mode.
### Step 5: Setup External Service Domain (Route a Domain to an External Web Service)
Use this mode when the upstream is **not** a local container on this host but an existing web service reached by URL (a hosted app, SaaS, or another server). No local container is required.
```bash
curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
```
**The wizard will ask you (External service settings only):**
1. Domain name, sub-path optional (e.g., `box.example.com` or `box.example.com/api`)
2. External service URL (e.g., `https://cornersendbox-impact-vms.lovable.app/`)
**What Happens:**
- **Checks if Traefik reverse proxy is running** (Traefik mode only -- FRP is not supported for HTTP routing)
- Creates `.env-ext-<domain>` with the domain and external URL
- Writes a dynamic Traefik config that terminates TLS for the public domain and forwards to the external URL
- Obtains a Let's Encrypt certificate for the public domain
**Configuration File Created:**
- `.env-ext-<domain>` - External service configuration (e.g., `.env-ext-box-example-com-api`)
**Example `.env-ext-box-example-com-api`:**
```bash
DOMAIN_NAME="box.example.com/api"
EXTERNAL_URL="https://cornersendbox-impact-vms.lovable.app/"
```
**Example output:**
```
[INFO] Setup External Service Domain
[INFO] New external service domain has been configured: box.example.com/api
[INFO] Public URL: https://box.example.com/api
[INFO] Forwarding to: https://cornersendbox-impact-vms.lovable.app
```
**Routing Semantics:**
- `https://box.example.com/api/x` → `https://cornersendbox-impact-vms.lovable.app/x` (public sub-path stripped, origin base path added)
- The origin receives its own `Host` header (`passHostHeader: false`), so the upstream must accept the request by its own hostname
- Origin TLS is verified with the system trust store; no `insecureSkipVerify` is generated
- Origin default port is `443` for `https` and `80` for `http` unless a port is present in the URL
**Batch Processing:**
Create multiple `.env-ext-*` files to publish several external services in one run:
```
.env-ext-box-example-com-api
.env-ext-demo-example-net
```
**Troubleshooting:**
- The script checks whether the external hostname resolves and only warns if it does not; note that Traefik resolves the name itself, inside its container
### Alternative: Using Configuration Files Directly
**For Reverse Proxy Setup:**
@ -189,12 +243,39 @@ The script supports port-based routing without domain names:
[INFO] Processing port 2 of 2: .env-port-18082
[INFO] =========================================
...
[INFO] Batch processing completed: 2 port(s) processed
```
[INFO] Batch processing completed: 2 port(s) processed
```
### Step 5: Manage Existing Configurations (Optional)
**For External Service Setup:**
To view and remove existing domain or port configurations:
The script supports routing a domain to an external web service URL:
1. **With `.env-ext-<domain>` file:**
- Create `.env-ext-<domain>` file with the domain and external URL
- Ensure Traefik reverse proxy is running
- Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash`
2. **Batch processing (multiple external services):**
- Create multiple `.env-ext-*` files in the same directory
- Ensure Traefik reverse proxy is running
- Run: `curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash`
- Script automatically processes all `.env-ext-*` files in batch mode
- Example output:
```
[INFO] Found 2 external service config files, will process all in batch mode
[INFO] =========================================
[INFO] Processing external service 1 of 2: .env-ext-box-example-com-api
[INFO] =========================================
[INFO] Setting up external service domain: box.example.com/api
...
[INFO] Batch processing completed: 2 external service(s) processed
```
3. **Mode precedence:** if `.env-port-*` files exist, the script runs port batch processing and skips domain and external service files (same precedence as before: port, then external service, then domain)
### Step 6: Manage Existing Configurations (Optional)
To view and remove existing domain, external service or port configurations:
```bash
curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash -s -- --manage
@ -202,9 +283,11 @@ curl -s "https://www.ivantito.com/app-pub/demos/test/deploy-rvs-prxy.sh" | bash
**What Happens:**
- Lists all current domain configurations (`.env-<domain>` files)
- Lists all current external service configurations (`.env-ext-<domain>` files)
- Lists all current port configurations (`.env-port-<port>` files)
- Prompts you to select which configurations to remove (enter numbers separated by space)
- **For domains**: Removes the configuration file AND removes the routing config from Traefik
- **For external services**: Removes the configuration file AND removes the routing config from Traefik
- **For ports**: Removes the configuration file, removes the routing config from Traefik, removes the entry point, and recreates Traefik container without that port
**Example Output:**
@ -223,25 +306,24 @@ Ports:
3. .env-port-18081 - Host port 18081 -> nginx-container
4. .env-port-18082 - Host port 18082 -> api-container
Select configurations to remove (enter numbers separated by space, or 'q' to quit): 1 3
External Services:
5. .env-ext-box-example-com-api - box.example.com/api -> https://cornersendbox-impact-vms.lovable.app
Select configurations to remove (enter numbers separated by space, or 'q' to quit): 1 5
[INFO] Removing: .env-app-example-com
[INFO] Removing domain config from Traefik: app.example.com
[INFO] Removed: .env-app-example-com
[INFO] Removing: .env-port-18081
[INFO] Removing port config from Traefik: port 18081
[INFO] Removed: .env-port-18081
[INFO] Updating Traefik container to remove entry points...
[INFO] Stopping Traefik container...
[INFO] Traefik container recreated without removed entry points
[INFO] Configuration cleanup complete.
[INFO] Removing: .env-ext-box-example-com-api
[INFO] Removing external service config from Traefik: box.example.com/api
[INFO] Removed: .env-ext-box-example-com-api
```
**Important Notes:**
- Removing a port configuration will restart the Traefik container (brief downtime ~5 seconds)
- Domain removal does not require Traefik restart (dynamic config removal)
- Domain and external service removal does not require Traefik restart (dynamic config removal)
- All changes are permanent and cannot be undone - make sure you want to remove before confirming
### Step 6: Configure Extra Traefik Entrypoints (QUIC, Custom Ports, etc.)
### Step 7: Configure Extra Traefik Entrypoints (QUIC, Custom Ports, etc.)
Beyond the default entrypoints (`web` on :80, `websecure` on :443), you can add extra entrypoints such as HTTP/3 QUIC (UDP 443) or other custom protocols. Entrypoints are defined via command-line arguments to the Traefik container, so the container must be recreated to apply them.
@ -536,12 +618,17 @@ If environment variables are not set, the script will prompt for:
- Domain name for routing
- Docker network selection
When the wizard runs for an existing proxy, the setup menu offers three options:
- `1) Setup New Domain` - routes the domain to a local Docker container
- `2) Setup Port Exposure` - exposes a host port to a container port
- `3) Setup External Service Domain` - routes the domain to an external web service URL (asks for domain and URL only)
### Container Management Commands
#### Traefik Container (Traefik Mode)
**Entrypoints:**
Default entrypoints are `web` (:80) and `websecure` (:443). See **[Step 6: Configure Extra Traefik Entrypoints](#step-6-configure-extra-traefik-entrypoints-quic-custom-ports-etc)** for a complete guide on adding/removing extra entrypoints (QUIC, custom ports, etc.) during both first-time setup and on a running Traefik container.
Default entrypoints are `web` (:80) and `websecure` (:443). See **[Step 7: Configure Extra Traefik Entrypoints](#step-7-configure-extra-traefik-entrypoints-quic-custom-ports-etc)** for a complete guide on adding/removing extra entrypoints (QUIC, custom ports, etc.) during both first-time setup and on a running Traefik container.
```bash
# Start/run container

View File

@ -7,18 +7,20 @@
- `.env-your-domain2-com` -- **parameters for the domain your.domain2.com of your Application**
- `.env-your-domainN-com` -- **parameters for the domain your.domainN.com of your Application**
- `.env-port-<port>` -- **parameters for port-based routing (e.g., .env-port-18081)**
- Assume your "Application" is already existing.
- `.env-ext-your-domain-com` -- **parameters for routing a domain to an external web service URL (e.g. .env-ext-app-example-com)**
- Assume your "Application" is already existing. (For external service routing there is no local Application - an upstream URL is used instead.)
### Key Capabilities
- **Separate Configuration Files**: `.env.rvs-prxy` for reverse proxy instance, `.env-your-domain-com` (or any domain format) for each domain, `.env-port-<port>` for port-based routing
- **Separate Configuration Files**: `.env.rvs-prxy` for reverse proxy instance, `.env-your-domain-com` (or any domain format) for each domain, `.env-port-<port>` for port-based routing, `.env-ext-your-domain-com` for external service routing
- **Interactive Setup Wizard**: Guided configuration when no configuration files exist
- **Automatic Mode Detection**: Automatically detects whether to setup reverse proxy, add new domain, or setup port exposure
- **Three Deployment Modes**:
- **Automatic Mode Detection**: Automatically detects whether to setup reverse proxy, add new domain, setup port exposure, or route a domain to an external service
- **Four Deployment Modes**:
- **Setup Reverse Proxy**: Deploys Traefik or FRP Tunnel with Traefik
- **Setup New Domain**: Adds new domain to existing reverse proxy (supports both Traefik and FRP modes)
- **Setup New Domain**: Adds new domain to existing reverse proxy, routed to a local Docker application container (supports both Traefik and FRP modes)
- **Setup Port Exposure**: Exposes host port to connect directly to container port (Traefik mode only)
- **Batch Processing**: Automatically processes multiple `.env-<domain>` and `.env-port-*` files in a single run
- **Setup External Service Domain**: Routes a domain to an external web service URL - no local container required (Traefik mode only)
- **Batch Processing**: Automatically processes multiple `.env-<domain>`, `.env-port-*` and `.env-ext-*` files in a single run
- **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 Domain Setup**: Add new domains to existing FRP tunnel by allocating new remote ports and updating proxy server configuration
@ -26,6 +28,7 @@
- **Docker Integration**: Seamless integration with Docker containers and networks
- **HTTPS/TLS Support**: Automatic SSL certificate management via Let's Encrypt
- **Port-Based Routing**: Direct host port to container port routing without domain names
- **External Service Routing**: Public domain with automatic Let's Encrypt certificate, TLS terminated by Traefik and proxied to an upstream HTTPS/HTTP URL; origin receives its own `Host` header, and path mapping (sub-path strip / origin base-path add) is automatic
### Workflow
@ -44,6 +47,13 @@
- **Checks if application service is running**
- Configures domain in existing reverse proxy
3. **Add external service domain (proxy running)**: Setup External Service Domain
- Same as step 2, but the upstream is an external web service URL instead of a local container
- Interactive wizard asks for domain name and external service URL (if no `.env-ext-<domain>` exists)
- Creates `.env-ext-<domain>` with `DOMAIN_NAME` and `EXTERNAL_URL`
- **No application service check** (no local container is involved)
- Configures the domain in the existing Traefik proxy (Traefik mode only)
**Proxy Mode Detection:**
- Script automatically detects running proxy from Docker containers
- Traefik mode: detects `traefik` container
@ -102,6 +112,14 @@
- Accepts any domain format: `.com`, `.net`, `.org`, `.org.hk`, `.com.hk`, subdomains, etc.
- **Simplified format:** Only requires 3 variables (see below)
**External Service Configuration (`.env-ext-<domain>`):**
- Pattern: `.env-ext-<domain-with-dashes>` (e.g., `.env-ext-app-example-com`, `.env-ext-box-example-com-api`)
- Contains routing settings for a public domain forwarded to an external web service URL (DOMAIN_NAME, EXTERNAL_URL)
- One file per domain
- Multiple external service files can coexist
- Traefik mode only (no FRP support - FRP tunnels TCP ports, not HTTP routing)
- **Simplified format:** Only requires 2 variables (see below)
#### Key Environment Variables
**Domain-Specific Configuration (`.env-<domain>`):**
@ -169,6 +187,29 @@ CONTAINER_PORT="80"
- Access services via `http://<host-ip>:<port>` without domain name routing
- Example: `http://this-host:18081` → connects to container port 80
**External Service Configuration (`.env-ext-<domain>`):**
**Required Variables (only 2):**
- `DOMAIN_NAME` - Public domain handled by this proxy, optional sub-path allowed (e.g., `app.example.com` or `box.example.com/api`)
- `EXTERNAL_URL` - Full upstream URL of the external web service (e.g., `https://service.example.net/` or `https://service.example.net:8443/api`)
**Example `.env-ext-box-example-com-api`:**
```bash
DOMAIN_NAME="box.example.com/api"
EXTERNAL_URL="https://cornersendbox-impact-vms.lovable.app/"
```
**Routing Semantics:**
- Scheme is derived from `EXTERNAL_URL`; an `https` origin is contacted over TLS with full certificate verification (no `insecureSkipVerify`)
- Default origin port: `443` for `https`, `80` for `http`; a port in `EXTERNAL_URL` overrides it
- `passHostHeader: false` - the origin receives the upstream host, not the public domain
- `DOMAIN_NAME` may carry a sub-path: the sub-path is stripped before forwarding and any base path in `EXTERNAL_URL` is added back, so `https://box.example.com/api/x` → `https://cornersendbox-impact-vms.lovable.app/x`
- Automatic HTTPS via Let's Encrypt for the public domain; the origin certificate is verified, not managed
**Use Case:**
- Publish an existing web service (SaaS, hosted app, another server) on a domain handled by this proxy, without deploying a local container
- Example: `https://box.example.com/` → `https://cornersendbox-impact-vms.lovable.app/`
### Approaches
#### Traefik Only
@ -211,13 +252,14 @@ CONTAINER_PORT="80"
- HTTP to HTTPS redirect support
- Let's Encrypt SSL certificate automation
- Sub-path routing support (e.g., `example.com/api`)
- External service routing to a URL upstream (`.env-ext-<domain>`), with or without sub-path
- Non-destructive configuration updates (no restart required by default)
- Docker network integration (`traefik-public` network)
- **Pre-requisites:**
- Docker installed on the local server (same server where script runs)
- User has permission to execute Docker commands
- Local application container must be running and connected to `traefik-public` network
- Local application container must be running and connected to `traefik-public` network (not required for external service routing - no local container is involved)
#### Traefik + FRP

View File

@ -9,6 +9,8 @@ The `deploy-rvs-prxy.sh` script is an automated deployment tool supporting both
**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
3. **Setup Port Exposure**: Exposes a host port to a container port
4. **Setup External Service Domain**: Adds a domain routed to an external web service URL
**Configuration File Structure:**
- `.env.rvs-prxy` - Reverse proxy instance configuration (FRP mode, Traefik version, etc.)
@ -16,18 +18,23 @@ The `deploy-rvs-prxy.sh` script is an automated deployment tool supporting both
- 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
- `.env-ext-<domain>` - External service routing configuration (DOMAIN_NAME, EXTERNAL_URL)
- Filename pattern: Dots replaced with dashes (e.g., `box.example.com/api` → `.env-ext-box-example-com-api`)
- Multiple domain, port and external service files can coexist
**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` exists, proxy running, no domain/port/ext file → Interactive wizard for domain/port/external service setup
- `.env.rvs-prxy` + `.env-<domain>` exists → Setup New Domain
- `.env.rvs-prxy` + `.env-port-<port>` exists → Setup Port Exposure
- `.env.rvs-prxy` + `.env-ext-<domain>` exists → Setup External Service Domain
- Batch precedence when several types coexist: port files first, then external service files, then domain files
**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)
- **External Service Mode**: Validates DOMAIN_NAME and EXTERNAL_URL; requires Traefik mode (`FRP=false`), since FRP tunnels TCP ports rather than performing HTTP routing
**Workflow:**
@ -40,17 +47,18 @@ First Run (No .env.rvs-prxy):
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
2. Interactive wizard asks for domain, port or external service settings
3. Creates .env-<domain>, .env-port-<port> or .env-ext-<domain> with settings
4. Validation checks domain/port/external service settings
5. Checks if application service/container is running (skipped for external service routing)
6. Configures domain/port/external service in existing reverse proxy
7. Shows: "Service will be accessible at: https://domain.name or http://host-ip:port"
Three Deployment Modes:
Four Deployment Modes:
1. Setup Reverse Proxy - Deploys Traefik or FRP Tunnel
2. Setup New Domain - Adds domain-based routing
2. Setup New Domain - Adds domain-based routing to a local container
3. Setup Port Exposure - Adds port-based routing
4. Setup External Service Domain - Adds domain-based routing to an external URL (Traefik only)
### Core Components
@ -60,15 +68,16 @@ Three Deployment Modes:
- **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
- Supports four modes: proxy setup, domain setup, port exposure, and external service routing
- Classifies config files into `DOMAIN_ENV_FILES`, `PORT_ENV_FILES`, and `EXT_ENV_FILES`; the first file of each type determines the detected mode (port > external > domain)
**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
- Choice between domain setup, port exposure, or external service routing 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
- Automatic saving to `.env.rvs-prxy`, `.env-<domain>`, `.env-port-<port>`, or `.env-ext-<domain>` files
**2. Instance Management (`prompt_instance_name`)**
- Auto-detects existing instances from Docker volumes (FRP mode)
@ -117,6 +126,12 @@ Three Deployment Modes:
- Creates unique configuration filenames to avoid conflicts
- Supports dynamic configuration loading (no restart required by default)
5. **External Service Configuration** (`configure_traefik_external`, called by `setup_external_domain`)
- Generates routing rules for a public domain whose upstream is an external URL
- Requires Traefik mode (`FRP=false`) - rejects `.env-ext-*` files when FRP is enabled
- No local container lookup and no Docker network requirement for the upstream
- Persists settings as `.env-ext-<domain>` via `save_ext_env()` for later re-runs
### Local Docker Operations
- `local_docker_exec()`: Executes Docker commands directly on the local server
@ -184,6 +199,48 @@ http:
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.
**External Service Config** (dynamic, per-domain, written by `configure_traefik_external`):
```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
middlewares:
<domain>-strip:
stripPrefix:
paths:
- '<public-sub-path>'
<domain>-add:
addPrefix:
path: '<origin-base-path>'
services:
<domain>-service:
loadBalancer:
servers:
- url: '<scheme>://<external-host>[:<port>]'
passHostHeader: false
```
Implementation notes:
- Config file name: `app-ext-<domain-without-sub-path>.yml` inside the `traefik_data` volume, written via a temporary `alpine` container (`local_volume_copy`)
- `parse_external_url()` splits `EXTERNAL_URL` into scheme, host, port (default `443` for `https`, `80` for `http`) and base path; a non-numeric or out-of-range port is rejected
- The origin path is never part of the server URL; it is added back with `addPrefix` so a public sub-path and an origin base path compose correctly
- `passHostHeader: false` makes the origin receive its own hostname instead of the public domain, so upstream vhost routing and origin certificates keep working
- Origin TLS uses the container trust store (no `insecureSkipVerify`); only the public domain gets a Let's Encrypt certificate
- DNS for the external host is resolved inside the Traefik container, so `check_external_service_reachable()` only performs a local `nslookup`/`host` check and warns without aborting
**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)

View File

@ -1,10 +1,12 @@
#!/bin/bash
# deploy-rvs-prxy.sh - Automated deployment script for Reverse Proxy setup
# This script supports two modes:
# This script supports four modes:
# 1) Setup Reverse Proxy (Traefik or FRP Tunnel with Traefik)
# 2) Setup New Domain into existing reverse proxy
# This script runs on the same computer as the service it connects to
# 2) Setup New Domain into existing reverse proxy (routes to a local Docker container)
# 3) Setup Port Exposure (exposes a host port to a container port)
# 4) Setup External Service Domain (routes a domain to an external web service URL)
# This script runs on the same computer as the reverse proxy
set -e # Exit on any error
@ -45,7 +47,8 @@ LOCAL_SERVICE_NAME=""
LOCAL_SERVICE_PORT=""
LOCAL_DOCKER_NETWORK=""
# Deployment mode: "proxy" (setup reverse proxy), "domain" (setup new domain), or "port" (expose host port)
# Deployment mode: "proxy" (setup reverse proxy), "domain" (setup new domain),
# "port" (expose host port), or "external" (route a domain to an external service)
DEPLOY_MODE=""
# Domain configuration file pattern: .env-your-domain-com
@ -54,12 +57,21 @@ DOMAIN_ENV_FILE=""
# Port configuration file pattern: .env-port-<port_number>
PORT_ENV_FILE=""
# External service configuration file pattern: .env-ext-your-domain-com
EXT_ENV_FILE=""
# External service target (Traefik mode only) - upstream URL of the remote web service
EXTERNAL_URL=""
# Array to store all domain configuration files for batch processing
declare -a DOMAIN_ENV_FILES=()
# Array to store all port configuration files for batch processing
declare -a PORT_ENV_FILES=()
# Array to store all external service configuration files for batch processing
declare -a EXT_ENV_FILES=()
# Function to load environment variables from .env.rvs-prxy files
load_env() {
local proxy_env_loaded=false
@ -89,6 +101,10 @@ load_env() {
if [[ "$env_file" == .env-port-* ]]; then
continue
fi
# Skip external service configuration files (.env-ext-*)
if [[ "$env_file" == .env-ext-* ]]; then
continue
fi
if [ -f "$env_file" ]; then
DOMAIN_ENV_FILES+=("$env_file")
fi
@ -102,6 +118,14 @@ load_env() {
fi
done
# Collect external service configuration files (.env-ext-* pattern)
# These files contain external URL routing settings: DOMAIN_NAME, EXTERNAL_URL
for ext_file in .env-ext-*; do
if [ -f "$ext_file" ]; then
EXT_ENV_FILES+=("$ext_file")
fi
done
# Check for legacy .env.port-* files and auto-rename to .env-port-*
for legacy_file in .env.port-*; do
if [ -f "$legacy_file" ]; then
@ -142,6 +166,17 @@ load_env() {
fi
fi
# Load the first external service config file for initial variable setup
if [ ${#EXT_ENV_FILES[@]} -gt 0 ]; then
echo -e "${BLUE}[INFO]${NC} Loading external service config from ${EXT_ENV_FILES[0]}" >&2
source "${EXT_ENV_FILES[0]}"
EXT_ENV_FILE="${EXT_ENV_FILES[0]}"
if [ ${#EXT_ENV_FILES[@]} -gt 1 ]; then
log_info "Found ${#EXT_ENV_FILES[@]} external service 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.rvs-prxy file, by detecting running proxy
# IMPORTANT: Running container detection takes precedence over .env settings
@ -186,6 +221,10 @@ load_env() {
# Port config exists - setup port-based routing
DEPLOY_MODE="port"
log_info "Deployment mode: Setup Port Exposure (found port config: ${PORT_ENV_FILE})"
elif [ ${#EXT_ENV_FILES[@]} -gt 0 ]; then
# External service config exists - route domain to external URL
DEPLOY_MODE="external"
log_info "Deployment mode: Setup External Service Domain (found external service config: ${EXT_ENV_FILE})"
elif [ "$domain_env_loaded" = true ]; then
# Domain config exists - setup new domain
DEPLOY_MODE="domain"
@ -207,6 +246,8 @@ load_env() {
source "$DOMAIN_ENV_FILE"
elif [ "$DEPLOY_MODE" = "port" ] && [ -n "$PORT_ENV_FILE" ]; then
source "$PORT_ENV_FILE"
elif [ "$DEPLOY_MODE" = "external" ] && [ -n "$EXT_ENV_FILE" ]; then
source "$EXT_ENV_FILE"
else
source .env.rvs-prxy
fi
@ -237,6 +278,18 @@ load_env() {
log_error "Please set these in your .env-<domain> file"
exit 1
fi
elif [ "$DEPLOY_MODE" = "external" ]; then
# External service config file exists - validate it
if [ -z "$DOMAIN_NAME" ]; then
log_error "DOMAIN_NAME is required for external service setup mode"
log_error "Please set DOMAIN_NAME in your .env-ext-<domain> file"
exit 1
fi
if [ -z "$EXTERNAL_URL" ]; then
log_error "EXTERNAL_URL is required for external service setup"
log_error "Please set it in your .env-ext-<domain> file (e.g. https://app.example.com/)"
exit 1
fi
elif [ "$DEPLOY_MODE" = "proxy" ]; then
# For proxy setup mode, validate proxy-specific settings
if [ "$FRP" = false ]; then
@ -354,6 +407,110 @@ EOF
PORT_ENV_FILE="$port_file"
}
# Function to save external service configuration to .env-ext-<domain> file
save_ext_env() {
local domain_name="$1"
local external_url="$2"
# Convert domain name to filename format: your-domain-com -> .env-ext-your-domain-com
# Sub-path (/) is also converted to keep the filename flat
local domain_file=".env-ext-$(echo "$domain_name" | sed 's/\./-/g; s/\//-/g')"
echo -e "${BLUE}[INFO]${NC} Saving external service configuration to $domain_file" >&2
# Create external service-specific env file
cat > "$domain_file" << EOF
# External service configuration for ${domain_name}
# Generated by deploy-rvs-prxy.sh on $(date)
# Traefik terminates TLS for this domain and proxies to EXTERNAL_URL (origin Host header)
DOMAIN_NAME="${domain_name}"
EXTERNAL_URL="${external_url}"
EOF
echo -e "${GREEN}[INFO]${NC} External service configuration saved to $domain_file" >&2
EXT_ENV_FILE="$domain_file"
}
# Function to parse EXTERNAL_URL into scheme/host/port/base-path components
# Sets: EXT_SCHEME, EXT_HOST, EXT_PORT, EXT_BASE_PATH
parse_external_url() {
EXT_SCHEME=""
EXT_HOST=""
EXT_PORT=""
EXT_BASE_PATH=""
local url="${EXTERNAL_URL# }"
url="${url% }"
case "$url" in
https://*) EXT_SCHEME="https" ;;
http://*) EXT_SCHEME="http" ;;
*) return 1 ;;
esac
# Strip scheme
local remainder="${url#*://}"
# Split host(+port) from path
local host_part="${remainder%%/*}"
local path_part=""
if [[ "$remainder" == *"/"* ]]; then
path_part="/${remainder#*/}"
fi
# Split host and port
if [[ "$host_part" == *:* ]]; then
EXT_HOST="${host_part%%:*}"
EXT_PORT="${host_part##*:}"
else
EXT_HOST="$host_part"
fi
# Validate host
if [ -z "$EXT_HOST" ]; then
return 1
fi
# Validate port (numeric, 1-65535) or default by scheme
if [ -z "$EXT_PORT" ]; then
if [ "$EXT_SCHEME" = "https" ]; then
EXT_PORT="443"
else
EXT_PORT="80"
fi
elif ! [[ "$EXT_PORT" =~ ^[0-9]+$ ]] || [ "$EXT_PORT" -lt 1 ] || [ "$EXT_PORT" -gt 65535 ]; then
return 1
fi
# Normalise base path (strip trailing slash, keep leading slash)
if [ "$path_part" != "/" ]; then
EXT_BASE_PATH="${path_part%/}"
fi
return 0
}
# Function to warn when the external host cannot be resolved (non-fatal)
check_external_service_reachable() {
log_info "Checking external service ${EXT_SCHEME}://${EXT_HOST}:${EXT_PORT} ..."
local resolved=""
if command -v getent >/dev/null 2>&1; then
resolved=$(getent hosts "$EXT_HOST" 2>/dev/null || true)
fi
if [ -n "$resolved" ]; then
log_info "External host ${EXT_HOST} resolves to: $(echo "$resolved" | awk '{print $1}' | head -3 | tr '\n' ' ')"
return 0
fi
log_warn "Could not resolve external host '${EXT_HOST}' from this server."
log_warn "Traefik resolves and connects to it from inside the container - DNS there may still work."
log_warn "If the domain does not load, verify ${EXTERNAL_URL} is reachable and publicly resolvable."
return 0
}
# Function to read from terminal instead of pipe
read_terminal() {
local prompt="$1"
@ -386,10 +543,11 @@ interactive_setup_wizard() {
echo -e "${BLUE}--- What would you like to setup? ---${NC}" >&2
echo -e " 1) ${GREEN}Setup New Domain${NC} - Route traffic based on domain name" >&2
echo -e " 2) ${GREEN}Setup Port Exposure${NC} - Expose host port to container port" >&2
echo -e " 3) ${GREEN}Setup External Service Domain${NC} - Route a domain to an external web service (URL)" >&2
echo "" >&2
while true; do
setup_choice=$(read_terminal "Select option [1-2] (default: 1 for Domain): " "1")
setup_choice=$(read_terminal "Select option [1-3] (default: 1 for Domain): " "1")
case "$setup_choice" in
1|"")
# Setup New Domain
@ -502,8 +660,54 @@ interactive_setup_wizard() {
log_info "Deployment mode: Setup Port Exposure (interactive setup)"
break
;;
3)
# Setup External Service Domain
echo -e "${GREEN}Selected: Setup External Service Domain${NC}" >&2
echo "" >&2
echo -e "${BLUE}--- Setup External Service Domain ---${NC}" >&2
echo -e "Let's route a new domain to an external web service." >&2
echo -e "No local Docker container is required - Traefik proxies to the URL below." >&2
echo "" >&2
# Get domain name (optional sub-path supported, e.g. app.example.com/api)
echo -e "Enter the domain name for this external service:" >&2
while [ -z "$DOMAIN_NAME" ]; do
DOMAIN_NAME=$(read_terminal "Domain (e.g., app.example.com or app.example.com/api): " "")
if [ -z "$DOMAIN_NAME" ]; then
echo -e "${RED}Domain name cannot be empty.${NC}" >&2
fi
done
# Get external service URL
echo -e "Enter the external web service URL:" >&2
while [ -z "$EXTERNAL_URL" ]; do
EXTERNAL_URL=$(read_terminal "External URL (e.g., https://cornersendbox-impact-vms.lovable.app/): " "")
if [ -z "$EXTERNAL_URL" ]; then
echo -e "${RED}External URL cannot be empty.${NC}" >&2
elif ! [[ "$EXTERNAL_URL" =~ ^https?://[^[:space:]]+$ ]]; then
echo -e "${RED}Invalid URL. It must start with http:// or https://${NC}" >&2
echo -e "${RED}Example: https://cornersendbox-impact-vms.lovable.app/${NC}" >&2
EXTERNAL_URL=""
fi
done
# Save to external service .env-ext-<domain> file
save_ext_env "$DOMAIN_NAME" "$EXTERNAL_URL"
# Load FRP setting from existing .env if it exists
if [ -f ".env.rvs-prxy" ]; then
source .env.rvs-prxy
else
# Set default FRP mode if .env doesn't exist
FRP=false
fi
DEPLOY_MODE="external"
log_info "Deployment mode: Setup External Service Domain (interactive setup)"
break
;;
*)
echo -e "${RED}Invalid choice. Please enter 1 or 2.${NC}" >&2
echo -e "${RED}Invalid choice. Please enter 1, 2 or 3.${NC}" >&2
;;
esac
done
@ -2063,6 +2267,185 @@ EOF
fi
}
# Function to configure Traefik to route a domain to an EXTERNAL web service (Traefik Mode)
# The backend is a remote URL (e.g. https://app.lovable.app/), not a local container.
configure_traefik_external() {
log_info "Configuring Traefik locally to route ${DOMAIN_NAME} to external service ${EXTERNAL_URL} ..."
# Validate and parse the external URL into scheme / host / port / base path
if ! parse_external_url; then
log_error "Invalid EXTERNAL_URL '${EXTERNAL_URL}'"
log_error "Expected format: https://host[:port][/path] (e.g. https://cornersendbox-impact-vms.lovable.app/)"
exit 1
fi
log_info "External target: ${EXT_SCHEME}://${EXT_HOST}:${EXT_PORT} (base path: ${EXT_BASE_PATH:-none})"
# Split DOMAIN_NAME into domain part and optional sub-path part
local domain_part
local path_part=""
if [[ "$DOMAIN_NAME" == *"/"* ]]; then
domain_part=$(echo "$DOMAIN_NAME" | cut -d'/' -f1)
path_part="/$(echo "$DOMAIN_NAME" | cut -d'/' -f2-)"
path_part="${path_part%/}"
if [ -z "$path_part" ]; then
path_part=""
fi
log_info "Detected sub-path configuration: domain=${domain_part}, path=${path_part}"
else
domain_part="$DOMAIN_NAME"
fi
# Non-fatal reachability hint (Traefik does the real resolution from its container)
check_external_service_reachable
# Middleware chain: strip our sub-path, then re-apply the origin base path
local prefix_middlewares=()
if [ -n "$path_part" ]; then
prefix_middlewares+=("${domain_part}-strip-prefix")
fi
if [ -n "$EXT_BASE_PATH" ]; then
prefix_middlewares+=("${domain_part}-add-prefix")
fi
# Router rule: whole domain, or domain plus sub-path
local router_rule="Host(\`${domain_part}\`)"
if [ -n "$path_part" ]; then
router_rule="${router_rule} && PathPrefix(\`${path_part}\`)"
fi
local temp_config="/tmp/app-ext-service.yml"
# HTTPS router (TLS terminated by Traefik, Let's Encrypt certificate)
cat > "$temp_config" << EOF
http:
routers:
${domain_part}-https:
rule: '${router_rule}'
service: ${domain_part}-ext
tls:
certResolver: letsencrypt
entryPoints:
- websecure
EOF
if [ ${#prefix_middlewares[@]} -gt 0 ]; then
printf ' middlewares:\n' >> "$temp_config"
for mw in "${prefix_middlewares[@]}"; do
printf ' - %s\n' "$mw" >> "$temp_config"
done
fi
# HTTP router (redirect to HTTPS)
cat >> "$temp_config" << EOF
${domain_part}-http:
rule: '${router_rule}'
service: ${domain_part}-ext
entryPoints:
- web
middlewares:
- redirect-to-https
EOF
if [ ${#prefix_middlewares[@]} -gt 0 ]; then
for mw in "${prefix_middlewares[@]}"; do
printf ' - %s\n' "$mw" >> "$temp_config"
done
fi
# Middleware definitions (only when a sub-path or origin base path is used)
if [ ${#prefix_middlewares[@]} -gt 0 ]; then
printf ' middlewares:\n' >> "$temp_config"
if [ -n "$path_part" ]; then
cat >> "$temp_config" << EOF
${domain_part}-strip-prefix:
stripPrefix:
prefixes:
- ${path_part}
EOF
fi
if [ -n "$EXT_BASE_PATH" ]; then
cat >> "$temp_config" << EOF
${domain_part}-add-prefix:
addPrefix:
prefix: ${EXT_BASE_PATH}
EOF
fi
fi
# Backend service: absolute URL of the external service, origin Host header
cat >> "$temp_config" << EOF
services:
${domain_part}-ext:
loadBalancer:
servers:
- url: '${EXT_SCHEME}://${EXT_HOST}:${EXT_PORT}'
passHostHeader: false
EOF
# Write the dynamic configuration into the Traefik volume
local config_file_name="app-ext-${domain_part}.yml"
local TRAEFIK_VOLUME_NAME="traefik_data"
local config_exists
config_exists=$(docker run --rm -v "${TRAEFIK_VOLUME_NAME}:/etc/traefik" alpine:latest ls -la /etc/traefik/config/ 2>/dev/null | grep "$config_file_name" || true)
if [ -n "$config_exists" ]; then
log_warn "Configuration file $config_file_name already exists, it will be overwritten"
log_info "This will update the existing external service configuration for ${DOMAIN_NAME}"
else
log_info "Creating new external service configuration for domain ${domain_part}"
fi
docker run --rm -v "${TRAEFIK_VOLUME_NAME}:/etc/traefik" -v "/tmp:/tmp" alpine:latest sh -c "cp /tmp/app-ext-service.yml /etc/traefik/config/$config_file_name"
rm -f "$temp_config"
log_info "Added external service configuration ${EXTERNAL_URL} for domain ${domain_part} to Traefik (file: $config_file_name)"
# Restart is optional - the file provider watches /etc/traefik/config
if [ "${RESTART_TRAEFIK:-false}" = "true" ]; then
docker restart traefik
log_info "Traefik restarted to apply new configuration"
else
log_info "Traefik dynamic configuration added (restart not performed, Traefik should auto-load the configuration)"
log_info "If needed, you can manually restart Traefik with: docker restart traefik"
fi
log_info "Traefik configured to proxy https://${DOMAIN_NAME} → ${EXTERNAL_URL}"
log_info "Origin receives the Host header of ${EXT_HOST} (passHostHeader=false)"
if [ -n "$path_part" ] || [ -n "$EXT_BASE_PATH" ]; then
log_info "Path mapping: https://${DOMAIN_NAME}<path> → ${EXT_SCHEME}://${EXT_HOST}:${EXT_PORT}${EXT_BASE_PATH}<path>"
fi
}
# Function to set up a domain routed to an external web service (Traefik Mode)
setup_external_domain() {
log_info "Setting up external service domain: ${DOMAIN_NAME}"
log_info "External service configuration loaded from: ${EXT_ENV_FILE:-.env-ext-*}"
# External URL routing is a Traefik-only capability
if [ "$FRP" = "true" ]; then
log_error "External service routing is supported in Traefik mode only (FRP=false)."
log_error "FRP mode detected - the tunnel cannot proxy to an external URL."
exit 1
fi
# Check if Traefik is running
if ! docker ps --filter name=^${INSTANCE_NAME}$ --format '{{.Names}}' | grep -q "^traefik$"; then
log_error "Traefik reverse proxy is not running!"
log_error "Please ensure the reverse proxy is setup first"
exit 1
fi
# No container / docker-network checks: the backend is an external URL
configure_traefik_external
log_info "External service domain ${DOMAIN_NAME} has been configured in Traefik"
log_info "Service will be accessible at: https://${DOMAIN_NAME}"
}
# Function to check if Application Service is running locally (Traefik Mode)
check_app_service_local() {
log_info "Checking if Application Service is running locally..."
@ -3065,15 +3448,17 @@ Usage: curl -s "<url>/deploy-rvs-prxy.sh" | bash
Automated deployment script for Reverse Proxy setup.
Modes:
1) Setup Reverse Proxy - Deploys Traefik or FRP Tunnel with Traefik
2) Setup New Domain - Adds a new domain to existing reverse proxy
3) Setup Port Exposure - Exposes a host port to connect to a container port
4) Manage Configurations - List and remove existing domains and ports
1) Setup Reverse Proxy - Deploys Traefik or FRP Tunnel with Traefik
2) Setup New Domain - Adds a new domain to a local Docker application container
3) Setup Port Exposure - Exposes a host port to connect to a container port
4) Setup External Service Domain - Routes a domain to an external web service URL (Traefik mode only)
5) Manage Configurations - List and remove existing domains, external services and ports
The script automatically detects the mode based on your configuration:
- If no reverse proxy exists: Setup Reverse Proxy mode
- If reverse proxy exists and DOMAIN_NAME is set: Setup New Domain mode
- If reverse proxy exists and HOST_PORT is set: Setup Port Exposure mode
- If reverse proxy exists and EXTERNAL_URL is set: Setup External Service Domain mode
Environment Variables (in .env.rvs-prxy file):
FRP=true|false Set to 'false' for Traefik mode, 'true' for FRP mode
@ -3098,6 +3483,11 @@ Port Exposure Variables (in .env-port-<port> file):
CONTAINER_NAME Name of the target Docker container
CONTAINER_PORT Port number inside the container to connect to
External Service Variables (in .env-ext-<domain> file):
DOMAIN_NAME Public domain to route (sub-path allowed, e.g. app.example.com/api)
EXTERNAL_URL Upstream URL of the external web service
(e.g. https://cornersendbox-impact-vms.lovable.app/)
Examples:
# First run - will trigger interactive wizard
curl -s "<url>/deploy-rvs-prxy.sh" | bash
@ -3121,10 +3511,19 @@ Port Exposure:
CONTAINER_NAME="your-container-name"
CONTAINER_PORT="80"
Then run the script to expose host port 18081 -> container port 80
External Service Domain:
Create a file named .env-ext-<domain> (e.g., .env-ext-app-example-com) with:
DOMAIN_NAME="app.example.com"
EXTERNAL_URL="https://cornersendbox-impact-vms.lovable.app/"
Then run the script. Traefik terminates TLS for app.example.com (Let's Encrypt)
and proxies to the external URL. The origin receives its own Host header
(passHostHeader=false); a sub-path in DOMAIN_NAME is stripped, and any path in
EXTERNAL_URL is added back to the origin request. Traefik mode only.
EOF
}
# Function to manage existing domain and port configurations
# Manage existing domain, external service and port configurations
manage_configurations() {
echo -e "${BLUE}=============================================${NC}" >&2
echo -e "${GREEN}Reverse Proxy Configuration Manager${NC}" >&2
@ -3137,6 +3536,7 @@ manage_configurations() {
[ -f "$f" ] || continue
[[ "$f" == .env.rvs-prxy* ]] && continue
[[ "$f" == .env-port-* ]] && continue
[[ "$f" == .env-ext-* ]] && continue
domain_files+=("$f")
done
@ -3146,10 +3546,16 @@ manage_configurations() {
[ -f "$f" ] && port_files+=("$f")
done
local total_configs=$((${#domain_files[@]} + ${#port_files[@]}))
# Collect external service files
local ext_files=()
for f in .env-ext-*; do
[ -f "$f" ] && ext_files+=("$f")
done
local total_configs=$((${#domain_files[@]} + ${#port_files[@]} + ${#ext_files[@]}))
if [ "$total_configs" -eq 0 ]; then
log_info "No domain or port configurations found."
log_info "No domain, external service or port configurations found."
return 0
fi
@ -3185,6 +3591,19 @@ manage_configurations() {
echo "" >&2
fi
if [ ${#ext_files[@]} -gt 0 ]; then
echo -e "${BLUE}External Services:${NC}" >&2
for f in "${ext_files[@]}"; do
local domain_name
domain_name=$(grep -o 'DOMAIN_NAME="[^"]*"' "$f" 2>/dev/null | sed 's/DOMAIN_NAME="//;s/"//' || echo "unknown")
local external_url
external_url=$(grep -o 'EXTERNAL_URL="[^"]*"' "$f" 2>/dev/null | sed 's/EXTERNAL_URL="//;s/"//' || echo "unknown")
echo -e " ${GREEN}${idx}.${NC} ${f} - ${domain_name} → ${external_url}" >&2
idx=$((idx + 1))
done
echo "" >&2
fi
# Prompt for removal
echo -e "${YELLOW}Select configurations to remove (enter numbers separated by space, or 'q' to quit):${NC}" >&2
read -r selection </dev/tty
@ -3195,7 +3614,7 @@ manage_configurations() {
fi
# Build array of all config files
local all_files=("${domain_files[@]}" "${port_files[@]}")
local all_files=("${domain_files[@]}" "${port_files[@]}" "${ext_files[@]}")
# Track if Traefik needs restart (for port removals)
local traefik_restart_needed=false
@ -3208,8 +3627,24 @@ manage_configurations() {
if [ -f "$file_to_remove" ]; then
log_info "Removing: ${file_to_remove}"
# Check if it's an external service config
if [[ "$file_to_remove" == .env-ext-* ]]; then
# Remove external service config from Traefik
local domain_name
domain_name=$(grep -o 'DOMAIN_NAME="[^"]*"' "$file_to_remove" 2>/dev/null | sed 's/DOMAIN_NAME="//;s/"//' || echo "")
if [ -n "$domain_name" ]; then
log_info "Removing external service config from Traefik: ${domain_name}"
# Remove the dynamic config file from Traefik volume
# Same domain_base logic as configure_traefik_external():
# cut -d'/' -f1 to match the actual filename
local domain_base
domain_base=$(echo "$domain_name" | cut -d'/' -f1)
docker run --rm -v "traefik_data:/etc/traefik" alpine:latest sh -c "rm -f /etc/traefik/config/app-ext-${domain_base}.yml 2>/dev/null" || true
fi
# Check if it's a domain config
if [[ "$file_to_remove" == .env-* ]] && [[ "$file_to_remove" != .env-port-* ]]; then
elif [[ "$file_to_remove" == .env-* ]] && [[ "$file_to_remove" != .env-port-* ]] && [[ "$file_to_remove" != .env-ext-* ]]; then
# Remove domain config from Traefik volume
local domain_name
domain_name=$(grep -o 'DOMAIN_NAME="[^"]*"' "$file_to_remove" 2>/dev/null | sed 's/DOMAIN_NAME="//;s/"//' || echo "")
@ -3479,14 +3914,66 @@ main() {
# Fallback for backward compatibility
setup_new_domain
fi
elif [ "$DEPLOY_MODE" = "external" ]; then
log_info "Setting up external service domain in existing Traefik proxy..."
# Process all external service config files in batch mode
if [ ${#EXT_ENV_FILES[@]} -gt 0 ]; then
local total=${#EXT_ENV_FILES[@]}
local count=0
for env_file in "${EXT_ENV_FILES[@]}"; do
count=$((count + 1))
echo "" >&2
log_info "========================================="
log_info "Processing external service $count of $total: $env_file"
log_info "========================================="
echo "" >&2
# Source the external service config file
source "$env_file"
EXT_ENV_FILE="$env_file"
# Validate external service config
if [ -z "$DOMAIN_NAME" ]; then
log_error "DOMAIN_NAME is required in $env_file"
continue
fi
if [ -z "$EXTERNAL_URL" ]; then
log_error "EXTERNAL_URL is required in $env_file"
continue
fi
# Setup the external service domain
setup_external_domain
done
echo "" >&2
log_info "========================================="
log_info "Batch processing completed: $count external service domain(s) processed"
log_info "========================================="
else
# Fallback for single external service config
setup_external_domain
fi
elif [ "$DEPLOY_MODE" = "domain_wizard" ]; then
log_info "Starting interactive wizard for domain setup..."
interactive_setup_wizard
# Source the newly created domain config
if [ -n "$DOMAIN_ENV_FILE" ]; then
source "$DOMAIN_ENV_FILE"
# The wizard may create a domain, port exposure or external service config
if [ "$DEPLOY_MODE" = "external" ] && [ -n "$EXT_ENV_FILE" ]; then
source "$EXT_ENV_FILE"
setup_external_domain
elif [ "$DEPLOY_MODE" = "port" ] && [ -n "$PORT_ENV_FILE" ]; then
source "$PORT_ENV_FILE"
setup_port_exposure
else
if [ -n "$DOMAIN_ENV_FILE" ]; then
source "$DOMAIN_ENV_FILE"
fi
setup_new_domain
fi
setup_new_domain
else
log_info "Setting up reverse proxy..."
setup_reverse_proxy