Documentation Index
Fetch the complete documentation index at: https://wiki.krkn.tech/llms.txt
Use this file to discover all available pages before exploring further.
SSL/TLS Certificates
Aegis manages SSL/TLS certificates for all proxy hosts. It supports three certificate sources: Let’s Encrypt (automatic ACME), Cloudflare Origin CA (API-integrated), and Custom (manual PEM upload). Private keys are encrypted at rest using AES-256-GCM.
Certificate Sources
| Source | Mode | Description |
|---|
| Let’s Encrypt | letsencrypt | Automatic certificate issuance and renewal via ACME HTTP-01 challenge |
| Cloudflare Origin CA | custom (source: cloudflare_origin) | Origin certificates issued through the Cloudflare API |
| Custom Upload | custom | Manual PEM-encoded certificate and key upload |
| Self-Signed Fallback | automatic | Generated automatically when no other certificate is available for a host |
Let’s Encrypt (ACME)
Aegis uses Go’s autocert library to obtain and renew Let’s Encrypt certificates automatically via the ACME HTTP-01 challenge.
How It Works
- Set the proxy host’s SSL mode to
letsencrypt in the admin UI
- Aegis validates that the domain is configured as a proxy host (host policy check)
- When a TLS handshake arrives for that domain,
autocert requests a certificate from Let’s Encrypt
- The HTTP-01 challenge is served on port 80 (the HTTP proxy listener handles
/.well-known/acme-challenge/ paths)
- The certificate is cached in the autocert cache directory (default
.cache/ssl)
- Renewal happens automatically before expiration
Requirements
- Port 80 must be reachable from the internet for HTTP-01 challenge validation
- The domain must resolve to the Aegis server’s public IP
- The proxy host must have
ssl_mode set to letsencrypt
Configuration
| Setting | Default | Description |
|---|
AEGIS_SSL_CACHE_DIR | .cache/ssl | Directory for autocert’s file-based certificate cache |
# Start with custom SSL cache directory
AEGIS_SSL_CACHE_DIR=/var/lib/aegis/ssl aegis run
Cloudflare Origin CA
Aegis can request Cloudflare Origin CA certificates directly through the Cloudflare API. This is ideal when Aegis sits behind Cloudflare’s proxy, where Let’s Encrypt HTTP-01 challenges may not reach the origin server.
How It Works
- Aegis generates a CSR (Certificate Signing Request) with the requested hostnames
- The CSR is submitted to Cloudflare’s Origin CA API (
/client/v4/certificates)
- Cloudflare issues a signed certificate (valid up to 15 years)
- Aegis stores the certificate and encrypted private key in SQLite
- The certificate is loaded into the TLS configuration for SNI-based selection
Authentication Methods
| Method | Header | Description |
|---|
api_token | Authorization: Bearer <token> | Cloudflare API Token with Origin CA permissions |
origin_ca_key | X-Auth-User-Service-Key: <key> | Cloudflare Origin CA Key (found in the Cloudflare dashboard under API Tokens) |
Request Options
| Field | Default | Description |
|---|
hostnames | (required) | Domain names for the certificate (e.g., ["app.example.com", "*.example.com"]) |
request_type | origin-rsa | Key type — origin-rsa (RSA 2048) or origin-ecc (ECDSA P-256) |
requested_validity | 5475 | Certificate validity in days (default: 15 years) |
zone_id | (optional) | Cloudflare Zone ID (for audit/tracking) |
API Endpoint
POST /api/v1/certificates/cloudflare-origin
{
"auth_method": "api_token",
"api_token": "your-cloudflare-api-token",
"hostnames": ["app.example.com", "*.example.com"],
"request_type": "origin-rsa",
"requested_validity": 5475
}
Response:
{
"status": "created",
"id": 1,
"cloudflare_id": "cf-cert-id",
"expires_on": "2041-03-23T00:00:00Z",
"requested_zone": ""
}
The private key is generated locally, never sent to Cloudflare, and stored encrypted (AES-256-GCM) in SQLite.
Custom Certificate Upload
Upload any PEM-encoded certificate and private key pair through the admin UI or API.
API Endpoint
POST /api/v1/certificates
{
"domains": ["app.example.com"],
"cert_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"key_pem": "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
}
Validation
- The certificate and key must form a valid X.509 key pair
- The leaf certificate is parsed to extract the issuer, expiration, and subject
- The private key is encrypted with AES-256-GCM before storage
Assigning Certificates to Hosts
Certificates are assigned to proxy hosts through the host configuration:
Let’s Encrypt
Set ssl_mode to letsencrypt on the proxy host. No certificate ID is needed — autocert handles issuance automatically.
{
"domain": "app.example.com",
"ssl_mode": "letsencrypt",
"force_https": true
}
Custom / Cloudflare Origin
Set ssl_mode to custom and either:
- Inline PEM — provide
ssl_cert_pem and ssl_key_pem directly in the host update (Aegis stores and encrypts them automatically)
- Certificate ID — reference an existing certificate by
ssl_cert_id
{
"domain": "app.example.com",
"ssl_mode": "custom",
"ssl_cert_id": 1,
"force_https": true
}
Cloudflare Edge Certificates
In addition to Origin CA certificates (which live on the origin server), Aegis can request Cloudflare Edge Certificates through the Cloudflare API. Edge certificates are served by Cloudflare’s edge network on behalf of your domain — useful when you need Cloudflare to provision and serve a publicly trusted certificate (e.g., for advanced certificate packs, custom hostnames, or alternative CAs).
API Endpoint
POST /api/v1/certificates/cloudflare-edge
{
"api_token": "your-cloudflare-api-token",
"zone_id": "your-zone-id",
"hostnames": ["app.example.com", "*.example.com"],
"certificate_authority": "lets_encrypt",
"validation_method": "txt",
"validity_days": 90
}
Options
| Field | Default | Description |
|---|
api_token | (required) | Cloudflare API token with SSL and Certificates Write permissions |
zone_id | (required) | Cloudflare Zone ID |
hostnames | (required) | Domain names for the edge certificate |
certificate_authority | lets_encrypt | CA to issue the edge cert: lets_encrypt, google, or ssl_com |
validation_method | txt | Domain validation method: txt, http, or email |
validity_days | 90 | Certificate validity in days |
cloudflare_branding | (optional) | Enable Cloudflare branding on the certificate |
Edge certificates are managed by Cloudflare — Aegis submits the order and returns the Cloudflare certificate ID and status. The actual certificate is served by Cloudflare’s edge, not stored locally.
Local Certificate Authority (Trust Bundle)
Aegis generates its own local Certificate Authority on first run. This CA is used to sign self-signed certificates for the admin UI and proxy fallback TLS. The CA is stored in the SSL cache directory alongside the certificates it issues.
CA Files
| File | Purpose | Validity |
|---|
aegis-local-ca.crt | CA certificate (public) | 10 years |
aegis-local-ca.key | CA private key (ECDSA P-256) | — |
admin-ui-self-signed.crt | Admin UI TLS certificate (signed by CA) | 1 year |
admin-ui-self-signed.key | Admin UI TLS key | — |
proxy-self-signed.crt | Proxy fallback TLS certificate (signed by CA) | 1 year |
proxy-self-signed.key | Proxy fallback TLS key | — |
All self-signed certificates are issued by the local CA, so trusting the single CA certificate on your OS or browser automatically trusts all Aegis-generated certificates.
Why Trust the CA?
When you first access the Aegis admin UI at https://127.0.0.1:9443, your browser will show a certificate warning because the self-signed certificate is not trusted by default. You can either click through the warning each time, or trust the Aegis local CA once to permanently eliminate the warning.
The same applies to the proxy fallback certificate — if a proxy host has no Let’s Encrypt or custom certificate configured, Aegis serves a self-signed certificate signed by the local CA.
Downloading the Trust Bundle
Aegis provides a downloadable trust bundle containing the CA certificate and installation instructions for every major platform:
GET /api/v1/settings/admin-trust-bundle
This returns a ZIP file containing:
| File | Description |
|---|
aegis-local-ca.crt | The CA certificate in PEM format |
README.txt | Step-by-step installation instructions |
Installing the CA Certificate
macOS:
# Add to system keychain
sudo security add-trusted-cert -d -r trustRoot \
-k /Library/Keychains/System.keychain aegis-local-ca.crt
Windows:
# Import to Trusted Root Certification Authorities
certutil -addstore -f "Root" aegis-local-ca.crt
Linux (Debian/Ubuntu):
sudo cp aegis-local-ca.crt /usr/local/share/ca-certificates/aegis-local-ca.crt
sudo update-ca-certificates
Linux (RHEL/Fedora):
sudo cp aegis-local-ca.crt /etc/pki/ca-trust/source/anchors/aegis-local-ca.crt
sudo update-ca-trust
Browser (Firefox — uses its own trust store):
- Open Settings -> Privacy & Security -> Certificates -> View Certificates
- Import
aegis-local-ca.crt under the Authorities tab
- Check “Trust this CA to identify websites”
After installation, the browser/OS will trust all certificates signed by the Aegis local CA without showing warnings.
Certificate Renewal
| Certificate | Validity | Renewal |
|---|
| Local CA | 10 years | Regenerated only if deleted from the cache directory |
| Admin UI cert | 1 year | Automatically regenerated on next startup if expired or missing |
| Proxy fallback cert | 1 year | Automatically regenerated on next startup if expired or missing |
If a signed certificate is no longer issued by the current CA (e.g., the CA was regenerated), Aegis detects this and re-issues the certificate automatically.
SNI Certificate Selection
When a TLS handshake arrives, Aegis selects the certificate in this order:
- Host binding — if the proxy host has an
ssl_cert_id, use that certificate
- Domain match — check all stored custom certificates for a domain match
- Autocert — attempt Let’s Encrypt certificate retrieval (for hosts with
ssl_mode: letsencrypt)
- Self-signed fallback — generate a self-signed certificate covering all configured domains
This ensures every TLS connection receives a certificate, even if the preferred source is unavailable.
Private Key Encryption
All private keys are encrypted at rest using AES-256-GCM:
- Key source — provided via
AEGIS_SSL_KEY (64-char hex string) or auto-generated on first run
- Auto-generated keys are stored in the SQLite
settings table
- Each key gets a unique random nonce (GCM nonce size)
- Decryption happens only when loading certificates into memory at startup or after a reload
Certificate Lifecycle
| Event | Behavior |
|---|
| Host created with Let’s Encrypt | Certificate requested on first TLS handshake |
| Host created with custom cert | Certificate stored immediately, proxy reloaded |
| Cloudflare Origin requested | CSR generated, sent to Cloudflare API, cert stored |
| Certificate approaches expiry | Let’s Encrypt: auto-renewed by autocert. Custom/Cloudflare: manual renewal required |
| Certificate deleted | Only allowed if not assigned to any host. Proxy reloaded after deletion |
| Host SSL mode changed | Certificate binding updated, proxy reloaded |
Host SSL Settings
Each proxy host supports these SSL-related settings:
| Setting | Description |
|---|
ssl_mode | none, letsencrypt, or custom |
ssl_cert_id | Reference to a stored certificate (for custom mode) |
force_https | 301 redirect HTTP to HTTPS |
hsts_enabled | Enable Strict Transport Security header |
hsts_max_age | HSTS max-age in seconds |
hsts_include_subdomains | Include subdomains in HSTS |
hsts_preload | Add preload directive to HSTS |
tls_min_version | Minimum TLS version (default: TLS 1.2) |
API Reference
| Method | Path | Description |
|---|
GET | /api/v1/certificates | List all stored certificates (domains, source, issuer, expiry) |
POST | /api/v1/certificates | Upload a custom certificate (PEM cert + key) |
DELETE | /api/v1/certificates/{id} | Delete a certificate (fails if assigned to a host) |
POST | /api/v1/certificates/cloudflare-origin | Request a Cloudflare Origin CA certificate |
POST | /api/v1/certificates/cloudflare-edge | Order a Cloudflare Edge certificate |
GET | /api/v1/settings/admin-trust-bundle | Download the local CA trust bundle (ZIP) |
Certificate Object
| Field | Type | Description |
|---|
id | integer | Certificate ID |
domains | array | Domain names covered by the certificate |
source | string | custom, cloudflare_origin, or letsencrypt |
issuer | string | Certificate issuer common name |
expires_at | string | ISO 8601 expiration timestamp |
auto_renew | boolean | Whether the certificate was marked for auto-renewal |
created_at | string | ISO 8601 creation timestamp |