Release status (checked 2026-09-06): v0.2.0 is the latest stable release, published with direct Debian 13, Ubuntu 26.04, and Fedora 44 packages. Every stable channel serves it: the three AUR entries, both APT suites, and the production COPR.
A modern face authentication system for Linux PAM. Provides Windows Hello-style facial auth with IR-required capture and layered static-presentation checks, configurable as a persistent daemon or daemonless one-shot. All inference runs locally on your hardware -- no cloud services, no runtime network requests, no telemetry. Your biometric data never leaves your machine.
This installs the stable source-build package. facelock-bin is the prebuilt
alternative and facelock-git follows development; all three AUR entries
served version 0.2.0-1 when checked on 2026-09-06, and each declares the
onnxruntime dependency the binary loads at runtime.
yay -S facelock # or paru -S facelockDebian-family release support is exactly Debian 13 (Trixie) and Ubuntu 26.04
LTS (Resolute). Both codenamed suites are published at
https://tysmith.me/facelock/apt and served 0.2.0 when checked on 2026-09-06:
| Supported target | Suite | Required package capability |
|---|---|---|
| Debian 13 | trixie |
TPM |
| Ubuntu 26.04 | resolute |
TPM |
Install the archive keyring, write a source entry naming your codename, then install the package:
sudo curl -fsSL https://tysmith.me/facelock/apt/tysmith-archive-keyring.gpg \
-o /usr/share/keyrings/tysmith-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/tysmith-archive-keyring.gpg] https://tysmith.me/facelock/apt trixie facelock" | sudo tee /etc/apt/sources.list.d/facelock.list
sudo apt update
sudo apt install facelockOn Ubuntu 26.04, use resolute instead of trixie in the source line. Both
suites are amd64 only. The quickstart
carries the signing key fingerprint to check the downloaded keyring against.
Source entries written for v0.1.4 name the main or legacy suite. They
keep working until 0.3.0: main maps to the Trixie package set and legacy
serves signed empty indexes. At 0.3.0, apt update fails until the entry is
removed. Rewrite those entries to your operating system's codename now.
Bookworm, Noble, and Ubuntu 25.x have no suite.
The supported COPR targets are Fedora 43, 44, and 45. The production COPR
served 0.2.0-1 on all three when checked on 2026-09-06; the older 0.1.3 build
stays in the repository, and dnf resolves to 0.2.0. The staging COPR is a
candidate channel, not a stable installation source. RHEL is not in the
supported matrix.
sudo dnf install dnf5-plugins
sudo dnf copr enable tyvsmith/facelock
sudo dnf install facelockInstall the distro-specific build prerequisites first; the Rust dependency and the separately loaded ONNX Runtime shared library are not the same thing. See the source-build prerequisites.
just build # build into target/debug; does not install
target/debug/facelock --helpjust build does not install Facelock, and --help does not prove that an
ONNX Runtime can be loaded. On Arch, where the system runtime is packaged, the
optional just install command builds and installs the current tree, prompts
for sudo for file writes, and does not edit PAM. Debian 13 and Ubuntu 26.04
package ONNX Runtime, but their multiarch paths and versioned SONAMEs are not
compatible with Facelock's current trusted runtime loader. Source builds there
need a separately installed compatible runtime to run inference; published
Facelock .deb packages bundle one. Fedora users should use the RPM/COPR
layout, and the quickstart records why the current NixOS source-tree module is
not yet a usable authentication installation.
After installing a package, or after a source installation with a working ONNX Runtime:
sudo facelock setup # interactive wizard: camera, models, encryption,
# daemon, enrollment, and optional PAM servicesThat's it. Open a new terminal and run sudo echo "ok" to confirm face auth fires. Keep a root shell open until you've verified it works.
The setup wizard already offers enrollment; do not add a redundant enrollment
command to the initial sequence. To re-run individual steps later:
sudo facelock enroll, sudo facelock test, sudo facelock setup --systemd,
or sudo facelock setup --pam.
Every wizard step can also be answered or declined from the command line — --camera, --models, --execution-provider, --encryption to supply a value, and --no-pam / --no-systemd / --no-enroll to decline an action outright. See the CLI reference for the full flag surface.
GPU support is runtime-only -- no Facelock rebuild is needed. On Arch, ask
pacman to switch from the CPU runtime to the matching official-repository ONNX
Runtime variant and set execution_provider in
/etc/facelock/config.toml:
| GPU Vendor | Package (Arch) | Config value |
|---|---|---|
| NVIDIA | onnxruntime-opt-cuda |
"cuda" |
| AMD | onnxruntime-opt-rocm |
"rocm" |
| Intel | none packaged | "openvino" |
Facelock has configuration support for CUDA, ROCm, and OpenVINO; those GPU
paths are not part of the release package validation matrix. CPU is the
default. Arch packages no OpenVINO build of ONNX Runtime, in the repositories
or the AUR. Build ONNX Runtime with the OpenVINO execution provider yourself to
use execution_provider = "openvino". See GPU acceleration.
just uninstall # source installations only; remove native packages with their package managerOrdinary uninstall preserves biometric and configuration state. Preview the
bounded purge with sudo facelock data purge --dry-run; destruction additionally
requires --allow-destruction. It operates only inside compiled Facelock roots
and reports unsafe or externally configured remnants for manual inspection.
| Mode | Config | How it works | Latency |
|---|---|---|---|
| Daemon | mode = "daemon" (default) |
PAM → D-Bus → persistent daemon | fastest: no model load, no reopen when warm |
| D-Bus activation | systemd + D-Bus service | systemd starts daemon on demand | + daemon start on the first call |
| Oneshot | mode = "oneshot" |
PAM → facelock auth subprocess |
+ model load on every call |
Daemon latency depends on camera state: a cold attempt pays a camera reopen, a retry within device.camera_release_secs of a failed attempt does not. That reopen cost is a property of your camera and driver, not a number to quote from someone else's laptop — measure it with sudo facelock bench camera-reopen, which prints the open / STREAMON / warmup split. The lighter default model (scrfd_2.5g) keeps inference fast.
The CLI works in all modes — it connects to the daemon if available, otherwise operates directly.
facelock setup Download models, validate systemd, configure PAM
facelock is-enrolled Is this user enrolled? (exit 0/1/2)
facelock capabilities Report machine-readable integration capabilities
facelock enroll Capture and store a face
facelock test Test recognition; inspect output, not exit 0 alone
facelock list List enrolled models
facelock remove <id> Remove a specific model
facelock clear Remove all models for a user
facelock preview Live camera preview
facelock config Show configuration (config edit to open $EDITOR)
facelock status Check system status
facelock daemon Run persistent daemon (daemon restart to restart it)
facelock auth One-shot auth (PAM helper)
facelock devices List cameras
facelock tpm status TPM status/management
facelock tpm encrypt Encrypt stored embeddings (tpm decrypt to reverse)
facelock tpm reseal Re-seal the TPM key under current PCRs
facelock bench Benchmarks and calibration
facelock pam Inspect or edit PAM services
facelock hyprlock Manage the built-in hyprlock adapter
facelock data purge Preview or destroy retained state
facelock audit View structured audit log
Desktop projects own their setup/removal wrapper and lock-screen UI. Facelock provides stable capability, enrollment, and arbitrary-service PAM commands for those wrappers; it does not ship desktop-specific downstream scripts. See the integration guide for the complete contract and a worked Omarchy example.
facelock-core Config, types, errors, D-Bus interface, traits
facelock-camera V4L2 capture, auto-detection, preprocessing
facelock-face ONNX inference (SCRFD detection + ArcFace embedding)
facelock-store SQLite face embedding storage
facelock-daemon Auth/enroll logic, rate limiting, liveness, audit
facelock-cli Unified CLI binary (facelock)
facelock-bench Standalone benchmark and calibration utility
facelock-tpm TPM-sealed key encryption, software AES-256-GCM
facelock-polkit Polkit authentication agent
pam-facelock PAM module (libc + toml + serde + zbus only)
facelock-test-support Mocks and fixtures for testing
Camera Frame → SCRFD Detection → 5-point landmarks
→ Affine Alignment → 112x112 face crop
→ ArcFace Embedding → 512-dim L2-normalized vector
→ Cosine Similarity vs stored embeddings → MATCH / NO MATCH
All keys are optional. Camera is auto-detected if device.path is omitted.
[device]
# path = "/dev/video2" # auto-detected if omitted (prefers IR)
[recognition]
# threshold = 0.80 # cosine similarity threshold
# execution_provider = "cpu" # "cpu", "cuda", "rocm", or "openvino"
# threads = 4 # ORT inference threads
[daemon]
# mode = "daemon" # "daemon" or "oneshot"
[security]
# require_ir = true # refuse auth on RGB cameras
# require_frame_variance = true # reject photo attacksFull reference: config/facelock.toml.
Facelock includes a hyprlock adapter for systems where a hyprlock PAM service is present. This does not imply package or hardware validation for every Hyprland distribution. Two things are needed:
- PAM line in
/etc/pam.d/hyprlock—sudo facelock setupdoes this automatically when you select hyprlock in the PAM step. - Lock-screen tweak in
~/.config/hypr/hyprlock.conf— setignore_empty_input = falseand add a face icon toplaceholder_text. Run as your normal user:facelock hyprlock enable # add face icon + enable empty-Enter submission facelock hyprlock enable --no-icon # functional change only (no icon) facelock hyprlock disable # revert (preserves fingerprint setup if present) facelock hyprlock status # show current integration state
facelock hyprlock enable preserves any existing fingerprint integration (icon , fingerprint:enabled = true, pam_fprintd.so) — face and fingerprint can coexist. If your hyprlock font isn't a Nerd Font, run with --no-icon; the functional integration still works.
This command family is frozen compatibility surface, not a template for new
desktop adapters. New desktops use facelock pam add --service <name> and own
their UI/configuration changes downstream. Omarchy likewise owns its
end-to-end integration and package choice; Facelock only supplies the backend
contracts described in the integration guide.
just check # unit tests + clippy + fmt
just test-arch-pam # Arch container PAM smoke tests
just test-arch-integration # end-to-end with camera (daemon mode)
just test-arch-oneshot # end-to-end with camera (no daemon)
just test-arch-dev-shell # interactive container for manual testingSee docs/testing-safety.md before editing PAM config on your system.
Privacy: Facelock is 100% local. Face detection and recognition run entirely on your hardware via ONNX Runtime. No images, embeddings, or metadata are ever sent to any external server. There is no telemetry, no analytics, no phone-home behavior. Models are downloaded once during setup and verified by SHA256 checksum -- after that, Facelock never touches the network.
Security:
- IR camera enforcement on by default (anti-spoofing)
- Frame variance and IR texture checks are enabled by default against static presentation attacks; landmark liveness is experimental and off by default. These checks do not establish resistance to video replay.
- Constant-time embedding comparison via
subtlecrate - AES-256-GCM encryption at rest with optional TPM-sealed keys
- Model SHA256 verification at every load
- D-Bus system bus policy: deny-all default;
Authenticateopen to every local user (daemon-checked UID), everything else root-only; no group - D-Bus caller UID verification on all daemon methods
- PAM audit logging to syslog
- Rate limiting (5 face-detected authentication failures/user/60s by default)
- systemd service hardening (ProtectSystem=strict, NoNewPrivileges, etc.)
See docs/security.md for the full threat model.
just version # show current version
just release 0.2.0 # bump version across all packaging files
git push origin main --tags # trigger CI release workflowA vX.Y.Z tag starts the release workflow. It attempts binaries and the direct
Fedora .rpm. It also attempts two suite-specific .deb artifacts, one for
each supported suite. Those builds are not publication proof: the release and
every required asset must be present and verified. Stable releases publish
AUR/APT and enable production COPR handling;
prereleases must not enter those stable channels.
v0.2.0 is the
latest stable release, published with direct package assets. See
docs/releasing.md for the gates and versioning contract.
Dual-licensed under MIT or Apache 2.0, at your option.
The ONNX face models used by Facelock are licensed separately under the InsightFace non-commercial research license. See models/NOTICE.md for details.