[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6PCV0NYSDDTY8WQ8ZCF0PE6":3,"skill-same:01M6PCV0NYSDDTY8WQ8ZCF0PE6":71},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":38,"linkOnly":39,"markdownContent":40,"markdownBody":41,"frontMatter":42,"refName":28,"commitSha":52,"skillDirectory":53,"forksCount":13,"repositoryHtmlUrl":54,"repositoryHomepageUrl":6,"ownerHtmlUrl":55,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":56,"install":57,"resources":70},"01M6PCV0NYSDDTY8WQ8ZCF0PE6","reverse-proxy",null,"Configure nginx and Traefik as reverse proxies. Implement SSL termination and routing. Use when setting up application gateways.","duc-duy-1612\u002FOnline-Delivery-Systems-Web","duc-duy-1612","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F192231384?v=4","01M6NSDKQQDKVTHZ8DZMZ1VYY6","01M6NSDKW8DDVTQHBT1HBDDJPT",0,"MIT","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Freverse-proxy\u002FSKILL.md",[],[18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37],"reverse","reverse proxy","proxy","community","relevant","scripts","critical","os","as","platform","main","security","up","only","configure","access","devops-security","nginx","gateways","license","2026-11-10 10:12:30",false,"---\nname: reverse-proxy\ndescription: Configure nginx and Traefik as reverse proxies. Implement SSL termination\n  and routing. Use when setting up application gateways.\ncategory: devops\nrisk: critical\nsource: https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\nsource_repo: BagelHole\u002FDevOps-Security-Agent-Skills\nsource_type: community\ndate_added: '2026-09-20'\nlicense: MIT\nlicense_source: https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\u002Fblob\u002Fmain\u002FLICENSE\ncompatibility: Requires the relevant OS\u002Fplatform tooling and privileged access where\n  noted. Docs-only; helper scripts and templates not bundled.\nmetadata:\n  author: devops-skills\n  version: '1.0'\n---\n\n# Reverse Proxy\n\nConfigure reverse proxies to route traffic, terminate TLS, enforce rate limits, and serve as the gateway between clients and backend services.\n\n## When to Use\n\n- Routing traffic from a public domain to one or more backend services.\n- Terminating TLS at the edge and forwarding plain HTTP to backends.\n- Adding rate limiting, CORS, security headers, and access control.\n- Consolidating multiple services under a single domain with path-based routing.\n- Handling WebSocket upgrades, gRPC proxying, or HTTP\u002F2 passthrough.\n\n## Prerequisites\n\n- Backend service(s) running on known host:port.\n- TLS certificate (Let's Encrypt, ACM, or self-signed for development).\n- nginx 1.25+ or Traefik 3.x installed.\n- DNS record pointing the domain to the proxy server.\n\n## nginx Reverse Proxy\n\n### Basic HTTPS Proxy with Redirect\n\n```nginx\n# \u002Fetc\u002Fnginx\u002Fsites-available\u002Fapp.example.com\nserver {\n    listen 80;\n    server_name app.example.com;\n    return 301 https:\u002F\u002F$host$request_uri;\n}\n\nserver {\n    listen 443 ssl http2;\n    server_name app.example.com;\n\n    # TLS configuration\n    ssl_certificate     \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapp.example.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapp.example.com\u002Fprivkey.pem;\n    ssl_protocols       TLSv1.2 TLSv1.3;\n    ssl_ciphers         ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384;\n    ssl_prefer_server_ciphers on;\n    ssl_session_cache   shared:SSL:10m;\n    ssl_session_timeout 10m;\n\n    # Security headers\n    add_header Strict-Transport-Security \"max-age=63072000; includeSubDomains; preload\" always;\n    add_header X-Frame-Options DENY always;\n    add_header X-Content-Type-Options nosniff always;\n    add_header Referrer-Policy strict-origin-when-cross-origin always;\n\n    # Proxy to backend\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n\n        # Timeouts\n        proxy_connect_timeout 5s;\n        proxy_read_timeout 60s;\n        proxy_send_timeout 60s;\n\n        # Buffering\n        proxy_buffering on;\n        proxy_buffer_size 4k;\n        proxy_buffers 8 4k;\n    }\n}\n```\n\n### Path-Based Routing to Multiple Services\n\n```nginx\nserver {\n    listen 443 ssl http2;\n    server_name app.example.com;\n\n    ssl_certificate     \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapp.example.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapp.example.com\u002Fprivkey.pem;\n\n    # Frontend SPA\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n        proxy_set_header Host $host;\n    }\n\n    # API backend\n    location \u002Fapi\u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:8080\u002F;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_read_timeout 120s;\n    }\n\n    # WebSocket endpoint\n    location \u002Fws\u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:8080;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n        proxy_set_header Host $host;\n        proxy_read_timeout 86400s;  # 24h for long-lived connections\n    }\n\n    # Static assets with caching\n    location \u002Fstatic\u002F {\n        alias \u002Fvar\u002Fwww\u002Fstatic\u002F;\n        expires 30d;\n        add_header Cache-Control \"public, immutable\";\n    }\n}\n```\n\n### Rate Limiting\n\n```nginx\n# Define rate limit zones in http block\nhttp {\n    # 10 requests\u002Fsecond per IP\n    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r\u002Fs;\n\n    # 1 request\u002Fsecond for login\n    limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r\u002Fs;\n\n    # Connection limit per IP\n    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;\n}\n\nserver {\n    listen 443 ssl http2;\n    server_name app.example.com;\n\n    # Apply rate limit to API\n    location \u002Fapi\u002F {\n        limit_req zone=api_limit burst=20 nodelay;\n        limit_req_status 429;\n        proxy_pass http:\u002F\u002F127.0.0.1:8080;\n    }\n\n    # Strict rate limit on auth endpoints\n    location \u002Fapi\u002Fauth\u002F {\n        limit_req zone=login_limit burst=5;\n        limit_req_status 429;\n        proxy_pass http:\u002F\u002F127.0.0.1:8080;\n    }\n\n    # Connection limit\n    location \u002F {\n        limit_conn conn_limit 100;\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n    }\n}\n```\n\n### Gzip and Brotli Compression\n\n```nginx\nhttp {\n    gzip on;\n    gzip_types text\u002Fplain text\u002Fcss application\u002Fjson application\u002Fjavascript text\u002Fxml application\u002Fxml image\u002Fsvg+xml;\n    gzip_min_length 256;\n    gzip_vary on;\n    gzip_proxied any;\n    gzip_comp_level 5;\n\n    # Brotli (requires ngx_brotli module)\n    # brotli on;\n    # brotli_types text\u002Fplain text\u002Fcss application\u002Fjson application\u002Fjavascript text\u002Fxml application\u002Fxml image\u002Fsvg+xml;\n    # brotli_comp_level 6;\n}\n```\n\n### Let's Encrypt with Certbot\n\n```bash\n# Install certbot with nginx plugin\nsudo apt install certbot python3-certbot-nginx\n\n# Obtain and install certificate\nsudo certbot --nginx -d app.example.com -d www.example.com\n\n# Auto-renewal is configured via systemd timer\nsudo systemctl status certbot.timer\n\n# Manual renewal test\nsudo certbot renew --dry-run\n```\n\n## Traefik Reverse Proxy\n\n### Static Configuration\n\n```yaml\n# traefik.yml\nentryPoints:\n  web:\n    address: \":80\"\n    http:\n      redirections:\n        entryPoint:\n          to: websecure\n          scheme: https\n  websecure:\n    address: \":443\"\n\ncertificatesResolvers:\n  letsencrypt:\n    acme:\n      email: admin@example.com\n      storage: \u002Fletsencrypt\u002Facme.json\n      httpChallenge:\n        entryPoint: web\n\nproviders:\n  docker:\n    exposedByDefault: false\n  file:\n    directory: \u002Fetc\u002Ftraefik\u002Fdynamic\u002F\n\napi:\n  dashboard: true\n  insecure: false\n\nlog:\n  level: INFO\n\naccessLog:\n  filePath: \u002Fvar\u002Flog\u002Ftraefik\u002Faccess.log\n```\n\n### Dynamic Configuration (File Provider)\n\n```yaml\n# \u002Fetc\u002Ftraefik\u002Fdynamic\u002Fservices.yml\nhttp:\n  routers:\n    app:\n      rule: \"Host(`app.example.com`)\"\n      entryPoints:\n        - websecure\n      service: app\n      tls:\n        certResolver: letsencrypt\n      middlewares:\n        - security-headers\n        - rate-limit\n\n    api:\n      rule: \"Host(`app.example.com`) && PathPrefix(`\u002Fapi`)\"\n      entryPoints:\n        - websecure\n      service: api\n      tls:\n        certResolver: letsencrypt\n\n  services:\n    app:\n      loadBalancer:\n        servers:\n          - url: \"http:\u002F\u002F127.0.0.1:3000\"\n        healthCheck:\n          path: \u002Fhealth\n          interval: 10s\n          timeout: 3s\n\n    api:\n      loadBalancer:\n        servers:\n          - url: \"http:\u002F\u002F127.0.0.1:8080\"\n        healthCheck:\n          path: \u002Fapi\u002Fhealth\n          interval: 10s\n          timeout: 3s\n\n  middlewares:\n    security-headers:\n      headers:\n        stsSeconds: 63072000\n        stsIncludeSubdomains: true\n        frameDeny: true\n        contentTypeNosniff: true\n        browserXssFilter: true\n        referrerPolicy: strict-origin-when-cross-origin\n\n    rate-limit:\n      rateLimit:\n        average: 100\n        burst: 50\n        period: 1m\n```\n\n### Traefik with Docker Labels\n\n```yaml\n# docker-compose.yml\nversion: \"3.8\"\n\nservices:\n  traefik:\n    image: traefik:v3.0\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    volumes:\n      - \u002Fvar\u002Frun\u002Fdocker.sock:\u002Fvar\u002Frun\u002Fdocker.sock:ro\n      - .\u002Ftraefik.yml:\u002Fetc\u002Ftraefik\u002Ftraefik.yml:ro\n      - letsencrypt:\u002Fletsencrypt\n\n  frontend:\n    image: my-frontend:latest\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.frontend.rule=Host(`app.example.com`)\"\n      - \"traefik.http.routers.frontend.tls.certresolver=letsencrypt\"\n      - \"traefik.http.services.frontend.loadbalancer.server.port=3000\"\n\n  api:\n    image: my-api:latest\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.api.rule=Host(`app.example.com`) && PathPrefix(`\u002Fapi`)\"\n      - \"traefik.http.routers.api.tls.certresolver=letsencrypt\"\n      - \"traefik.http.services.api.loadbalancer.server.port=8080\"\n      - \"traefik.http.routers.api.middlewares=api-ratelimit\"\n      - \"traefik.http.middlewares.api-ratelimit.ratelimit.average=50\"\n      - \"traefik.http.middlewares.api-ratelimit.ratelimit.burst=25\"\n\nvolumes:\n  letsencrypt:\n```\n\n## nginx Testing and Management\n\n```bash\n# Test configuration syntax\nsudo nginx -t\n\n# Reload without downtime\nsudo nginx -s reload\n\n# View active connections\nsudo nginx -s status\n\n# Check which config file is active\nnginx -V 2>&1 | grep -o '\\-\\-conf-path=[^ ]*'\n\n# Monitor access logs\ntail -f \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log\n\n# Monitor error logs\ntail -f \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log\n```\n\n## IP Allowlisting and Geoblocking\n\n```nginx\n# Allow only specific IPs (admin panel)\nlocation \u002Fadmin\u002F {\n    allow 203.0.113.0\u002F24;\n    allow 198.51.100.5;\n    deny all;\n    proxy_pass http:\u002F\u002F127.0.0.1:3000;\n}\n\n# Block by country (requires GeoIP2 module)\n# geoip2 \u002Fusr\u002Fshare\u002FGeoIP\u002FGeoLite2-Country.mmdb {\n#     auto_reload 60m;\n#     $geoip2_data_country_iso_code country iso_code;\n# }\n# if ($geoip2_data_country_iso_code = \"XX\") {\n#     return 403;\n# }\n```\n\n## Troubleshooting\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| 502 Bad Gateway | Backend not running or unreachable | Verify backend is listening; check `proxy_pass` URL |\n| 504 Gateway Timeout | Backend too slow | Increase `proxy_read_timeout`; check backend performance |\n| Mixed content warnings | `X-Forwarded-Proto` not set | Add `proxy_set_header X-Forwarded-Proto $scheme` |\n| WebSocket disconnects after 60s | Default proxy timeout expires | Set `proxy_read_timeout 86400s` for WebSocket locations |\n| Rate limit hits legitimate users | Zone rate too aggressive | Increase `rate` or `burst` values; use different zones per endpoint |\n| Let's Encrypt renewal fails | Port 80 blocked or wrong server block | Ensure `.well-known\u002Facme-challenge\u002F` is accessible |\n| Traefik shows 404 for all routes | Docker labels not detected | Verify Docker socket is mounted; check `exposedByDefault` setting |\n| TLS handshake failure | Certificate chain incomplete | Include intermediate certificates in `ssl_certificate` |\n\n## Related Skills\n\n- load-balancing (`load-balancing`) - Multi-backend traffic distribution\n- cdn-setup (`cdn-setup`) - CDN in front of reverse proxy\n- dns-management (`dns-management`) - DNS records for proxy domains\n- service-mesh (`service-mesh`) - Service-level routing in Kubernetes\n\n## Limitations\n\n- Infrastructure commands can disrupt services: confirm target host\u002Fscope and have backups\u002Fsnapshots before mutating state.\n- Docs-only import: upstream scripts and templates not bundled.\n\n","# Reverse Proxy\n\nConfigure reverse proxies to route traffic, terminate TLS, enforce rate limits, and serve as the gateway between clients and backend services.\n\n## When to Use\n\n- Routing traffic from a public domain to one or more backend services.\n- Terminating TLS at the edge and forwarding plain HTTP to backends.\n- Adding rate limiting, CORS, security headers, and access control.\n- Consolidating multiple services under a single domain with path-based routing.\n- Handling WebSocket upgrades, gRPC proxying, or HTTP\u002F2 passthrough.\n\n## Prerequisites\n\n- Backend service(s) running on known host:port.\n- TLS certificate (Let's Encrypt, ACM, or self-signed for development).\n- nginx 1.25+ or Traefik 3.x installed.\n- DNS record pointing the domain to the proxy server.\n\n## nginx Reverse Proxy\n\n### Basic HTTPS Proxy with Redirect\n\n```nginx\n# \u002Fetc\u002Fnginx\u002Fsites-available\u002Fapp.example.com\nserver {\n    listen 80;\n    server_name app.example.com;\n    return 301 https:\u002F\u002F$host$request_uri;\n}\n\nserver {\n    listen 443 ssl http2;\n    server_name app.example.com;\n\n    # TLS configuration\n    ssl_certificate     \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapp.example.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapp.example.com\u002Fprivkey.pem;\n    ssl_protocols       TLSv1.2 TLSv1.3;\n    ssl_ciphers         ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384;\n    ssl_prefer_server_ciphers on;\n    ssl_session_cache   shared:SSL:10m;\n    ssl_session_timeout 10m;\n\n    # Security headers\n    add_header Strict-Transport-Security \"max-age=63072000; includeSubDomains; preload\" always;\n    add_header X-Frame-Options DENY always;\n    add_header X-Content-Type-Options nosniff always;\n    add_header Referrer-Policy strict-origin-when-cross-origin always;\n\n    # Proxy to backend\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n        proxy_http_version 1.1;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n        proxy_set_header X-Forwarded-Proto $scheme;\n\n        # Timeouts\n        proxy_connect_timeout 5s;\n        proxy_read_timeout 60s;\n        proxy_send_timeout 60s;\n\n        # Buffering\n        proxy_buffering on;\n        proxy_buffer_size 4k;\n        proxy_buffers 8 4k;\n    }\n}\n```\n\n### Path-Based Routing to Multiple Services\n\n```nginx\nserver {\n    listen 443 ssl http2;\n    server_name app.example.com;\n\n    ssl_certificate     \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapp.example.com\u002Ffullchain.pem;\n    ssl_certificate_key \u002Fetc\u002Fletsencrypt\u002Flive\u002Fapp.example.com\u002Fprivkey.pem;\n\n    # Frontend SPA\n    location \u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n        proxy_set_header Host $host;\n    }\n\n    # API backend\n    location \u002Fapi\u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:8080\u002F;\n        proxy_set_header Host $host;\n        proxy_set_header X-Real-IP $remote_addr;\n        proxy_read_timeout 120s;\n    }\n\n    # WebSocket endpoint\n    location \u002Fws\u002F {\n        proxy_pass http:\u002F\u002F127.0.0.1:8080;\n        proxy_http_version 1.1;\n        proxy_set_header Upgrade $http_upgrade;\n        proxy_set_header Connection \"upgrade\";\n        proxy_set_header Host $host;\n        proxy_read_timeout 86400s;  # 24h for long-lived connections\n    }\n\n    # Static assets with caching\n    location \u002Fstatic\u002F {\n        alias \u002Fvar\u002Fwww\u002Fstatic\u002F;\n        expires 30d;\n        add_header Cache-Control \"public, immutable\";\n    }\n}\n```\n\n### Rate Limiting\n\n```nginx\n# Define rate limit zones in http block\nhttp {\n    # 10 requests\u002Fsecond per IP\n    limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r\u002Fs;\n\n    # 1 request\u002Fsecond for login\n    limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r\u002Fs;\n\n    # Connection limit per IP\n    limit_conn_zone $binary_remote_addr zone=conn_limit:10m;\n}\n\nserver {\n    listen 443 ssl http2;\n    server_name app.example.com;\n\n    # Apply rate limit to API\n    location \u002Fapi\u002F {\n        limit_req zone=api_limit burst=20 nodelay;\n        limit_req_status 429;\n        proxy_pass http:\u002F\u002F127.0.0.1:8080;\n    }\n\n    # Strict rate limit on auth endpoints\n    location \u002Fapi\u002Fauth\u002F {\n        limit_req zone=login_limit burst=5;\n        limit_req_status 429;\n        proxy_pass http:\u002F\u002F127.0.0.1:8080;\n    }\n\n    # Connection limit\n    location \u002F {\n        limit_conn conn_limit 100;\n        proxy_pass http:\u002F\u002F127.0.0.1:3000;\n    }\n}\n```\n\n### Gzip and Brotli Compression\n\n```nginx\nhttp {\n    gzip on;\n    gzip_types text\u002Fplain text\u002Fcss application\u002Fjson application\u002Fjavascript text\u002Fxml application\u002Fxml image\u002Fsvg+xml;\n    gzip_min_length 256;\n    gzip_vary on;\n    gzip_proxied any;\n    gzip_comp_level 5;\n\n    # Brotli (requires ngx_brotli module)\n    # brotli on;\n    # brotli_types text\u002Fplain text\u002Fcss application\u002Fjson application\u002Fjavascript text\u002Fxml application\u002Fxml image\u002Fsvg+xml;\n    # brotli_comp_level 6;\n}\n```\n\n### Let's Encrypt with Certbot\n\n```bash\n# Install certbot with nginx plugin\nsudo apt install certbot python3-certbot-nginx\n\n# Obtain and install certificate\nsudo certbot --nginx -d app.example.com -d www.example.com\n\n# Auto-renewal is configured via systemd timer\nsudo systemctl status certbot.timer\n\n# Manual renewal test\nsudo certbot renew --dry-run\n```\n\n## Traefik Reverse Proxy\n\n### Static Configuration\n\n```yaml\n# traefik.yml\nentryPoints:\n  web:\n    address: \":80\"\n    http:\n      redirections:\n        entryPoint:\n          to: websecure\n          scheme: https\n  websecure:\n    address: \":443\"\n\ncertificatesResolvers:\n  letsencrypt:\n    acme:\n      email: admin@example.com\n      storage: \u002Fletsencrypt\u002Facme.json\n      httpChallenge:\n        entryPoint: web\n\nproviders:\n  docker:\n    exposedByDefault: false\n  file:\n    directory: \u002Fetc\u002Ftraefik\u002Fdynamic\u002F\n\napi:\n  dashboard: true\n  insecure: false\n\nlog:\n  level: INFO\n\naccessLog:\n  filePath: \u002Fvar\u002Flog\u002Ftraefik\u002Faccess.log\n```\n\n### Dynamic Configuration (File Provider)\n\n```yaml\n# \u002Fetc\u002Ftraefik\u002Fdynamic\u002Fservices.yml\nhttp:\n  routers:\n    app:\n      rule: \"Host(`app.example.com`)\"\n      entryPoints:\n        - websecure\n      service: app\n      tls:\n        certResolver: letsencrypt\n      middlewares:\n        - security-headers\n        - rate-limit\n\n    api:\n      rule: \"Host(`app.example.com`) && PathPrefix(`\u002Fapi`)\"\n      entryPoints:\n        - websecure\n      service: api\n      tls:\n        certResolver: letsencrypt\n\n  services:\n    app:\n      loadBalancer:\n        servers:\n          - url: \"http:\u002F\u002F127.0.0.1:3000\"\n        healthCheck:\n          path: \u002Fhealth\n          interval: 10s\n          timeout: 3s\n\n    api:\n      loadBalancer:\n        servers:\n          - url: \"http:\u002F\u002F127.0.0.1:8080\"\n        healthCheck:\n          path: \u002Fapi\u002Fhealth\n          interval: 10s\n          timeout: 3s\n\n  middlewares:\n    security-headers:\n      headers:\n        stsSeconds: 63072000\n        stsIncludeSubdomains: true\n        frameDeny: true\n        contentTypeNosniff: true\n        browserXssFilter: true\n        referrerPolicy: strict-origin-when-cross-origin\n\n    rate-limit:\n      rateLimit:\n        average: 100\n        burst: 50\n        period: 1m\n```\n\n### Traefik with Docker Labels\n\n```yaml\n# docker-compose.yml\nversion: \"3.8\"\n\nservices:\n  traefik:\n    image: traefik:v3.0\n    ports:\n      - \"80:80\"\n      - \"443:443\"\n    volumes:\n      - \u002Fvar\u002Frun\u002Fdocker.sock:\u002Fvar\u002Frun\u002Fdocker.sock:ro\n      - .\u002Ftraefik.yml:\u002Fetc\u002Ftraefik\u002Ftraefik.yml:ro\n      - letsencrypt:\u002Fletsencrypt\n\n  frontend:\n    image: my-frontend:latest\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.frontend.rule=Host(`app.example.com`)\"\n      - \"traefik.http.routers.frontend.tls.certresolver=letsencrypt\"\n      - \"traefik.http.services.frontend.loadbalancer.server.port=3000\"\n\n  api:\n    image: my-api:latest\n    labels:\n      - \"traefik.enable=true\"\n      - \"traefik.http.routers.api.rule=Host(`app.example.com`) && PathPrefix(`\u002Fapi`)\"\n      - \"traefik.http.routers.api.tls.certresolver=letsencrypt\"\n      - \"traefik.http.services.api.loadbalancer.server.port=8080\"\n      - \"traefik.http.routers.api.middlewares=api-ratelimit\"\n      - \"traefik.http.middlewares.api-ratelimit.ratelimit.average=50\"\n      - \"traefik.http.middlewares.api-ratelimit.ratelimit.burst=25\"\n\nvolumes:\n  letsencrypt:\n```\n\n## nginx Testing and Management\n\n```bash\n# Test configuration syntax\nsudo nginx -t\n\n# Reload without downtime\nsudo nginx -s reload\n\n# View active connections\nsudo nginx -s status\n\n# Check which config file is active\nnginx -V 2>&1 | grep -o '\\-\\-conf-path=[^ ]*'\n\n# Monitor access logs\ntail -f \u002Fvar\u002Flog\u002Fnginx\u002Faccess.log\n\n# Monitor error logs\ntail -f \u002Fvar\u002Flog\u002Fnginx\u002Ferror.log\n```\n\n## IP Allowlisting and Geoblocking\n\n```nginx\n# Allow only specific IPs (admin panel)\nlocation \u002Fadmin\u002F {\n    allow 203.0.113.0\u002F24;\n    allow 198.51.100.5;\n    deny all;\n    proxy_pass http:\u002F\u002F127.0.0.1:3000;\n}\n\n# Block by country (requires GeoIP2 module)\n# geoip2 \u002Fusr\u002Fshare\u002FGeoIP\u002FGeoLite2-Country.mmdb {\n#     auto_reload 60m;\n#     $geoip2_data_country_iso_code country iso_code;\n# }\n# if ($geoip2_data_country_iso_code = \"XX\") {\n#     return 403;\n# }\n```\n\n## Troubleshooting\n\n| Symptom | Cause | Fix |\n|---------|-------|-----|\n| 502 Bad Gateway | Backend not running or unreachable | Verify backend is listening; check `proxy_pass` URL |\n| 504 Gateway Timeout | Backend too slow | Increase `proxy_read_timeout`; check backend performance |\n| Mixed content warnings | `X-Forwarded-Proto` not set | Add `proxy_set_header X-Forwarded-Proto $scheme` |\n| WebSocket disconnects after 60s | Default proxy timeout expires | Set `proxy_read_timeout 86400s` for WebSocket locations |\n| Rate limit hits legitimate users | Zone rate too aggressive | Increase `rate` or `burst` values; use different zones per endpoint |\n| Let's Encrypt renewal fails | Port 80 blocked or wrong server block | Ensure `.well-known\u002Facme-challenge\u002F` is accessible |\n| Traefik shows 404 for all routes | Docker labels not detected | Verify Docker socket is mounted; check `exposedByDefault` setting |\n| TLS handshake failure | Certificate chain incomplete | Include intermediate certificates in `ssl_certificate` |\n\n## Related Skills\n\n- load-balancing (`load-balancing`) - Multi-backend traffic distribution\n- cdn-setup (`cdn-setup`) - CDN in front of reverse proxy\n- dns-management (`dns-management`) - DNS records for proxy domains\n- service-mesh (`service-mesh`) - Service-level routing in Kubernetes\n\n## Limitations\n\n- Infrastructure commands can disrupt services: confirm target host\u002Fscope and have backups\u002Fsnapshots before mutating state.\n- Docs-only import: upstream scripts and templates not bundled.\n\n",{"name":5,"risk":24,"source":43,"license":14,"category":44,"metadata":45,"date_added":48,"description":7,"source_repo":49,"source_type":21,"compatibility":50,"license_source":51},"https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills","devops",{"author":46,"version":47},"devops-skills","1.0","2026-09-20","BagelHole\u002FDevOps-Security-Agent-Skills","Requires the relevant OS\u002Fplatform tooling and privileged access where noted. Docs-only; helper scripts and templates not bundled.","https:\u002F\u002Fgithub.com\u002FBagelHole\u002FDevOps-Security-Agent-Skills\u002Fblob\u002Fmain\u002FLICENSE","f3312ba749561b6159f477dbfc9313c875d40a56",".agents\u002Fskills_archive\u002Freverse-proxy","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612","2026-10-25 23:50:58",{"source":8,"skillName":5,"commands":58,"prompt":68,"zipAvailable":69},[59,62,65],{"tool":60,"command":61},"npx","npx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill reverse-proxy",{"tool":63,"command":64},"bunx","bunx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill reverse-proxy",{"tool":66,"command":67},"pnpm","pnpm dlx skills add duc-duy-1612\u002FOnline-Delivery-Systems-Web --skill reverse-proxy","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Freverse-proxy\u002FSKILL.md",true,[],[72,94,118,142,170,194],{"skillNo":73,"name":74,"nameZh":6,"description":75,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":76,"categories":77,"keywords":83,"publishedAt":38},"01M6Q0FA5FZ410Z33Z3TFQ4DBA","zero-trust","Implement zero-trust network architecture. Configure identity-based access, micro-segmentation, and continuous verification. Use when implementing modern security architectures.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fzero-trust\u002FSKILL.md",[78],{"categoryNo":79,"categoryName":80,"taxonomyType":81,"taxonomyTypeDesc":82},"01JBSEEDCAT000000000000011","运维与部署","SCENARIO","使用场景",[84,85,86,87,88,89,74,90,34,33,32,31,21,28,91,24,92,23,22,93],"ZeRO","trust","zero trust","architecture","assessment","verification","segmentation","active","scope","implementing",{"skillNo":95,"name":96,"nameZh":6,"description":97,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":98,"categories":99,"keywords":100,"publishedAt":38},"01M6Q0F1YZJW3KX5FBKEVZ8CV4","zcode-delegate","Delegate coding tasks to the Z.AI ZCode CLI only when the user explicitly requests it, while the orchestrator retains review and landing responsibility.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fzcode-delegate\u002FSKILL.md",[],[101,102,103,104,105,106,107,108,109,110,111,112,113,31,114,21,115,116,24,117],"delegate","zcode","zcode delegate","review","cli","orchestration","tasks","run","Bash","model","node","read","orchestrator","files","desktop app","app","agent-orchestration",{"skillNo":119,"name":120,"nameZh":6,"description":121,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":124,"publishedAt":38},"01M6Q0ETK41VGNMYEXW0T00AJN","youtube-transcript","Fetch YouTube transcripts through DeepAPI or local fallback tooling and save clean text output.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-transcript\u002FSKILL.md",[],[125,126,127,128,129,130,131,37,132,133,134,135,136,21,28,137,138,139,140,141],"transcript","youtube transcript","youtube","safe","github","codex","research","https","text","fetch","tooling","clean","local","output","deepapi","youtube transcripts","blob",{"skillNo":143,"name":144,"nameZh":6,"description":145,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":146,"categories":147,"keywords":159,"publishedAt":38},"01M6Q0EPPH2PVMDW40017F8WX0","youtube-transcript-skills","Fetch YouTube video transcripts, search videos\u002Fchannels, browse channels, and extract playlists via the getyoutubetranscript.com API - free tier, no card required.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-transcript-skills\u002FSKILL.md",[148,151,154],{"categoryNo":149,"categoryName":150,"taxonomyType":81,"taxonomyTypeDesc":82},"01JBSEEDCAT000000000000010","后端与接口",{"categoryNo":152,"categoryName":153,"taxonomyType":81,"taxonomyTypeDesc":82},"01JBSEEDCAT000000000000016","图像与多媒体",{"categoryNo":155,"categoryName":156,"taxonomyType":157,"taxonomyTypeDesc":158},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[125,126,127,160,128,161,129,130,37,162,163,164,165,134,166,21,28,167,168,169],"youtube transcript skills","gemini","search","api","Video","browse","api-integration","free","card","channels",{"skillNo":171,"name":172,"nameZh":6,"description":173,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":174,"categories":175,"keywords":180,"publishedAt":38},"01M6Q0EAB96PX83W5PTE8A0R8D","youtube-notetaker","Turn YouTube talks into local study notes with slides, transcripts, editable annotations, and a markdown-backed viewer.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-notetaker\u002FSKILL.md",[176,179],{"categoryNo":177,"categoryName":178,"taxonomyType":81,"taxonomyTypeDesc":82},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":152,"categoryName":153,"taxonomyType":81,"taxonomyTypeDesc":82},[127,181,182,105,128,183,184,185,186,37,164,187,188,189,190,28,191,137,192,193],"youtube notetaker","notetaker","workflow","official","notes","code","markdown","slides","annotations","README","study","dair-academy","viewer",{"skillNo":195,"name":196,"nameZh":6,"description":197,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":198,"categories":199,"keywords":201,"publishedAt":38},"01M6Q0E55F0GW5MX48V8HXS8B5","youtube-full","Fetch YouTube transcripts, search videos, browse channels, and extract playlists via TranscriptAPI — no yt-dlp, no Google API key, works from any cloud server.","https:\u002F\u002Fgithub.com\u002Fduc-duy-1612\u002FOnline-Delivery-Systems-Web\u002Fblob\u002Fmain\u002F.agents\u002Fskills_archive\u002Fyoutube-full\u002FSKILL.md",[200],{"categoryNo":149,"categoryName":150,"taxonomyType":81,"taxonomyTypeDesc":82},[202,127,203,204,128,161,162,205,206,163,164,165,134,207,166,21,28,167,208,140],"youtube full","full","google","server","dlp","credits","automatic"]