Files
restic-manager/web/templates/pages/add_host.html
T
steve c5777122db Add-host: default repo username to hostname; always show htpasswd snippet
The pending page suppressed the htpasswd snippet when repo_username
was blank — but with --private-repos the username is required for
auth, and operators routinely leave the field blank assuming the
system will pick something sensible.

* handleUIAddHostPost defaults repo_username to the typed hostname
  when blank. Matches what --private-repos expects (URL path
  segment == username).
* pending_host.html: snippet now renders whenever a password is
  present (always true after the generate-on-blank logic landed
  earlier).
* Form help-text updated to describe the default explicitly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:08:23 +01:00

116 lines
7.8 KiB
HTML

{{define "title"}}{{.Title}}{{end}}
{{define "content"}}
{{$page := .Page}}
<div class="max-w-[1280px] mx-auto px-8 pt-9 pb-24">
<div class="crumbs"><a href="/">Dashboard</a><span class="sep">/</span><span class="text-ink-mid">Add host</span></div>
<h1 class="text-2xl font-medium tracking-[-0.012em] mt-2.5">Add a host</h1>
<p class="text-pretty text-ink-mute text-[13px] mt-1.5 max-w-[580px]">
Mints a one-time enrolment token (TTL 1 hour) and binds the repo
credentials to it. The token can only be used once — generate a fresh
one if it expires or you typed something wrong.
</p>
{{if $page.Error}}
<div class="mt-6 px-4 py-3 rounded-[5px] text-[13px]"
style="background: color-mix(in oklch, var(--bad), transparent 88%);
border: 1px solid color-mix(in oklch, var(--bad), transparent 70%);
color: oklch(0.85 0.10 25);">
{{$page.Error}}
</div>
{{end}}
<form method="post" action="/hosts/new" class="grid grid-cols-12 gap-8 mt-7">
<div class="col-span-7 panel rounded-[7px] px-8 py-7">
<h3 class="text-[13px] font-semibold uppercase tracking-[0.08em] text-ink-mute mb-4">Host</h3>
<div class="mb-5">
<label class="field-label" for="ah-name">Hostname</label>
<input id="ah-name" name="hostname" type="text" class="field mono" autofocus required value="{{$page.Hostname}}">
<div class="field-help">Becomes the host's display name. Most operators use the box's actual hostname so logs line up.</div>
</div>
<div class="mb-7">
<label class="field-label" for="ah-tags">Tags <span class="text-ink-fade font-normal">· optional, comma-separated</span></label>
<input id="ah-tags" name="tags" type="text" class="field mono" placeholder="prod, db" value="{{$page.Tags}}">
<div class="field-help">Free-form. Used for filtering and grouping on the dashboard.</div>
</div>
<h3 class="text-[13px] font-semibold uppercase tracking-[0.08em] text-ink-mute mb-4 pt-6 border-t border-line-soft">Initial schedule <span class="text-ink-fade font-normal">· manual</span></h3>
<div class="mb-7">
<label class="field-label" for="ah-paths">Paths <span class="text-ink-fade font-normal">· one per line</span></label>
<textarea id="ah-paths" name="paths" rows="3" class="field mono"
style="resize: vertical;"
placeholder="/etc&#10;/home&#10;/var/lib/postgresql">{{$page.Paths}}</textarea>
<div class="field-help">
These paths become an <strong>initial manual schedule</strong> on the new host — manual = no cron, only fires when you click <span class="mono text-ink-mid">Run&nbsp;now</span>. You can edit this schedule (or add automated ones alongside it) from the host's <strong>Schedules</strong> tab. Leave blank to skip — the host will enrol but can't back up until you add a schedule.
</div>
</div>
<h3 class="text-[13px] font-semibold uppercase tracking-[0.08em] text-ink-mute mb-4 pt-6 border-t border-line-soft">Restic repository</h3>
<div class="mb-5">
<label class="field-label" for="ah-url">Repo URL</label>
<input id="ah-url" name="repo_url" type="text" class="field mono" required
placeholder="rest:https://restic.lab/host-name/"
value="{{$page.RepoURL}}">
<div class="field-help">Whatever <span class="mono text-ink-mid">restic -r</span> would accept. Most fleets terminate at a <span class="mono text-ink-mid">restic/rest-server</span>; <span class="mono text-ink-mid">s3:</span> and <span class="mono text-ink-mid">b2:</span> URLs work equally well.</div>
</div>
<div class="mb-5">
<label class="field-label" for="ah-user">Repo username <span class="text-ink-fade font-normal">· optional — defaults to hostname</span></label>
<input id="ah-user" name="repo_username" type="text" class="field mono" value="{{$page.RepoUsername}}">
<div class="field-help">For <span class="mono text-ink-mid">rest-server</span> with <span class="mono text-ink-mid">--private-repos</span>, this is the per-host htpasswd user — and the URL path segment must match. Leave blank and we'll use the hostname above.</div>
</div>
<div class="mb-7">
<label class="field-label" for="ah-pass">Repo password <span class="text-ink-fade font-normal">· optional — leave blank to generate</span></label>
<input id="ah-pass" name="repo_password" type="password" class="field">
<div class="field-help">Encrypted at rest using the server's AEAD key, pushed to the agent only over the authenticated WebSocket. Leave blank and we'll mint a 24-byte URL-safe random password — you'll see it on the next page (and can come back to it from the dashboard's pending-host link until the agent connects).</div>
</div>
<div class="flex gap-2 pt-5 border-t border-line-soft">
<button type="submit" class="btn btn-primary btn-lg">Mint token &amp; show install command</button>
<a href="/" class="btn btn-lg">Cancel</a>
</div>
</div>
<aside class="col-span-5">
<div class="text-[11px] uppercase tracking-[0.1em] text-ink-fade mb-3">What happens next</div>
<ol class="list-none p-0 m-0 space-y-4">
<li class="relative pl-9">
<span class="absolute left-0 top-0 w-[22px] h-[22px] border border-line rounded-full text-[11px] leading-[20px] text-center text-ink-mute mono">1</span>
<div class="text-[13px] text-ink font-medium">You get a one-time install command</div>
<div class="text-[12px] text-ink-mute mt-1 leading-[1.55]">A <span class="mono text-ink-mid">curl … | bash</span> snippet with the server URL and a 1h token baked in.</div>
</li>
<li class="relative pl-9">
<span class="absolute left-0 top-0 w-[22px] h-[22px] border border-line rounded-full text-[11px] leading-[20px] text-center text-ink-mute mono">2</span>
<div class="text-[13px] text-ink font-medium">You run it on the box you want to back up</div>
<div class="text-[12px] text-ink-mute mt-1 leading-[1.55]">Installer drops the agent binary as root, registers a sandboxed systemd unit, and enrols.</div>
</li>
<li class="relative pl-9">
<span class="absolute left-0 top-0 w-[22px] h-[22px] border border-line rounded-full text-[11px] leading-[20px] text-center text-ink-mute mono">3</span>
<div class="text-[13px] text-ink font-medium">The host appears on the dashboard within seconds</div>
<div class="text-[12px] text-ink-mute mt-1 leading-[1.55]">Server pushes the encrypted repo creds over the WS on first <span class="mono text-ink-mid">hello</span>; agent decrypts and persists to <span class="mono text-ink-mid">secrets.enc</span>.</div>
</li>
<li class="relative pl-9">
<span class="absolute left-0 top-0 w-[22px] h-[22px] border border-line rounded-full text-[11px] leading-[20px] text-center text-ink-mute mono">4</span>
<div class="text-[13px] text-ink font-medium">You hit “Run now” on the manual schedule</div>
<div class="text-[12px] text-ink-mute mt-1 leading-[1.55]">First snapshot lands in the repo. Add automated schedules from the host's Schedules tab whenever you're ready.</div>
</li>
</ol>
<div class="mt-8 panel rounded-[6px] px-4 py-3.5">
<div class="text-[11px] uppercase tracking-[0.08em] font-semibold text-warn mb-1.5">Prerequisite</div>
<p class="text-pretty text-[12px] text-ink-mid leading-[1.55]">
<span class="mono text-ink">restic</span> ≥ 0.16 must already be installed on the target host. The agent does not install it for you — different distros, different package managers, too much surface area to maintain.
</p>
</div>
</aside>
</form>
</div>
{{end}}