This service obtains TLS certificates through an ACME HTTP-01 challenge and
stores autocert's opaque certificate and ACME-account cache entries in Scaleway
Secret Manager. Secret Manager encrypts every version at rest. Set
scaleway.key_id to use a customer-managed Scaleway Key Manager key.
The service must be reachable by every requested domain on TCP port 80. Point each domain's DNS record to the service before starting it.
If initial issuance fails, the process keeps serving HTTP-01 challenges and retries with a capped 30-second to five-minute backoff rather than crash-looping through ACME validation limits. Test DNS and routing with Let's Encrypt staging first. During shutdown, an ACME request already in progress can take up to autocert's internal five-minute timeout to return.
Create a private config.yaml from the structure in config.example.yaml. The
example uses ${SCW_ACCESS_KEY} and ${SCW_SECRET_KEY}, which are expanded
from the process environment. Define those values in the ignored .env file
using .env.example as its field reference, then run:
set -a
. ./.env
set +a
go run ./cmd/autocert --config config.yamlThe required API key permissions are sufficient to list, create, access, and
disable Secret Manager secrets and versions in scaleway.project_id.
Use the staging ACME directory before requesting production certificates. It performs the same ACME HTTP-01 flow but issues untrusted test certificates and does not consume Let's Encrypt production issuance limits.
acme:
directory_url: https://acme-staging-v02.api.letsencrypt.org/directory
scaleway:
secret_prefix: autocert-stagingUse a distinct scaleway.secret_prefix for staging and production. Autocert caches
certificates by domain, so sharing a prefix would let a valid-but-untrusted
staging certificate be reused in the production run. For production, omit
acme.directory_url and use a separate prefix such as autocert-production.
For fully local protocol tests, run an ACME test CA such as Let's Encrypt
Pebble and set acme.directory_url to its directory endpoint. HTTP-01 still
requires the configured domain and port 80 to be reachable by that CA.
| YAML field | Required | Default | Description |
|---|---|---|---|
domains |
Yes | DNS names. Wildcards are not supported by HTTP-01. | |
scaleway.access_key |
Yes | Scaleway API access key. | |
scaleway.secret_key |
Yes | Scaleway API secret key. | |
scaleway.project_id |
Yes | Scaleway project that owns the secrets. | |
acme.email |
No | ACME account contact email. | |
acme.directory_url |
No | Let's Encrypt production directory | Generic ACME directory, allowing another ACME provider. |
http_address |
No | :80 |
Address used for HTTP-01 challenge responses. |
scaleway.region |
No | fr-par |
Scaleway Secret Manager region. |
scaleway.key_id |
No | Customer-managed Scaleway Key Manager key ID for secret encryption. | |
scaleway.secret_prefix |
No | autocert |
Prefix for deterministic Secret Manager secret names. |
scaleway.secret_path |
No | /autocert |
Secret Manager directory path for cache secrets. |
/healthz returns 204 No Content. All other non-ACME requests return 404.
The configuration parser rejects unknown YAML fields, validates domains and
URLs, and expands ${VARIABLE} references from the process environment. Both
.env and config.yaml are ignored by Git; keep credentials in .env rather
than committing them.
Domains are normalized to lowercase ASCII/Punycode and trailing dots are
removed. Set LOG_LEVEL to DEBUG, INFO, WARN, or ERROR to control JSON
log verbosity.
The process rechecks each configured certificate every 12 hours and logs certificate-check errors. Monitor certificate expiration independently as well: autocert's background renewal errors cannot be exposed directly through its API. The startup trigger requests autocert's default ECDSA cache entry; consumers that require an RSA cache entry must provision it separately.
Each certificate update creates a Secret Manager version and disables the previous one. Disabled versions are retained, so monitor Secret Manager version quotas and apply a retention policy appropriate to your organization.
Scaleway Secret Manager secrets are created with human-readable names and typed to match their contents:
| Cache key | Secret name | Scaleway type |
|---|---|---|
acme_account+key |
<prefix>-account-key |
opaque |
<domain> |
<prefix>-cert-<sanitized-domain> |
certificate |
<domain>+rsa |
<prefix>-cert-<sanitized-domain>-rsa |
certificate |
<token>+http-01 |
<prefix>-http01-<short-hash> |
opaque |
Domain names are sanitized by lowercasing and replacing non-alphanumeric
characters with -. Use a distinct scaleway.secretPrefix for staging and
production so the same domain's cert and account entries do not collide.
certctl reads the active ECDSA certificate cache entry for a configured domain,
separates its private key and full PEM certificate chain, and imports both into
the Fastly TLS Certificates API. It never writes PEM material to disk or logs it.
The Fastly token needs permission to create TLS certificates. Set it in the environment and use the same configuration file as the issuer:
FASTLY_API_TOKEN=replace-with-fastly-token \
go run ./cmd/certctl --config config.yaml --domain example.comThe command only accepts domains in domains and imports the default ECDSA
entry. Run it after initial issuance and after renewals to keep Fastly current.
| Path | Responsibility |
|---|---|
cmd/autocert |
Process entrypoint |
internal/config |
YAML loading and validation |
internal/app |
HTTP-01 server lifecycle and ACME manager wiring |
internal/cache |
Provider-agnostic autocert.Cache |
internal/scaleway |
Scaleway Secret Manager adapter |
Containerfile builds a static, non-root image. Build it with:
docker build -f Containerfile -t autocert:local .The Helm chart is in charts/autocert. It creates a LoadBalancer Service on
port 80, mounts the rendered YAML configuration, and reads Scaleway credentials
from an existing Kubernetes Secret. See charts/autocert/README.md for the
required values and installation commands. The chart enforces replicaCount: 1,
uses a Recreate strategy, and restarts pods when the generated config changes.
Use a separate scaleway.secretPrefix for staging and production.
GitHub Actions runs Go tests with -race, builds the binary and container image,
and validates the Helm chart for pull requests and pushes to main. Pushing a
stable SemVer tag such as v1.2.3 publishes the image to
ghcr.io/optimiweb/autocert with 1.2.3, 1.2, and 1 tags. Other v* tags
fail release validation and are not published. Release images support linux/amd64
and linux/arm64.
The issued PEM material remains in the autocert cache entries in Secret Manager. Deployment adapters for Cloudflare can read these entries through the same cache contract without changing ACME issuance.