Bor: Self-Hosted Linux Policy Management for Homelabs

Bor is a self-hosted policy manager for Linux desktops: Firefox, Chrome, KDE Plasma and Flatpak policies pushed over mTLS. Setup, enrollment and limits.

A diagram showing a central Bor server managing policies on multiple Linux client machines in a homelab network.

Bor is an open-source policy management system for Linux desktops. A central server distributes configuration policies to enrolled machines, and a small Go agent on each one applies them locally. If you run a few Linux desktops at home (a kids’ laptop, a living-room kiosk, a family PC) and want their browser and desktop settings managed from one place, it’s a self-hostable answer.

This guide sticks to what the project’s README documents. Bor is young (the first release came out in 2026), so check the README for anything that has changed.

What Bor actually manages

According to the README, the agent currently enforces:

  • Firefox ESR: the system-wide policies.json (RPM/DEB installs and Flatpak)
  • Google Chrome and Chromium: managed JSON policies (including Flatpak)
  • KDE Plasma: KDE Kiosk settings and KCM module restrictions
  • Flatpak: remotes and application install, update and removal, with a Flathub catalogue on the server

It is not a general server configuration tool: there’s no “make sure this package is installed on my servers” or “edit sshd_config everywhere” module. For that, Ansible remains the tool.

Other features from the README worth knowing about: real-time distribution over a gRPC stream, node groups, role-based access control, an audit log, tamper protection (managed files edited outside Bor are restored), and optional LDAP/AD integration.

Architecture: gRPC and mTLS

The server runs two TLS listeners:

PortPurposeClient certificate
8443Admin web UI (REST) and agent enrollmentOptional
8444Agent policy stream and certificate renewalMandatory (mTLS)

Enrollment uses a one-time token generated in the web UI. With it, the agent obtains its own client certificate. From then on every agent connection is mutually authenticated, so a machine without a valid certificate can’t join the policy stream. Agent certificates are renewed automatically. On first start the server generates its own internal CA, and policies, nodes and the audit log live in PostgreSQL.

Running the server

The quick start in the README uses Compose from the repository:

git clone https://github.com/VuteTech/Bor.git
cd Bor
cp .env.example .env
$EDITOR .env   # set DB_PASSWORD, JWT_SECRET and BOR_ADMIN_PASSWORD at minimum
podman-compose up -d   # docker compose works as well

Then log in at https://<server>:8443 with the admin credentials from .env. The server’s certificate comes from its own CA, so expect a browser warning until you trust that CA. If agents will reach the server by a name or IP the certificate doesn’t cover, .env.example documents a BOR_HOSTNAMES variable for extra certificate names.

Make sure your agents can reach both ports, 8443 for enrollment and 8444 for the policy stream. If you put a reverse proxy in front, it must pass TLS through to port 8444 untouched: the agents’ mTLS needs to reach Bor itself.

Enrolling a desktop

Every Bor server serves the agent packages and signed apt/dnf/zypper repositories itself. In the web UI, the Deploy agent wizard (the download icon in the header, or the button on the Nodes page) generates a single script that:

  1. trusts the server’s CA,
  2. adds the signed repository,
  3. installs the agent,
  4. enrolls it with a one-time token,
  5. starts the service.

Run that script on the desktop and the machine appears under Nodes. Managed machines never need internet access for this, which suits a homelab with a locked-down VLAN. The same instructions are available as a static page at https://<server>:8443/agent/.

A practical first policy: a Firefox kiosk

For a living-room dashboard, create a Firefox policy in the web UI that sets the home page to your Home Assistant instance, locks it, and disables private browsing and Firefox accounts. These are standard Firefox enterprise policies (Homepage, DisablePrivateBrowsing, DisableFirefoxAccounts). Bring the kiosk machine into a node group and bind the policy to it. If someone changes the managed policy file locally, Bor’s tamper protection restores it.

Is it worth it in a homelab?

If you have two or more Linux desktops used by other people, yes: browser and desktop lock-down from one dashboard is otherwise tedious. If your “fleet” is servers and containers, Bor doesn’t cover that, and Ansible (or plain config management in Git) is the better fit.

What’s Next

Now that you’ve got a taste of centralized policy management, you can start building a more robust and secure homelab.

Frequently Asked Questions

Which distros does the Bor agent support?
The releases ship agent packages as .deb, .rpm, .apk and Arch Linux packages for x86_64, arm64 and ppc64le, and every Bor server also serves the packages and repositories itself.
Can Bor manage servers like Ansible does?
No. Bor enforces desktop policies: Firefox, Chrome and Chromium policies, KDE Plasma Kiosk settings and Flatpak apps and remotes. For installing packages or editing server config, use Ansible or similar.
What does the Bor server need?
The project's quick start runs it with Podman or Docker Compose next to PostgreSQL. It listens on 8443 for the admin UI and enrollment and on 8444 for the agents' mTLS policy stream.

Get notified when new articles and designs land:

No spam. Unsubscribe any time.

Sergej Voronko
Sergej Voronko
SAP Basis · Senior Operations Manager · Linux infrastructure engineer
About the author →

[discussion]

Comments are powered by Giscus — backed by GitHub Discussions. Sign in with GitHub to join the conversation.