Improve SSL and ACME documentation
- Clarify that EASYHAPROXY_CERTBOT_AUTOCONFIG or CERTBOT_SERVER is required - Add complete docker-compose.yml examples for ACME setup - Explain SSL termination at HAProxy level vs backend containers - Reorganize SSL docs to emphasize volume method over label method - Add troubleshooting section for common ACME warnings - Clarify certificate storage paths and selection priority - Add examples showing both ACME and manual certificates together Resolves confusion about ACME configuration requirements and makes it clear that volume-mounted certificates are the recommended method for manual SSL certificates.
This commit is contained in:
parent
c340de1d9d
commit
4aba68dd37
3 changed files with 244 additions and 44 deletions
|
|
@ -26,15 +26,12 @@ services:
|
|||
- "443:443/tcp"
|
||||
- "1936:1936/tcp"
|
||||
|
||||
networks:
|
||||
- easyhaproxy
|
||||
|
||||
volumes:
|
||||
certs_certbot:
|
||||
external: true
|
||||
# external: true
|
||||
certs_haproxy:
|
||||
external: true
|
||||
# external: true
|
||||
|
||||
networks:
|
||||
easyhaproxy:
|
||||
external: true
|
||||
# external: true
|
||||
|
|
|
|||
151
docs/acme.md
151
docs/acme.md
|
|
@ -54,19 +54,21 @@ Tips
|
|||
|
||||
## Environment Variables
|
||||
|
||||
To enable the ACME protocol we need to enable Certbot in EasyHAProxy by setting up to the following environment variables:
|
||||
To enable the ACME protocol we need to enable Certbot in EasyHAProxy by setting up the following environment variables:
|
||||
|
||||
| Environment Variable | Required? | Description |
|
||||
|------------------------------------------|-----------|----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| EASYHAPROXY_CERTBOT_EMAIL | YES | Your email in the certificate authority. |
|
||||
| EASYHAPROXY_CERTBOT_AUTOCONFIG | - | Will use pre-sets for your Certificate Authority (CA). See table below. |
|
||||
| EASYHAPROXY_CERTBOT_SERVER | - | The ACME Endpoint of your certificate authority. If you use AUTOCONFIG, it is set automatically. See table below. |
|
||||
| EASYHAPROXY_CERTBOT_EMAIL | **YES** | Your email for the certificate authority. Required for certificate issuance. |
|
||||
| EASYHAPROXY_CERTBOT_AUTOCONFIG | **YES\*** | Pre-configured settings for your Certificate Authority (CA). See table below. **Required if CERTBOT_SERVER is not set.** |
|
||||
| EASYHAPROXY_CERTBOT_SERVER | **YES\*** | The ACME endpoint URL of your certificate authority. **Required if AUTOCONFIG is not set.** Auto-set when using AUTOCONFIG. |
|
||||
| EASYHAPROXY_CERTBOT_EAB_KID | - | External Account Binding (EAB) Key Identifier (KID) provided by your certificate authority. Some CA require it. See table below. |
|
||||
| EASYHAPROXY_CERTBOT_EAB_HMAC_KEY | - | External Account Binding (EAB) HMAC Key provided by your certificate authority. Some CA require it. See table below. |
|
||||
| EASYHAPROXY_CERTBOT_RETRY_COUNT | - | Wait 'n' requests before retrying issue invalid requests. Default 60. |
|
||||
| EASYHAPROXY_CERTBOT_PREFERRED_CHALLENGES | - | The preferred challenges for Certbot. Available: `http` |
|
||||
| EASYHAPROXY_CERTBOT_MANUAL_AUTH_HOOK | - | The path to a script that will be executed (default: None) |
|
||||
|
||||
**\*Important:** You must set **either** `EASYHAPROXY_CERTBOT_AUTOCONFIG` **or** `EASYHAPROXY_CERTBOT_SERVER` (not both). Using `AUTOCONFIG` is recommended as it automatically configures the server URL for popular certificate authorities.
|
||||
|
||||
## Auto Config Certificate Authority (CA)
|
||||
|
||||
Here are detailed instructions per Certificate Authority (CA). If anyone is missing, please let's know.
|
||||
|
|
@ -147,5 +149,146 @@ docker run \
|
|||
- Do not set port 443 for the container when using ACME, because EasyHAProxy will create the HTTPS binding automatically once the certificate is issued.
|
||||
:::
|
||||
|
||||
## Complete Docker Compose Example
|
||||
|
||||
Here's a complete `docker-compose.yml` showing proper ACME configuration:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
easyhaproxy:
|
||||
image: byjg/easy-haproxy:5.0.0
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
# REQUIRED: Persist Certbot certificates (ACME)
|
||||
- certs_certbot:/etc/easyhaproxy/certs/certbot
|
||||
# OPTIONAL: For manual certificates (see SSL documentation)
|
||||
- certs_haproxy:/etc/easyhaproxy/certs/haproxy
|
||||
environment:
|
||||
# Service discovery
|
||||
EASYHAPROXY_DISCOVER: docker
|
||||
EASYHAPROXY_LABEL_PREFIX: easyhaproxy
|
||||
|
||||
# ACME/Certbot Configuration (Method 1: Recommended)
|
||||
EASYHAPROXY_CERTBOT_EMAIL: your-email@example.com
|
||||
EASYHAPROXY_CERTBOT_AUTOCONFIG: letsencrypt
|
||||
|
||||
# ACME/Certbot Configuration (Method 2: Manual)
|
||||
# EASYHAPROXY_CERTBOT_EMAIL: your-email@example.com
|
||||
# EASYHAPROXY_CERTBOT_SERVER: https://acme-v02.api.letsencrypt.org/directory
|
||||
|
||||
# Other settings
|
||||
EASYHAPROXY_SSL_MODE: "default"
|
||||
HAPROXY_CUSTOMERRORS: "true"
|
||||
HAPROXY_USERNAME: admin
|
||||
HAPROXY_PASSWORD: password
|
||||
HAPROXY_STATS_PORT: 1936
|
||||
ports:
|
||||
- "80:80/tcp"
|
||||
- "443:443/tcp"
|
||||
- "1936:1936/tcp"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "-u", "admin:password", "http://localhost:1936"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
start_period: 30s
|
||||
retries: 3
|
||||
|
||||
# Example backend service with ACME enabled
|
||||
myapp:
|
||||
image: nginx:alpine
|
||||
labels:
|
||||
easyhaproxy.http.host: example.com
|
||||
easyhaproxy.http.port: 80
|
||||
easyhaproxy.http.localport: 80
|
||||
easyhaproxy.http.certbot: "true" # Enable ACME for this domain
|
||||
|
||||
volumes:
|
||||
certs_certbot:
|
||||
# This volume MUST be persisted to avoid rate limits
|
||||
certs_haproxy:
|
||||
# Optional: only needed if using manual certificates
|
||||
```
|
||||
|
||||
## Certificate Storage Paths
|
||||
|
||||
EasyHAProxy uses different paths for different certificate types:
|
||||
|
||||
| Path | Purpose | When to Mount |
|
||||
|----------------------------------|-------------------------------------|----------------------------------------------|
|
||||
| `/etc/easyhaproxy/certs/certbot` | ACME/Certbot automatic certificates | **Required** when using ACME |
|
||||
| `/etc/easyhaproxy/certs/haproxy` | Manual/custom certificates | Optional - only if using custom certificates |
|
||||
|
||||
Both volumes can be mounted simultaneously. Per-domain certificate selection:
|
||||
- If a domain has `certbot=true` label, ACME certificate is used
|
||||
- Otherwise, manual certificate from `/etc/easyhaproxy/certs/haproxy` is used (if present)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Warning: "ACME environment not ready: ACME server not configured"
|
||||
|
||||
**Cause:** You set `EASYHAPROXY_CERTBOT_EMAIL` but forgot to configure the ACME server.
|
||||
|
||||
**Solution:** Add one of these to your environment variables:
|
||||
|
||||
```yaml
|
||||
# Option 1: Use AUTOCONFIG (recommended)
|
||||
EASYHAPROXY_CERTBOT_AUTOCONFIG: letsencrypt
|
||||
|
||||
# Option 2: Set server manually
|
||||
EASYHAPROXY_CERTBOT_SERVER: https://acme-v02.api.letsencrypt.org/directory
|
||||
```
|
||||
|
||||
### Certificates Not Being Issued
|
||||
|
||||
**Common causes:**
|
||||
1. Port 80 is not publicly accessible
|
||||
2. DNS doesn't point to your server
|
||||
3. Container label missing `certbot=true`
|
||||
4. Container port is not 80 (`easyhaproxy.<definition>.port` must be 80)
|
||||
5. Rate limits hit (check `/etc/easyhaproxy/certs/certbot` volume)
|
||||
|
||||
**Debug steps:**
|
||||
```bash
|
||||
# Check EasyHAProxy logs
|
||||
docker logs easyhaproxy
|
||||
|
||||
# Check if Certbot volume is persisted
|
||||
docker volume inspect certs_certbot
|
||||
|
||||
# Verify port 80 is accessible
|
||||
curl -I http://your-domain.com/.well-known/acme-challenge/test
|
||||
```
|
||||
|
||||
### Rate Limit Errors
|
||||
|
||||
If you hit Let's Encrypt rate limits:
|
||||
- Wait for the limit window to reset (usually 1 week)
|
||||
- Use staging server for testing: `EASYHAPROXY_CERTBOT_AUTOCONFIG: letsencrypt_test`
|
||||
- Ensure `/etc/easyhaproxy/certs/certbot` volume is properly persisted
|
||||
- See: https://letsencrypt.org/docs/rate-limits/
|
||||
|
||||
### Using Both ACME and Manual Certificates
|
||||
|
||||
You can use both simultaneously:
|
||||
1. Mount both volumes (`certs_certbot` and `certs_haproxy`)
|
||||
2. Use `certbot=true` label for domains that should use ACME
|
||||
3. Omit the label for domains using manual certificates
|
||||
|
||||
Example:
|
||||
```yaml
|
||||
services:
|
||||
# This service uses ACME
|
||||
app1:
|
||||
labels:
|
||||
easyhaproxy.http.host: auto.example.com
|
||||
easyhaproxy.http.certbot: "true"
|
||||
|
||||
# This service uses manual certificate
|
||||
app2:
|
||||
labels:
|
||||
easyhaproxy.http.host: manual.example.com
|
||||
# No certbot label - will use /etc/easyhaproxy/certs/haproxy/manual.example.com.pem
|
||||
```
|
||||
|
||||
----
|
||||
[Open source ByJG](http://opensource.byjg.com)
|
||||
128
docs/ssl.md
128
docs/ssl.md
|
|
@ -4,42 +4,31 @@ sidebar_position: 9
|
|||
|
||||
# Setup custom certificates
|
||||
|
||||
You can use your own certificates with EasyHAProxy. You just need to let EasyHAProxy know that certificate.
|
||||
You can use your own certificates with EasyHAProxy instead of (or in addition to) automatic ACME/Certbot certificates.
|
||||
|
||||
There are two ways to do that.
|
||||
:::info How SSL Termination Works
|
||||
SSL termination happens at the **HAProxy level**, NOT in your backend containers.
|
||||
|
||||
- Your backend containers should **only** expose HTTP (port 80), not HTTPS
|
||||
- HAProxy handles all SSL/TLS encryption and decryption
|
||||
- Backend containers receive plain HTTP traffic from HAProxy
|
||||
- Do NOT configure SSL in your backend application when using EasyHAProxy
|
||||
|
||||
This is the **correct design** - it centralizes SSL management at the proxy layer.
|
||||
:::
|
||||
|
||||
:::info Certificate Types
|
||||
EasyHAProxy supports two certificate sources:
|
||||
- **ACME/Certbot automatic certificates** - Issued automatically via Let's Encrypt or other ACME providers (see [ACME documentation](./acme.md))
|
||||
- **Manual/custom certificates** - Your own certificates loaded via volume mount (recommended) or labels (this page)
|
||||
|
||||
Both can be used simultaneously. Per domain, ACME certificates (if `certbot=true` label is set) take precedence over manual certificates.
|
||||
:::
|
||||
|
||||
There are two ways to provide custom certificates:
|
||||
|
||||
- [Setup certificate as a label definition in docker container](#setup-certificate-as-a-label-definition-in-docker-container)
|
||||
- [Map the certificate as a docker volume](#map-the-certificate-as-a-docker-volume)
|
||||
|
||||
## Setup certificate as a label definition in docker container
|
||||
|
||||
1. Create a single PEM from the certificate and key.
|
||||
|
||||
```bash title="Combine certificate and key"
|
||||
cat example.com.crt example.com.key > single.pem
|
||||
|
||||
cat single.pem
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5ZheHqmBnEJP+
|
||||
U9r1gxYWKLzdqrMrcxtQN6M1hIH9n0peuJeIrybdcV7sMbStMXI=
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEojCCA4qgAwIBAgIUegW2BimwuL4RzRZ2WYkHA6U5nkAwDQYJKoZIhvcNAQEL
|
||||
3j4wz8/I5fdsk090j4s5KA==
|
||||
-----END PRIVATE KEY-----
|
||||
```
|
||||
|
||||
2. Convert the `single.pem` to BASE64 in a single line:
|
||||
|
||||
```bash title="Convert to BASE64"
|
||||
cat single.pem | base64 -w0
|
||||
```
|
||||
|
||||
3. Define a label in yout container
|
||||
|
||||
Add the Base64 string you generated before to the label `easyhaproxy.[definition].sslcert`
|
||||
- [Setup certificate as a label definition](#setup-certificate-as-a-label-definition-in-docker-container)
|
||||
|
||||
## Map the certificate as a docker volume
|
||||
|
||||
|
|
@ -77,8 +66,79 @@ MIIEojCCA4qgAwIBAgIUegW2BimwuL4RzRZ2WYkHA6U5nkAwDQYJKoZIhvcNAQEL
|
|||
3. Copy this certificate to EasyHAProxy volume:
|
||||
|
||||
```bash title="Copy certificate to container"
|
||||
docker cp single.pem easyhaproxy:/etc/easyhaproxy/certs/haproxy
|
||||
# IMPORTANT: Filename must match the domain!
|
||||
docker cp single.pem easyhaproxy:/etc/easyhaproxy/certs/haproxy/example.com.pem
|
||||
```
|
||||
|
||||
:::warning Important Notes
|
||||
- The filename **must match the domain name**: `example.com.pem` for domain `example.com`
|
||||
- When using volume-mounted certificates, **do NOT** use the `easyhaproxy.[definition].sslcert` label
|
||||
- The volume mount method and the label method are **mutually exclusive** per domain
|
||||
- SSL termination happens at HAProxy - your backend containers should only serve HTTP
|
||||
:::
|
||||
|
||||
4. Configure your backend container (no sslcert label needed):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
easyhaproxy:
|
||||
image: byjg/easy-haproxy:5.0.0
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- certs_haproxy:/etc/easyhaproxy/certs/haproxy
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
|
||||
myapp:
|
||||
image: nginx
|
||||
labels:
|
||||
easyhaproxy.web.host: example.com
|
||||
easyhaproxy.web.port: 80 # Frontend port (HAProxy listens here)
|
||||
easyhaproxy.web.localport: 80 # Backend port (your container)
|
||||
# NO sslcert label when using volume method!
|
||||
|
||||
volumes:
|
||||
certs_haproxy:
|
||||
```
|
||||
|
||||
## Setup certificate as a label definition in docker container
|
||||
|
||||
:::info Alternative Method
|
||||
This method embeds certificates directly in container labels. Use it when you want certificates in version control or don't want to manage external files. **Volume method is recommended for most use cases.**
|
||||
:::
|
||||
|
||||
1. Create a single PEM from the certificate and key:
|
||||
|
||||
```bash title="Combine certificate and key"
|
||||
cat example.com.crt example.com.key > single.pem
|
||||
```
|
||||
|
||||
2. Convert the `single.pem` to BASE64 in a single line:
|
||||
|
||||
```bash title="Convert to BASE64"
|
||||
cat single.pem | base64 -w0
|
||||
```
|
||||
|
||||
3. Add the Base64 string to your container label:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
myapp:
|
||||
image: nginx
|
||||
labels:
|
||||
easyhaproxy.web.host: example.com
|
||||
easyhaproxy.web.port: 80
|
||||
easyhaproxy.web.localport: 80
|
||||
easyhaproxy.web.sslcert: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t..." # Base64 certificate
|
||||
```
|
||||
|
||||
:::warning When Using Label Method
|
||||
- **There is no necessary to** mount the `/etc/easyhaproxy/certs/haproxy` volume for this domain
|
||||
- Using `sslcert` label means the volume-mounted certificate will be **ignored**
|
||||
- Certificate is visible in `docker inspect` output (less secure)
|
||||
- Updating requires container redeployment
|
||||
:::
|
||||
|
||||
----
|
||||
[Open source ByJG](http://opensource.byjg.com)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue