No lock-in

Self-hosting Dirless.

Every component of Dirless is open source under Apache-2.0, and the protocol between the components is identical whether we run the backend or you do. The hosted service is a convenience, not a dependency: if we disappeared tomorrow, you could run the whole stack yourself. This page explains what that takes - deliberately at the component level, so it fits your infrastructure instead of prescribing ours.

On this page
Overview

The architecture

Dirless has three moving parts at runtime, connected by HTTPS and end-to-end encryption:

Your IdP AWS IAM Identity Center
pulls users & groups
dirless-syncer encrypts each snapshot with age
uploads encrypted snapshots over HTTPS
dirless-backend your server - stores & serves ciphertext
agents poll for new snapshots
dirless-agent each enrolled host - decrypts locally
answers glibc NSS lookups
getent · ssh · login standard Linux, no LDAP anywhere

Components

The components

All four are static-friendly Crystal binaries, released as RPMs in the dirless.com package repository (x86_64 and aarch64) and buildable from source at github.com/dirless.

BinaryRuns whereJob
dirless-backend A server you control HTTP API that stores encrypted snapshots and serves them to agents. State lives in an embedded database; there is no external database to run.
dirless-syncer Near your IdP (e.g. an EC2 instance) Pulls users and groups from AWS IAM Identity Center, encrypts them per host, pushes to your backend. Self-enrolls on first run.
dirless-cli Each host, once Enrollment (keypair + registration), plus export, import, and migration tooling.
dirless-agent Each host, as a daemon Fetches and decrypts snapshots, serves user/group lookups to glibc through the bundled NSS module.

Requirements

What you need

PieceRequirement
A backend server Any modern Linux box, even a small one - the backend serves and stores ciphertext, it does not crunch. One is enough to start; the login path does not depend on its uptime.
TLS in front of it The backend speaks plain HTTP on localhost and expects a reverse proxy to terminate TLS. Any proxy works: Caddy, nginx, HAProxy, a cloud load balancer.
A DNS name Something like dirless.example.com pointing at the proxy. Agents and the syncer are configured with this URL.
IdP read access The syncer needs read-only access to IAM Identity Center: identitystore:List* and sso:ListInstances. On EC2 an instance role is the natural fit.
A shared secret One long random string, generated by you. It authenticates syncers, agents, and the CLI against your backend and derives your tenant ID.

Step 1

Running the backend

The backend is one binary and one TOML file. The repository ships an annotated example config; the essentials are the listen address, a directory for its embedded database, and your shared secret:

/etc/dirless/dirless.toml
[server]
host = "127.0.0.1"     # stay on localhost; TLS belongs to your proxy
port = 4000

[storage]
db_dir = "/var/lib/dirless/tenants"

[hmac]
secret = "generate-a-long-random-secret-and-put-it-here"

Run it under whatever supervises processes in your world - systemd, runit, a container, a BSD rc script. It is a single foreground process with no children and no external services. Point your proxy at it and confirm it answers:

Shell
curl https://dirless.example.com/v1/health
Backups are one directory. Everything the backend knows lives under db_dir, and all of it is ciphertext. Snapshot that directory with your existing backup tooling and you have backed up Dirless. For the plaintext escape hatch, there is always dirless-cli export from any enrolled host.

Step 2

Running the syncer

The syncer runs wherever it can reach both your IdP and your backend - for AWS IAM Identity Center that usually means a small EC2 instance with a read-only instance role. Configure it with your backend URL and shared secret; it enrolls itself on first run, discovers your identity store, and from then on pushes an encrypted snapshot on every sync interval.

There is nothing sacred about its schedule or lifecycle: run it as a daemon, from a timer, or by hand while testing. Each run is idempotent - pull, encrypt, push.


Step 3

Enrolling hosts

Hosts are enrolled exactly as they are against the hosted service - the only difference is the URL:

Shell (each host)
dirless-cli enroll --server https://dirless.example.com --token <your-shared-secret>

Enrollment generates the host's age keypair, registers its public key with your backend, and writes credentials to /etc/dirless/. Start dirless-agent, and the host resolves your directory through standard NSS:

Shell (each host)
getent passwd alice
alice:x:100001:100000:Alice Anderson:/home/alice:/bin/zsh

From here, everything in the rest of the documentation - the getting-started guide, SSH certificates and host-based access control, export and import - works unchanged against your own backend.


Philosophy

What we leave to you

This page stops at the component level on purpose. Which distribution, which proxy, which process supervisor, which cloud, how many backend replicas, how you rotate secrets, how you monitor - those decisions belong to the people who operate the deployment, and your existing conventions will serve you better than a copy of ours. What Dirless guarantees is the contract: open-source components, open formats on the way in and out, and a protocol that does not care who operates the server.

If you get stuck self-hosting, open an issue on the relevant repo at github.com/dirless - real deployments finding rough edges is exactly what we want to hear about.


What's next