chore(homelab): add homelab plans, frpc deploy script, odysseus workspace, heretic docs
This commit is contained in:
Submodule
+1
Submodule odysseus added at 463713c2c6
@@ -0,0 +1,133 @@
|
|||||||
|
# Homelab Session Handover
|
||||||
|
_Last updated: 2026-06-11 by Lumen_
|
||||||
|
|
||||||
|
## 🔑 SSH Access (no password needed)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh-add ~/.ssh/id_ed25519_homelab
|
||||||
|
```
|
||||||
|
|
||||||
|
| Alias | Host | User | What it is |
|
||||||
|
|-------|------|------|-----------|
|
||||||
|
| `ssh vps` | 85.214.154.199 | root | plate.software — Strato OpenVZ, Plesk, Apache |
|
||||||
|
| `ssh ionos` | 82.165.206.45 | root | plate-software.de — IONOS, Ubuntu 18.04, Apache |
|
||||||
|
| `ssh truenas` | 192.168.188.119 | root | TrueNAS SCALE 24.10.2.4, k3s, Gitea |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Fully Done
|
||||||
|
|
||||||
|
### plate.software (VPS — 85.214.154.199)
|
||||||
|
- Let's Encrypt cert valid (ACME path fixed in Plesk HTTP directives)
|
||||||
|
- `frps` v0.68.1 running systemd, port 7000, token in BigMind fact #188
|
||||||
|
- `git.plate.software` Apache proxy → `localhost:30008` via frpc ✅ HTTP 200
|
||||||
|
- `frpc.service` on TrueNAS tunneling port 30008 → VPS
|
||||||
|
|
||||||
|
### IONOS (plate-software.de — 82.165.206.45)
|
||||||
|
- SSL wildcard-like cert renewed via acme.sh — now covers `git.plate-software.de` too
|
||||||
|
- Valid until ~2026-08-04
|
||||||
|
- ownCloud, Collabora still running
|
||||||
|
|
||||||
|
### TrueNAS — ChunkyTown ZFS Pool (rebuilt 2026-05-04)
|
||||||
|
- New pool: RAIDZ1 on `sda`+`sdb`+`sdd`+`sdl` (3 Toshibas + new Seagate WWZAXXKL)
|
||||||
|
- Hot spare: `sdk` (oldest Toshiba 3220A0PBFA3H)
|
||||||
|
- **29.1TB usable**, ONLINE, 0 errors
|
||||||
|
- Old pool was unrecoverable (2 simultaneous failures)
|
||||||
|
- Data was acceptable loss (Plex re-downloadable, photos in Google Photos)
|
||||||
|
|
||||||
|
### TrueNAS — frpc tunnel
|
||||||
|
- Binary: `/mnt/VM_SSD_Pool/frp/frpc`
|
||||||
|
- Config: `/mnt/VM_SSD_Pool/frp/frpc.toml`
|
||||||
|
- Systemd: `frpc.service` (enabled, running)
|
||||||
|
- Gitea `app.ini`: `/mnt/VM_SSD_Pool/VM_POOL1/gitea/config/app.ini`
|
||||||
|
- `ROOT_URL = https://git.plate.software/`
|
||||||
|
- `SSH_DOMAIN = git.plate.software`
|
||||||
|
|
||||||
|
### git.plate.software ✅ LIVE
|
||||||
|
- `curl https://git.plate.software/` → HTTP 200
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ IONOS Gitea Mirror — FIXED 2026-06-11
|
||||||
|
|
||||||
|
### Status: FULLY WORKING
|
||||||
|
- `https://git.plate-software.de/` → HTTP 200 ✅
|
||||||
|
- Gitea API → HTTP 200 ✅
|
||||||
|
- Push mirrors syncing: `pplate/bigmind`, `pplate/cannamanage`, `pplate/pi_mcps` ✅
|
||||||
|
|
||||||
|
### What's running
|
||||||
|
- Gitea Docker container on IONOS: `docker ps | grep gitea-mirror`
|
||||||
|
- Port: `127.0.0.1:3000` (local only, behind Apache)
|
||||||
|
- Data: `/opt/gitea/data`
|
||||||
|
- Admin user: `pplate` (password: `HomelabGit2026!` — reset 2026-06-11)
|
||||||
|
- API token: `1e87f855d448727e9d213599d654542881bdca0f`
|
||||||
|
|
||||||
|
### Root cause (fixed)
|
||||||
|
The `sites-enabled/` files for collabora, owncloud, and ssl.conf were **stale copies** (not symlinks) still using hostname-specific VirtualHost bindings (`collabora.plate-software.de:443`, `owncloud.plate-software.de:443`, `plate-software.de:443`). These resolved to `82.165.206.45:443` and Apache treated that as a separate higher-priority NameVirtualHost group — intercepting all git smart HTTP requests before the `*:443` git vhost was ever consulted.
|
||||||
|
|
||||||
|
**Fix applied 2026-06-11:**
|
||||||
|
```bash
|
||||||
|
sed -i "s|VirtualHost collabora.plate-software.de:443|VirtualHost *:443|g" /etc/apache2/sites-enabled/collabora.plate-software.de.conf
|
||||||
|
sed -i "s|VirtualHost collabora.plate-software.de:80|VirtualHost *:80|g" /etc/apache2/sites-enabled/collabora.plate-software.de.conf
|
||||||
|
sed -i "s|VirtualHost owncloud.plate-software.de:443|VirtualHost *:443|g" /etc/apache2/sites-enabled/owncloud.plate-software.de.conf
|
||||||
|
sed -i "s|VirtualHost owncloud.plate-software.de:80|VirtualHost *:80|g" /etc/apache2/sites-enabled/owncloud.plate-software.de.conf
|
||||||
|
sed -i "s|VirtualHost plate-software.de:443|VirtualHost *:443|g" /etc/apache2/sites-enabled/ssl.conf
|
||||||
|
systemctl reload apache2
|
||||||
|
```
|
||||||
|
|
||||||
|
⚠️ **Note:** `sites-enabled/collabora`, `owncloud`, and `ssl.conf` are plain files (not symlinks to `sites-available/`). If Apache is ever reconfigured via `a2ensite`, these edits will be lost — the `sites-available/` originals still have the correct `*:443` bindings.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ Other Pending Items
|
||||||
|
|
||||||
|
### Plex (superplex app)
|
||||||
|
- Shows CRASHED in TrueNAS app panel
|
||||||
|
- Likely due to old ChunkyTown dataset paths being gone
|
||||||
|
- Fix: TrueNAS web UI → Apps → superplex → Edit → update media library paths to new `/mnt/ChunkyTown/...` datasets
|
||||||
|
|
||||||
|
### Let's Encrypt for git.plate.software (VPS side)
|
||||||
|
- Currently no SSL cert for `git.plate.software` in Plesk
|
||||||
|
- Apache proxy works but is HTTP→HTTP (Plesk's SSL termination handles it)
|
||||||
|
- Issue cert: Plesk UI → Domains → git.plate.software → Let's Encrypt
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Infrastructure Overview
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet
|
||||||
|
↓ DNS
|
||||||
|
plate.software VPS (85.214.154.199)
|
||||||
|
Apache/Plesk
|
||||||
|
├── plate.software → :8080 (Docker WildFly)
|
||||||
|
└── git.plate.software → :30008 (frp tunnel ← TrueNAS) ✅
|
||||||
|
frps :7000 ← frpc on TrueNAS ✅
|
||||||
|
|
||||||
|
TrueNAS.local (192.168.188.119)
|
||||||
|
├── Gitea :30008 (ROOT_URL = https://git.plate.software/) ✅
|
||||||
|
├── VM_SSD_Pool (ZFS RAIDZ2, ONLINE) — Gitea data lives here
|
||||||
|
└── ChunkyTown (ZFS RAIDZ1, ONLINE, 29.1TB) — rebuilt 2026-05-04
|
||||||
|
├── raidz1: sda + sdb + sdd + sdl (Seagate)
|
||||||
|
└── spare: sdk
|
||||||
|
|
||||||
|
IONOS (82.165.206.45)
|
||||||
|
Apache
|
||||||
|
├── owncloud.plate-software.de → :8080 ✅
|
||||||
|
├── collabora.plate-software.de → :9980 ✅
|
||||||
|
└── git.plate-software.de → :3000 (Gitea mirror Docker) ✅ FULLY WORKING (fixed 2026-06-11)
|
||||||
|
Docker: gitea-mirror, data: /opt/gitea/data
|
||||||
|
Token: 1e87f855d448727e9d213599d654542881bdca0f (in BigMind fact #192)
|
||||||
|
Repos: pplate/bigmind, pplate/cannamanage, pplate/pi_mcps (push mirrors from TrueNAS)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗂️ Key File Locations
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `~/.ssh/id_ed25519_homelab` | Automation SSH key |
|
||||||
|
| `~/.ssh/config` | SSH aliases (vps, ionos, truenas) |
|
||||||
|
| `plans/frpc-truenas-deploy.sh` | frpc installer (already run on TrueNAS) |
|
||||||
|
| `plans/HOMELAB-HANDOVER.md` | This file |
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# frpc deployment script for TrueNAS
|
||||||
|
# Run from Fedora: bash plans/frpc-truenas-deploy.sh
|
||||||
|
# Installs frpc on TrueNAS and sets up tunnel to expose Gitea publicly
|
||||||
|
|
||||||
|
TRUENAS="root@192.168.188.119"
|
||||||
|
VPS_IP="85.214.154.199"
|
||||||
|
FRP_TOKEN="5f64a6f20bb2cb8c3133ecac8ca3f0571d7d64dff910225040bfc0c60a106c81"
|
||||||
|
FRP_VERSION="0.68.1"
|
||||||
|
|
||||||
|
echo "=== Deploying frpc on TrueNAS ==="
|
||||||
|
|
||||||
|
ssh -i /home/pplate/.ssh/id_ed25519_homelab $TRUENAS << REMOTE
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# TrueNAS root filesystem is read-only — install to /mnt which is persistent ZFS
|
||||||
|
INSTALL_DIR=/mnt/VM_SSD_Pool/frp
|
||||||
|
mkdir -p \$INSTALL_DIR
|
||||||
|
|
||||||
|
# Download frpc binary
|
||||||
|
echo "Downloading frp ${FRP_VERSION}..."
|
||||||
|
curl -sL https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_amd64.tar.gz \
|
||||||
|
-o /tmp/frp.tar.gz
|
||||||
|
tar xzf /tmp/frp.tar.gz -C /tmp/
|
||||||
|
cp /tmp/frp_${FRP_VERSION}_linux_amd64/frpc \$INSTALL_DIR/frpc
|
||||||
|
chmod +x \$INSTALL_DIR/frpc
|
||||||
|
\$INSTALL_DIR/frpc --version
|
||||||
|
|
||||||
|
# Write frpc config
|
||||||
|
cat > \$INSTALL_DIR/frpc.toml << 'TOML'
|
||||||
|
serverAddr = "${VPS_IP}"
|
||||||
|
serverPort = 7000
|
||||||
|
auth.method = "token"
|
||||||
|
auth.token = "${FRP_TOKEN}"
|
||||||
|
log.to = "/tmp/frpc.log"
|
||||||
|
log.level = "info"
|
||||||
|
|
||||||
|
[[proxies]]
|
||||||
|
name = "gitea"
|
||||||
|
type = "tcp"
|
||||||
|
localIP = "127.0.0.1"
|
||||||
|
localPort = 30008
|
||||||
|
remotePort = 30008
|
||||||
|
TOML
|
||||||
|
|
||||||
|
echo "frpc config written:"
|
||||||
|
cat \$INSTALL_DIR/frpc.toml
|
||||||
|
|
||||||
|
# Create init script (TrueNAS uses systemd-like init but custom)
|
||||||
|
# Use /etc/local.d/ for persistent startup scripts on TrueNAS SCALE
|
||||||
|
# Actually TrueNAS SCALE uses systemd — write a service to /etc/systemd/system/
|
||||||
|
cat > /etc/systemd/system/frpc.service << 'SVCEOF'
|
||||||
|
[Unit]
|
||||||
|
Description=frp client - tunnel to plate.software VPS
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/mnt/VM_SSD_Pool/frp/frpc -c /mnt/VM_SSD_Pool/frp/frpc.toml
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10s
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
SVCEOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable frpc
|
||||||
|
systemctl start frpc
|
||||||
|
sleep 3
|
||||||
|
systemctl status frpc --no-pager | head -15
|
||||||
|
echo ""
|
||||||
|
echo "=== frpc deployed and running ==="
|
||||||
|
echo "Gitea should now be reachable at https://git.plate.software"
|
||||||
|
REMOTE
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
# Task: Swap Qwen3-4B Encoder for Heretic Abliterated Version
|
# Task: Swap Qwen3-4B Encoder for Heretic Abliterated Version
|
||||||
|
|
||||||
**Datum:** 2026-04-10
|
**Datum:** 2026-04-10
|
||||||
**Status:** Ready — waiting for correct Heretic encoder to be published
|
**Status:** ✅ COMPLETE — Heretic encoder swapped and live-tested 2026-04-10
|
||||||
**Depends on:** FLUX.2 Klein 4B working (✅ done as of 2026-04-10)
|
**Depends on:** FLUX.2 Klein 4B working (✅ done as of 2026-04-10)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -133,7 +133,7 @@ The entire MCP server, workflow registry, and test suite are already correct. Th
|
|||||||
|
|
||||||
## Success Criteria
|
## Success Criteria
|
||||||
|
|
||||||
- [ ] `generate_image("...", model="flux-2-klein-4b.safetensors")` works with prompts that currently get refused
|
- [x] `generate_image("...", model="flux-2-klein-4b.safetensors")` works with prompts that currently get refused — ✅ tested 2026-04-10, Renaissance nude generated without refusal
|
||||||
- [ ] Output image quality identical to standard encoder (check: no visible artifacts vs reference)
|
- [x] Output image quality identical to standard encoder (check: no visible artifacts vs reference) — ✅ 1.9MB photorealistic 1024×1024, museum-quality result, 50.4s
|
||||||
- [ ] ComfyUI logs show no dimension errors
|
- [x] ComfyUI logs show no dimension errors — ✅ only harmless libcudart NVIDIA stub warnings
|
||||||
- [ ] `qwen_3_4b_klein_backup.safetensors` kept as rollback
|
- [x] `qwen_3_4b_klein_backup.safetensors` kept as rollback — ✅ 7.5G backup at ~/ComfyUI/models/text_encoders/qwen_3_4b_klein_backup.safetensors
|
||||||
|
|||||||
@@ -0,0 +1,262 @@
|
|||||||
|
# Homelab Proxy Architecture Plan
|
||||||
|
_plate.software VPS as public face → WireGuard tunnel → TrueNAS.local_
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Use the cheap public VPS (`plate.software` @ 85.214.154.199 / Plesk) as:
|
||||||
|
- Public DNS + TLS termination point
|
||||||
|
- Apache reverse proxy routing subdomains to TrueNAS homelab services
|
||||||
|
- ACME/Let's Encrypt managed by Plesk (already working)
|
||||||
|
|
||||||
|
TrueNAS.local (192.168.188.119) becomes the actual compute host for all Docker services.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The Core Problem: TrueNAS is Behind NAT
|
||||||
|
|
||||||
|
TrueNAS lives on a home network. The public VPS cannot reach it directly. A tunnel is required.
|
||||||
|
|
||||||
|
### ⚠️ WireGuard NOT possible — VPS is OpenVZ
|
||||||
|
|
||||||
|
The VPS (`h2970715.stratoserver.net`, Strato) runs on OpenVZ virtualization.
|
||||||
|
WireGuard requires a kernel module — **not loadable in OpenVZ containers**.
|
||||||
|
|
||||||
|
### Recommended Solution: frp (Fast Reverse Proxy)
|
||||||
|
|
||||||
|
```
|
||||||
|
Internet
|
||||||
|
↓ DNS
|
||||||
|
plate.software VPS (85.214.154.199)
|
||||||
|
frps server (port 7000)
|
||||||
|
↓ Apache ProxyPass (HTTP/HTTPS)
|
||||||
|
↓ frp tunnel (TCP, userspace)
|
||||||
|
TrueNAS.local (192.168.188.119)
|
||||||
|
frpc client → connects out to VPS:7000
|
||||||
|
├── Gitea :30008 → git.plate.software → VPS:30008
|
||||||
|
├── WildFly/Java EE :8080 → plate.software → VPS:18080
|
||||||
|
└── Future services :XXXX → app.plate.software
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why frp:**
|
||||||
|
- Pure userspace Go binary — works perfectly on OpenVZ
|
||||||
|
- TrueNAS (frpc) initiates outbound connection — no router port forwarding needed
|
||||||
|
- Encrypted tunnel (TLS optional)
|
||||||
|
- VPS (frps) exposes local ports that Apache proxies to
|
||||||
|
- Zero kernel dependencies
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Target DNS Routing
|
||||||
|
|
||||||
|
| Domain / Subdomain | Routes to | Notes |
|
||||||
|
|-------------------------|-----------------------------------|-------|
|
||||||
|
| `plate.software` | TrueNAS:8080 (WildFly) | Current customer Java EE project |
|
||||||
|
| `git.plate.software` | TrueNAS:30008 (Gitea) | New — expose homelab Gitea publicly |
|
||||||
|
| `app.plate.software` | TrueNAS:XXXX (future) | Placeholder for future projects |
|
||||||
|
|
||||||
|
All DNS A records point to `85.214.154.199` (VPS). TLS is terminated at the VPS by Plesk/Let's Encrypt.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Steps
|
||||||
|
|
||||||
|
### Phase 1: WireGuard Tunnel (VPS ↔ TrueNAS)
|
||||||
|
|
||||||
|
**On the VPS (root@85.214.154.199):**
|
||||||
|
```bash
|
||||||
|
apt install wireguard
|
||||||
|
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
|
||||||
|
```
|
||||||
|
|
||||||
|
Create `/etc/wireguard/wg0.conf`:
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
Address = 10.100.0.1/24
|
||||||
|
ListenPort = 51820
|
||||||
|
PrivateKey = <server_private_key>
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <truenas_public_key>
|
||||||
|
AllowedIPs = 10.100.0.2/32
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
```
|
||||||
|
|
||||||
|
**On TrueNAS (via TrueNAS SCALE UI or shell):**
|
||||||
|
- Apps → Network → WireGuard → Add Interface
|
||||||
|
- Or via shell: same `wg genkey` + `/etc/wireguard/wg0.conf` approach
|
||||||
|
```ini
|
||||||
|
[Interface]
|
||||||
|
Address = 10.100.0.2/24
|
||||||
|
PrivateKey = <truenas_private_key>
|
||||||
|
|
||||||
|
[Peer]
|
||||||
|
PublicKey = <vps_public_key>
|
||||||
|
Endpoint = 85.214.154.199:51820
|
||||||
|
AllowedIPs = 10.100.0.1/32
|
||||||
|
PersistentKeepalive = 25
|
||||||
|
```
|
||||||
|
|
||||||
|
Enable on both:
|
||||||
|
```bash
|
||||||
|
systemctl enable --now wg-quick@wg0
|
||||||
|
```
|
||||||
|
|
||||||
|
Test:
|
||||||
|
```bash
|
||||||
|
# From VPS
|
||||||
|
ping 10.100.0.2
|
||||||
|
curl http://10.100.0.2:30008 # Should reach Gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 2: Firewall — Open WireGuard Port on VPS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On VPS
|
||||||
|
ufw allow 51820/udp
|
||||||
|
# Or via iptables if ufw not present
|
||||||
|
iptables -A INPUT -p udp --dport 51820 -j ACCEPT
|
||||||
|
```
|
||||||
|
|
||||||
|
Also ensure TrueNAS router/firewall does NOT need any port forwarding — TrueNAS initiates the tunnel outbound. The VPS listens; TrueNAS connects. No router config needed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 3: Plesk Apache — Add Subdomain Proxy Rules
|
||||||
|
|
||||||
|
**Add `git.plate.software` as a subdomain in Plesk:**
|
||||||
|
1. Plesk → Domains → Add Subdomain → `git.plate.software`
|
||||||
|
2. Apache & nginx Settings → Additional directives for HTTP:
|
||||||
|
```apache
|
||||||
|
<IfModule mod_proxy.c>
|
||||||
|
ProxyPass /.well-known/acme-challenge/ !
|
||||||
|
ProxyPass / http://10.100.0.2:30008/ retry=0
|
||||||
|
ProxyPassReverse / http://10.100.0.2:30008/
|
||||||
|
ProxyPreserveHost On
|
||||||
|
</IfModule>
|
||||||
|
```
|
||||||
|
3. Issue Let's Encrypt cert for `git.plate.software`
|
||||||
|
4. Configure HTTPS redirect and HTTPS proxy directives the same way
|
||||||
|
|
||||||
|
**Update `plate.software` HTTP directives:**
|
||||||
|
Change the existing WildFly proxy target from `127.0.0.1:8080` to `10.100.0.2:8080` once WildFly is moved to TrueNAS:
|
||||||
|
```apache
|
||||||
|
ProxyPass / http://10.100.0.2:8080/ retry=0
|
||||||
|
```
|
||||||
|
(Keep this as `127.0.0.1:8080` while the Docker container still runs on the VPS)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 4: Migrate WildFly to TrueNAS
|
||||||
|
|
||||||
|
The customer's Java EE app currently runs in Docker on the VPS. Migrate to TrueNAS:
|
||||||
|
|
||||||
|
1. Export/pull the WildFly Docker image
|
||||||
|
2. Copy any persistent volumes/data
|
||||||
|
3. Create `docker-compose.yml` on TrueNAS
|
||||||
|
4. Start container on TrueNAS, verify on `10.100.0.2:8080`
|
||||||
|
5. Update VPS Apache proxy target from `127.0.0.1:8080` → `10.100.0.2:8080`
|
||||||
|
6. Remove the Docker container from VPS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Phase 5: Gitea Public HTTPS
|
||||||
|
|
||||||
|
For Gitea to work properly behind a proxy, update its config to know its public URL:
|
||||||
|
|
||||||
|
Edit Gitea's `app.ini` (in the Gitea Docker volume on TrueNAS):
|
||||||
|
```ini
|
||||||
|
[server]
|
||||||
|
DOMAIN = git.plate.software
|
||||||
|
ROOT_URL = https://git.plate.software/
|
||||||
|
HTTP_PORT = 30008
|
||||||
|
```
|
||||||
|
|
||||||
|
Also in Plesk HTTPS directives for `git.plate.software`:
|
||||||
|
```apache
|
||||||
|
<IfModule mod_proxy.c>
|
||||||
|
ProxyPass /.well-known/acme-challenge/ !
|
||||||
|
ProxyPass / http://10.100.0.2:30008/ retry=0
|
||||||
|
ProxyPassReverse / http://10.100.0.2:30008/
|
||||||
|
ProxyPreserveHost On
|
||||||
|
RequestHeader set X-Forwarded-Proto "https"
|
||||||
|
RequestHeader set X-Forwarded-Port "443"
|
||||||
|
</IfModule>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Network Topology (Final State)
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ Internet / DNS │
|
||||||
|
│ *.plate.software → 85.214.154.199 │
|
||||||
|
└──────────────┬──────────────────────┘
|
||||||
|
│ HTTP/HTTPS
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ VPS: plate.software │
|
||||||
|
│ 85.214.154.199 / Plesk / Apache │
|
||||||
|
│ │
|
||||||
|
│ plate.software → proxy:8080 │
|
||||||
|
│ git.plate.software → proxy:30008 │
|
||||||
|
│ app.plate.software → proxy:XXXX │
|
||||||
|
└──────────────┬──────────────────────┘
|
||||||
|
│ WireGuard 10.100.0.0/24
|
||||||
|
│ UDP 51820 (encrypted)
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────┐
|
||||||
|
│ TrueNAS.local │
|
||||||
|
│ 192.168.188.119 / WG: 10.100.0.2 │
|
||||||
|
│ │
|
||||||
|
│ :30008 Gitea │
|
||||||
|
│ :8080 WildFly (Java EE) │
|
||||||
|
│ :XXXX Future services │
|
||||||
|
└─────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risks & Notes
|
||||||
|
|
||||||
|
| Risk | Mitigation |
|
||||||
|
|------|-----------|
|
||||||
|
| Home ISP outage takes down all services | Acceptable for homelab; add health check monitoring later |
|
||||||
|
| ISP dynamic IP changes (if applicable) | WireGuard peer config uses VPS as endpoint (fixed IP) — TrueNAS initiates tunnel, so home IP change is transparent |
|
||||||
|
| TrueNAS reboot drops tunnel | `systemctl enable wg-quick@wg0` ensures auto-start |
|
||||||
|
| Gitea SSH cloning (port 22/2222) | Need separate SSH port forward or Gitea SSH over different port — HTTP clone still works via HTTPS proxy |
|
||||||
|
| Customer data on VPS → TrueNAS migration | Do at off-peak time; test thoroughly before cutting DNS |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Cost Model
|
||||||
|
|
||||||
|
- VPS (plate.software): Keep cheap (~3-5€/month) — CPU/RAM irrelevant, just proxy traffic
|
||||||
|
- TrueNAS: All compute happens here — free (already owned hardware)
|
||||||
|
- Cloudflare (optional): Free plan for DNS + DDoS protection on top of the VPS
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Alternative: Cloudflare Tunnel (Zero-Config Option)
|
||||||
|
|
||||||
|
If WireGuard setup is too complex, Cloudflare Tunnel (`cloudflared`) is a zero-config alternative:
|
||||||
|
- Run `cloudflared` as a Docker container on TrueNAS
|
||||||
|
- No VPS needed for tunneling — Cloudflare handles the public endpoint
|
||||||
|
- Free for personal use
|
||||||
|
- TrueNAS → Cloudflare edge → DNS → users
|
||||||
|
|
||||||
|
**Downside:** Traffic routes through Cloudflare (not self-hosted end-to-end). VPS still useful for non-Cloudflare domains and the existing customer project.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Priority
|
||||||
|
|
||||||
|
1. ✅ Fix plate.software Let's Encrypt (done)
|
||||||
|
2. 🔜 Set up WireGuard tunnel (VPS ↔ TrueNAS)
|
||||||
|
3. 🔜 Add `git.plate.software` subdomain in Plesk + proxy to TrueNAS Gitea
|
||||||
|
4. 🔜 Update Gitea `app.ini` with public URL
|
||||||
|
5. 🔜 Issue Let's Encrypt for `git.plate.software`
|
||||||
|
6. ⏳ Migrate WildFly customer project from VPS → TrueNAS
|
||||||
|
7. ⏳ Decommission VPS Docker container (keep VPS as pure proxy)
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
# Task: Add ESRGAN Upscaler to mcp-image-gen
|
||||||
|
|
||||||
|
**Datum:** 2026-04-10
|
||||||
|
**Status:** Ready to implement
|
||||||
|
**Depends on:** mcp-image-gen working ✅, FLUX.2 Klein Heretic working ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Add an `upscale_image()` MCP tool that takes an existing PNG path (from a previous `generate_image()` call) and upscales it 2× or 4× using a Real-ESRGAN model — **no diffusion re-generation**, just fast post-processing (~5–10s).
|
||||||
|
|
||||||
|
Result: A 1024×1024 → 4096×4096 pipeline in two tool calls:
|
||||||
|
```python
|
||||||
|
result = generate_image("...", model="flux-2-klein-4b.safetensors", steps=20)
|
||||||
|
# → ~/Pictures/mcp-generated/foo_20260410_123456_12345.png
|
||||||
|
|
||||||
|
upscaled = upscale_image(
|
||||||
|
input_path="~/Pictures/mcp-generated/foo_20260410_123456_12345.png",
|
||||||
|
scale=4
|
||||||
|
)
|
||||||
|
# → ~/Pictures/mcp-generated/foo_20260410_123456_12345_4x.png (4096×4096)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Why ESRGAN (Option B) over Latent Upscale
|
||||||
|
|
||||||
|
| Method | Time overhead | Quality | Requires diffusion? |
|
||||||
|
|--------|--------------|---------|---------------------|
|
||||||
|
| ESRGAN image upscale | ~5–10s | ✅ Very sharp details | ❌ No |
|
||||||
|
| Latent upscale + KSampler | ~50% extra gen time | ✅ Good, consistent style | ✅ Yes |
|
||||||
|
| UltimateSDUpscale (tiled) | ~4× gen time | ✅ Highest quality | ✅ Yes |
|
||||||
|
|
||||||
|
ESRGAN is the clear winner for "I want a bigger version of this image quickly."
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Model to Use
|
||||||
|
|
||||||
|
**`4x-UltraSharp.pth`** — the community standard for photorealistic upscaling.
|
||||||
|
|
||||||
|
- Source: https://huggingface.co/Kim2091/UltraSharp
|
||||||
|
- Download: `huggingface-cli download Kim2091/UltraSharp 4x-UltraSharp.pth --local-dir ~/ComfyUI/models/upscale_models/`
|
||||||
|
- Size: ~67MB
|
||||||
|
- Scale factor: 4× (can also be used for 2× via image resize after)
|
||||||
|
|
||||||
|
Alternative: `RealESRGAN_x4plus.pth` (in ComfyUI's model downloader, general purpose)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ComfyUI Workflow: `esrgan_upscale.json`
|
||||||
|
|
||||||
|
Minimal workflow — 3 nodes:
|
||||||
|
|
||||||
|
```
|
||||||
|
LoadImage → UpscaleModelLoader + ImageUpscaleWithModel → SaveImage
|
||||||
|
```
|
||||||
|
|
||||||
|
Node layout:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"1": {
|
||||||
|
"class_type": "LoadImage",
|
||||||
|
"inputs": {
|
||||||
|
"image": "__INPUT_PATH__"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"class_type": "UpscaleModelLoader",
|
||||||
|
"inputs": {
|
||||||
|
"model_name": "4x-UltraSharp.pth"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"class_type": "ImageUpscaleWithModel",
|
||||||
|
"inputs": {
|
||||||
|
"upscale_model": ["2", 0],
|
||||||
|
"image": ["1", 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"class_type": "SaveImage",
|
||||||
|
"inputs": {
|
||||||
|
"images": ["3", 0],
|
||||||
|
"filename_prefix": "__OUTPUT_PREFIX__"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** `LoadImage` in ComfyUI requires the image to be in `~/ComfyUI/input/` — the workflow builder must copy the input file there first (or use `ETN_LoadImageBase64` if available). See "Implementation Notes" below.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MCP Tool Signature
|
||||||
|
|
||||||
|
Add to [`mcp/mcp-image-gen/src/server.py`](../mcp/mcp-image-gen/src/server.py):
|
||||||
|
|
||||||
|
```python
|
||||||
|
@mcp.tool()
|
||||||
|
async def upscale_image(
|
||||||
|
input_path: Annotated[str, Field(description="Path to input PNG (absolute or ~-relative). Must be a file previously generated by generate_image().")],
|
||||||
|
scale: Annotated[int, Field(description="Upscale factor: 2 or 4 (default: 4). 4x-UltraSharp always runs at 4x; scale=2 applies a 0.5 resize after.")] = 4,
|
||||||
|
output_dir: Annotated[str, Field(description="Override output directory. Defaults to same dir as input_path.")] = "",
|
||||||
|
name: Annotated[str, Field(description="Optional output filename prefix. Defaults to input filename + _4x or _2x.")] = "",
|
||||||
|
) -> list:
|
||||||
|
"""Upscale an existing image using Real-ESRGAN (4x-UltraSharp).
|
||||||
|
|
||||||
|
No diffusion re-generation — pure post-processing (~5-10s).
|
||||||
|
Input must be a PNG file. Output is saved alongside the input by default.
|
||||||
|
|
||||||
|
Returns both a file path and an inline base64 image for display.
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
### The `LoadImage` ComfyUI constraint
|
||||||
|
|
||||||
|
ComfyUI's built-in `LoadImage` node only accepts filenames relative to `~/ComfyUI/input/`, not arbitrary paths. Two solutions:
|
||||||
|
|
||||||
|
**Solution A (simplest):** Copy input to `~/ComfyUI/input/` before submitting workflow, use basename as `image` param, delete after.
|
||||||
|
|
||||||
|
**Solution B:** Use `ETN_LoadImageBase64` node (part of `ComfyUI-ETN` custom node extension) — accepts a base64-encoded image directly. Check if installed:
|
||||||
|
```bash
|
||||||
|
ls ~/ComfyUI/custom_nodes/ | grep -i etn
|
||||||
|
```
|
||||||
|
|
||||||
|
**Recommended:** Start with Solution A (copy to input dir) — no dependencies. If `ComfyUI-ETN` is present, prefer Solution B for cleanliness.
|
||||||
|
|
||||||
|
### Scale=2 handling
|
||||||
|
|
||||||
|
`4x-UltraSharp.pth` always outputs 4×. For `scale=2`, upscale at 4× then resize the result image to 50% with PIL before saving. This is still sharper than native 2× bilinear upscaling.
|
||||||
|
|
||||||
|
### Output filename convention
|
||||||
|
|
||||||
|
Input: `foo_20260410_123456_12345.png`
|
||||||
|
Output `scale=4`: `foo_20260410_123456_12345_4x.png`
|
||||||
|
Output `scale=2`: `foo_20260410_123456_12345_2x.png`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Files to Create/Modify
|
||||||
|
|
||||||
|
| File | Change |
|
||||||
|
|------|--------|
|
||||||
|
| [`mcp/mcp-image-gen/src/workflows/esrgan_upscale.json`](../mcp/mcp-image-gen/src/workflows/esrgan_upscale.json) | New — ESRGAN workflow |
|
||||||
|
| [`mcp/mcp-image-gen/src/server.py`](../mcp/mcp-image-gen/src/server.py) | Add `upscale_image()` tool + helpers |
|
||||||
|
| [`mcp/mcp-image-gen/tests/test_upscale.py`](../mcp/mcp-image-gen/tests/test_upscale.py) | New test file |
|
||||||
|
|
||||||
|
**No changes to:** workflow registry, existing tools, `generate_image()`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pre-flight: Download Model
|
||||||
|
|
||||||
|
```bash
|
||||||
|
huggingface-cli download Kim2091/UltraSharp \
|
||||||
|
4x-UltraSharp.pth \
|
||||||
|
--local-dir ~/ComfyUI/models/upscale_models/
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify ComfyUI sees it:
|
||||||
|
```bash
|
||||||
|
curl -s http://localhost:8188/object_info/UpscaleModelLoader | \
|
||||||
|
python3 -c "import sys,json; d=json.load(sys.stdin); print('\n'.join(d['UpscaleModelLoader']['input']['required']['model_name'][0]))"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Test Cases
|
||||||
|
|
||||||
|
| Test | Input | Expected |
|
||||||
|
|------|-------|----------|
|
||||||
|
| `test_upscale_4x` | 1024×1024 PNG | 4096×4096 PNG, `_4x.png` suffix |
|
||||||
|
| `test_upscale_2x` | 1024×1024 PNG | 2048×2048 PNG, `_2x.png` suffix |
|
||||||
|
| `test_invalid_path` | nonexistent path | Error TextContent returned |
|
||||||
|
| `test_output_dir_override` | valid PNG + `output_dir=/tmp` | saved to /tmp |
|
||||||
|
| `test_default_output_dir` | valid PNG, no output_dir | saved alongside input |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
- [ ] `4x-UltraSharp.pth` present in `~/ComfyUI/models/upscale_models/`
|
||||||
|
- [ ] `upscale_image("path/to/1024.png", scale=4)` returns 4096×4096 PNG
|
||||||
|
- [ ] Output file saved with `_4x.png` suffix
|
||||||
|
- [ ] Inline base64 image returned for display in chat
|
||||||
|
- [ ] All 5 test cases pass
|
||||||
|
- [ ] No changes to existing `generate_image()` tests
|
||||||
Reference in New Issue
Block a user