The Jaeger→Tempo swap landed in the authoritative places (compose.yml,
stack.toml, infra/grafana) but several satellites still referenced the
removed `jaeger` service:
- deploy.sh Tier-4 ran `up jaeger loki prometheus` — `jaeger` no longer
exists, so `docker compose up` errored ("no such service") and aborted
the observability tier, taking loki/prometheus on that line with it.
- bootstrap_certs.py provisioned a cert for the dead jaeger.fhirworx.io
and never provisioned tempo.fhirworx.io.
- README (template + generated), the nginx dashboard tile, and the Gitea
home tile all advertised a Jaeger URL that no longer resolves.
- dev/seeds/grafana/ was a stale, unmounted, unreferenced duplicate of
infra/grafana still carrying a jaeger datasource — removed as dead.
All now point at tempo. README regenerated from the template.
424 lines
14 KiB
Cheetah
424 lines
14 KiB
Cheetah
{{template "base/head" .}}
|
|
<style>
|
|
/* HTI-5 dashboard tokens — defined locally so the inline template is self-contained.
|
|
gitea.css maps Gitea's --color-* vars to hti5 tokens at load time. */
|
|
.homelab-dashboard {
|
|
max-width: 1180px;
|
|
margin: 0 auto;
|
|
padding: 3rem 1.5rem;
|
|
font-family: "Source Serif 4", Georgia, serif;
|
|
}
|
|
|
|
/* Rule lines */
|
|
.homelab-dashboard .rule-line {
|
|
border: none;
|
|
border-top: 3px solid var(--color-text);
|
|
margin-bottom: 1rem;
|
|
}
|
|
.homelab-dashboard .rule-line-thin {
|
|
border: none;
|
|
border-top: 1px solid var(--color-border);
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
/* Masthead */
|
|
.homelab-dashboard .masthead {
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
.homelab-dashboard .masthead-row {
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
gap: 0.5rem;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.homelab-dashboard .masthead-brand {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
.homelab-dashboard .masthead-logo {
|
|
width: clamp(48px, 6vw, 80px);
|
|
height: clamp(48px, 6vw, 80px);
|
|
display: block;
|
|
flex: 0 0 auto;
|
|
}
|
|
.homelab-dashboard .masthead-row h1 {
|
|
font-family: "Playfair Display", Georgia, serif !important;
|
|
font-size: clamp(2.5rem, 5vw, 3.5rem) !important;
|
|
font-weight: 800 !important;
|
|
color: var(--color-text) !important;
|
|
letter-spacing: -0.02em !important;
|
|
line-height: 1.1 !important;
|
|
border: none !important;
|
|
margin: 0 !important;
|
|
}
|
|
.homelab-dashboard .masthead-eyebrow {
|
|
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.12em;
|
|
color: var(--color-text-light);
|
|
align-self: flex-end;
|
|
padding-bottom: 0.35rem;
|
|
}
|
|
.homelab-dashboard .tagline {
|
|
font-family: "Source Serif 4", Georgia, serif;
|
|
font-size: 1.125rem;
|
|
color: var(--color-text-light);
|
|
max-width: 65ch;
|
|
line-height: 1.65;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
/* Section header */
|
|
.homelab-dashboard .section-header {
|
|
margin-bottom: 1.5rem;
|
|
background: transparent !important;
|
|
padding: 0 !important;
|
|
border: none !important;
|
|
}
|
|
.homelab-dashboard .section-eyebrow {
|
|
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.12em;
|
|
color: var(--color-text-light);
|
|
margin-bottom: 0.4rem;
|
|
display: block;
|
|
}
|
|
.homelab-dashboard .section-header h2 {
|
|
font-family: "Playfair Display", Georgia, serif !important;
|
|
font-size: 1.75rem !important;
|
|
font-weight: 700 !important;
|
|
letter-spacing: -0.01em !important;
|
|
color: var(--color-text) !important;
|
|
line-height: 1.2 !important;
|
|
border: none !important;
|
|
background: transparent !important;
|
|
padding: 0 !important;
|
|
margin: 0 !important;
|
|
display: block !important;
|
|
}
|
|
|
|
/* Grid */
|
|
.homelab-dashboard .grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
gap: 1.25rem;
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
/* Tiles */
|
|
.homelab-dashboard .tile {
|
|
background: var(--color-box-body);
|
|
border: 1px solid var(--color-border) !important;
|
|
border-top: 3px solid var(--color-text) !important;
|
|
padding: 1.5rem;
|
|
position: relative;
|
|
overflow: hidden;
|
|
transition: border-color 0.15s ease, background 0.15s ease;
|
|
cursor: pointer;
|
|
text-decoration: none !important;
|
|
display: block;
|
|
border-radius: 0 !important;
|
|
}
|
|
.homelab-dashboard .tile:hover {
|
|
border-color: var(--color-primary) !important;
|
|
background: var(--color-body);
|
|
}
|
|
.homelab-dashboard .tile .icon {
|
|
font-size: 1.5rem;
|
|
margin-bottom: 0.75rem;
|
|
display: block;
|
|
line-height: 1;
|
|
}
|
|
.homelab-dashboard .tile.storage .icon,
|
|
.homelab-dashboard .tile.database .icon { color: var(--color-warning); }
|
|
.homelab-dashboard .tile.git .icon { color: var(--color-primary); }
|
|
.homelab-dashboard .tile.ci .icon { color: var(--color-primary); }
|
|
.homelab-dashboard .tile.notebook .icon,
|
|
.homelab-dashboard .tile.research .icon { color: var(--color-text); }
|
|
.homelab-dashboard .tile.catalog .icon { color: var(--color-primary); }
|
|
.homelab-dashboard .tile.query .icon { color: var(--color-primary); }
|
|
.homelab-dashboard .tile.observability .icon { color: var(--color-warning); }
|
|
.homelab-dashboard .tile.metrics .icon { color: var(--color-primary); }
|
|
.homelab-dashboard .tile.logs .icon { color: var(--color-primary); }
|
|
.homelab-dashboard .tile.proxy .icon { color: var(--color-text); }
|
|
|
|
/* Tile eyebrow — mono metadata label */
|
|
.homelab-dashboard .tile-eyebrow {
|
|
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
font-size: 0.7rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.12em;
|
|
color: var(--color-text-light);
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
/* Tile title — Playfair Display */
|
|
.homelab-dashboard .tile-title {
|
|
font-family: "Playfair Display", Georgia, serif !important;
|
|
font-size: 1.25rem !important;
|
|
font-weight: 700 !important;
|
|
line-height: 1.2 !important;
|
|
letter-spacing: -0.01em !important;
|
|
color: var(--color-text) !important;
|
|
margin: 0.25rem 0 0.5rem !important;
|
|
border: none !important;
|
|
text-transform: none !important;
|
|
transition: color 0.15s ease;
|
|
}
|
|
.homelab-dashboard .tile:hover .tile-title {
|
|
color: var(--color-primary) !important;
|
|
}
|
|
|
|
/* Tile description — Source Serif 4 */
|
|
.homelab-dashboard .tile-desc {
|
|
font-family: "Source Serif 4", Georgia, serif;
|
|
font-size: 0.95rem;
|
|
color: var(--color-text-light);
|
|
line-height: 1.55;
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
/* Tile port — mono metadata */
|
|
.homelab-dashboard .tile-port {
|
|
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
font-size: 0.65rem;
|
|
color: var(--color-text-light);
|
|
opacity: 0.7;
|
|
display: inline-block;
|
|
}
|
|
|
|
/* Status dot */
|
|
.homelab-dashboard .status-dot {
|
|
position: absolute;
|
|
top: 1rem;
|
|
right: 1rem;
|
|
width: 8px;
|
|
height: 8px;
|
|
background: var(--color-success);
|
|
border-radius: 50%;
|
|
}
|
|
|
|
/* Badge */
|
|
.homelab-dashboard .tile-badge {
|
|
position: absolute;
|
|
top: -1px;
|
|
left: 1.25rem;
|
|
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
color: var(--color-primary-foreground, #F7F5F0);
|
|
font-size: 0.6rem;
|
|
padding: 3px 7px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.08em;
|
|
}
|
|
.homelab-dashboard .tile-badge.new { background: var(--color-warning); }
|
|
.homelab-dashboard .tile-badge.gpu { background: var(--color-primary); }
|
|
.homelab-dashboard .tile-badge.data { background: var(--color-primary); }
|
|
|
|
/* Bottom accent */
|
|
.homelab-dashboard .stripe {
|
|
position: absolute;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
height: 2px;
|
|
background: var(--color-border);
|
|
}
|
|
|
|
/* Footer */
|
|
.homelab-dashboard .ftr {
|
|
padding-top: 1rem;
|
|
border-top: 3px solid var(--color-text);
|
|
color: var(--color-text-light);
|
|
font-family: "JetBrains Mono", "Fira Code", monospace;
|
|
font-size: 0.65rem;
|
|
letter-spacing: 0.08em;
|
|
}
|
|
.homelab-dashboard .ftr span { color: var(--color-warning); }
|
|
</style>
|
|
<div class="homelab-dashboard">
|
|
<div class="masthead">
|
|
<div class="rule-line"></div>
|
|
<div class="masthead-row">
|
|
<div class="masthead-brand">
|
|
<img src="/assets/img/logo.svg" alt="fhirworx" class="masthead-logo">
|
|
<h1>Homelab</h1>
|
|
</div>
|
|
<span class="masthead-eyebrow">git.fhirworx.io</span>
|
|
</div>
|
|
<p class="tagline">
|
|
Self-hosted infrastructure for FHIR data engineering — version control, CI/CD,
|
|
notebooks, and the full lakehouse stack.
|
|
</p>
|
|
<div class="rule-line-thin"></div>
|
|
</div>
|
|
|
|
<div class="section-header">
|
|
<span class="section-eyebrow">Services</span>
|
|
<h2>Infrastructure</h2>
|
|
</div>
|
|
|
|
<div class="grid">
|
|
<a data-subdomain="traefik" target="_blank" class="tile proxy">
|
|
<span class="tile-badge new">New</span>
|
|
<span class="status-dot"></span>
|
|
<span class="icon">🔗</span>
|
|
<div class="tile-eyebrow">Networking</div>
|
|
<div class="tile-title">Traefik</div>
|
|
<p class="tile-desc">Cloud-native reverse proxy and load balancer</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="s3console" target="_blank" class="tile storage">
|
|
<span class="status-dot"></span>
|
|
<span class="icon">💾</span>
|
|
<div class="tile-eyebrow">Storage</div>
|
|
<div class="tile-title">RustFS</div>
|
|
<p class="tile-desc">S3-compatible object storage for all your data needs</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="git" class="tile git">
|
|
<span class="status-dot"></span>
|
|
<span class="icon">🐙</span>
|
|
<div class="tile-eyebrow">Version Control</div>
|
|
<div class="tile-title">Gitea</div>
|
|
<p class="tile-desc">Self-hosted Git service with packages and CI</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="notebooks" target="_blank" class="tile notebook">
|
|
<span class="tile-badge gpu">GPU</span>
|
|
<span class="status-dot"></span>
|
|
<span class="icon">📑</span>
|
|
<div class="tile-eyebrow">Analysis</div>
|
|
<div class="tile-title">Notebooks</div>
|
|
<p class="tile-desc">Marimo reactive notebooks with CUDA acceleration</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="zotero" target="_blank" class="tile research">
|
|
<span class="tile-badge gpu">GPU</span>
|
|
<span class="status-dot"></span>
|
|
<span class="icon">📚</span>
|
|
<div class="tile-eyebrow">Research</div>
|
|
<div class="tile-title">Zotero</div>
|
|
<p class="tile-desc">Research reference manager in the cloud</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="docs" target="_blank" class="tile research">
|
|
<span class="tile-badge new">New</span>
|
|
<span class="status-dot"></span>
|
|
<span class="icon">📖</span>
|
|
<div class="tile-eyebrow">Documentation</div>
|
|
<div class="tile-title">Docs</div>
|
|
<p class="tile-desc">API reference and CMS bibliography browser</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="nessie" data-path="/api/v2/config" target="_blank" class="tile catalog">
|
|
<span class="tile-badge data">Data</span>
|
|
<span class="status-dot"></span>
|
|
<span class="icon">🌳</span>
|
|
<div class="tile-eyebrow">Catalog</div>
|
|
<div class="tile-title">Nessie</div>
|
|
<p class="tile-desc">Git-like versioned data catalog for Apache Iceberg</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="trino" target="_blank" class="tile query">
|
|
<span class="tile-badge data">Data</span>
|
|
<span class="status-dot"></span>
|
|
<span class="icon">🔍</span>
|
|
<div class="tile-eyebrow">Query</div>
|
|
<div class="tile-title">Trino</div>
|
|
<p class="tile-desc">Distributed SQL query engine for the lakehouse</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="polaris" target="_blank" class="tile catalog">
|
|
<span class="tile-badge new">New</span>
|
|
<span class="status-dot"></span>
|
|
<span class="icon">⭐</span>
|
|
<div class="tile-eyebrow">Catalog</div>
|
|
<div class="tile-title">Polaris</div>
|
|
<p class="tile-desc">Apache Iceberg catalog with governance and Unity-style access</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="grafana" target="_blank" class="tile observability">
|
|
<span class="status-dot"></span>
|
|
<span class="icon">📊</span>
|
|
<div class="tile-eyebrow">Observability</div>
|
|
<div class="tile-title">Grafana</div>
|
|
<p class="tile-desc">Observability dashboards for metrics, logs, and traces</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="tempo" target="_blank" class="tile metrics">
|
|
<span class="status-dot"></span>
|
|
<span class="icon">👁</span>
|
|
<div class="tile-eyebrow">Tracing</div>
|
|
<div class="tile-title">Tempo</div>
|
|
<p class="tile-desc">Distributed tracing for microservices</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="prometheus" target="_blank" class="tile logs">
|
|
<span class="status-dot"></span>
|
|
<span class="icon">📈</span>
|
|
<div class="tile-eyebrow">Metrics</div>
|
|
<div class="tile-title">Prometheus</div>
|
|
<p class="tile-desc">Metrics collection and alerting</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
|
|
<a data-subdomain="loki" data-path="/ready" target="_blank" class="tile database">
|
|
<span class="status-dot"></span>
|
|
<span class="icon">📋</span>
|
|
<div class="tile-eyebrow">Logs</div>
|
|
<div class="tile-title">Loki</div>
|
|
<p class="tile-desc">Log aggregation system by Grafana</p>
|
|
<span class="tile-port"></span>
|
|
<div class="stripe"></div>
|
|
</a>
|
|
</div>
|
|
|
|
<div class="ftr">
|
|
<span>fhirworx.io</span> — self-hosted data lakehouse — © 2025
|
|
</div>
|
|
</div>
|
|
<script>
|
|
(function() {
|
|
var parts = location.hostname.split('.');
|
|
var base = parts.length > 2 ? parts.slice(1).join('.') : location.hostname;
|
|
document.querySelectorAll('.homelab-dashboard [data-subdomain]').forEach(function(el) {
|
|
var sub = el.dataset.subdomain;
|
|
var path = el.dataset.path || '';
|
|
var fqdn = sub + '.' + base;
|
|
el.href = location.protocol + '//' + fqdn + path;
|
|
el.target = '_blank';
|
|
var port = el.querySelector('.tile-port');
|
|
if (port) port.textContent = fqdn;
|
|
});
|
|
})();
|
|
</script>
|
|
{{template "base/footer" .}}
|