Stenvakt: lock it down, keep a way in

Stenvakt

15 min read Original article ↗

A safe-mode run on the demo server web-1: the server armed its own 300-second rollback timer, the app tried a fresh SSH login, the login worked, and the app cancelled the timer.

Stenvakt is a Mac app that patches the Linux servers you run yourself. With safe mode on, if a firewall or SSH change cuts you off, the server undoes it by itself.

Your Mac, your servers.

SSH

with the keys you already use.

A line engraving of K2 in blue ink on yellow paper, made from Svy123's 2006 photograph of the mountain
K2, engraved in blue from Svy123’s 2006 photograph

With safe mode on, the server arms its own timer before a firewall or SSH step, so a change that cuts you off is undone on the server, whatever your Mac is doing.

Stenvakt runs on your Mac, macOS 14 or newer, and reaches your servers over plain SSH. It reviews each server, watches what reaches it and patches it in a safe order: checks first, then updates, then firewall and SSH changes, reboot last. No agent is installed on the server; a fix installs only what it names, such as ufw or fail2ban. I build it alone, in Croatia, and run it on my own servers. Sten is stone, vakt is guard.

Review reads a server, scores its security and health, then lists what to fix now, what is worth doing and what is nice to have.

It is read-only: nothing changes until you pick a fix and preview it. These are the app’s four demo servers; pick one.

Review, read-only

web-1 Ubuntu 24.04.1 LTS · reviewed 14:31

SecurityNeeds work

HealthGood

3 to fix now, 3 worth doing, 3 nice to have

Autofix 2 Pro

Prepare 3 fixes
Load
0.62
4 cores
Memory free
38%
swap 12% used
Disk used
78%
root volume
Uptime
41 days
6.8.0-48-generic
Updates
14
3 security

Points lost

Security −34

−20 Firewall & network

−14 Updates & lifecycle

Health −17

−12 Backups & recovery

−5 Disk & logs

Fix now

  • Docker publishes sensitive ports to the internet: 3001 8080 Firewall & network

    Docker bypasses ufw, so these are open even with the firewall on. Block them or bind them to 127.0.0.1.

    Prepare fixAccept risk
  • PHP 8.1 in coolify is end-of-life (ended 2025-12) Updates & lifecycle

    It no longer gets security fixes. Move to a supported version after testing your apps.

    manualAccept risk
  • No sign of backups, and this server runs a database Backups & recovery

    One bad update or deleted volume and the data is gone. Back up off the server and test a restore.

    manualAccept risk

Should do

  • 3 security update(s) waiting Updates & lifecycle

    Install them soon, ideally in the Tools tab one at a time.

    Prepare fixAccept risk
  • Security updates are not automatic Updates & lifecycle

    Without them a server drifts into known vulnerabilities between your visits.

    Prepare fixAccept risk
shared-1 Ubuntu 22.04.5 LTS · reviewed 14:31

Shared SSH: other developers log in here, so SSH restrictions are locked

SecurityNeeds work

HealthGood

2 to fix now, 2 worth doing, 2 nice to have

Autofix 1 ProPrepare 1 fix

Load
1.10
2 cores
Memory free
21%
swap 30% used
Disk used
64%
root volume
Uptime
112 days
5.15.0-122-generic
Updates
31
6 security

Points lost

Security −42

−25 Firewall & network

−17 SSH

Health −21

−14 Updates & lifecycle

−7 CPU & memory

Fix now

  • MySQL (port 3306) is open to the internet Firewall & network

    A database, cache or admin service should never be reachable publicly. Bind it to localhost or close the port.

    Prepare fixAccept risk
  • Password logins are allowed over SSH SSH

    Anyone on the internet can guess passwords. Key-only login removes that whole class of attack.

    locked: sharedAccept risk

Should do

  • 6 security update(s) waiting Updates & lifecycle

    Install them soon, ideally in the Tools tab one at a time.

    Prepare fixAccept risk
  • A reboot is waiting Updates & lifecycle

    A kernel or core library update only takes effect after a reboot.

    Prepare fixAccept risk
db-1 Debian 12 · reviewed 14:31

SecurityNeeds work

HealthNeeds work

2 to fix now, 3 worth doing, 1 nice to have

Prepare 1 fix

Load
0.31
2 cores
Memory free
9%
swap 41% used
Disk used
87%
root volume
Uptime
9 days
6.1.0-26-amd64
Updates
4
0 security

Points lost

Security −29

−25 Firewall & network

−4 Updates & lifecycle

Health −38

−15 Backups & recovery

−13 CPU & memory

−10 Disk & logs

Fix now

  • PostgreSQL (port 5432) is open to the internet Firewall & network

    A database, cache or admin service should never be reachable publicly. Bind it to localhost or close the port.

    Prepare fixAccept risk
  • No sign of backups, and this server runs a database Backups & recovery

    One bad update or deleted volume and the data is gone. Back up off the server and test a restore.

    manualAccept risk

Should do

  • Memory is tight (9% free) CPU & memory

    Add RAM, add swap, or trim what runs here.

    manualAccept risk
  • The disk is 87% full Disk & logs

    Clean up before it becomes an outage.

    manualAccept risk
lab Ubuntu 24.04.1 LTS · reviewed 14:31

Test server: AI agents may apply changes here without asking. Safe mode stays on.

SecurityAt risk

HealthSolid

3 to fix now, 1 worth doing, 2 nice to have

Autofix 1 ProPrepare 3 fixes

Load
0.04
1 core
Memory free
71%
no swap
Disk used
22%
root volume
Uptime
2 days
6.8.0-48-generic
Updates
0
up to date

Points lost

Security −51

−25 Firewall & network

−18 SSH

−8 Users & access

Health −9

−6 Updates & lifecycle

−3 Disk & logs

Fix now

  • No firewall is active Firewall & network

    Every service that listens is reachable from the internet.

    Prepare fixAccept risk
  • Password logins are allowed over SSH SSH

    Anyone on the internet can guess passwords. Key-only login removes that whole class of attack.

    Prepare fixAccept risk
  • Root can log in with a password SSH

    Disable root password login, or better, use a named admin user with sudo.

    Prepare fixAccept risk

Should do

  • Nothing bans repeated failed logins Users & access

    fail2ban bans addresses that keep guessing, and keeps your logs quiet.

    Prepare fixAccept risk

Safe mode, both endings

  1. First, the server arms a timer.

    Before a firewall or SSH step, Stenvakt saves the server’s config and starts a rollback timer on the server itself: 300 seconds, or any window you set from 60 to 3600.

    armed on the server

    rollback armed: reverts in 300s unless access is confirmed

  2. Then it tries a fresh login.

    The app opens a brand-new SSH connection, the way you would log in tomorrow, instead of trusting the session that is already open.

    still counting

    Safe mode: proving you can still log in (new connection)

  3. If it works, the app cancels it.

    Once the new login works, the app cancels the timer on the server and the change stays. There is no keep button to remember.

    cancelled, the change stays

    access verified, rollback cancelled

  4. If it fails, the timer runs on.

    The change locked you out, or the connection dropped. The timer lives on the server, so it keeps counting whatever your Mac is doing: asleep, offline or closed.

    running on the server

    FAILED: a new connection no longer works. The change locked you out.

  5. At zero, the server puts it back.

    The saved config comes back and the server answers again, as it was before the change. The app tells you plainly that the change was not applied.

    rolled back by itself

    ok: the server answers again, it rolled itself back. The change was NOT applied.

web-11 of 4 servers ticked Running on web-1…

Staged on web-1Block Docker ports from the internetSafe mode on: rolls back by itself

ActivityAllIssues

Run on web-1

web-1 ([email protected]:2222)

  • rollback armed: reverts in 300s unless access is confirmed
  • blocking ports: 3001 8080
  • Safe mode: proving you can still log in (new connection)
  • access verified, rollback cancelled
  • [web-1] done
  • FAILED: a new connection no longer works. The change locked you out.
  • The server rolls itself back in about 300 seconds.
  • the server answers again, it rolled itself back. The change was NOT applied.

How long may the server wait?

Safe modeFirewall and SSH steps first save the server’s config and arm an automatic rollback. The app then proves you can still log in over a new connection and only then keeps the change.

300

Your number, counting down the way the server’s own timer does. If a change cut you off, the server would undo it at zero, whatever your Mac was doing.

This copy pauses when you scroll away. The server’s never does.

Something is knocking.

Watch reads each server’s own logs over SSH: SSH guesses, firewall blocks, web bots, logins and where they came from. Nothing is installed for Watch; it reads logs that are already there.

Watch, from the server’s own logs

Where connections come from6data: DB-IP.com

Netherlands

1.612

412 ssh · 300 firewall · 900 web, from 1 address

BrazilBR

1 · login

1 login

on your listnot on your lista login from a country not on your list

Should log in fromHR, DE

Countries come from a DB-IP database on your Mac. A login from a country you did not list gets its own red column, so one login is never a sliver.

What reached the serverper hour, last 24 scans

SSH guesses1.840

+136% vs last 24 h · from 63 addresses

Blocked by the firewall960

from 118 addresses

Web requests6.120

2.310 4xx · 40 5xx

Banned right now14

by fail2ban

Counted from the server’s own logs at each scan. One square per past scan, brighter for more traffic.

Needs attention4

Login from an unexpected country: [email protected] in Brazil

1 login, last by publickey at 16:31, from an address not on your list, and Brazil is not one of the countries you expect (DE, HR). If it is yours, add it to Other allowed IPs (This Mac, at the foot of the sidebar). If not, rotate the SSH keys and review the account.

Block 198.51.100.88

Blocking an address is a firewall change, so safe mode arms its timer first.

Ports being hitshare of blocked

Each row fills with its share of what the firewall blocked.
  • opensslcomes ticked.3.0.13 → 3.0.13-0ubuntu3.6A security fix that is not a major jump.
  • nodejsapps need a restart.22.9.0 → 22.11.0Every app that runs on it, after the update.
  • dockerrestarts every container.27.3.1 → 27.4.0When it is upgraded, unless live-restore is on.
  • php8.3is left alone.8.3.14Up to date.
  • undo it.Undo last update…The exact old versions are recorded, so the last update can go back.

Tools finds the runtimes and services on each server and updates one at a time. Services, listening ports and containers are compared before and after, and the run stops at the first problem.

Agents, over MCP

Your agent asks first.

Claude Code, Codex and Cursor connect over MCP. Reading runs at once. Anything that changes a server waits for you in the app, unless it is a test server you marked as allowing agent changes.

Agents can never turn safe mode off, and never see passwords, keys or tokens.

Waits for you

claude-code asks to run: Block Docker ports from the internet on web-1

Docker published 3001 and 8080 to the internet, past the firewall.

Risky steps run in safe mode

Details

ActivityRun on web-1

  • Approved: Block Docker ports from the internet on web-1
  • rollback armed: reverts in 300s unless access is confirmed
  • blocking ports: 3001 8080
  • Safe mode: proving you can still log in (new connection)
  • access verified, rollback cancelled

297s, cancelled

This one happened. On 25 October, Docker on my own server had published ports 3001 and 8080 past the firewall. Claude Code proposed the block, I approved it in the app, safe mode ran, the new login worked and the app cancelled the timer.

The request here is a replay of it. Press Approve & run and the log streams in, with your rollback window and your clock.

  • backupsare read back.dump → last line → 12 of 12 tablesA dump only counts once it has been checked against the live database.
  • imagescome back if they fail.pull → recreate → healthy?A newer image is proved before it is kept. If it fails, the old one runs again by itself.
  • portsare closed, then checked.block 8787, 443 still answersBlocked with safe mode armed. If a port that answered before stops, it is undone at once.
  • sshgoes key-only, when it is safe.0 password logins in the logOnly after the login log shows nobody still uses a password, and a fresh key login is proved.
  • rebootsare always yours.2 sessions open. Reboot?It shows who is on the server and asks. Afterwards it checks that everything came back.
  • pause it.Your agent watches the run.It can read it, leave notes, pause or abort. Only you can resume.

Polish comes with Autopilot: everything in Pro, plus Polish, from €24.99 a month with 14 days free. Reading the plan is free. Every step stops at the first failure, and Polish never deletes data, volumes or backups.

Start with one server.

Free for Macs with Apple silicon and macOS 14 or newer. Paste this into Terminal, or download the DMG.

curl -fsSL https://stenvakt.com/install.sh | sh

Download for Mac

The line above installs and opens it. The DMG needs one click in System Settings the first time: how.

Questions

A line engraving of K2 in white ink on charcoal, made from Svy123's 2006 photograph of the mountain
K2, engraved in white from Svy123’s 2006 photograph
When can I use it?

Now. Stenvakt is free to download for Macs with Apple silicon and macOS 14 or newer. Paste one line into Terminal or open the DMG. It keeps itself current: new versions are signed, come only from stenvakt.com and install with one click from the sidebar. The changelog lists what changed.

Which Linux servers does it work with?

It is built and tested on Ubuntu and Debian, the ones most VPS hosts hand you. AlmaLinux, Rocky and other RHEL-family servers are recognised, but not every fix covers them yet. You need SSH access as root or as a user with passwordless sudo.

Can a firewall or SSH change lock me out?

Not with safe mode on. Before a firewall or SSH step the server arms its own rollback timer, the app tries a brand-new login, and if that login fails the server puts the old config back. If you were already locked out by hand, read locked out after ufw enable.

Does every change run in safe mode?

No. Safe mode covers firewall and SSH steps, the ones that can lock you out. Updates run without a timer; Tools updates one tool at a time and can undo the last update.

What if my Mac sleeps mid-change?

The timer runs on the server, not on your Mac. If the app cannot confirm a new login, the server undoes the change when its timer runs out, whatever your Mac is doing.

How long is the rollback window?

300 seconds unless you change it, anywhere from 60 to 3600. A longer window gives a slow server time to answer; a shorter one gets you back in sooner.

Does it install an agent on the server?

No. Stenvakt logs in over SSH with the keys you already use and runs only what you approved. Nothing new listens on the server. A fix installs what it names, such as ufw, fail2ban, a docker-user-block service or the small relay behind email alerts.

Can it tell me when something happens on a server?

Yes, with Pro. Watch shows what reached the server, where it came from and which logins worked, and blocks an address in one click. Login guard holds logins from keys it does not know. Turn on email alerts and you get a mail when a guard refuses a login or freezes something. Always-on checks, which you opt into, keep an eye on expiring certificates and actively exploited packages while your Mac is closed; the app shows exactly what it sends first.

Does it check for new security holes?

Yes. Review looks for well-known holes and gets new checks when big ones appear, such as the OpenSSH long-password bypass on Alpine and other musl servers, and n8n running inside containers. It also warns when sshd still runs a program an update replaced, so an installed fix is not active until sshd restarts. With Pro, the exploit monitor flags packages that are being actively exploited.

Can it update the software my server runs?

Yes. Tools lists the web servers, databases, runtimes and containers on a server, with the version each runs and whether an update is waiting, including snaps and Kubernetes. It updates one tool at a time and can undo the last update.

What is Polish?

A cleanup plan for a whole server: containers and Coolify apps, packages inside images, exposed ports, key-only SSH and updates. Review shows the plan read-only, for free. Running it step by step for you comes with the Autopilot plan, from €24.99 a month with a 14-day free trial.

How is it different from Webmin or Cockpit?

Those are admin panels that run on the server and let you change almost anything from a browser. Stenvakt runs on your Mac, adds nothing that listens on the server, and focuses on one job: finding what is risky and fixing it without locking you out. The full comparisons: Webmin, Cockpit, and by hand or with Lynis.

Can I use it on a server other people log in to?

Yes. Mark the server as shared and Stenvakt never changes SSH access on it, so nobody else loses their login. Its other fixes still run, firewall steps in safe mode. More in changing SSH on a shared server.

Can my AI agent lock me out?

Its changes wait for your approval in the app, unless it is a test server you marked as allowing agent changes; then they apply without asking. Either way, with safe mode on, firewall and SSH steps get the rollback timer, and agents can never turn safe mode off. They never see passwords, keys or tokens.

What does it cost?

Stenvakt is free, with no limit on servers. Safe mode, Review and Preview stay free, and updates are free for everyone. Pro adds Watch, Login guard, scheduled backups and more for €4.99 a month or €39.99 a year, with a 14-day free trial. For several people, write to us about a Team plan. See pricing.