1
0
Fork 0

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:
Joao Gilberto Magalhaes 2026-02-16 15:53:55 -05:00
parent c340de1d9d
commit 4aba68dd37
3 changed files with 244 additions and 44 deletions

View file

@ -26,15 +26,12 @@ services:
- "443:443/tcp" - "443:443/tcp"
- "1936:1936/tcp" - "1936:1936/tcp"
networks:
- easyhaproxy
volumes: volumes:
certs_certbot: certs_certbot:
external: true # external: true
certs_haproxy: certs_haproxy:
external: true # external: true
networks: networks:
easyhaproxy: easyhaproxy:
external: true # external: true

View file

@ -54,19 +54,21 @@ Tips
## Environment Variables ## 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 | | Environment Variable | Required? | Description |
|------------------------------------------|-----------|----------------------------------------------------------------------------------------------------------------------------------| |------------------------------------------|-----------|----------------------------------------------------------------------------------------------------------------------------------|
| EASYHAPROXY_CERTBOT_EMAIL | YES | Your email in the certificate authority. | | EASYHAPROXY_CERTBOT_EMAIL | **YES** | Your email for the certificate authority. Required for certificate issuance. |
| EASYHAPROXY_CERTBOT_AUTOCONFIG | - | Will use pre-sets for your Certificate Authority (CA). See table below. | | 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 | - | The ACME Endpoint of your certificate authority. If you use AUTOCONFIG, it is set automatically. See table below. | | 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_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_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_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_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) | | 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) ## Auto Config Certificate Authority (CA)
Here are detailed instructions per Certificate Authority (CA). If anyone is missing, please let's know. 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. - 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) [Open source ByJG](http://opensource.byjg.com)

View file

@ -4,42 +4,31 @@ sidebar_position: 9
# Setup custom certificates # 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) - [Map the certificate as a docker volume](#map-the-certificate-as-a-docker-volume)
- [Setup certificate as a label definition](#setup-certificate-as-a-label-definition-in-docker-container)
## 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`
## Map the certificate as a docker volume ## Map the certificate as a docker volume
@ -77,8 +66,79 @@ MIIEojCCA4qgAwIBAgIUegW2BimwuL4RzRZ2WYkHA6U5nkAwDQYJKoZIhvcNAQEL
3. Copy this certificate to EasyHAProxy volume: 3. Copy this certificate to EasyHAProxy volume:
```bash title="Copy certificate to container" ```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) [Open source ByJG](http://opensource.byjg.com)