<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>hoster</title>
    <link>https://docs.hoster.lhelge.se/</link>
    <description>A single-binary deployment orchestrator for one VPS</description>
    <atom:link href="https://docs.hoster.lhelge.se/rss.xml" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Mon, 9 Nov 2026 00:00:00 +0000</lastBuildDate>
    <item>
      <title>hoster 0.2.0</title>
      <link>https://docs.hoster.lhelge.se/blog/hoster-0-2-0/</link>
      <guid isPermaLink="true">https://docs.hoster.lhelge.se/blog/hoster-0-2-0/</guid>
      <pubDate>Mon, 9 Nov 2026 00:00:00 +0000</pubDate>
      <dc:creator>LHelge</dc:creator>
      <description>&lt;p&gt;0.2.0 redesigns the admin UI from the ground up. Every page from 0.1 is still there, but each one
was rebuilt against one design system. This site now uses it as well.&lt;/p&gt;
&lt;h2 id=&quot;one-design-system&quot;&gt;One design system&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Catppuccin, light and dark.&lt;/strong&gt; Latte in light mode and Mocha in dark mode, following your
system setting. In Latte, the accent and status colours are darkened until all text reaches
4.5:1 contrast.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JetBrains Mono&lt;/strong&gt; for everything machine-derived (names, digests, paths, numbers, labels) and
the system font for prose. The font ships with the binary, so nothing loads from a CDN.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lucide icons&lt;/strong&gt;, served as one cached SVG sprite.&lt;/li&gt;
&lt;li&gt;Every page was checked at 1440 px and 375 px in both themes. Primary and destructive actions
are at least 44 px tall on narrow screens.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;page-by-page&quot;&gt;Page by page&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Shell.&lt;/strong&gt; A sidebar with navigation, counts and warning badges. It moves above the page on
narrow screens.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboard.&lt;/strong&gt; KPI tiles for traffic and latency, a stacks table and a certificates card.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stacks.&lt;/strong&gt; Stacks are shown as cards with a status filter. Each stack has tabs:
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Overview&lt;/em&gt;: KPI tiles, slowest routes, routes and volumes.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Services&lt;/em&gt;: uptime and ports. This replaces the old Containers page.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Logs&lt;/em&gt;: per-service chips, &lt;em&gt;since&lt;/em&gt; presets and a follow switch.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Environment&lt;/em&gt;: env vars and write-only secrets.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Deployments&lt;/em&gt;: history, with a detail page for each deployment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;New stack.&lt;/strong&gt; The apply page is now an editor. Beside it, the plan and pre-flight checks are
shown before you confirm.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Certificates.&lt;/strong&gt; Summary tiles, an alert for failing certificates, a table and bulk actions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Settings.&lt;/strong&gt; A section sub-nav, registry credentials as field rows, and read-only views of
the effective configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System.&lt;/strong&gt; Version cards, the update flow and facts about the host.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/overview/#the-admin-ui&quot;&quot; class=&quot;wikilink&quot;&gt;How hoster works&lt;/a&gt; describes each page.&lt;/p&gt;
&lt;h2 id=&quot;updating&quot;&gt;Updating&lt;/h2&gt;&lt;pre class=&quot;code-block&quot;&gt;&lt;code&gt;&lt;span class=&quot;hl-source hl-shell hl-bash&quot;&gt;&lt;span class=&quot;hl-meta hl-function-call hl-shell&quot;&gt;&lt;span class=&quot;hl-variable hl-function hl-shell&quot;&gt;hoster&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hl-meta hl-function-call hl-arguments hl-shell&quot;&gt; update&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or use &lt;em&gt;Update&lt;/em&gt; on the System page. Nothing changed in &lt;code&gt;hoster.toml&lt;/code&gt; or in the stack file format.&lt;/p&gt;
</description>
      <category>release</category>
      <category>admin-ui</category>
    </item>
    <item>
      <title>hoster 0.2.1</title>
      <link>https://docs.hoster.lhelge.se/blog/hoster-0-2-1/</link>
      <guid isPermaLink="true">https://docs.hoster.lhelge.se/blog/hoster-0-2-1/</guid>
      <pubDate>Mon, 9 Nov 2026 00:00:00 +0000</pubDate>
      <dc:creator>LHelge</dc:creator>
      <description>&lt;p&gt;0.2.1 makes no change to the binary. It is the release that publishes this version of the docs
site, which only deploys when a release is tagged.&lt;/p&gt;
&lt;h2 id=&quot;the-docs-look-like-the-admin-ui&quot;&gt;The docs look like the admin UI&lt;/h2&gt;
&lt;p&gt;The site now uses the admin UI’s design system from &lt;a href=&quot;https://docs.hoster.lhelge.se/blog/hoster-0-2-0/&quot;&quot; class=&quot;wikilink&quot;&gt;0.2.0&lt;/a&gt;: Catppuccin Latte or
Mocha, following your system setting, JetBrains Mono for code and paths, and the same sidebar,
cards and tables. Each docs page lists the other guides by category in the sidebar, and on wide
screens an “On this page” list sits beside the text.&lt;/p&gt;
&lt;h2 id=&quot;a-post-for-every-release&quot;&gt;A post for every release&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://docs.hoster.lhelge.se/blog/&quot;&quot;&gt;Releases&lt;/a&gt; page has a post for every release since &lt;a href=&quot;https://docs.hoster.lhelge.se/blog/hoster-0-1-0/&quot;&quot; class=&quot;wikilink&quot;&gt;0.1.0&lt;/a&gt;, written for
the people running hoster: what changed, and what to know before updating. The GitHub release keeps
the full list of commits. The &lt;a href=&quot;https://docs.hoster.lhelge.se/feed.xml&quot;&quot;&gt;Atom feed&lt;/a&gt; lets you follow new releases.&lt;/p&gt;
&lt;h2 id=&quot;updating&quot;&gt;Updating&lt;/h2&gt;
&lt;p&gt;Not needed; nothing changed in the binary. &lt;code&gt;hoster update&lt;/code&gt; brings you to 0.2.1 as usual if you
want the version number to match.&lt;/p&gt;
</description>
      <category>release</category>
    </item>
    <item>
      <title>hoster 0.1.0</title>
      <link>https://docs.hoster.lhelge.se/blog/hoster-0-1-0/</link>
      <guid isPermaLink="true">https://docs.hoster.lhelge.se/blog/hoster-0-1-0/</guid>
      <pubDate>Sun, 8 Nov 2026 00:00:00 +0000</pubDate>
      <dc:creator>LHelge</dc:creator>
      <description>&lt;p&gt;hoster 0.1.0 is the first release. It covers everything the &lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/overview/&quot;&quot; class=&quot;wikilink&quot;&gt;design&lt;/a&gt; calls for in v1:
a GitHub Actions release workflow pushes an image, and a minute later the new version serves
traffic on its hostname with a valid certificate, without dropping a request.&lt;/p&gt;
&lt;pre class=&quot;code-block&quot;&gt;&lt;code&gt;&lt;span class=&quot;hl-source hl-shell hl-bash&quot;&gt;&lt;span class=&quot;hl-meta hl-function-call hl-shell&quot;&gt;&lt;span class=&quot;hl-variable hl-function hl-shell&quot;&gt;curl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hl-meta hl-function-call hl-arguments hl-shell&quot;&gt;&lt;span class=&quot;hl-variable hl-parameter hl-option hl-shell&quot;&gt;&lt;span class=&quot;hl-punctuation hl-definition hl-parameter hl-shell&quot;&gt; -&lt;/span&gt;fsSL&lt;/span&gt; https://github.com/LHelge/hoster/releases/latest/download/install.sh&lt;/span&gt; &lt;span class=&quot;hl-keyword hl-operator hl-logical hl-pipe hl-shell&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hl-meta hl-function-call hl-shell&quot;&gt;&lt;span class=&quot;hl-variable hl-function hl-shell&quot;&gt;sudo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hl-meta hl-function-call hl-arguments hl-shell&quot;&gt; bash&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/install/&quot;&quot; class=&quot;wikilink&quot;&gt;Installing hoster&lt;/a&gt; walks through the rest of the setup: the GitHub OAuth App, &lt;code&gt;hoster.toml&lt;/code&gt; and
&lt;code&gt;hoster doctor&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;what-s-in-it&quot;&gt;What’s in it&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One binary under systemd.&lt;/strong&gt; A statically linked Rust binary, for x86_64 and aarch64, runs as
a systemd user service of a dedicated &lt;code&gt;hoster&lt;/code&gt; user. The reverse proxy, ACME client, deploy
engine, webhook receiver, registry poller and admin UI are all part of it.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An embedded proxy.&lt;/strong&gt; Pingora terminates TLS on :443 and routes by host and path prefix. Routes
can strip prefixes and set their own timeouts, and responses stream through.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Certificates.&lt;/strong&gt; HTTP-01 issuance and renewal through Let’s Encrypt, with persisted backoff so
failures never use up the rate limit, and a DNS check before each attempt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploys by digest, without downtime.&lt;/strong&gt; A new container starts next to the old one and must
pass its health probes. The route then swaps atomically and the old container drains. A deploy
that crashes halfway is recovered on restart.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploys from CI without a secret.&lt;/strong&gt; The &lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/deploying-from-ci/&quot;&quot; class=&quot;wikilink&quot;&gt;deploy webhook&lt;/a&gt; accepts the
job’s GitHub OIDC token and checks it against each stack’s &lt;code&gt;[deploy]&lt;/code&gt; rule. A registry poller
is the fallback for images that track a tag.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stacks.&lt;/strong&gt; A &lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/stack-format/&quot;&quot; class=&quot;wikilink&quot;&gt;TOML stack file&lt;/a&gt; declares services, routes, env vars, encrypted
secrets and named volumes. Each stack runs on its own podman network.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An admin UI with GitHub login.&lt;/strong&gt; Apply and diff stack files, deploy, roll back, cancel, follow
container logs live, manage secrets and registry credentials, and watch certificate status and
live traffic statistics.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Housekeeping.&lt;/strong&gt; Reconciliation at startup and on a timer, image garbage collection that keeps
a rollback image per service, and &lt;code&gt;hoster backup&lt;/code&gt; for a consistent database snapshot (see
&lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/backup/&quot;&quot; class=&quot;wikilink&quot;&gt;Backing up and restoring&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-update.&lt;/strong&gt; &lt;code&gt;hoster update&lt;/code&gt; and &lt;code&gt;hoster rollback&lt;/code&gt;, or the System page, fetch a release,
verify its checksum, switch to it and roll back automatically if it fails to start.&lt;/li&gt;
&lt;/ul&gt;
</description>
      <category>release</category>
    </item>
    <item>
      <title>hoster 0.1.1</title>
      <link>https://docs.hoster.lhelge.se/blog/hoster-0-1-1/</link>
      <guid isPermaLink="true">https://docs.hoster.lhelge.se/blog/hoster-0-1-1/</guid>
      <pubDate>Sun, 8 Nov 2026 00:00:00 +0000</pubDate>
      <dc:creator>LHelge</dc:creator>
      <description>&lt;p&gt;The first install of 0.1.0 on a real host, Ubuntu 26.04, failed before hoster ever ran. This
release fixes that.&lt;/p&gt;
&lt;h2 id=&quot;the-unit-starts-on-ubuntu&quot;&gt;The unit starts on Ubuntu&lt;/h2&gt;
&lt;p&gt;Ubuntu 23.10 and later restrict unprivileged user namespaces
(&lt;code&gt;kernel.apparmor_restrict_unprivileged_userns=1&lt;/code&gt;), which leaves the systemd user manager with no
capabilities. Every unit directive that drops capabilities then fails, and the unit stopped with
&lt;code&gt;218/CAPABILITIES&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hoster.service&lt;/code&gt; no longer sets &lt;code&gt;CapabilityBoundingSet=&lt;/code&gt;, &lt;code&gt;PrivateDevices=&lt;/code&gt;,
&lt;code&gt;ProtectKernelModules=&lt;/code&gt;, &lt;code&gt;ProtectKernelLogs=&lt;/code&gt; or &lt;code&gt;ProtectClock=&lt;/code&gt;. hoster runs with no capabilities
anyway, and &lt;code&gt;NoNewPrivileges=&lt;/code&gt; and the &lt;code&gt;@privileged&lt;/code&gt; system call filter still cover what those
directives added. A new advisory &lt;code&gt;hoster doctor&lt;/code&gt; check, &lt;code&gt;unit_sandbox&lt;/code&gt;, says when such a host skips
the file-system sandbox. &lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/install/#hardening&quot;&quot; class=&quot;wikilink&quot;&gt;Hardening&lt;/a&gt; lists which protections apply where.&lt;/p&gt;
&lt;p&gt;CI now starts the unit for real with a stub binary, so a directive that fails to start is caught
before release.&lt;/p&gt;
&lt;h2 id=&quot;updating&quot;&gt;Updating&lt;/h2&gt;
&lt;p&gt;If 0.1.0 failed to start on your host, run the install command again; it installs the new unit
too:&lt;/p&gt;
&lt;pre class=&quot;code-block&quot;&gt;&lt;code&gt;&lt;span class=&quot;hl-source hl-shell hl-bash&quot;&gt;&lt;span class=&quot;hl-meta hl-function-call hl-shell&quot;&gt;&lt;span class=&quot;hl-variable hl-function hl-shell&quot;&gt;curl&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hl-meta hl-function-call hl-arguments hl-shell&quot;&gt;&lt;span class=&quot;hl-variable hl-parameter hl-option hl-shell&quot;&gt;&lt;span class=&quot;hl-punctuation hl-definition hl-parameter hl-shell&quot;&gt; -&lt;/span&gt;fsSL&lt;/span&gt; https://github.com/LHelge/hoster/releases/latest/download/install.sh&lt;/span&gt; &lt;span class=&quot;hl-keyword hl-operator hl-logical hl-pipe hl-shell&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;hl-meta hl-function-call hl-shell&quot;&gt;&lt;span class=&quot;hl-variable hl-function hl-shell&quot;&gt;sudo&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hl-meta hl-function-call hl-arguments hl-shell&quot;&gt; bash&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>release</category>
    </item>
    <item>
      <title>hoster 0.1.2</title>
      <link>https://docs.hoster.lhelge.se/blog/hoster-0-1-2/</link>
      <guid isPermaLink="true">https://docs.hoster.lhelge.se/blog/hoster-0-1-2/</guid>
      <pubDate>Sun, 8 Nov 2026 00:00:00 +0000</pubDate>
      <dc:creator>LHelge</dc:creator>
      <description>&lt;h2 id=&quot;admin-ui-actions-are-no-longer-refused&quot;&gt;Admin UI actions are no longer refused&lt;/h2&gt;
&lt;p&gt;hoster 0.1.0 and 0.1.1 sent &lt;code&gt;Referrer-Policy: no-referrer&lt;/code&gt;. Under that policy, browsers send
&lt;code&gt;Origin: null&lt;/code&gt; on a same-origin POST, so the admin UI’s CSRF check refused every action button
(for example &lt;em&gt;Check for updates&lt;/em&gt;) with “cross-origin request refused”. hoster now sends
&lt;code&gt;Referrer-Policy: same-origin&lt;/code&gt;. Other sites still get no referrer, and the admin UI’s own requests
keep their origin.&lt;/p&gt;
&lt;h2 id=&quot;hosting-a-static-site&quot;&gt;Hosting a static site&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/static-sites/&quot;&quot; class=&quot;wikilink&quot;&gt;Hosting a static site&lt;/a&gt; is a new guide for deploying a site built by a static site generator. CI packs it
into a small nginx image, and hoster deploys it like any other service, with deploys by digest,
certificates and zero downtime. A complete example lives in
&lt;a href=&quot;https://github.com/LHelge/hoster/tree/main/examples/static-site&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;&lt;code&gt;examples/static-site/&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;updating&quot;&gt;Updating&lt;/h2&gt;&lt;pre class=&quot;code-block&quot;&gt;&lt;code&gt;&lt;span class=&quot;hl-source hl-shell hl-bash&quot;&gt;&lt;span class=&quot;hl-meta hl-function-call hl-shell&quot;&gt;&lt;span class=&quot;hl-variable hl-function hl-shell&quot;&gt;hoster&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;hl-meta hl-function-call hl-arguments hl-shell&quot;&gt; update&lt;/span&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/install/#updates-and-rollback&quot;&quot; class=&quot;wikilink&quot;&gt;Updates and rollback&lt;/a&gt; has the details. Because of the bug above, the &lt;em&gt;Update&lt;/em&gt; button on
the System page only works from 0.1.2 on.&lt;/p&gt;
</description>
      <category>release</category>
    </item>
    <item>
      <title>hoster 0.1.3</title>
      <link>https://docs.hoster.lhelge.se/blog/hoster-0-1-3/</link>
      <guid isPermaLink="true">https://docs.hoster.lhelge.se/blog/hoster-0-1-3/</guid>
      <pubDate>Sun, 8 Nov 2026 00:00:00 +0000</pubDate>
      <dc:creator>LHelge</dc:creator>
      <description>&lt;p&gt;This release changes nothing about how hoster runs. The release is the first one to ship this
site.&lt;/p&gt;
&lt;h2 id=&quot;the-docs-have-a-home&quot;&gt;The docs have a home&lt;/h2&gt;
&lt;p&gt;The user guides used to be Markdown files in the repository. They now make up this site, built
with &lt;a href=&quot;https://github.com/LHelge/aphid&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot;&gt;aphid&lt;/a&gt;, with a new &lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/overview/&quot;&quot; class=&quot;wikilink&quot;&gt;How hoster works&lt;/a&gt; page as the entry point. A
broken cross-reference now fails the build, so links between guides stay correct.&lt;/p&gt;
&lt;p&gt;The site is deployed by hoster itself. Each release tag packs it into an nginx image and deploys it
through the same OIDC webhook described in &lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/deploying-from-ci/&quot;&quot; class=&quot;wikilink&quot;&gt;Deploying from CI&lt;/a&gt;, following
&lt;a href=&quot;https://docs.hoster.lhelge.se/wiki/static-sites/&quot;&quot; class=&quot;wikilink&quot;&gt;the static site guide&lt;/a&gt; step by step. Messages from the binary, &lt;code&gt;install.sh&lt;/code&gt;, the
systemd unit and the System page now link here.&lt;/p&gt;
&lt;h2 id=&quot;under-the-hood&quot;&gt;Under the hood&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The release workflow’s docs settings no longer leak into the build job’s environment, where
the tests read them as hoster config overrides. That bug stopped the first attempt at this
release.&lt;/li&gt;
&lt;li&gt;The GitHub Actions now run on their Node 24 versions, and the release build reuses CI’s cache.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;updating&quot;&gt;Updating&lt;/h2&gt;
&lt;p&gt;Optional; nothing changed in the binary’s behaviour. &lt;code&gt;hoster update&lt;/code&gt; brings you up to date as usual.&lt;/p&gt;
</description>
      <category>release</category>
    </item>
  </channel>
</rss>
