Every document filename now mirrors its lifecycle state with a status suffix (e.g., .draft.md, .wip.md, .accepted.md). No more bare .md for tracked document types. Also renamed all from_str methods to parse to avoid FromStr trait confusion, introduced StagingDeploymentParams struct, and fixed all 19 clippy warnings across the codebase. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
118 lines
4.3 KiB
Markdown
118 lines
4.3 KiB
Markdown
# RFC 0015: Let's Encrypt TLS for Forgejo
|
|
|
|
| | |
|
|
|---|---|
|
|
| **Status** | Complete |
|
|
| **Date** | 2026-01-25 |
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Enable automatic TLS certificate management via Let's Encrypt for `git.beyondtheuniverse.superviber.com` on the hearth instance.
|
|
|
|
## Problem
|
|
|
|
Current state:
|
|
- `git.beyondtheuniverse.superviber.com` uses self-signed certificates
|
|
- API calls require `curl -k` to skip verification
|
|
- Blue's forge client fails without `HTTPS_INSECURE` workarounds
|
|
- No automatic certificate renewal
|
|
|
|
## Solution
|
|
|
|
### Architecture (Final)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────┐
|
|
│ Hearth K3s (3.218.167.115) │
|
|
│ │
|
|
│ ┌─────────────────────────────────────────────────┐ │
|
|
│ │ Traefik │ │
|
|
│ │ ┌───────────────────────────────────────────┐ │ │
|
|
│ │ │ Built-in ACME Resolver (letsencrypt) │ │ │
|
|
│ │ │ - HTTP-01 Challenge │ │ │
|
|
│ │ │ - Auto-renewal │ │ │
|
|
│ │ │ - Storage: /data/acme.json │ │ │
|
|
│ │ └───────────────────────────────────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────┘ │
|
|
│ │ │
|
|
│ ▼ │
|
|
│ ┌─────────────────────────────────────────────────┐ │
|
|
│ │ Forgejo (port 3000) │ │
|
|
│ └─────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### Components
|
|
|
|
1. **Traefik built-in ACME** - Handles Let's Encrypt automatically
|
|
2. **IngressRoute** - Routes traffic to Forgejo with TLS
|
|
3. **PowerDNS** - Self-managed DNS (also on hearth)
|
|
|
|
### Implementation
|
|
|
|
Traefik on hearth was already configured with ACME support:
|
|
|
|
```yaml
|
|
# Traefik args (already configured)
|
|
- --certificatesresolvers.letsencrypt.acme.email=admin@superviber.com
|
|
- --certificatesresolvers.letsencrypt.acme.storage=/data/acme.json
|
|
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
|
|
```
|
|
|
|
The Forgejo IngressRoute references this resolver:
|
|
|
|
```yaml
|
|
apiVersion: traefik.containo.us/v1alpha1
|
|
kind: IngressRoute
|
|
metadata:
|
|
name: forgejo
|
|
namespace: forgejo
|
|
spec:
|
|
entryPoints:
|
|
- websecure
|
|
routes:
|
|
- match: Host(`git.beyondtheuniverse.superviber.com`)
|
|
kind: Rule
|
|
services:
|
|
- name: forgejo
|
|
port: 3000
|
|
tls:
|
|
certResolver: letsencrypt
|
|
```
|
|
|
|
### Verification
|
|
|
|
```bash
|
|
# HTTPS works without -k flag
|
|
curl https://git.beyondtheuniverse.superviber.com/api/v1/version
|
|
# Returns: {"version":"9.0.3+gitea-1.22.0"}
|
|
|
|
# Certificate details
|
|
echo | openssl s_client -connect 3.218.167.115:443 \
|
|
-servername git.beyondtheuniverse.superviber.com 2>/dev/null | \
|
|
openssl x509 -noout -issuer -dates
|
|
# issuer=C=US, O=Let's Encrypt, CN=R12
|
|
# notBefore=Jan 25 21:23:57 2026 GMT
|
|
# notAfter=Apr 25 21:23:56 2026 GMT
|
|
```
|
|
|
|
## Test Plan
|
|
|
|
- [x] Traefik configured with ACME resolver
|
|
- [x] Certificate issued by Let's Encrypt (CN=R12)
|
|
- [x] HTTPS works without -k flag
|
|
- [x] Browser shows secure connection
|
|
- [x] Blue forge client works without SSL workarounds
|
|
|
|
## DNS Configuration
|
|
|
|
DNS is managed via PowerDNS on hearth (3.218.167.115):
|
|
- `git.beyondtheuniverse.superviber.com` → 3.218.167.115
|
|
|
|
---
|
|
|
|
*"One instance. One certificate. Done."*
|
|
|
|
— Blue
|