R-449. Until today one app upgrade out of 53 had ever been measured, by hand, and the whole update arc was designed against that single data point. C3 first: the negative control, whose TO image exits immediately, came back failed. That is what makes the greens mean anything, and it cost 556s because a negative is only honest if it waits out the full settle window. Seven edges, three apps. All five real catalog upgrades kept the customer's data. The finding that changes an assumption the arc was carrying: whether an upgrade can be UNDONE is a property of the individual APP, not of upgrades. Docmost refuses - 'corrupted migrations: previously executed migration 20260213T085259-notifications is missing' - and privatebin does not. That reproduces the Nextcloud result on a second app by a DIFFERENT mechanism, so the struck word 'rollback' now rests on two measurements instead of one. The finding nobody was looking for, R-459: our own bookstack template moves MariaDB across a major and sets no MARIADB_* env at all, so the engine logs that the datadir upgrade it requires is being skipped, and serves anyway. The cause is assigned rather than guessed - the app half alone produces no upgrade line, both edges that move the engine produce it - which is exactly what decomposing E3 into E3a and E3b was for. It also explains why E3's abort looked like it worked: the datadir was never converted. Whether that ever breaks is NOT established, and the row says so. Also opened: R-460 (bookstack's file half cannot be seeded headlessly), R-461 (target-selection.md names a venue that does not exist and fences a VM that is gone), R-462 (the widening, costed with this run's real numbers - and the cost is dominated by fixtures, which do not amortise). Teardown all three layers, hub checked rather than asserted. local-lvm read 30.50 percent before and after. The capability map was deliberately NOT edited: this measured apps, not the product.
felhom.eu
Website, manifests, and infrastructure for Felhőm.eu — a managed home-server service for Hungarian households.
Overview
This repository contains:
- Website (
website/) — Static HTML pages served at felhom.eu - Kubernetes manifests (
manifests/) — All k3s deployments for the felhom.eu ecosystem - Assets (
website/assets/) — Logo, images, OG images
The website runs on a single-node k3s cluster alongside the rest of the Felhőm management infrastructure (Healthchecks, Umami analytics, contact mailer).
Branding
| Aspect | Value |
|---|---|
| Brand name | Felhőm.eu (with accent: ő) |
| Domain | felhom.eu (without accent — domain limitation) |
| Tagline | „Saját felhőd, saját szabályaid" |
| Controller product | Felhő Felügyelő (customer-facing name) |
| Controller code name | felhom-controller (backend/repo/container) |
| Language | Hungarian throughout all customer-facing content |
| Contact email | info@felhom.eu |
| Admin email | admin@felhom.eu |
Why "Felhőm"?
"Felhő" means "cloud" in Hungarian. The "m" suffix makes it possessive — "my cloud" (felhőm). The .eu domain is part of the brand identity and appears in the logo. The double meaning of "felhő" (tech cloud + weather cloud) is intentional and used in product naming (e.g., Felhő Felügyelő = "Cloud Supervisor/Inspector").
Website Pages
| File | URL | Purpose |
|---|---|---|
index.html |
/ |
Landing page — hero, services, app preview, backup intro, contact |
alkalmazasok.html |
/alkalmazasok |
Full application catalog (45+ apps with categories) |
technologiak.html |
/technologiak |
Technology stack explanation (Docker, Felhő Felügyelő, Proxmox, Kubernetes) |
biztonsagimentes.html |
/biztonsagimentes |
Backup strategy — 3-2-1 rule, monitoring, restore procedures |
gyik.html |
/gyik |
FAQ — structured Q&A with JSON-LD schema |
kapcsolat.html |
/kapcsolat |
Contact form + email, sends via contact-mailer API |
szolgaltatasok-nonpublic.html |
/szolgaltatasok-nonpublic |
Pricing/services page (not linked in nav, robots disallowed) |
All pages use:
- Clean URLs — nginx serves
.htmlfiles without extension (/gyik→gyik.html) - Unified CSS — each page contains the full CSS (no external stylesheet, for simplicity)
- Responsive design — mobile hamburger menu, responsive grids
- UTF-8 with BOM — all HTML files are saved as UTF-8-BOM for Hungarian character support
- Umami analytics — privacy-friendly tracking script on every page
Infrastructure
Architecture
Internet
│
▼
Cloudflare (DNS only, no proxy)
│
▼ CNAME → dooplex.hopto.org
│
Home network (dynamic IP via No-IP DynDNS)
│
▼ Port forward 80/443
│
k3s cluster (single node)
├── nginx-ingress (TLS termination via cert-manager + Let's Encrypt)
│
├── felhom-system namespace:
│ ├── felhom-webpage (nginx + git-sync sidecar)
│ ├── filebrowser (files.felhom.eu — website file management)
│ ├── contact-mailer (Go app — /api/contact endpoint)
│ ├── umami + umami-db (stats.felhom.eu — web analytics)
│ └── healthchecks (status.felhom.eu — monitoring)
│
└── cert-manager (letsencrypt-prod cluster issuer)
Kubernetes Manifests
| Manifest | Services | Subdomains |
|---|---|---|
webpage.yaml |
nginx (website), FileBrowser, git-sync | felhom.eu, www.felhom.eu, files.felhom.eu |
contact-mailer.yaml |
Go HTTP server for contact form | felhom.eu/api/* (path-based routing) |
umami.yaml |
Umami v3 + PostgreSQL | stats.felhom.eu |
healthchecks.yaml |
Healthchecks | status.felhom.eu |
Website Deployment
The website uses a git-sync sidecar pattern:
git-synccontainer polls this repository (sparse checkout:/website/only)- Syncs to a shared
emptyDirvolume nginxcontainer serves from the synced content- Changes pushed to this repo are live within minutes (no manual deployment)
FileBrowser at files.felhom.eu provides a web UI for quick edits to website files (emergency fixes, asset uploads) without needing git. It writes to a Longhorn PVC that the website nginx also reads from.
Storage
All persistent data uses Longhorn distributed storage:
filebrowser-files(1Gi, ReadWriteMany) — website filesfilebrowser-db(100Mi) — FileBrowser SQLite databaseumami-db-data(2Gi) — Umami PostgreSQL datahealthchecks-data(1Gi) — Healthchecks SQLite data
DNS Configuration (Cloudflare)
Domain: felhom.eu — Cloudflare DNS (free plan), DNS only mode (no proxy/orange cloud).
Records
| Type | Name | Content | Notes |
|---|---|---|---|
| CNAME | felhom.eu |
dooplex.hopto.org | Main website |
| CNAME | www |
dooplex.hopto.org | www redirect |
| CNAME | files |
dooplex.hopto.org | FileBrowser |
| CNAME | stats |
dooplex.hopto.org | Umami analytics |
| CNAME | status |
dooplex.hopto.org | Healthchecks |
| CNAME | ntfy |
dooplex.hopto.org | Push notifications |
| MX | felhom.eu |
route{1,2,3}.mx.cloudflare.net | Incoming email → Cloudflare Email Routing |
| MX | send |
feedback-smtp.eu-west-1.amazonses.com | Resend sending domain |
| TXT | felhom.eu |
v=spf1 include:_spf.mx.clo... |
SPF for Cloudflare |
| TXT | send |
v=spf1 include:amazonses... |
SPF for Resend |
| TXT | cf2024-1._domainkey |
DKIM for Cloudflare Email Routing | |
| TXT | resend._domainkey |
DKIM for Resend | |
| TXT | _dmarc |
v=DMARC1; p=none; |
DMARC policy |
| TXT | felhom.eu |
google-site-verification=... |
Google Search Console |
Incoming Email
Cloudflare Email Routing (free) handles all incoming mail:
info@felhom.eu→ forwarded to personal Gmailadmin@felhom.eu→ forwarded to personal Gmail- Catch-all → not configured
Outgoing Email (Transactional)
Resend (free tier) handles outgoing email via API:
- Contact form submissions → sends formatted email to
info@felhom.eu - Healthchecks alerts → sends to
admin@felhom.eu - Sending domain:
send.felhom.eu(verified with SPF, DKIM) - From address:
Felhom.eu <info@felhom.eu>
Contact Form Flow
- User fills form on
/kapcsolat - JavaScript POST to
/api/contact contact-mailer(Go, in k3s) validates + calls Resend API- Email delivered to
info@felhom.euvia Resend → Cloudflare Email Routing → Gmail
SEO
Google Search Console
- Property:
https://felhom.eu - Verified via DNS TXT record
- Sitemap submitted:
https://felhom.eu/sitemap.xml - 7 pages indexed (all public pages)
On-Page SEO
Every page includes:
<title>with Hungarian keywords + brand<meta name="description">with unique content per page<meta name="keywords">with relevant Hungarian terms<link rel="canonical">to prevent duplicate content- Open Graph tags (og:title, og:description, og:image, og:locale=hu_HU)
- Twitter Card tags (summary_large_image)
- JSON-LD structured data (LocalBusiness on index, Article on technologiak, FAQPage on gyik)
Technical SEO
robots.txt— allows all, disallows/szolgaltatasok-nonpublic, includes sitemap URLsitemap.xml— lists all 6 public pages with priority + changefreq- Clean URLs (no
.htmlextensions) - Static asset caching (7 day expiry for CSS/JS/images)
- Security headers (X-Frame-Options, X-Content-Type-Options)
Analytics
Umami v3 (self-hosted, privacy-focused):
- Dashboard:
https://stats.felhom.eu - Tracking script:
<script defer src="https://stats.felhom.eu/script.js" data-website-id="d419db57-..."> - Cookie-free, GDPR compliant — no consent banner needed
- Backend: dedicated PostgreSQL instance in k3s
Monitoring
Healthchecks (self-hosted):
- Dashboard:
https://status.felhom.eu - Monitors backup jobs, service health
- Sends email alerts via Resend when checks fail
Development Workflow
Quick content edits
- Log into FileBrowser at
https://files.felhom.eu - Edit HTML files directly
- Changes are live immediately
Standard workflow
- Clone this repo from Gitea (
gitea.dooplex.hu) - Edit files locally
- Push to
mainbranch git-syncsidecar picks up changes automatically (~1-2 min)
Adding a new page
- Create
website/newpage.html(copy structure from existing page) - Add to navigation in all pages'
<nav>section - Add to
sitemap.xmlwith appropriate priority - Push — clean URLs handle
/newpageautomatically
Related Repositories
| Repository | Purpose |
|---|---|
| app-catalog-felhom.eu | Docker Compose templates + .felhom.yml metadata for 45+ apps |
| felhom-controller | felhom-controller Go app + customer deploy scripts |
| deploy-portainer | Legacy — Portainer-based deploy scripts (deprecated) |
| homelab-manifests | k3s cluster manifests for dooplex.hu services |
| misc-scripts | Utility scripts (collect-repos.sh, etc.) |
File Encoding
All HTML files in website/ are UTF-8 with BOM (byte order mark). This ensures proper Hungarian character rendering (á, é, í, ó, ö, ő, ú, ü, ű) across all tools and platforms. The BOM is the 3-byte sequence EF BB BF at the start of each file.
When editing files, ensure your editor preserves UTF-8-BOM encoding. VS Code: check "UTF-8 with BOM" in the bottom status bar.