orchard
mirrorEvery site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.
blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics
1{{ define "main" }}
2<div class="container-fluid px-4 py-4">
3 <div class="page-head">
4 <div>
5 <div class="auth-eyebrow">account</div>
6 <h1 class="page-title">{{ .User.Username }}</h1>
7 </div>
8 </div>
9
10 {{ template "alerts" . }}
11
12 <div class="row g-3">
13 <div class="col-12 col-lg-5">
14 <div class="panel">
15 <div class="panel-title">identity</div>
16 <dl class="field-list">
17 <div><dt>username</dt><dd>{{ .User.Username }}</dd></div>
18 <div><dt>ntfy account</dt><dd>{{ .User.NtfyAccount }}</dd></div>
19 <div><dt>created</dt><dd>{{ when .User.Created }}</dd></div>
20 </dl>
21 <p class="auth-hint">The ntfy account is a separate namespace and ntfy cannot rename one,
22 so changing the username here leaves it alone.</p>
23 </div>
24 </div>
25
26 <div class="col-12 col-lg-4">
27 <div class="panel">
28 <div class="panel-title">recovery codes</div>
29 <div class="stat {{ if lt .Remaining 3 }}is-low{{ end }}">{{ .Remaining }}</div>
30 <div class="pips" aria-hidden="true">
31 {{ range pips .Remaining }}<span class="pip {{ if . }}is-lit{{ end }}"></span>{{ end }}
32 </div>
33 <a href="/security" class="btn btn-sm btn-outline-light">Manage →</a>
34 </div>
35 </div>
36
37 <div class="col-12 col-lg-3">
38 <div class="panel">
39 <div class="panel-title">rename</div>
40 {{ if .InSudo }}
41 <form method="POST" action="/account/username">
42 <div class="form-floating mb-3">
43 <input type="text" class="form-control" name="username" id="id_new_username"
44 placeholder="username" value="{{ .User.Username }}" required
45 autocapitalize="none" spellcheck="false">
46 <label for="id_new_username">Username</label>
47 </div>
48 <button type="submit" class="btn btn-primary btn-sm">Save</button>
49 </form>
50 {{ else }}
51 <p class="auth-hint mt-0">Needs a sign in from the last few minutes.</p>
52 <a href="/login?next=/account" class="btn btn-sm btn-outline-light">Sign in again</a>
53 {{ end }}
54 </div>
55 </div>
56
57 <div class="col-12">
58 <div class="panel">
59 <div class="panel-title">behind this login</div>
60 <div class="site-grid">
61 {{ template "siteCard" dict "host" "analytics.bythewood.me" "name" "Analytics" "desc" "Traffic, referrers and where visitors are" }}
62 {{ template "siteCard" dict "host" "status.bythewood.me" "name" "Status" "desc" "Uptime checks, Lighthouse audits and crawls" }}
63 {{ template "siteCard" dict "host" "logging.bythewood.me" "name" "Logging" "desc" "Every site's records, searchable" }}
64 {{ template "siteCard" dict "host" "repos.bythewood.me" "name" "Repos" "desc" "Git remote, mirrors and push tokens" }}
65 {{ template "siteCard" dict "host" "search.bythewood.me" "name" "Search" "desc" "AI search over the web, with every sentence cited" }}
66 {{ template "siteCard" dict "host" "chat.bythewood.me" "name" "Chat" "desc" "A conversation with the local model, with tools and attachments" }}
67 {{ template "siteCard" dict "host" "llm.bythewood.me" "name" "LLM" "desc" "The model gateway, its api keys and every prompt through it" }}
68 </div>
69 <p class="auth-hint">Push tokens for repos stay in repos, since they are its credentials and
70 not this site's. That page is behind this session now.</p>
71 </div>
72 </div>
73 </div>
74</div>
75{{ end }}