<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Vps on WebDevStation</title>
    <link>https://webdevstation.com/tags/vps/</link>
    <description>1 article tagged Vps — tutorials, code examples and notes from building real systems, newest first.</description>
    <generator>Hugo</generator>
    <language>en</language>
    <managingEditor>Alex</managingEditor>
    <webMaster>Alex</webMaster>
    <copyright>© 2026 WebDevStation</copyright>
    <lastBuildDate>Tue, 10 Nov 2026 10:10:00 +0100</lastBuildDate>
    <atom:link href="https://webdevstation.com/tags/vps/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Self-host AI agents on a VPS: kwant with systemd or Docker Compose</title>
      <link>https://webdevstation.com/posts/self-host-ai-agents-vps-kwant/</link>
      <pubDate>Tue, 10 Nov 2026 10:10:00 +0100</pubDate>
      <author>Alex</author>
      <guid isPermaLink="true">https://webdevstation.com/posts/self-host-ai-agents-vps-kwant/</guid>
      <description>Run a self-hosted AI agent team on a VPS with kwant: one-line install, a systemd unit or Docker Compose, then HTTPS, sign-in links and safe defaults.</description>
      <content:encoded><![CDATA[<p>An AI agent team on a laptop has one obvious weakness: close the lid and the team stops. The routine you scheduled for 7am doesn&rsquo;t run, the follow-up a bot promised itself waits, and your phone has nothing to connect to. If you want an always-on AI agent team, it has to live on a machine that stays on. For most of us, that&rsquo;s a small VPS.</p>
<p>This guide covers three ways to self-host AI agents on a VPS with <a href="https://kwant.si">kwant</a>: the one-line installer, the binary under a systemd unit, and Docker Compose. After that, it puts HTTPS in front, signs in your laptop and phone, and locks things down before you leave it running.</p>
<p><strong>Disclosure:</strong> I build kwant. It&rsquo;s open source (AGPL-3.0): a team of AI bots in one Rust binary, with the web app and SQLite built in. It&rsquo;s the same idea as Grok Bot, Claude Duet or OpenAI dots, a team of named bots you message, except you run it yourself with your own accounts.</p>
<p><strong>Version checked:</strong> 0.8.0, released November 10, 2026. Sources: the <a href="https://github.com/alexsergivan/kwant/releases/tag/mac-v0.8.0">release notes</a>, the <a href="https://github.com/alexsergivan/kwant#self-hosting-on-a-vps">README&rsquo;s VPS section</a>, the repository&rsquo;s <a href="https://github.com/alexsergivan/kwant/blob/main/docker-compose.yml"><code>docker-compose.yml</code></a> and the <a href="https://kwant.si/docs/install">install docs</a>. If you just want kwant on your desktop, read <a href="/posts/install-kwant-linux-deb-appimage/">Install kwant on Linux</a> instead. For what the team actually does, see <a href="/posts/self-hosted-ai-agent-team-one-binary/">Self-Host a Team of AI Agents in One Binary</a>.</p>
<h2 id="when-a-vps-is-worth-it">When a VPS is worth it</h2>
<p>The desktop apps are the quickest start, and for interactive work they&rsquo;re enough. A server earns its keep when:</p>
<ul>
<li><strong>Routines should run on schedule.</strong> kwant runs routines on a schedule and follow-ups bots schedule for themselves, and collects the results in an <strong>Inbox</strong>: what&rsquo;s waiting on you, what finished, what failed. None of that happens while the machine is asleep.</li>
<li><strong>You want it on your phone.</strong> Installing the web app and getting Web Push notifications needs a page served over HTTPS (or from <code>127.0.0.1</code>). A server with a domain gives you that.</li>
<li><strong>Several devices should share one team.</strong> One server, one data folder, every browser signed in to the same bots.</li>
</ul>
<p>You don&rsquo;t have to choose between the laptop and the server. The Mac and Linux apps have <strong>Add a server…</strong> in the menu bar (the tray on Linux). It takes the server&rsquo;s address or a sign-in link and opens it in its own window next to the kwant on your own computer.</p>
<h2 id="pick-your-install-path">Pick your install path</h2>
<table>
	<thead>
			<tr>
					<th>Path</th>
					<th>What runs</th>
					<th>Good for</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>One-line installer</td>
					<td>Prebuilt <code>kwnt</code> in <code>~/.local/bin</code>, as a <strong>user</strong> service</td>
					<td>Ubuntu 22.04+ or Debian 12+, x86_64 or arm64, quickest setup</td>
			</tr>
			<tr>
					<td>Binary + systemd unit</td>
					<td><code>kwnt</code> in <code>/usr/local/bin</code>, a dedicated <code>kwnt</code> system user</td>
					<td>You want a classic system service you control line by line</td>
			</tr>
			<tr>
					<td>Docker Compose</td>
					<td>kwnt, the Laya router and a private Chromium for the bots</td>
					<td>You already run things in Compose; about 4 GB of free RAM</td>
			</tr>
	</tbody>
</table>
<p>The prebuilt server binary needs glibc 2.35 or newer, which is why the floor is Ubuntu 22.04 or Debian 12. Release 0.8.0 ships it as <code>kwnt-linux-x86_64.tar.gz</code> and <code>kwnt-linux-aarch64.tar.gz</code>, so an ARM VPS works too.</p>
<p>Whichever path you pick, you need at least one AI account: a Claude, Codex or Grok CLI login, an Anthropic, OpenAI or xAI API key, or your own OpenAI- or Anthropic-compatible server. On a VPS, API keys are the least fiddly option. Add them in the app under <strong>Settings → This space → Accounts</strong>.</p>
<h2 id="path-1-the-one-line-installer">Path 1: the one-line installer</h2>
<p>Log in as the user that should run kwant (not root) and run:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -fsSL https://kwant.si/install.sh | sh
</span></span></code></pre></div><p>As with any <code>curl | sh</code>, you can download <a href="https://kwant.si/install.sh">the script</a> and read it first. What it does:</p>
<ul>
<li>Downloads the prebuilt <code>kwnt</code> from the latest release and checks it against its published SHA-256. If they don&rsquo;t match, nothing is installed.</li>
<li>Puts <code>kwnt</code> in <code>~/.local/bin</code> and your data in <code>~/.kwnt</code>.</li>
<li>Never runs <code>sudo</code>. When something needs admin rights, it prints the command instead.</li>
<li>Starts kwant as a systemd <strong>user</strong> service when the system allows it, so it comes back after a reboot. If starting at boot needs admin rights, it prints the one command for that: <code>sudo loginctl enable-linger &lt;your-user&gt;</code>.</li>
<li>Installs the Laya router and a browser for the bots in the background, plus Claude Code when no AI CLI is there yet.</li>
<li>Ends with a one-time sign-in link that works for 15 minutes.</li>
</ul>
<p>That service runs plain <code>kwnt serve</code>, which listens on <code>127.0.0.1:8799</code> by default. Nothing is reachable from the internet yet, which is what you want. To open the link from your laptop, tunnel the port first. The installer prints the exact command:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>ssh -N -L 8799:127.0.0.1:8799 you@your-vps
</span></span></code></pre></div><p>Then open the link in your laptop&rsquo;s browser. A request through the tunnel counts as &ldquo;this machine&rdquo;, so it needs no token. In the browser you choose your AI and sign in.</p>
<p>To upgrade, run the same line again. It upgrades kwant in place and keeps your data. Lost the link? <code>kwnt signin-link</code> prints a new one.</p>
<p>The installer&rsquo;s unit reads optional settings from <code>~/.kwnt/kwnt.env</code>, one <code>NAME=value</code> per line. That&rsquo;s where <code>KWNT_ALLOWED_ORIGINS</code> goes once you add HTTPS below.</p>
<h2 id="path-2-the-kwnt-binary-under-systemd">Path 2: the kwnt binary under systemd</h2>
<p><code>kwnt</code> is self-contained: SQLite and the web app are inside it, so the server needs no Node.js. You can build it yourself with <code>make build</code> in a clone (that needs Rust and Node on the build machine) or take it from the release tarball. The tarball route, on your own machine:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>curl -fLO https://github.com/alexsergivan/kwant/releases/latest/download/kwnt-linux-x86_64.tar.gz
</span></span><span style="display:flex;"><span>curl -fLO https://github.com/alexsergivan/kwant/releases/latest/download/kwnt-linux-x86_64.tar.gz.sha256
</span></span><span style="display:flex;"><span>sha256sum -c kwnt-linux-x86_64.tar.gz.sha256
</span></span><span style="display:flex;"><span>tar -xzf kwnt-linux-x86_64.tar.gz
</span></span><span style="display:flex;"><span>scp kwnt you@your-vps:/tmp/kwnt
</span></span></code></pre></div><p>Use <code>kwnt-linux-aarch64.tar.gz</code> for an ARM VPS. On the server, install the binary and create a dedicated system user:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo install -m <span style="color:#ae81ff">755</span> /tmp/kwnt /usr/local/bin/kwnt
</span></span><span style="display:flex;"><span>sudo useradd --system --create-home --home-dir /var/lib/kwnt kwnt
</span></span></code></pre></div><p>Then the unit, based on the one in the README. I changed one line: it binds to <code>127.0.0.1</code> instead of <code>0.0.0.0</code>, because a reverse proxy on the same box is going to face the internet, not kwnt.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-ini" data-lang="ini"><span style="display:flex;"><span><span style="color:#75715e"># /etc/systemd/system/kwnt.service</span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[Unit]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Description</span><span style="color:#f92672">=</span><span style="color:#e6db74">kwant AI bot platform</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">After</span><span style="color:#f92672">=</span><span style="color:#e6db74">network.target</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[Service]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Type</span><span style="color:#f92672">=</span><span style="color:#e6db74">simple</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">User</span><span style="color:#f92672">=</span><span style="color:#e6db74">kwnt</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">ExecStart</span><span style="color:#f92672">=</span><span style="color:#e6db74">/usr/local/bin/kwnt serve --host 127.0.0.1 --port 8799</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Restart</span><span style="color:#f92672">=</span><span style="color:#e6db74">always</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">Environment</span><span style="color:#f92672">=</span><span style="color:#e6db74">KWNT_DATA_DIR=/var/lib/kwnt</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Environment=KWNT_ALLOWED_ORIGINS=https://kwant.example.com</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#66d9ef">[Install]</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">WantedBy</span><span style="color:#f92672">=</span><span style="color:#e6db74">multi-user.target</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo systemctl daemon-reload
</span></span><span style="display:flex;"><span>sudo systemctl enable --now kwnt
</span></span></code></pre></div><p>If you keep the README&rsquo;s <code>--host 0.0.0.0</code> instead, close port 8799 in your firewall. On a non-loopback bind, <code>kwnt serve</code> prints a one-time sign-in link at startup. For the unit above, the fallback is the API token, which you paste on the sign-in screen:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>sudo cat /var/lib/kwnt/api-token
</span></span></code></pre></div><p>Run kwnt commands as the user that runs kwnt. Each install has its own token, so one from your laptop won&rsquo;t open the server. If you want CLI logins rather than API keys, sign the <code>claude</code>, <code>codex</code> or <code>grok</code> CLI in as the <code>kwnt</code> user.</p>
<p><code>Restart=always</code> keeps the service up, but it doesn&rsquo;t replace a clean stop. If you run your own Go services next to it, <a href="/posts/graceful-shutdown-in-go-web-services/">Graceful Shutdown in Go Web Services</a> covers the <code>SIGTERM</code> side of systemd and Docker restarts.</p>
<h2 id="path-3-ai-agents-with-docker-compose">Path 3: AI agents with Docker Compose</h2>
<p>The repository&rsquo;s Compose file starts three services: <strong>kwnt</strong>, the <strong>Laya</strong> router with its model baked in, and a private <strong>Chromium</strong> for the bots. The Docker socket isn&rsquo;t mounted. You need Docker with Compose and about 4 GB of free RAM.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>git clone https://github.com/alexsergivan/kwant.git <span style="color:#f92672">&amp;&amp;</span> cd kwant
</span></span><span style="display:flex;"><span>KWNT_CLIS<span style="color:#f92672">=</span>claude,codex docker compose up -d --build   <span style="color:#75715e"># any of claude,codex,grok; leave out for none</span>
</span></span><span style="display:flex;"><span>docker compose exec kwnt kwnt doctor                  <span style="color:#75715e"># what works, and the fix for what doesn&#39;t</span>
</span></span><span style="display:flex;"><span>docker compose exec kwnt claude auth login            <span style="color:#75715e"># or: codex login --device-auth, grok login --device-auth</span>
</span></span><span style="display:flex;"><span>docker compose exec kwnt kwnt signin-link             <span style="color:#75715e"># one-time sign-in link + QR code, 15 minutes</span>
</span></span></code></pre></div><p>Two things to know:</p>
<ul>
<li><strong>Without <code>--build</code></strong>, <code>docker compose up -d</code> pulls the released image <code>ghcr.io/alexsergivan/kwnt</code> instead of building it. That image has no AI CLIs inside, so you add an API key in the app. <code>KWNT_CLIS</code> builds them in, and they&rsquo;re off by default for a reason: per the README&rsquo;s measurements, they add about 0.9 GB.</li>
<li><strong>Pin and upgrade.</strong> Put <code>KWNT_VERSION=0.8.0</code> in <code>.env</code> to pin a version. To upgrade: <code>docker compose pull kwnt &amp;&amp; docker compose up -d</code>.</li>
</ul>
<p>The README also lists measured idle memory: Laya about 1.7–2.3 GB, the browser about 0.4 GB, kwnt itself about 25 MB. The browser container is capped at 1.5 GB. Most of the 4 GB is the router and Chromium, not kwant.</p>
<p>Data lives in the <code>kwnt-data</code> volume and CLI sign-ins in <code>kwnt-home</code>, so both survive rebuilds. The Compose file publishes the UI on <code>127.0.0.1:8799</code> only (<code>KWNT_HOST_PORT</code> changes the port). One limitation: kwant&rsquo;s own <code>execute_shell</code> tool runs in per-team Docker containers, which would need the host&rsquo;s Docker socket, so it isn&rsquo;t available in this stack. The CLIs&rsquo; own shell tools work inside the kwnt container.</p>
<p>If you&rsquo;re coming from an older image where kwnt ran as root and it says <code>/data isn't writable</code>, the documented fix is a one-off <code>docker compose run --rm -u root kwnt chown -R 10001:10001 /data</code>.</p>
<p>For the &ldquo;cheap box plus Docker&rdquo; approach in general, I wrote up how I host Go apps in <a href="/posts/one-of-thee-easiest-ways-to-host-go-web-apps/">One of The Easiest Ways to Host your Go Web App</a>. The same kind of small VPS fits, as long as it has the RAM.</p>
<h2 id="https-in-front-and-kwnt_allowed_origins">HTTPS in front, and KWNT_ALLOWED_ORIGINS</h2>
<p>All three paths leave kwant on loopback. Put a TLS reverse proxy in front and tell kwant its public address. With <a href="https://caddyserver.com">Caddy</a>, which fetches certificates for you, the whole <code>Caddyfile</code> is:</p>
<pre tabindex="0"><code>kwant.example.com {
	reverse_proxy 127.0.0.1:8799
}
</code></pre><p>Then set <code>KWNT_ALLOWED_ORIGINS</code> to that HTTPS origin (a comma-separated list if you have several):</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Docker Compose, in the clone</span>
</span></span><span style="display:flex;"><span>echo KWNT_ALLOWED_ORIGINS<span style="color:#f92672">=</span>https://kwant.example.com &gt;&gt; .env <span style="color:#f92672">&amp;&amp;</span> docker compose up -d
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># One-line installer</span>
</span></span><span style="display:flex;"><span>echo KWNT_ALLOWED_ORIGINS<span style="color:#f92672">=</span>https://kwant.example.com &gt;&gt; ~/.kwnt/kwnt.env <span style="color:#f92672">&amp;&amp;</span> systemctl --user restart kwnt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># System unit: uncomment the Environment= line, then</span>
</span></span><span style="display:flex;"><span>sudo systemctl daemon-reload <span style="color:#f92672">&amp;&amp;</span> sudo systemctl restart kwnt
</span></span></code></pre></div><p>With nginx, forward the original <code>Host</code> header and allow WebSocket upgrades. The live browser stream checks <code>Origin</code> against <code>Host</code>. This is the block from kwant&rsquo;s docs, inside your HTTPS <code>server</code>:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-nginx" data-lang="nginx"><span style="display:flex;"><span><span style="color:#66d9ef">location</span> <span style="color:#e6db74">/</span> {
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">proxy_pass</span> <span style="color:#e6db74">http://127.0.0.1:8799</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">proxy_http_version</span> <span style="color:#ae81ff">1</span><span style="color:#e6db74">.1</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">Host</span> $http_host;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">Upgrade</span> $http_upgrade;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">Connection</span> <span style="color:#e6db74">&#34;upgrade&#34;</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">proxy_set_header</span> <span style="color:#e6db74">X-Forwarded-Proto</span> $scheme;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">proxy_buffering</span> <span style="color:#66d9ef">off</span>;
</span></span><span style="display:flex;"><span>    <span style="color:#f92672">proxy_read_timeout</span> <span style="color:#e6db74">90s</span>;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Requests that come through the proxy carry proxy headers, so kwant treats them as remote even though the proxy is on the same machine. That&rsquo;s correct. It means you sign in properly rather than inheriting &ldquo;local&rdquo; trust.</p>
<h2 id="sign-in-with-a-link-or-a-qr-code">Sign in with a link or a QR code</h2>
<p>With <code>KWNT_ALLOWED_ORIGINS</code> set, <code>kwnt signin-link</code> (or <code>docker compose exec kwnt kwnt signin-link</code>) prints a one-time link for your domain plus a QR code to scan with your phone. It works once, for 15 minutes. The browser that opens it gets an HttpOnly cookie that lasts a year.</p>
<p>For the next device, run it again, or use a browser that&rsquo;s already signed in: <strong>Settings → All spaces → Signed-in devices → Add a phone or browser</strong> shows a one-time QR code. The same list lets you sign each browser out. A new browser can also choose <strong>Sign in from another device</strong>, which shows a code for 10 minutes. Your signed-in browsers then show <strong>New device wants access</strong> with Approve or Deny. Approve only a code that&rsquo;s on a screen you&rsquo;re holding.</p>
<p>On the phone, install the web app from Settings (on an iPhone, add it to the Home Screen first) and turn on <strong>Settings → All spaces → Notifications → Notify me on this device</strong>. kwant then sends a Web Push notification for each kind you tick, such as an approval or a question, even with the app closed.</p>
<h2 id="routines-keep-running">Routines keep running</h2>
<p>This is the part that makes the server worth having. Set up a routine once (or ask a bot to set one up; it comes with an Undo button) and it runs on schedule whether your laptop is open or not. Results land in the Inbox, and approvals land on your phone.</p>
<p>Start small: one routine that already works when I run it by hand, in a space set aside for server work. Spaces each have their own bots, accounts, routines and approval rule, so a work space can use the company API keys while a personal space uses yours.</p>
<h2 id="security-notes-before-you-walk-away">Security notes before you walk away</h2>
<p>A self-hosted agent team runs commands and holds API keys, so treat the box like any other server with credentials on it:</p>
<ul>
<li><strong>One public port: HTTPS.</strong> Don&rsquo;t publish 8799, Chromium&rsquo;s debugging port or the Docker socket. The Compose file already keeps CDP on its private network, and the browser container runs read-only with all capabilities dropped.</li>
<li><strong>Keep sign-in output private.</strong> A one-time link signs in as you, and anyone who can read the server&rsquo;s output or <code>docker compose logs</code> can use it before you do.</li>
<li><strong>Leave approvals on.</strong> New spaces default to <em>Ask only when risky</em>: <code>git push</code>, network calls, unknown commands and changes outside the bot&rsquo;s folder show an approval card with the exact command. You get <em>Allow once</em>, <em>Always allow</em> or <em>Deny</em>. <strong>Payments always ask, in every mode.</strong> In 0.8.0, turning approvals off makes bots just do the work, but they still ask for sign-ins, keys, payments and anything that reaches other people or can&rsquo;t be undone. On an unattended server, I&rsquo;d keep the default.</li>
<li><strong>Don&rsquo;t switch the token check off.</strong> <code>KWNT_REQUIRE_TOKEN=never</code> exists, but only for running behind your own authentication.</li>
<li><strong>Back up the data folder</strong> (<code>~/.kwnt</code>, <code>/var/lib/kwnt</code> or the <code>kwnt-data</code> volume) privately. It holds the database, account profiles and saved passwords.</li>
<li><strong>Know where messages go.</strong> kwant has no telemetry, but your prompts still go to whichever AI providers you add. A server doesn&rsquo;t make an external model local.</li>
</ul>
<p>If you&rsquo;d rather build the loop yourself, <a href="/posts/tool-use-in-go-agent-loop/">Tool Use in Go</a> shows what an agent loop looks like from the inside. A server deployment is where things like approvals and persistence stop being optional.</p>
<h2 id="vps-checklist">VPS checklist</h2>
<ul>
<li><input disabled="" type="checkbox"> Ubuntu 22.04+ or Debian 12+ (glibc 2.35+), x86_64 or arm64. About 4 GB of free RAM for Compose.</li>
<li><input disabled="" type="checkbox"> Install with the one-liner, the binary plus systemd, or <code>docker compose up -d</code>.</li>
<li><input disabled="" type="checkbox"> kwant listening on <code>127.0.0.1:8799</code>, not the public interface.</li>
<li><input disabled="" type="checkbox"> Caddy or nginx with TLS in front, and <code>KWNT_ALLOWED_ORIGINS</code> set to the HTTPS origin.</li>
<li><input disabled="" type="checkbox"> Laptop and phone signed in with a one-time link or QR code.</li>
<li><input disabled="" type="checkbox"> One AI account or API key added, and <code>kwnt doctor</code> clean.</li>
<li><input disabled="" type="checkbox"> One routine that already works by hand, approvals on <em>Ask only when risky</em>.</li>
<li><input disabled="" type="checkbox"> Private backups of the data folder.</li>
</ul>
<p><strong>Next step:</strong> pick a path above and get one routine running on your server. If you&rsquo;re on a free tier, kwant&rsquo;s own guide walks through <a href="https://kwant.si/blog/self-host-grok-bot-alternative-free-oracle-cloud">Oracle Cloud&rsquo;s free tier</a>. If this is the self-hosted AI agent setup you were after, <a href="https://github.com/alexsergivan/kwant">star kwant on GitHub</a>. It helps other people find it.</p>]]></content:encoded>
      <category>AI Engineering</category>
      <category>DevOps</category>
    </item>
  </channel>
</rss>
