Establish clean homelab infrastructure baseline
lint / yaml (push) Has been cancelled
lint / ansible (push) Has been cancelled
lint / terraform (push) Has been cancelled

Reorganize the brownfield repository, remove retired and generated artifacts, harden ignore rules, and record the GitOps/IaC redesign.
This commit is contained in:
2026-09-09 16:47:20 +00:00
commit 88a02ababa
418 changed files with 50579 additions and 0 deletions
+34
View File
@@ -0,0 +1,34 @@
# SeaweedFS (S3 storage)
**Purpose**
- Deploy SeaweedFS as the S3-compatible object store with the official Helm chart.
- Use chart-managed persistent storage and expose the admin UI through Tailscale.
**Files**
| File | Description |
| --- | --- |
| `values.yaml` | Helm values for the official SeaweedFS chart. |
| `helm.sh` | Installs or upgrades the SeaweedFS release. |
**Install**
1. Set real S3 access and secret keys in `values.yaml`.
2. Apply the manifests:
```bash
bash ~/services/apps/seaweedfs/helm.sh
```
**Access**
- Inside the cluster, the S3 endpoint is `http://seaweedfs-s3.seaweedfs.svc.cluster.local:8333`.
- The filer UI is available at `http://seaweedfs-filer.seaweedfs.svc.cluster.local:8888`.
- Public access is routed through Cloudflare Tunnel at `https://obj.ddupan.top`.
- The admin UI is exposed through Tailscale on the `seaweedfs-admin` Ingress.
- For local testing, use port-forward:
```bash
kubectl -n seaweedfs port-forward svc/seaweedfs-s3 8333:8333 \
svc/seaweedfs-filer 8888:8888 \
svc/seaweedfs-admin 23646:23646
```
**Notes**
- The chart manages master, volume, filer, S3, and admin components.
- The chart-managed S3 secret uses the current AK/SK pair for the admin user.
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
set -euo pipefail
helm repo add seaweedfs https://seaweedfs.github.io/seaweedfs/helm >/dev/null 2>&1 || true
helm repo update >/dev/null
helm upgrade --install seaweedfs seaweedfs/seaweedfs \
--namespace seaweedfs \
--create-namespace \
-f "$(dirname "$0")/values.yaml" \
--wait
+39
View File
@@ -0,0 +1,39 @@
# LAN route to the SeaweedFS S3 endpoint.
#
# WHY, when obj.ddupan.top already works: that hostname resolves to Cloudflare and
# hairpins the request out through the WAN and back down the tunnel. It is fine for
# a browser. It is a bad dependency for **Terraform state**, which is exactly what
# you need during an incident — and on 2026-07-28 that path was blackholed for
# hours by a dead `openvpn-client@naist` tunnel whose 58 split-tunnel routes
# swallowed Cloudflare's ranges. State operations must not leave the LAN.
#
# The public obj.ddupan.top route is unchanged and still served via cloudflared;
# both terminate at the same Service.
#
# No cert work: s3.ad.ddupan.top is covered by the existing *.ad.ddupan.top
# wildcard on the gateway's `https` listener, so this is an HTTPRoute plus one DNS
# A record in ../../infrastructure/samba-ad — the documented way to add a LAN service.
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: seaweedfs-s3
namespace: seaweedfs
spec:
parentRefs:
- name: eg
namespace: envoy-gateway-system
# Pin to the wildcard listener; the https-auth listener only matches
# auth.ddupan.top and would report a needless "no matching listener".
sectionName: https
hostnames:
- s3.ad.ddupan.top
rules:
- backendRefs:
- name: seaweedfs-s3
port: 8333
# S3 PUTs of Terraform state can be large (smtp-relay's is already ~1.1MB
# because the azuread app registration carries a lot). Envoy's default
# per-try timeout is comfortably above that, but the retry policy matters
# more: a half-written state file is far worse than a failed apply, so do
# not add retries here. Terraform handles its own locking and retry.
+76
View File
@@ -0,0 +1,76 @@
global:
seaweedfs:
image:
repository: ""
name: chrislusf/seaweedfs
tag: latest
master:
enabled: true
replicas: 1
data:
type: persistentVolumeClaim
size: 10Gi
storageClass: localpv-zfs-ceph
logs:
type: emptyDir
volume:
enabled: true
replicas: 1
dataDirs:
- name: data1
type: persistentVolumeClaim
size: 100Gi
storageClass: localpv-zfs-ceph
maxVolumes: 0
idx:
type: emptyDir
logs:
type: emptyDir
filer:
enabled: true
replicas: 1
data:
type: persistentVolumeClaim
size: 10Gi
storageClass: localpv-zfs-ceph
logs:
type: emptyDir
s3:
enabled: true
enableAuth: true
# Identities come from a Secret synced out of OpenBao by External Secrets
# (../../platform/external-secrets/externalsecrets.yaml -> kv/k8s/seaweedfs-s3), NOT from
# the chart's own s3.credentials.
#
# WHY: those keys used to be INLINE in this file and were committed in the
# initial commit. They also slipped past a content scan, because the regex
# looked for `secret[:=]` and the key is written `secretKey` — the word is
# followed by "Key", not a colon. See CLAUDE.md on scanning by content.
# The leaked anvAdmin key is in git history and still needs ROTATING.
existingConfigSecret: seaweedfs-s3-config
s3:
enableAuth: true
# No credentials block on purpose — populating it makes the chart render a
# Secret from values, which is what put credentials in git in the first place.
admin:
enabled: true
replicas: 1
data:
type: emptyDir
logs:
type: emptyDir
ingress:
enabled: true
className: tailscale
host: seaweedfs-admin
path: /
pathType: Prefix
annotations: {}
tls:
- hosts:
- seaweedfs-admin