diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62f801d --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Playwright MCP scratch files (local browser sessions) +/.playwright-mcp/ + +# Local screenshots from manual testing +services-page.png +*.screenshot.png \ No newline at end of file diff --git a/.playwright-mcp/console-2026-07-28T18-57-22-424Z.log b/.playwright-mcp/console-2026-07-28T18-57-22-424Z.log deleted file mode 100644 index a407321..0000000 --- a/.playwright-mcp/console-2026-07-28T18-57-22-424Z.log +++ /dev/null @@ -1,6 +0,0 @@ -[ 94ms] [ERROR] Failed to load resource: the server responded with a status of 404 (File not found) @ http://127.0.0.1:8099/favicon.ico:0 -[ 218ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://comfyui.ffaerber.duckdns.org/?_probe=1785265042484:0 -[ 273ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://grafana.ffaerber.duckdns.org/?_probe=1785265042484:0 -[ 273ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://prometheus.ffaerber.duckdns.org/?_probe=1785265042484:0 -[ 369ms] [ERROR] Failed to load resource: the server responded with a status of 401 () @ https://staking.ffaerber.duckdns.org/?_probe=1785265042484:0 -[ 372ms] [ERROR] Failed to load resource: the server responded with a status of 404 () @ https://gnosis.ffaerber.duckdns.org/?_probe=1785265042484:0 diff --git a/.playwright-mcp/page-2026-07-28T18-57-22-523Z.yml b/.playwright-mcp/page-2026-07-28T18-57-22-523Z.yml deleted file mode 100644 index 6311e2b..0000000 --- a/.playwright-mcp/page-2026-07-28T18-57-22-523Z.yml +++ /dev/null @@ -1,217 +0,0 @@ -- generic [active] [ref=f1e1]: - - banner [ref=f1e2]: - - generic [ref=f1e3]: - - heading "ffaerber" [level=1] [ref=f1e4] - - paragraph [ref=f1e5]: Self-hosted homelab โ€” every service running in the house, one click away. - - main [ref=f1e6]: - - generic [ref=f1e7]: - - generic [ref=f1e8]: - - heading "Services" [level=2] [ref=f1e9] - - paragraph [ref=f1e10]: All public-facing services from the homelab, grouped by what they do. A green dot means the service answered just now; grey means it is down or unreachable from your browser. - - generic [ref=f1e11]: - - generic [ref=f1e12]: - - heading "Edge & proxy" [level=3] [ref=f1e13]: ๐ŸŒEdge & proxy - - list [ref=f1e14]: - - listitem [ref=f1e15]: - - link "Traefik Reverse proxy and edge router for the whole homelab. status unknown" [ref=f1e16] [cursor=pointer]: - - /url: https://ffaerber.duckdns.org/dashboard/ - - generic [ref=f1e17]: ๐Ÿ›ก๏ธ - - generic [ref=f1e18]: - - generic [ref=f1e19]: Traefik - - generic [ref=f1e20]: Reverse proxy and edge router for the whole homelab. - - img "status unknown" [ref=f1e21] - - generic [ref=f1e22]: - - heading "Observability" [level=3] [ref=f1e23]: ๐Ÿ“ŠObservability - - list [ref=f1e24]: - - listitem [ref=f1e25]: - - link "Grafana Dashboards for metrics, logs and system health. status unknown" [ref=f1e26] [cursor=pointer]: - - /url: https://grafana.ffaerber.duckdns.org - - generic [ref=f1e27]: ๐Ÿ“ˆ - - generic [ref=f1e28]: - - generic [ref=f1e29]: Grafana - - generic [ref=f1e30]: Dashboards for metrics, logs and system health. - - img "status unknown" [ref=f1e31] - - listitem [ref=f1e32]: - - link "Prometheus Metrics collection and alerting. status unknown" [ref=f1e33] [cursor=pointer]: - - /url: https://prometheus.ffaerber.duckdns.org - - generic [ref=f1e34]: ๐Ÿ”ฅ - - generic [ref=f1e35]: - - generic [ref=f1e36]: Prometheus - - generic [ref=f1e37]: Metrics collection and alerting. - - img "status unknown" [ref=f1e38] - - generic [ref=f1e39]: - - heading "Media" [level=3] [ref=f1e40]: ๐ŸŽฌMedia - - list [ref=f1e41]: - - listitem [ref=f1e42]: - - link "Jellyfin Self-hosted movies, shows and music. status unknown" [ref=f1e43] [cursor=pointer]: - - /url: https://jellyfin.ffaerber.duckdns.org - - generic [ref=f1e44]: ๐ŸŽž๏ธ - - generic [ref=f1e45]: - - generic [ref=f1e46]: Jellyfin - - generic [ref=f1e47]: Self-hosted movies, shows and music. - - img "status unknown" [ref=f1e48] - - listitem [ref=f1e49]: - - link "Immich Self-hosted photo and video library. status unknown" [ref=f1e50] [cursor=pointer]: - - /url: https://immich.ffaerber.duckdns.org - - generic [ref=f1e51]: ๐Ÿ“ธ - - generic [ref=f1e52]: - - generic [ref=f1e53]: Immich - - generic [ref=f1e54]: Self-hosted photo and video library. - - img "status unknown" [ref=f1e55] - - listitem [ref=f1e56]: - - link "ComfyUI Node-based image generation UI on the GPU. status unknown" [ref=f1e57] [cursor=pointer]: - - /url: https://comfyui.ffaerber.duckdns.org - - generic [ref=f1e58]: ๐ŸŽจ - - generic [ref=f1e59]: - - generic [ref=f1e60]: ComfyUI - - generic [ref=f1e61]: Node-based image generation UI on the GPU. - - img "status unknown" [ref=f1e62] - - generic [ref=f1e63]: - - heading "Downloads & files" [level=3] [ref=f1e64]: ๐Ÿ’พDownloads & files - - list [ref=f1e65]: - - listitem [ref=f1e66]: - - link "qBittorrent Torrent downloads over VPN. status unknown" [ref=f1e67] [cursor=pointer]: - - /url: https://bittorrent.ffaerber.duckdns.org - - generic [ref=f1e68]: ๐Ÿงฒ - - generic [ref=f1e69]: - - generic [ref=f1e70]: qBittorrent - - generic [ref=f1e71]: Torrent downloads over VPN. - - img "status unknown" [ref=f1e72] - - listitem [ref=f1e73]: - - link "Filebrowser Web file browser for the homelab storage. status unknown" [ref=f1e74] [cursor=pointer]: - - /url: https://files.ffaerber.duckdns.org - - generic [ref=f1e75]: ๐Ÿ“ - - generic [ref=f1e76]: - - generic [ref=f1e77]: Filebrowser - - generic [ref=f1e78]: Web file browser for the homelab storage. - - img "status unknown" [ref=f1e79] - - generic [ref=f1e80]: - - heading "Ethereum" [level=3] [ref=f1e81]: ฮžEthereum - - list [ref=f1e82]: - - listitem [ref=f1e83]: - - link "Mainnet Geth Ethereum mainnet execution client (RPC). status unknown" [ref=f1e84] [cursor=pointer]: - - /url: https://mainnet.ffaerber.duckdns.org - - generic [ref=f1e85]: โ›“๏ธ - - generic [ref=f1e86]: - - generic [ref=f1e87]: Mainnet Geth - - generic [ref=f1e88]: Ethereum mainnet execution client (RPC). - - img "status unknown" [ref=f1e89] - - listitem [ref=f1e90]: - - link "Mainnet Beacon Lighthouse consensus / beacon node. status unknown" [ref=f1e91] [cursor=pointer]: - - /url: https://beacon.ffaerber.duckdns.org - - generic [ref=f1e92]: ๐Ÿ—ผ - - generic [ref=f1e93]: - - generic [ref=f1e94]: Mainnet Beacon - - generic [ref=f1e95]: Lighthouse consensus / beacon node. - - img "status unknown" [ref=f1e96] - - listitem [ref=f1e97]: - - link "Staking Tracker Daily validator rewards and tax reports. status unknown" [ref=f1e98] [cursor=pointer]: - - /url: https://staking.ffaerber.duckdns.org - - generic [ref=f1e99]: ๐Ÿ’ฐ - - generic [ref=f1e100]: - - generic [ref=f1e101]: Staking Tracker - - generic [ref=f1e102]: Daily validator rewards and tax reports. - - img "status unknown" [ref=f1e103] - - listitem [ref=f1e104]: - - link "Gnosis Nethermind Gnosis Chain execution client (RPC). status unknown" [ref=f1e105] [cursor=pointer]: - - /url: https://gnosis.ffaerber.duckdns.org - - generic [ref=f1e106]: โ›“๏ธ - - generic [ref=f1e107]: - - generic [ref=f1e108]: Gnosis Nethermind - - generic [ref=f1e109]: Gnosis Chain execution client (RPC). - - img "status unknown" [ref=f1e110] - - listitem [ref=f1e111]: - - link "Bee Ethereum Swarm node โ€” decentralized storage API. status unknown" [ref=f1e112] [cursor=pointer]: - - /url: https://bee.ffaerber.duckdns.org - - generic [ref=f1e113]: ๐Ÿ - - generic [ref=f1e114]: - - generic [ref=f1e115]: Bee - - generic [ref=f1e116]: Ethereum Swarm node โ€” decentralized storage API. - - img "status unknown" [ref=f1e117] - - listitem [ref=f1e118]: - - link "Bee Dashboard Web UI for the Swarm Bee node. status unknown" [ref=f1e119] [cursor=pointer]: - - /url: https://bee-dashboard.ffaerber.duckdns.org - - generic [ref=f1e120]: ๐ŸŽ›๏ธ - - generic [ref=f1e121]: - - generic [ref=f1e122]: Bee Dashboard - - generic [ref=f1e123]: Web UI for the Swarm Bee node. - - img "status unknown" [ref=f1e124] - - listitem [ref=f1e125]: - - link "t4t Provider Truth-for-Truth data provider node. status unknown" [ref=f1e126] [cursor=pointer]: - - /url: https://t4t-provider.ffaerber.duckdns.org - - generic [ref=f1e127]: ๐Ÿ” - - generic [ref=f1e128]: - - generic [ref=f1e129]: t4t Provider - - generic [ref=f1e130]: Truth-for-Truth data provider node. - - img "status unknown" [ref=f1e131] - - generic [ref=f1e132]: - - heading "AI & speech" [level=3] [ref=f1e133]: ๐Ÿค–AI & speech - - list [ref=f1e134]: - - listitem [ref=f1e135]: - - link "Whisper Self-hosted speech-to-text on the GPU. status unknown" [ref=f1e136] [cursor=pointer]: - - /url: https://whisper.ffaerber.duckdns.org - - generic [ref=f1e137]: ๐Ÿ‘‚ - - generic [ref=f1e138]: - - generic [ref=f1e139]: Whisper - - generic [ref=f1e140]: Self-hosted speech-to-text on the GPU. - - img "status unknown" [ref=f1e141] - - listitem [ref=f1e142]: - - link "Kokoro Self-hosted text-to-speech, 49 voices. status unknown" [ref=f1e143] [cursor=pointer]: - - /url: https://kokoro.ffaerber.duckdns.org - - generic [ref=f1e144]: ๐Ÿ—ฃ๏ธ - - generic [ref=f1e145]: - - generic [ref=f1e146]: Kokoro - - generic [ref=f1e147]: Self-hosted text-to-speech, 49 voices. - - img "status unknown" [ref=f1e148] - - listitem [ref=f1e149]: - - link "Ollama Local LLM serving on the GPU. status unknown" [ref=f1e150] [cursor=pointer]: - - /url: https://ollama.ffaerber.duckdns.org - - generic [ref=f1e151]: ๐Ÿฆ™ - - generic [ref=f1e152]: - - generic [ref=f1e153]: Ollama - - generic [ref=f1e154]: Local LLM serving on the GPU. - - img "status unknown" [ref=f1e155] - - listitem [ref=f1e156]: - - link "Open WebUI Chat UI for Ollama models. status unknown" [ref=f1e157] [cursor=pointer]: - - /url: https://chat.ffaerber.duckdns.org - - generic [ref=f1e158]: ๐Ÿ’ฌ - - generic [ref=f1e159]: - - generic [ref=f1e160]: Open WebUI - - generic [ref=f1e161]: Chat UI for Ollama models. - - img "status unknown" [ref=f1e162] - - generic [ref=f1e163]: - - heading "Dev platform" [level=3] [ref=f1e164]: ๐Ÿ› ๏ธDev platform - - list [ref=f1e165]: - - listitem [ref=f1e166]: - - link "Gitea Self-hosted Git and CI for all ffaerber repos. status unknown" [ref=f1e167] [cursor=pointer]: - - /url: https://git.ffaerber.duckdns.org - - generic [ref=f1e168]: ๐Ÿ”ง - - generic [ref=f1e169]: - - generic [ref=f1e170]: Gitea - - generic [ref=f1e171]: Self-hosted Git and CI for all ffaerber repos. - - img "status unknown" [ref=f1e172] - - generic [ref=f1e173]: - - generic [ref=f1e174]: - - heading "Projects" [level=2] [ref=f1e175] - - paragraph [ref=f1e176]: The code behind the services lives across a few GitHub orgs. - - list [ref=f1e177]: - - listitem [ref=f1e178]: - - link "github.com/ffaerber โ†—" [ref=f1e179] [cursor=pointer]: - - /url: https://github.com/ffaerber - - text: โ€” dapps, Ethereum infra, GPU speech services - - listitem [ref=f1e180]: - - link "github.com/cipherdolls โ†—" [ref=f1e181] [cursor=pointer]: - - /url: https://github.com/cipherdolls - - text: โ€” AI companion platform - - contentinfo [ref=f1e182]: - - generic [ref=f1e183]: - - navigation [ref=f1e184]: - - link "github.com/ffaerber โ†—" [ref=f1e185] [cursor=pointer]: - - /url: https://github.com/ffaerber - - link "github.com/cipherdolls โ†—" [ref=f1e186] [cursor=pointer]: - - /url: https://github.com/cipherdolls - - paragraph [ref=f1e187]: - - text: Served from a container built in - - link "ffaerber/homepage" [ref=f1e188] [cursor=pointer]: - - /url: https://git.ffaerber.duckdns.org/ffaerber/homepage - - text: . \ No newline at end of file diff --git a/index.html b/index.html index 15ca315..13dbdec 100644 --- a/index.html +++ b/index.html @@ -81,13 +81,14 @@ done = true; setStatusDot(dot, state); } - var img = new Image(); - img.onload = function () { settle("up"); }; - img.onerror = function () { settle("up"); }; - img.onloadstart = function () {}; - var timeout = setTimeout(function () { settle("down"); }, 6000); - img.src = url + "?_probe=" + Date.now(); - window.addEventListener("beforeunload", function () { clearTimeout(timeout); }); + var controller = window.AbortController ? new AbortController() : null; + var timeout = setTimeout(function () { + if (controller) controller.abort(); + settle("down"); + }, 6000); + fetch(url, { mode: "no-cors", cache: "no-store", redirect: "follow", signal: controller ? controller.signal : undefined }) + .then(function () { clearTimeout(timeout); settle("up"); }) + .catch(function () { clearTimeout(timeout); settle("down"); }); } fetch(src) diff --git a/services-page.png b/services-page.png deleted file mode 100644 index 3593423..0000000 Binary files a/services-page.png and /dev/null differ diff --git a/services.json b/services.json index 99eb639..64e890d 100644 --- a/services.json +++ b/services.json @@ -39,7 +39,7 @@ { "name": "ethereum", "label": "Ethereum", - "icon": " ฮž", + "icon": "ฮž", "services": [ { "name": "Mainnet Geth", "url": "https://mainnet.ffaerber.duckdns.org", "desc": "Ethereum mainnet execution client (RPC).", "icon": "โ›“๏ธ" }, { "name": "Mainnet Beacon", "url": "https://beacon.ffaerber.duckdns.org", "desc": "Lighthouse consensus / beacon node.", "icon": "๐Ÿ—ผ" }, @@ -66,6 +66,7 @@ "label": "Dev platform", "icon": "๐Ÿ› ๏ธ", "services": [ + { "name": "Homepage", "url": "https://homepage.ffaerber.duckdns.org", "desc": "This page โ€” the homelab services index you are looking at.", "icon": "๐Ÿ " }, { "name": "Gitea", "url": "https://git.ffaerber.duckdns.org", "desc": "Self-hosted Git and CI for all ffaerber repos.", "icon": "๐Ÿ”ง" } ] }