|
| 1 | +--- |
| 2 | +sidebar_position: 10 |
| 3 | +sidebar_label: Setup TLS / HTTPS Docker Compose + Traefik v2 |
| 4 | +--- |
| 5 | + |
| 6 | +# Setup TLS / HTTPS Docker Compose + Traefik v2 |
| 7 | + |
| 8 | +This guide documents how to enable HTTPS for a ReportPortal Docker Compose deployment using **Traefik v2** as the reverse proxy. It covers both **self-signed certificates** (for local or internal testing) and **Let’s Encrypt certificates** (for publicly trusted TLS). |
| 9 | + |
| 10 | +## 1. Supported TLS Scenarios |
| 11 | + |
| 12 | +| **Certificate Type** | **Environment** | **Public Internet Required** | |
| 13 | +| ----------- | ----- | ------------ | |
| 14 | +| Self-signed (OpenSSL) | Localhost / Internal VPC | No | |
| 15 | +| Let’s Encrypt (HTTP-01) | Public EC2 + Route 53 | Yes | |
| 16 | +| Let’s Encrypt (DNS-01) | Private VPC | No | |
| 17 | + |
| 18 | +:::important |
| 19 | +Let’s Encrypt HTTP-01 validation requires **public internet reachability**.<br /> |
| 20 | +Deployments in private subnets without an Internet Gateway **must use DNS-01** instead. |
| 21 | +::: |
| 22 | + |
| 23 | +## 2. Test Environment (Reference) |
| 24 | + |
| 25 | +**AWS Infrastructure (HTTP-01 scenario)** |
| 26 | + |
| 27 | +| **Component** | **Specification** | |
| 28 | +| ----------- |----------------------------------| |
| 29 | +| EC2 | t3.medium (2 vCPU, 4 GB RAM) / |
| 30 | +| OS | Ubuntu 24.04 / Amazon Linux 2023 | |
| 31 | +| Subnet | Public subnet with IGW | |
| 32 | +| DNS | Route 53 public hosted zone | |
| 33 | +| Domain | <a>tls-docker.example.com</a> | |
| 34 | + |
| 35 | +Using a public subnet removes ambiguity during troubleshooting. |
| 36 | + |
| 37 | +**Required Security Group Rules** |
| 38 | + |
| 39 | +| **Type** | **Port** | **Source** | **Purpose** | |
| 40 | +| ----------- | ----- | ------------ | ----- | |
| 41 | +| HTTP | 80 | 0.0.0.0/0 | ACME HTTP-01 | |
| 42 | +| HTTPS | 443 | 0.0.0.0/0 | HTTPS access | |
| 43 | +| TCP | 8081 | Your IP | Traefik dashboard | |
| 44 | +| SSH | 22 | Your IP | Management | |
| 45 | + |
| 46 | +## 3. Scenario 1 — Self-Signed Certificates (OpenSSL) |
| 47 | + |
| 48 | +### 3.1 Generate Certificates |
| 49 | + |
| 50 | +``` |
| 51 | +mkdir -p certs |
| 52 | +
|
| 53 | +openssl genrsa -out certs/reportportal.key 2048 |
| 54 | +
|
| 55 | +openssl req -new -x509 \ |
| 56 | + -key certs/reportportal.key \ |
| 57 | + -out certs/reportportal.crt \ |
| 58 | + -days 365 \ |
| 59 | + -subj "/CN=localhost" \ |
| 60 | + -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" |
| 61 | +``` |
| 62 | + |
| 63 | +### 3.2 Traefik File Provider (TLS) |
| 64 | + |
| 65 | +Create ```certs/tls.yml```: |
| 66 | + |
| 67 | +``` |
| 68 | +tls: |
| 69 | +certificates: |
| 70 | +- certFile: /certs/reportportal.crt |
| 71 | +keyFile: /certs/reportportal.key |
| 72 | +``` |
| 73 | + |
| 74 | +### 3.3 Validation — Self-Signed TLS |
| 75 | + |
| 76 | +**Verify key matches certificate** |
| 77 | + |
| 78 | +``` |
| 79 | +openssl x509 -noout -modulus -in certs/reportportal.crt | openssl md5 |
| 80 | +openssl rsa -noout -modulus -in certs/reportportal.key | openssl md5 |
| 81 | +``` |
| 82 | + |
| 83 | +**Trust validation** |
| 84 | + |
| 85 | +``` |
| 86 | +curl -v --cacert certs/reportportal.crt https://localhost |
| 87 | +``` |
| 88 | + |
| 89 | +**Fingerprint comparison** |
| 90 | + |
| 91 | +``` |
| 92 | +oopenssl x509 -in certs/reportportal.crt -noout -fingerprint -sha256 |
| 93 | +
|
| 94 | +openssl s_client -connect localhost:443 </dev/null 2>/dev/null \ |
| 95 | +| openssl x509 -noout -fingerprint -sha256 |
| 96 | +``` |
| 97 | + |
| 98 | +**Subject and validity** |
| 99 | + |
| 100 | +``` |
| 101 | +openssl s_client -connect localhost:443 </dev/null 2>/dev/null \ |
| 102 | +| openssl x509 -noout -subject -issuer -dates |
| 103 | +``` |
| 104 | + |
| 105 | +## 4. Scenario 2 — Let’s Encrypt (HTTP-01) |
| 106 | + |
| 107 | +### 4.1 Prerequisites (Mandatory) |
| 108 | + |
| 109 | +* Domain resolves to a **public IP** |
| 110 | +* EC2 subnet has route: |
| 111 | + |
| 112 | +``` |
| 113 | +0.0.0.0/0 → Internet Gateway |
| 114 | +``` |
| 115 | + |
| 116 | +* Ports **80** and **443** reachable from the internet |
| 117 | + |
| 118 | +### 4.2 Prepare ACME Storage |
| 119 | + |
| 120 | +``` |
| 121 | +touch acme.json |
| 122 | +chmod 600 acme.json |
| 123 | +``` |
| 124 | + |
| 125 | +### 4.3 Docker Compose — Traefik Gateway |
| 126 | + |
| 127 | +``` |
| 128 | +services: |
| 129 | +gateway: |
| 130 | +image: traefik:v2.11.32 |
| 131 | +restart: unless-stopped |
| 132 | +ports: |
| 133 | +- "80:80" |
| 134 | +- "443:443" |
| 135 | +- "8081:8081" |
| 136 | +volumes: |
| 137 | +- /var/run/docker.sock:/var/run/docker.sock:ro |
| 138 | +- ./acme.json:/acme.json |
| 139 | +command: |
| 140 | +- --providers.docker=true |
| 141 | +- --providers.docker.exposedbydefault=false |
| 142 | +
|
| 143 | + - --entrypoints.web.address=:80 |
| 144 | + - --entrypoints.websecure.address=:443 |
| 145 | + - --entrypoints.traefik.address=:8081 |
| 146 | + |
| 147 | + - --entrypoints.web.http.redirections.entrypoint.to=websecure |
| 148 | + - --entrypoints.web.http.redirections.entrypoint.scheme=https |
| 149 | + |
| 150 | + - --certificatesresolvers.letsencrypt.acme.email=admin@example.com |
| 151 | + - --certificatesresolvers.letsencrypt.acme.storage=/acme.json |
| 152 | + - --certificatesresolvers.letsencrypt.acme.httpchallenge=true |
| 153 | + - --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web |
| 154 | + |
| 155 | + - --api.dashboard=true |
| 156 | + - --api.insecure=true |
| 157 | +``` |
| 158 | + |
| 159 | +### 4.4 Service TLS Labels |
| 160 | + |
| 161 | +``` |
| 162 | +labels: |
| 163 | +- "traefik.enable=true" |
| 164 | +- "traefik.http.routers.app.rule=Host(`tls-docker.example.com`)" |
| 165 | +- "traefik.http.routers.app.entrypoints=websecure" |
| 166 | +- "traefik.http.routers.app.tls=true" |
| 167 | +- "traefik.http.routers.app.tls.certresolver=letsencrypt" |
| 168 | +- "traefik.http.services.app.loadbalancer.server.port=8080" |
| 169 | +``` |
| 170 | + |
| 171 | +## 5. Validation — Let’s Encrypt (HTTP-01) |
| 172 | + |
| 173 | +**DNS resolution** |
| 174 | + |
| 175 | +``` |
| 176 | +dig +short tls-docker.example.com |
| 177 | +dig @8.8.8.8 +short tls-docker.example.com |
| 178 | +``` |
| 179 | + |
| 180 | +**TCP reachability** |
| 181 | + |
| 182 | +``` |
| 183 | +nc -vz tls-docker.example.com 80 |
| 184 | +``` |
| 185 | + |
| 186 | +**HTTP reachability** |
| 187 | + |
| 188 | +``` |
| 189 | +curl -v http://tls-docker.example.com |
| 190 | +``` |
| 191 | + |
| 192 | +**ACME challenge path** |
| 193 | + |
| 194 | +``` |
| 195 | +404 Not Found is expected and correct |
| 196 | +``` |
| 197 | + |
| 198 | +**HTTPS validation** |
| 199 | + |
| 200 | +``` |
| 201 | +curl -v https://tls-docker.example.com |
| 202 | +``` |
| 203 | + |
| 204 | +**Certificate issuer verification** |
| 205 | + |
| 206 | +``` |
| 207 | +echo | openssl s_client \ |
| 208 | +-connect tls-docker.example.com:443 \ |
| 209 | +-servername tls-docker.example.com \ |
| 210 | +2>/dev/null | openssl x509 -noout -issuer -subject -dates |
| 211 | +``` |
| 212 | + |
| 213 | +Expected issuer: |
| 214 | + |
| 215 | +``` |
| 216 | +CN = Let's Encrypt |
| 217 | +``` |
| 218 | + |
| 219 | +## 6. Private Subnets — Important Limitation |
| 220 | + |
| 221 | +If the domain resolves to a **private IP (RFC1918)** or the subnet routes traffic via **NAT Gateway only**, Let’s Encrypt **HTTP-01 will fail**. |
| 222 | + |
| 223 | +**Symptoms** |
| 224 | + |
| 225 | +* DNS resolves internally but not publicly |
| 226 | +* ACME challenge never triggered |
| 227 | +* Traefik serves default certificate |
| 228 | + |
| 229 | +**Solution**<br /> |
| 230 | +Use **DNS-01 validation** with Route 53. |
| 231 | + |
| 232 | +## 7. Troubleshooting |
| 233 | + |
| 234 | +| **Issue** | **Cause** | **Resolution** | |
| 235 | +|-----------------|------------------|--| |
| 236 | +| ACME never triggers | No public ingress | Use DNS-01 | |
| 237 | +| Default Traefik cert | No issued cert | Check ACME logs | |
| 238 | +| <a>example.com</a> email error | Invalid ACME email | Use real domain | |
| 239 | +| Permission denied acme.json | Wrong file mode | chmod 600 | |
| 240 | +| 404 from HTTPS | Host rule mismatch | Verify router rule | |
| 241 | + |
| 242 | +## 8. Summary |
| 243 | + |
| 244 | +* Self-signed TLS works for **local and internal environments** |
| 245 | +* Let’s Encrypt HTTP-01 works **only with public ingress** |
| 246 | +* DNS-01 is required for **private VPC deployments** |
| 247 | +* Traefik configuration remains identical; only the ACME method changes |
0 commit comments