From e8e81d358687904f211f3f67f134dd69c66672a6 Mon Sep 17 00:00:00 2001 From: chungyan5 Date: Wed, 29 Oct 2025 08:56:13 +0000 Subject: [PATCH] code for same domain and same service backend, should over-write the previous setting; but not yet test --- .env.sample | 9 --- Design_Doc/tech/traefik/DevProc.md | 99 ++++++++++++++++++++++++++++++ auto-sys-deploy.sh | 52 ++++++++++++++-- 3 files changed, 146 insertions(+), 14 deletions(-) diff --git a/.env.sample b/.env.sample index fcd22ae..b56d68e 100644 --- a/.env.sample +++ b/.env.sample @@ -59,18 +59,9 @@ PROXY_SSH_PORT=13076 # Remote port for SSH proxy (default 130 # === Target Proxy Server Configuration (Traefik Mode) === # This section is used when FRP=false -# Deployment Name -#DEPLOY_NAME=itl-pt # Unique name for this deployment - # Destination path for host or docker volume folder deployment DEST_PATH=/ # Destination path on target server -# Docker volume deployment settings (set to true to use volume instead of host folder) -#USE_DOCKER_VOLUME=true # Set to true to use Docker volume, false for host folder - -# Docker volume name (only used if USE_DOCKER_VOLUME=true) -#DOCKER_VOLUME_NAME=itl-pt_html # Name of Docker volume to use - # 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 diff --git a/Design_Doc/tech/traefik/DevProc.md b/Design_Doc/tech/traefik/DevProc.md index 537ca79..2b496f9 100644 --- a/Design_Doc/tech/traefik/DevProc.md +++ b/Design_Doc/tech/traefik/DevProc.md @@ -386,6 +386,105 @@ This implementation allows you to have multiple services configured with different paths on the same domain (e.g., event.cgu.org.hk/api and event.cgu.org.hk/admin), and all configurations will coexist in the same Traefik container without overwriting each other. +- Currently the codebase create the domain as https://DOMAIN_NAME where DOMAIN_NAME can be **NO sub-path** or **having sub-path**, I aim to handle http://DOMAIN_NAME which will be transfer to https://DOMAIN_NAME by traefik. I look around internet and find out this possible solution, you analysis, if can work, apply to the auto. script which our setup including this function + ``` + To configure Traefik v3.x middleware to redirect HTTP traffic to HTTPS, you can use the `RedirectScheme` middleware. This middleware allows you to specify that all HTTP requests should be redirected to HTTPS automatically. + + Traefik v3.x Middleware for HTTP to HTTPS Redirection + Overview + To set up a middleware in Traefik v3.x that redirects HTTP traffic to HTTPS, you need to configure the appropriate middleware and routers. This ensures that any requests made over HTTP are automatically redirected to their HTTPS counterparts. + + Middleware Configuration + Create a Redirect Middleware: This middleware will handle the redirection from HTTP to HTTPS. + yaml + + 复制代码 + http: + middlewares: + redirect-to-https: + redirectScheme: + scheme: "https" + permanent: true + Apply Middleware to Routers: You need to attach the middleware to your HTTP routers. + yaml + + 复制代码 + http: + routers: + my-router: + rule: "Host(`example.com`)" + entryPoints: + - "http" + middlewares: + - redirect-to-https + service: my-service + Entry Points Configuration + Ensure that your entry points are correctly set up to listen on both HTTP and HTTPS: + + yaml + + 复制代码 + entryPoints: + http: + address: ":80" + https: + address: ":443" + Important Notes + Permanent Redirects: Setting permanent: true will send a 301 status code, indicating a permanent redirect. If you want a temporary redirect, set it to false. + Testing: After configuration, test the setup using a browser or tools like curl to ensure that HTTP requests are redirected to HTTPS. + Browser Behavior: Browsers may cache redirects, so clear your cache or use incognito mode for testing. + This setup will ensure that all HTTP traffic is securely redirected to HTTPS, enhancing the security of your applications. + ``` + - Result -- implemented the HTTP to HTTPS redirect functionality + 1. Added global redirect middleware in the main Traefik configuration: + - Created a redirect-to-https middleware that redirects HTTP to HTTPS permanently + - Added an http-catchall router that catches all HTTP requests and redirects them to HTTPS + - This ensures that any HTTP request to the domain will be redirected to HTTPS + + 2. Enhanced individual service configuration: + - For each service, created both HTTP and HTTPS routers + - The HTTPS router (${TARGET_SERVICE_NAME}-https) handles the actual service with TLS + - The HTTP router (${TARGET_SERVICE_NAME}-http) redirects to HTTPS using the middleware + - For sub-path routing, both the strip prefix and redirect middleware are applied in the correct order + + 3. Maintained sub-path functionality: + - Sub-path services get proper path stripping and redirect handling + - Both HTTP and HTTPS entry points are correctly specified + + 4. Backward compatibility: + - All existing functionality is preserved + - The configuration works for both regular domains and sub-paths + + This implementation ensures that when users access http://DOMAIN_NAME, they will be automatically redirected to https://DOMAIN_NAME with proper TLS certificate handling via Let's Encrypt. The configuration follows Traefik v3.x standards and handles both root domain and sub-path routing scenarios. + +- Currently code, i want to review as: if my `.env` with same `DOMAIN_NAME=event.cgu.org.hk` to previous, then i re-run again, Does it will over-write the old setting and replaced by the new set of setting from `.env`? or corrupt existing running traefik? + - Result + 1. Unique configuration file naming: + - Uses both domain base name and service name to create unique configuration files + - Sanitizes service names to ensure valid filenames + + 2. Conflict detection: + - Checks if a configuration file already exists for the same domain and service combination + - Issues a warning when overwriting an existing configuration file + + 3. Safe operation: + - Running the same configuration twice with same service name and domain will overwrite the existing configuration (which is expected behavior) + - Running with different service names on the same domain will create separate configuration files, allowing multiple services for the same domain as long as they have different paths + - For root domains, multiple services would conflict, and this is now detected + + 4. Traefik compatibility: + - Traefik automatically reloads configuration files when they change + - The system won't corrupt the running Traefik container; it will just update its configuration + + To answer your question directly: + + - Same `DOMAIN_NAME` and `TARGET_SERVICE_NAME`: The script will overwrite the existing configuration for that specific service, which is the expected behavior when reconfiguring the same service + - Same `DOMAIN_NAME`, different `TARGET_SERVICE_NAME`: This can create routing conflicts if both services try to handle the same domain without sub-paths. The script will warn about overwriting existing configuration files. + - Same `DOMAIN_NAME` with different sub-paths: This will work correctly (e.g., event.cgu.org.hk/api and event.cgu.org.hk/admin can coexist) + - Corruption risk: The script will not corrupt the running Traefik container; it just updates the configuration files which Traefik monitors and reloads automatically + + The system is now more robust and will warn you about potential conflicts while maintaining Traefik container stability. + - Todo - NOT yet full test, - tested as diff --git a/auto-sys-deploy.sh b/auto-sys-deploy.sh index 3d49678..2d6d0a4 100755 --- a/auto-sys-deploy.sh +++ b/auto-sys-deploy.sh @@ -864,7 +864,7 @@ create_traefik_container_on_target() { # Create the Docker volume for persistent data ssh_exec "docker volume create $TRAEFIK_VOLUME_NAME" - # Create a minimal dynamic configuration file for the dashboard and basic routing + # Create a minimal dynamic configuration file for the dashboard and basic routing, plus HTTP to HTTPS redirect local temp_config="/tmp/traefik-$$.yml" cat > "$temp_config" << 'EOF_HEREDOC' http: @@ -875,6 +875,13 @@ http: dashboard: rule: "PathPrefix(`/dashboard`)" service: api@internal + http-catchall: + rule: "PathRegexp(`{any:.*}`)" + entryPoints: + - "web" + service: "noop@internal" + middlewares: + - "redirect-to-https" middlewares: api-headers: headers: @@ -884,6 +891,10 @@ http: stsIncludeSubdomains: true stsPreload: true stsSeconds: 15552000 + redirect-to-https: + redirectScheme: + scheme: "https" + permanent: true EOF_HEREDOC # Upload the configuration to target server @@ -1116,13 +1127,23 @@ configure_traefik_on_target() { cat > "$temp_config" << EOF http: routers: - ${TARGET_SERVICE_NAME}-router: + ${TARGET_SERVICE_NAME}-https: rule: 'Host(\`${domain_part}\`) && PathPrefix(\`${path_part}\`)' service: ${TARGET_SERVICE_NAME}-service tls: certResolver: letsencrypt + entryPoints: + - websecure middlewares: - ${TARGET_SERVICE_NAME}-strip-prefix + ${TARGET_SERVICE_NAME}-http: + rule: 'Host(\`${domain_part}\`) && PathPrefix(\`${path_part}\`)' + service: ${TARGET_SERVICE_NAME}-service + entryPoints: + - web + middlewares: + - redirect-to-https + - ${TARGET_SERVICE_NAME}-strip-prefix middlewares: ${TARGET_SERVICE_NAME}-strip-prefix: stripPrefix: @@ -1140,11 +1161,20 @@ EOF cat > "$temp_config" << EOF http: routers: - ${TARGET_SERVICE_NAME}-router: + ${TARGET_SERVICE_NAME}-https: rule: 'Host(\`${DOMAIN_NAME}\`)' service: ${TARGET_SERVICE_NAME}-service tls: certResolver: letsencrypt + entryPoints: + - websecure + ${TARGET_SERVICE_NAME}-http: + rule: 'Host(\`${DOMAIN_NAME}\`)' + service: ${TARGET_SERVICE_NAME}-service + entryPoints: + - web + middlewares: + - redirect-to-https services: ${TARGET_SERVICE_NAME}-service: loadBalancer: @@ -1158,12 +1188,24 @@ EOF scp_upload "$temp_config" "/tmp/app-service.yml" rm -f "$temp_config" - # Generate a unique configuration file name based on the service name to avoid overwrites - local config_file_name="app-service-${TARGET_SERVICE_NAME}.yml" + # Generate a unique configuration file name based on the domain and service name to avoid conflicts + # Use the domain (without path) and service name to create a unique identifier + local domain_base=$(echo "$DOMAIN_NAME" | cut -d'/' -f1) + local config_file_name="app-service-${domain_base}-${TARGET_SERVICE_NAME//[^a-zA-Z0-9]/-}.yml" + + # Check if a config file already exists for this domain and service combination + local config_exists + config_exists=$(ssh_exec "docker run --rm -v ${THIS_INSTANCE}-traefik_data:/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" + fi # Copy the configuration file into the volume using a temporary container ssh_exec "docker run --rm -v ${THIS_INSTANCE}-traefik_data:/etc/traefik -v /tmp:/tmp alpine:latest sh -c \"cp /tmp/app-service.yml /etc/traefik/config/$config_file_name\"" + log_info "Added configuration for service ${TARGET_SERVICE_NAME} on domain $domain_base to Traefik (file: $config_file_name)" + # Connect the traefik container to the traefik-public network to ensure communication ssh_exec "docker network connect traefik-public traefik 2>/dev/null || true"