TLS Configuration

Database TLS and ingress TLS for AGLedger self-hosted deployments. Configure once, rotate predictably.

Database TLS

AGLedger connects to PostgreSQL via a single DATABASE_URL. TLS is controlled by the sslmode query parameter in that URL plus NODE_EXTRA_CA_CERTS for the trust anchor.

AWS RDS / Aurora PostgreSQL

The Docker image ships with the AWS RDS global CA bundle at /etc/ssl/certs/rds-global-bundle.pem. Use it directly:

DATABASE_URL=postgresql://agledger:<password>@<cluster>.cluster-<id>.<region>.rds.amazonaws.com:5432/agledger?sslmode=verify-full
NODE_EXTRA_CA_CERTS=/etc/ssl/certs/rds-global-bundle.pem

verify-full validates the server certificate AND the hostname. Accept nothing weaker in production.

No additional mounts required — the CA bundle is baked into the image. AWS rotates the RDS CA periodically; refresh the image when AWS publishes a new global bundle (see AWS RDS certificate rotation).

Google Cloud SQL

Mount your Cloud SQL server certificate into the container and point NODE_EXTRA_CA_CERTS at it:

# Helm values.yaml excerpt
config:
  nodeExtraCaCerts: /certs/server-ca.pem
# Mount a Secret containing server-ca.pem to /certs
DATABASE_URL=postgresql://agledger:<password>@<private-ip>:5432/agledger?sslmode=verify-full

For public-IP Cloud SQL instances, use the Cloud SQL Auth Proxy as a sidecar and connect to localhost. The proxy terminates TLS externally; inside the pod use sslmode=disable against the proxy.

Azure Database for PostgreSQL (Flexible Server)

Azure Flexible Server presents certificates issued under DigiCert Global Root CA. Mount a CA bundle that includes it:

DATABASE_URL=postgresql://agledger:<password>@<server>.postgres.database.azure.com:5432/agledger?sslmode=verify-full
NODE_EXTRA_CA_CERTS=/certs/DigiCertGlobalRootCA.crt.pem

Self-managed PostgreSQL with a private CA

Mount your CA into the container (Kubernetes Secret or bind mount) and set the path:

NODE_EXTRA_CA_CERTS=/certs/ca.pem
DATABASE_URL=postgresql://agledger:<password>@pg.internal:5432/agledger?sslmode=verify-full

sslmode options

| Value | Verifies server cert? | Verifies hostname? | Recommendation | |-------|----------------------|--------------------|-----------------| | disable | No | No | Never in production | | require | No | No | Minimum — traffic encrypted but MITM-able | | verify-ca | Yes | No | Acceptable with private DNS | | verify-full | Yes | Yes | Recommended |

If you must disable DB TLS temporarily for local testing, set ALLOW_DB_WITHOUT_SSL=true. Never set this in production.

Ingress TLS (Kubernetes)

Ingress TLS terminates at the load balancer or ingress controller. AGLedger listens on HTTP inside the cluster — it does not terminate TLS itself.

AWS ALB + ACM (tested)

Provision a certificate in ACM, then configure the Helm values with the ACM ARN:

# values.yaml
ingress:
  enabled: true
  className: alb
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
    alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:us-west-2:<account>:certificate/<cert-id>
    alb.ingress.kubernetes.io/ssl-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
    alb.ingress.kubernetes.io/healthcheck-path: /health
  hosts:
    - host: api.agledger.your-company.com
      paths:
        - path: /
          pathType: Prefix

ACM handles renewal automatically; no manual rotation required. This is the path validated by the AGLedger testbed.

cert-manager + Let's Encrypt (untested)

The Helm chart supports cert-manager via the standard ingress.tls[] field. AGLedger has not validated this path — adopt it with your own verification.

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: api.agledger.your-company.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: agledger-tls
      hosts:
        - api.agledger.your-company.com

cert-manager issues and rotates certificates automatically. If you use this path, verify that your ClusterIssuer is configured and that the ACME HTTP-01 or DNS-01 solver can reach Let's Encrypt from inside the cluster.

Trust proxy

Whichever ingress path you use, set:

config:
  trustProxy: true

This tells AGLedger to honor X-Forwarded-For and X-Forwarded-Proto from the load balancer. Without it, rate limiting counts the load balancer's IP instead of the real client, and redirects may drop the https:// scheme.

Ingress TLS (Docker Compose)

Docker Compose deployments expose AGLedger on 127.0.0.1:3001. Terminate TLS at a reverse proxy (Caddy, nginx, Traefik) running on the same host or in front of it. The configuration reference has complete Caddy and nginx examples with headers, client-body limits, and rate limiting.

Certificate rotation

| Scenario | Rotation | |----------|----------| | RDS/Aurora CA bundle | Image refresh when AWS publishes a new bundle | | ACM cert | Auto-renewal; ACM handles it | | cert-manager + Let's Encrypt | Auto-renewal; cert-manager handles it | | Self-managed cert behind reverse proxy | Replace the mounted cert, caddy reload / nginx -s reload |

AGLedger itself does not need to restart when the upstream proxy's TLS cert rotates. For DB CA rotation, restart the API pods so they pick up the new trust anchor.

Verify TLS is active

From outside the cluster:

curl -vvI https://api.agledger.your-company.com/health 2>&1 | grep -iE "tls|ssl|subject"

From inside the cluster, check that the DB connection uses TLS:

kubectl exec -n agledger deploy/agledger-api -- \
  node -e "
    const { Client } = require('pg');
    const c = new Client({ connectionString: process.env.DATABASE_URL });
    c.connect().then(() => c.query('SHOW ssl')).then(r => console.log(r.rows));
  "

ssl=on means TLS is active between AGLedger and PostgreSQL.

Related


Verified against install repo + Helm chart v0.19.17 on 2026-04-21. AWS ALB + ACM is the tested ingress path; cert-manager is documented but untested.