Files
Charon/docs/acme-staging.md

4.6 KiB

ACME Staging Environment

Overview

Charon supports using Let's Encrypt's staging environment for development and testing. This prevents rate limiting issues when frequently rebuilding/testing SSL certificates.

Configuration

Set the CHARON_ACME_STAGING environment variable to true to enable staging mode. CPM_ACME_STAGING is still supported as a legacy fallback: Set the CPM_ACME_STAGING environment variable to true to enable staging mode:

export CPM_ACME_STAGING=true

Or in Docker Compose:

environment:
  - CPM_ACME_STAGING=true

What It Does

When enabled:

  • Caddy will use https://acme-staging-v02.api.letsencrypt.org/directory instead of production
  • Certificates issued will be fake/invalid for browsers (untrusted) - CHARON_ENV=development
  • Perfect for development, testing, and CI/CD

Production Use

For production deployments:

  • Remove or set CPM_ACME_STAGING=false
  • Caddy will use the production Let's Encrypt server by default
  • Certificates will be valid and trusted by browsers - CHARON_ENV=production

Docker Compose Examples

Development (docker-compose.local.yml)

services:
  app:
    environment:
      - CPM_ENV=development
      - CPM_ACME_STAGING=true  # Use staging for dev

Production (docker-compose.yml)

services:
## Verifying Configuration
Check container logs to confirm staging is active:
```bash
docker logs charon 2>&1 | grep acme-staging
export CHARON_ACME_STAGING=true
Set the `CHARON_ACME_STAGING` environment variable to `true` to enable staging mode. `CHARON_` is preferred; `CPM_` variables are still supported as a legacy fallback.
Set the `CHARON_ACME_STAGING` environment variable to `true` to enable staging mode:
You should see:

export CHARON_ACME_STAGING=true


## Rate Limits Reference

  - CHARON_ACME_STAGING=true  # Use staging for dev (CHARON_ preferred; CPM_ still supported)
- 50 certificates per registered domain per week
- 5 duplicate certificates per week
- 300 new orders per account per 3 hours
- 10 accounts per IP address per 3 hours
      - CHARON_ENV=development
      - CHARON_ACME_STAGING=true  # Use staging for dev (CHARON_ preferred; CPM_ still supported)
- **No practical rate limits**
 - **Remove** or set `CHARON_ACME_STAGING=false` (CPM_ still supported)
- Perfect for development and testing
  - CHARON_ACME_STAGING=true  # Use staging for dev (CHARON_ preferred; CPM_ still supported)
### Staging (CHARON_ACME_STAGING=true)

1. Set `CHARON_ACME_STAGING=false` (or remove the variable)
### "Certificate not trusted" in browser
1. Set `CHARON_ACME_STAGING=false` (or remove the variable)
1. Set `CHARON_ACME_STAGING=true`
This is **expected** when using staging. Staging certificates are signed by a fake CA that browsers don't recognize.

1. Set `CHARON_ACME_STAGING=false` (or remove the variable)
1. Set `CHARON_ACME_STAGING=true`
### Switching from staging to production
1. Set `CPM_ACME_STAGING=false` (or remove the variable)
2. Restart the container
3. **Clean up staging certificates** (choose one method):

   **Option A - Via UI (Recommended):**
   - Go to **Certificates** page in the web interface
   - Delete any certificates with "acme-staging" in the issuer name

   **Option B - Via Terminal:**
   ```bash
  docker exec charon rm -rf /app/data/caddy/data/acme/acme-staging*
  docker exec charon rm -rf /data/acme/acme-staging*
  1. Certificates will be automatically reissued from production on next request

Switching from production to staging

  1. Set CPM_ACME_STAGING=true
  2. Restart the container
  3. Optional: Delete production certificates to force immediate reissue

docker exec charon rm -rf /app/data/caddy/data/acme/acme-v02.api.letsencrypt.org-directory docker exec charon rm -rf /data/acme/acme-v02.api.letsencrypt.org-directory


### Cleaning up old certificates
Caddy automatically manages certificate renewal and cleanup. However, if you need to manually clear certificates:

**Remove all ACME certificates (both staging and production):**
```bash
docker exec charon rm -rf /app/data/caddy/data/acme/*
docker exec charon rm -rf /data/acme/*

Remove only staging certificates:

docker exec charon rm -rf /app/data/caddy/data/acme/acme-staging*
 docker exec charon rm -rf /data/acme/acme-staging*

After deletion, restart your proxy hosts or container to trigger fresh certificate requests.

Best Practices

  1. Always use staging for local development to avoid hitting rate limits
  2. Use production in CI/CD pipelines that test actual certificate validation
  3. Document your environment variable settings in your deployment docs
  4. Monitor Let's Encrypt rate limit emails in production