FreezeOS Overview
FreezeOS is a secure, immutable, fleet-managed Linux operating system designed for managed endpoints. Every device is enrolled with a central fleet server, encrypted with server-issued keys, and monitored via automatic health checks.
Key Concepts
- Immutable Root — The base system is a read-only squashfs image. Changes are written to a persistent overlay. The core OS cannot be tampered with at runtime.
- Two-Factor Encryption — System partitions are unlocked by server-issued tokens (automatic at boot). User data is unlocked by a PIN entered at login.
- Fleet Management — All devices check in with the fleet server periodically. The server issues fresh tokens, collects health data, and pushes OTA updates.
- A/B System Slots — Two system partitions enable zero-downtime updates with automatic rollback on failure.
- Policy Enforcement — Organizations can define policies (security, network, power, restrictions) that are pushed to devices and enforced automatically.
System Requirements
| Component | Minimum | Recommended |
|---|---|---|
| CPU | x86_64, 2 cores | 4+ cores with AES-NI |
| RAM | 2 GB | 4+ GB |
| Storage | 40 GB | 64+ GB SSD |
| Network | Ethernet or WiFi | Ethernet |
| Boot | UEFI | UEFI with Secure Boot |
Quick Start
- Download the FreezeOS ISO from the download page
- Write to USB:
dd if=freezeos-latest.iso of=/dev/sdX bs=4M status=progress - Boot the target machine from USB
- Follow the enrollment wizard to register with your fleet server
- The installer will partition, encrypt, and install the OS automatically
- Reboot into your new FreezeOS installation
Installation
FreezeOS is installed from a live ISO environment. The ISO boots into an enrollment wizard that handles hardware diagnostics, fleet registration, and automated OS installation.
Writing the ISO
On Linux:
sudo dd if=freezeos-latest.iso of=/dev/sdX bs=4M status=progress conv=fdatasync
On macOS:
sudo dd if=freezeos-latest.iso of=/dev/rdiskN bs=4m
Double-check the target device. dd will overwrite the entire disk without confirmation.
Boot Menu Options
| Entry | Description |
|---|---|
| FreezeOS | Normal boot with KMS graphics |
| FreezeOS (verbose) | Full kernel logging |
| FreezeOS (USB fix) | Disables IOMMU for problematic USB controllers |
| FreezeOS (nomodeset) | Disables KMS for GPU compatibility issues |
| FreezeOS (safe mode) | Minimal boot with nomodeset + noacpi |
Installation Process
The installation runs three sequential scripts:
- partition.sh (0-10%) — Creates GPT partition table with 10 partitions, sets up LUKS encryption on each, creates filesystems
- install-os.sh (10-90%) — Downloads the fleet system image (squashfs) from the fleet server and writes it to the system partition
- bootloader.sh (90-100%) — Installs GRUB EFI bootloader, builds initramfs with the FreezeOS init script, configures boot entries
First Boot
After installation, the device reboots into FreezeOS. The first boot performs several setup tasks.
Boot Sequence
- GRUB loads the kernel and initramfs
- The FreezeOS init script validates the system token
- System partition is LUKS-decrypted with the server key
- Squashfs integrity is verified via SHA-256
- OverlayFS mounts the immutable base + persistent overlay
switch_roothands off to systemd- LightDM presents the login screen
- User enters their PIN to unlock personal data partitions
First Login
Enter the PIN you chose during enrollment. This PIN derives the encryption key for your personal data, app data, and swap partitions via PBKDF2.
The system token refreshes automatically on each device checkin. If your device has been offline for more than 7 days, the token may expire — the device will need network connectivity to refresh.
Partition Layout
FreezeOS uses a 10-partition GPT layout. Each partition has a specific role in the security and update architecture. Several partitions are dynamically sized based on the total disk capacity (minimum 40 GB required).
| # | Name | Size | Type | Encryption | Purpose |
|---|---|---|---|---|---|
| 1 | ESP | 512 MB | FAT32 | None | EFI System Partition, GRUB bootloader |
| 2 | /boot | 1 GB | ext4 | None | Kernels, initramfs, tokens, node config |
| 3 | System A | 8 GB | LUKS | Server key | Primary system slot (squashfs) |
| 4 | Apps | Dynamic | LUKS | Server key | Persistent overlay (upper) |
| 5 | User Storage | 60% of available | LUKS | PIN-derived | /home — personal data |
| 6 | Swap | RAM-sized | LUKS | PIN-derived | Encrypted swap space |
| 7 | BIOS Boot | 2 MB | Raw | None | Legacy GRUB (fallback) |
| 8 | System B | 8 GB | LUKS | Server key | Secondary system slot (A/B updates) |
| 9 | App Data | Dynamic | LUKS | PIN-derived | Application persistent data |
| 10 | Recovery | 2 GB | ext4 | None | Recovery environment and tools |
Dynamic Sizing Algorithm
After subtracting all fixed-size partitions (ESP, /boot, System A/B, BIOS Boot, Recovery, Swap = ~19.5 GB + swap), the remaining space is called available space. Dynamic partitions scale proportionally with no caps:
| Partition | Formula | Min |
|---|---|---|
| User Storage (Part 5) | 60% of available space | — |
| Apps (Part 4) | 25% of available space | 4 GB |
| App Data (Part 9) | 15% of available space | 4 GB |
| Swap (Part 6) | Matches system RAM | 1 GB (max 16 GB) |
Example Partition Sizes
Example sizes assuming 4 GB RAM (swap = 4 GB):
| Disk Size | Apps | App Data | Swap | User Storage |
|---|---|---|---|---|
| 64 GB | 8.9 GB | 5.3 GB | 4 GB | ~21 GB |
| 128 GB | 25.6 GB | 15.4 GB | 4 GB | ~61 GB |
| 256 GB | 56.4 GB | 33.8 GB | 4 GB | ~135 GB |
| 512 GB | 117.9 GB | 70.7 GB | 4 GB | ~283 GB |
FreezeOS requires a minimum disk size of 40 GB. The installer will refuse to proceed on smaller disks.
Key Domains
- Server-key partitions (3, 4, 8) — Unlocked automatically at boot using the key from the fleet server token. No user interaction required.
- PIN-derived partitions (5, 6, 9) — Unlocked at login. Key is derived via
PBKDF2-HMAC-SHA256(PIN, SHA256(cert) + salt, 600000, 64). - Unencrypted partitions (1, 2, 7, 10) — Required for boot and recovery. Contain no user data.
Boot Flow
The FreezeOS boot process is managed by a custom init script (~93KB) that runs in a minimal busybox initramfs environment.
Sequence
GRUB EFI → initramfs → Token Validate → LUKS Decrypt → SHA-256 Verify → Overlay Mount → switch_root → systemd → LightDM → PIN Unlock → Desktop
1. GRUB
Standalone EFI binary with all modules embedded. Loads kernel and initramfs from the /boot partition. Passes kernel parameters including log server URL.
2. Initramfs Init
The freezeos-init.sh script runs as PID 1 in a busybox environment. It handles:
- Parsing kernel command line for tokens, recovery flags, log server
- Loading crypto kernel modules (ECB → cryptd → crypto_simd → XTS → SHA512 → AES-NI)
- Token validation (HMAC-SHA256 signature check, expiry check)
- LUKS decryption of system and apps partitions
- Squashfs integrity verification
- OverlayFS mount (squashfs lower + apps upper)
- Config injection (user, network, PAM hooks)
- switch_root to the merged filesystem
3. Systemd
After switch_root, systemd takes over and boots normally. The freezeos-boot-success.service resets the boot attempt counter to prevent false rollbacks.
Immutable OS Model
FreezeOS uses an OverlayFS-based immutable OS design. The base system image is a read-only squashfs file that cannot be modified at runtime.
How It Works
┌──────────────────────────────────┐ │ Overlay Upper (Apps partition) │ ← Read-Write (persistent) ├──────────────────────────────────┤ │ OverlayFS Merge Point │ ← Unified root filesystem ├──────────────────────────────────┤ │ SquashFS Lower (System partition)│ ← Read-Only (immutable) └──────────────────────────────────┘
- User-installed packages and config changes write to the overlay upper on the Apps partition
- The base system squashfs is never modified
- OTA updates replace the squashfs image entirely
- Safe mode boots with a tmpfs overlay, bypassing all user modifications
- Factory reset wipes the overlay, restoring the pristine base image
A/B System Updates
FreezeOS maintains two system partitions (Slot A and Slot B) for zero-downtime updates with automatic rollback.
Update Process
- New squashfs image downloaded from fleet server
- SHA-256 integrity verified
- Written to the inactive slot
- A/B state file updated to flip active slot
- Device reboots into new system
freezeos-boot-success.serviceconfirms successful boot
Automatic Rollback
If the boot attempt counter exceeds 3, the init script automatically rolls back to the previous slot. This protects against bad updates that prevent the system from booting fully.
A/B State File
Located at /boot/freezeos/ab-state, this shell-sourceable file tracks:
ACTIVE_SLOT=A SLOT_A_VERSION=2.9.86 SLOT_A_HASH=24117be33... SLOT_B_VERSION=2.9.85 SLOT_B_HASH=abc123def... BOOT_ATTEMPTS=0
Encryption
Every data partition on a FreezeOS device is encrypted with LUKS (Linux Unified Key Setup) using AES-XTS with 512-bit keys.
Encryption Specifications
| Parameter | Value |
|---|---|
| Cipher | AES-XTS-plain64 |
| Key Size | 512 bits (256-bit AES + 256-bit XTS) |
| LUKS Key Size | 64 bytes |
| Certificate | RSA-4096 |
| Token Signing | HMAC-SHA256 |
| PIN Key Derivation | PBKDF2-HMAC-SHA256, 600,000 iterations |
Two Key Domains
Server-Controlled (System, Apps, System B)
The LUKS key is generated during enrollment and stored encrypted on the fleet server. At each checkin, the key is embedded in a signed token and delivered to the device. The init script extracts the key and unlocks these partitions automatically.
PIN-Derived (User Storage, App Data, Swap)
The LUKS key is derived from the user's PIN combined with the device certificate fingerprint:
key = PBKDF2-HMAC-SHA256(
password = PIN,
salt = SHA256(DER(device_cert)) + enrollment_salt,
iterations = 600000,
key_length = 64 bytes
)
Token System
FreezeOS uses HMAC-SHA256 signed tokens to securely deliver LUKS encryption keys from the fleet server to devices.
Token Format
Tokens are Base64-encoded JSON with an HMAC-SHA256 signature. Each token contains:
- node_id — The device identifier
- key — Base64-encoded LUKS key
- type — "system" or "apps"
- issued_at — Token issue timestamp
- expires_at — Token expiry timestamp
- signature — HMAC-SHA256 of the payload
Token Lifetimes
| Token | Lifetime | Storage |
|---|---|---|
| System Token | 7 days | /boot/freezeos/system_token.enc |
| Apps Token | 30 days | /boot/freezeos/apps_token.enc |
Expired tokens are still accepted for key extraction — only tampered (bad signature) tokens are rejected. This means a device can boot even if it hasn't checked in recently, as long as the token hasn't been tampered with.
PIN Unlock
When a user logs in at the LightDM screen, their PIN is used to derive the encryption key for personal data partitions.
How It Works
- User enters PIN at LightDM login
- PAM hook (
freezeos-data-unlock) intercepts the PIN - Key derived:
PBKDF2(PIN, SHA256(cert_DER) + salt, 600000, 64) - LUKS unlock attempted on User Storage, App Data, and Swap partitions
- On success, partitions are mounted and login proceeds
- On failure, login is denied
Salt
A 32-byte hex salt is generated during enrollment and stored at /boot/freezeos/data.salt. Combined with the certificate fingerprint, this ensures the derived key is unique per device.
Certificates
Each FreezeOS device has an RSA-4096 client certificate issued by the fleet CA during enrollment.
Certificate Usage
- mTLS Authentication — The client cert authenticates the device to the fleet server during checkins
- PIN Key Derivation — The certificate fingerprint (SHA-256 of DER) is used as part of the PBKDF2 salt
- Identity — The cert's CN contains the node ID
Certificate Renewal
Certificates are valid for 365 days. The freezeos-cert-renew service runs via systemd timer and renews certificates that expire within 2 days by contacting the fleet server's renew endpoint.
File Locations
/boot/freezeos/certs/client.crt # Device certificate /boot/freezeos/certs/client.key # Private key /boot/freezeos/certs/ca.crt # Fleet CA certificate
Admin Security Hardening
The FreezeOS admin portal and fleet API implement defense-in-depth security controls aligned with NIST 800-53 and DISA STIG requirements.
Credential Management
All database credentials and cryptographic keys are loaded from environment variables. No passwords are stored in source code.
- Environment file —
/etc/freezeos/fleet.env(mode 0640, owner:group tech:www-data) - PHP auto-loader — Config files auto-parse the env file via
putenv() - Flask systemd —
EnvironmentFile=/etc/freezeos/fleet.envin service unit - Python routes — Centralized
fleet/mysql_conn.pyreadsFLEET_MYSQL_*env vars
Security Headers
All HTTP responses include the following security headers:
X-Content-Type-Options: nosniff X-Frame-Options: DENY X-XSS-Protection: 1; mode=block Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=(), usb=() Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; frame-ancestors 'none' Strict-Transport-Security: max-age=31536000; includeSubDomains Cache-Control: no-store, no-cache, must-revalidate, private
Session cookies use Secure, HttpOnly, and SameSite=Strict flags.
Production Safeguards
- Fail-fast on dev keys — Flask refuses to start in production mode (
FLEET_DEBUG=0) if HMAC or master encryption keys are left at development defaults - 256-bit random keys — Token HMAC signing and LUKS key encryption use cryptographically random 256-bit keys
- No shell_exec — LDAP connection tests use native PHP LDAP functions instead of shell commands
- CSRF protection — All state-changing operations require a 256-bit CSRF token
- Rate limiting — Login: 5 attempts / 15-minute lockout. Auth API: 5 failures / 5-minute window
NIST 800-53 Control Mapping
| Control | Title | Implementation |
|---|---|---|
| AC-2 | Account Management | Admin user lifecycle, role assignment, deactivation |
| AC-3 | Access Enforcement | RBAC permission checks on every page and API endpoint |
| AC-6 | Least Privilege | 5 roles: viewer, operator, auditor, admin, super_admin |
| AU-2 | Audit Events | Login, logout, CRUD, role changes, MFA events, all admin actions |
| AU-3 | Content of Audit Records | Who, what, when, where (IP), detail, user agent |
| IA-2 | Identification and Authentication | Bcrypt password hashing + TOTP multi-factor authentication |
| IA-5 | Authenticator Management | Password complexity (8+ chars, upper, digit, special), MFA recovery codes |
| SC-8 | Transmission Confidentiality | HTTPS enforced via HSTS, secure session cookies |
| SC-12 | Cryptographic Key Establishment | AES-256-GCM for LUKS keys, HMAC-SHA256 for tokens, RSA-4096 for certificates |
| SC-28 | Protection of Information at Rest | MySQL TDE (InnoDB tablespace encryption), encrypted redo/undo/binlogs |
Role-Based Access Control
The admin portal implements granular RBAC with 5 roles, enforced on every page and API endpoint.
Roles
| Role | Level | Access |
|---|---|---|
| Viewer | 1 | Read-only: dashboard, devices, hardware catalog, wiki |
| Auditor | 2 | Read-only on everything + audit log access |
| Operator | 3 | Manage devices, groups, OUs, printers, issues, wiki |
| Admin | 4 | Everything except role management and security settings |
| Super Admin | 5 | Full access including role assignment, MFA enforcement, security settings |
Permission Matrix
Each action is mapped to a permission key (e.g., devices.manage) which lists allowed roles. Example permissions:
dashboard.view— All rolesdevices.manage— Operator, Admin, Super Adminpolicies.manage— Admin, Super Adminusers.roles— Super Admin onlyaudit.view— Auditor, Super Adminsecurity.manage— Super Admin only
Enforcement
Pages call require_permission('permission.name') after authentication. API endpoints call require_permission('permission.name', true) which returns HTTP 403 JSON instead of an HTML page. The sidebar navigation dynamically shows/hides links based on the current user's role.
Multi-Factor Authentication
FreezeOS supports TOTP-based MFA (RFC 6238) for admin portal access, meeting NIST 800-63B AAL2 requirements.
How It Works
- Admin navigates to MFA Settings in the sidebar
- Clicks Set Up Two-Factor Authentication
- Scans QR code with any authenticator app (Google Authenticator, Authy, 1Password, etc.)
- Enters the 6-digit code to verify setup
- Receives 8 one-time recovery codes (must be saved securely)
Login Flow with MFA
- Enter email + password (standard login)
- If MFA enabled: redirected to verification page
- Enter 6-digit TOTP code or a one-time recovery code
- Session established with
mfa_verified=trueflag
Technical Details
- Algorithm: HMAC-SHA1 with 30-second time step (RFC 6238 compliant)
- Secret: 20-byte random, stored encrypted in database
- Window: ±1 period tolerance for clock skew
- Recovery codes: 8 codes, 8-character hex, single-use
- MFA timeout: Verification must complete within 5 minutes of password entry
- Audit trail: All MFA events logged (setup, disable, recovery code use, failed attempts)
Audit Logging
Every admin action is recorded in an immutable audit log, meeting NIST 800-53 AU-2/AU-3/AU-12 controls.
What is Logged
| Category | Events |
|---|---|
| Authentication | login, logout, login_failed, login_rate_limited, login_sso |
| MFA | mfa_setup, mfa_disable, mfa_failed, mfa_recovery_used, mfa_recovery_regen |
| Devices | revoke, suspend, restore, move (OU), group add/remove, policy toggle |
| Policies | create, update, delete, assign, unassign, toggle |
| Organizations | member add/remove/promote/demote, policy toggle |
| Printers | create, update, delete, deploy, undeploy |
| Identity | provider change, LDAP test, Entra test |
| Users | account create, role change |
Audit Record Fields
id BIGINT Auto-increment (immutable) user_id INT Admin who performed the action username VARCHAR Username at time of action action VARCHAR Action verb (login, create, update, delete, revoke, etc.) target_type VARCHAR Entity type (node, policy, user, org, session, etc.) target_id VARCHAR Entity identifier (UUID, database ID) detail TEXT Human-readable description ip_address VARCHAR Source IP address user_agent VARCHAR Browser/client user agent string created_at DATETIME Timestamp (UTC)
Viewing the Audit Log
The audit log is accessible at System > Audit Log in the sidebar (requires Auditor or Super Admin role). It supports filtering by action, target type, username, date range, and free-text search.
Database Encryption at Rest
All database storage is encrypted using MySQL 8.0 Transparent Data Encryption (TDE), meeting NIST 800-53 SC-28.
What is Encrypted
- All 35 InnoDB tablespaces — Every table uses
ENCRYPTION='Y' - InnoDB redo logs —
innodb_redo_log_encrypt=ON - InnoDB undo logs —
innodb_undo_log_encrypt=ON - Binary logs —
binlog_encryption=ON - New tables —
default_table_encryption=ON(automatic)
Key Management
Encryption keys are managed by MySQL's keyring_file plugin. The master encryption key is stored in /var/lib/mysql-keyring/keyring (mode 0750, owned by mysql). Individual tablespace keys are encrypted by the master key and stored within the tablespace headers.
LUKS Keys (Application-Level)
In addition to database-level TDE, all LUKS encryption keys stored in the nodes table are encrypted with AES-256-GCM before database storage. The encryption master key is loaded from the FLEET_MASTER_KEY environment variable (256-bit random).
Enrollment
Device enrollment registers a new device with the fleet server, generates encryption keys, issues a client certificate, and provisions the device with tokens.
Enrollment Pipeline
- Boot the ISO on the target device
- The enrollment wizard runs hardware diagnostics
- User provides fleet server URL and credentials (or uses pre-configured URL)
- Device sends hardware profile to fleet server
- Fleet server generates LUKS keys, signs a client certificate, creates tokens
- Device receives tokens + certificate + node configuration
- Installer partitions the disk and installs the OS
- Device reboots and begins normal checkin cycle
Node Configuration
After enrollment, /boot/freezeos/node.json contains:
{
"node_id": "abc123...",
"fleet_url": "https://os.freeze2k.net",
"machine_serial": "SERIALNO",
"image_version": "2.9.86"
}
Device Checkin
Enrolled devices periodically check in with the fleet server to refresh tokens, report health data, and receive updates.
What Happens During Checkin
- Device POSTs to
/api/fleet/checkinwith node_id and optional health card - Server verifies the device exists and is not revoked/suspended
- Server issues fresh system and apps tokens
- Server returns merged policies for the device
- Device stores new tokens in
/boot/freezeos/
Checkin Triggers
- Boot — Every boot triggers a checkin during init
- Timer — Periodic checkin via systemd timer
- Manual — Can be triggered from the system info panel
Health Monitoring
FreezeOS includes a built-in health check system that scores device health from 0-100 across 17+ component tests.
Health Check Categories
- CPU — Temperature, frequency, load
- Memory — Usage, errors, swap pressure
- Storage — SMART data, disk usage, I/O performance
- GPU — Driver status, rendering tests
- Network — Connectivity, DNS resolution, fleet server reachability
- Battery — Capacity, cycle count, charge health
- USB — Controller status, device enumeration
Health cards are submitted with each checkin. The fleet portal displays health scores with color-coded badges (green >= 80, yellow >= 60, red < 60).
Policy Management
Organizations can create and assign policies to manage device configuration across their fleet.
Policy Categories
| Category | Settings |
|---|---|
| Date/Time | NTP enable/disable, timezone, custom NTP servers, RTC local time mode |
| Display | Wallpaper URL & style (stretched/centered/tiled/zoomed), lock wallpaper, DPMS enable, standby timeout |
| Proxy | Proxy mode (none/manual/auto), HTTP/HTTPS/FTP proxy, no-proxy bypass list, PAC URL |
| Security | Screen lock & delay, password min length/uppercase/digit, USB storage, SSH, firewall (UFW) |
| Power | Suspend on idle, lid close action, power button action, suspend when docked, CPU governor |
| Network | WiFi on/off, hotspot, custom DNS servers, DNS-over-TLS, require VPN, allowed SSIDs whitelist |
| Software | APT allowed, Flatpak allowed, blocked executables list, browser extensions, forced homepage |
| Updates | Auto-update enable, schedule (daily/weekly/monthly), auto-reboot after update, update channel |
| Restrictions | Terminal, settings panel, file manager, external drives, printing, camera, microphone |
| Custom Commands | Up to 3 shell commands, custom script URL, cron scheduling expression |
How Policies Work
- Admin creates a policy in the web portal and configures settings
- Policy is assigned to specific devices via the "Assign Devices" page
- During checkin, the device receives merged policies (higher priority wins)
- The
freezeos-policy-enforce.shscript applies settings idempotently - A systemd timer re-checks policies every 30 minutes
Policy Priority & Merging
Each policy has a priority number (0-999). When a device has multiple policies assigned, the fleet server merges them:
- Settings from higher priority policies override lower priority ones
- Settings not defined in any assigned policy use system defaults
- The merged result is a single flat JSON object delivered to the device
Enforcement Cycle
Policy enforcement runs on a continuous cycle:
- Timer fires — A systemd timer triggers
freezeos-policy-fetch.shevery 30 minutes - Fetch policies — The script calls
/api/fleet/policies?node_id={id}to get merged policies - Hash check — The fetched JSON is hashed (SHA-256) and compared against the last-applied hash
- Enforce if changed — If the hash differs (or no prior hash exists),
freezeos-policy-enforce.shapplies all settings idempotently - Store hash — The new hash is saved for future comparison
Enforcement also runs on every device boot (via checkin) and can be triggered manually.
Custom Commands
The Custom Commands category allows organizations to run arbitrary shell commands on managed devices. This is useful for org-specific configuration that doesn't fit into standard policy categories.
| Setting | Description |
|---|---|
| Custom Command 1-3 | Shell commands executed during each policy enforcement cycle |
| Custom Script URL | URL to a shell script that is downloaded and executed on enforcement |
| Custom Cron | Cron expression (e.g. */30 * * * *) for scheduling custom command execution independently of the enforcement cycle |
Custom commands run as root. Use with caution. Script URLs must be trusted — they are downloaded and executed with full system privileges.
OTA Updates
FreezeOS receives over-the-air system updates from the fleet server. Updates replace the entire squashfs system image on the inactive A/B slot.
Update Pipeline
- Device queries
/api/fleet/images/latestfor the newest version - If newer than current, downloads the squashfs image
- SHA-256 hash verified against server-provided hash
- Image written to the inactive system slot
- A/B state flipped to new slot
- Device reboots
- If boot fails 3 times, automatic rollback to previous slot
Update Channels
- stable — Production-tested releases
- beta — Pre-release testing
- nightly — Latest builds
Recovery Modes
FreezeOS provides multiple recovery options for when things go wrong.
| Mode | How to Access | Description |
|---|---|---|
| Network Recovery | GRUB menu or freezeos.recovery=1 | Downloads fresh system image from fleet server |
| Safe Mode | GRUB menu or freezeos.safemode=1 | Boots with tmpfs overlay, bypassing all user changes |
| Automatic Rollback | Automatic after 3 failed boots | Reverts to previous A/B slot |
| Manual Rollback | freezeos-system-update --rollback | Manually switch to previous slot |
Network Recovery
Network recovery re-provisions the device by downloading a fresh system image from the fleet server.
Process
- Select "FreezeOS Network Recovery" from the GRUB menu
- Init script detects
freezeos.recovery=1kernel parameter - Establishes network connectivity (Ethernet or WiFi)
- Contacts fleet server, performs checkin to get fresh tokens
- Downloads latest system image
- Writes to active system slot
- Reboots into recovered system
Safe Mode
Safe mode boots with a tmpfs (RAM-based) overlay instead of the persistent Apps partition overlay. This bypasses all user-installed packages and configuration changes.
When to Use
- A user-installed package breaks the system
- Configuration change prevents login
- Need to diagnose issues without user modifications
Changes made in safe mode are lost on reboot (they're in RAM only).
Factory Reset
Factory reset wipes the persistent overlay (Apps partition), restoring the device to the base squashfs image state.
Factory reset removes all user-installed packages, configuration changes, and overlay data. User personal data on the User Storage partition is not affected.
Desktop Environment
FreezeOS uses XFCE 4 with a custom "Tron" theme featuring cyan glow accents, dark backgrounds, and wireframe icons.
Included Applications
- FreezeOS Diagnostics — GTK3 hardware health check UI
- FreezeOS System Info — GTK3 system information panel
- FreezeOS Commander — Fleet management and diagnostics terminal
- System Update — OTA update GUI wizard
- Firefox — Web browser (policy-configurable)
- Thunar — File manager
- XFCE Terminal — Terminal emulator
Diagnostics Tools
FreezeOS includes built-in diagnostic tools for hardware testing and system monitoring.
FreezeOS Diagnostics
A GTK3 application accessible from XFCE Settings Manager that runs comprehensive hardware tests and generates a health score.
FreezeOS Commander
A terminal-based fleet management tool that provides:
- Device status and fleet server connectivity
- Network diagnostics (ping, DNS, fleet reachability)
- Manual checkin and token refresh
- System update management
- Log submission
Log Submission
Devices can submit diagnostic logs to the fleet server for remote debugging.
Usage
report_log # Submit all logs report_log kernel # Submit kernel logs only report_log network # Submit network logs only
Submitted logs appear in the web portal under "My Logs" and expire after 30 days. Organization accounts can view logs from all member devices.
Web Portal
The FreezeOS web portal at os.freeze2k.net provides fleet management through a browser.
Portal Pages
| Page | Access | Description |
|---|---|---|
| My Devices | All users | View, deauthorize, restore, delete devices |
| My Logs | All users | View submitted diagnostic logs |
| Account | All users | Profile info, password change |
| Organization | Org accounts | Add/remove members, manage roles |
| Policies | Org accounts | Create, edit, assign policies to devices |
| Admin | Admin accounts | Manage all users, orgs, devices, policies |
Account Types
FreezeOS has three account types, each with escalating levels of access and control over the fleet.
User (Individual)
- Enroll and manage own devices
- View own device health, logs, and status
- Change own password and account settings
- Submit and view own diagnostic logs
Organization
Everything a User can do, plus:
- Create an organization and invite members by email
- View all devices across the organization
- View aggregated logs from all member devices
- Create, edit, and assign policies to member devices
- Manage organization members (add, remove, promote)
Admin (Global)
Everything an Organization can do, plus:
- Manage all users, organizations, and devices system-wide
- Change any user's account type (user, org, admin)
- Suspend or delete any account
- View all logs across the entire fleet
- Create and manage global policies
- Manage system images and OTA updates
Permissions Matrix
| Action | User | Org | Admin |
|---|---|---|---|
| Enroll devices | ✓ | ✓ | ✓ |
| View own devices | ✓ | ✓ | ✓ |
| View own logs | ✓ | ✓ | ✓ |
| Manage own account | ✓ | ✓ | ✓ |
| Create organization | — | ✓ | ✓ |
| Add/remove members | — | ✓ | ✓ |
| View member devices | — | ✓ | ✓ |
| View member logs | — | ✓ | ✓ |
| Create/assign policies | — | ✓ | ✓ |
| Manage all users | — | — | ✓ |
| Change account types | — | — | ✓ |
| Suspend/delete accounts | — | — | ✓ |
| View all logs | — | — | ✓ |
| Manage system images | — | — | ✓ |
Organizations
Organization accounts can manage multiple users and their devices under a single umbrella.
Features
- Member Management — Add users by email, assign admin or member roles
- Aggregated Logs — View logs from all member devices with member filter
- Policy Management — Create policies and assign to any member's device
- Device Visibility — See all devices across the organization
Member Roles
| Role | Description |
|---|---|
| Owner | The organization account itself. Full control over the org, its members, policies, and all member devices. Cannot be removed. |
| Admin | Can manage other members (promote/demote/remove), create and assign policies, view all devices and logs |
| Member | Devices are visible to the org. Policies can be applied to their devices. Can view own devices and logs only. |
Organization Scope
An organization has visibility and control over member devices as follows:
- Device visibility — The org can see all devices enrolled by its members, including health scores, last checkin time, and system version
- Log access — The org can view diagnostic logs submitted by any member device, with member-level filtering
- Policy assignment — The org can assign policies to any member's device. Policies are enforced automatically on the device.
- Device actions — The org can deauthorize, restore, or trigger updates on member devices
Policy Assignment Flow
- Org admin creates a policy in the portal with desired settings
- Org admin navigates to the policy's "Assign Devices" page
- Select one or more member devices to assign the policy to
- On the next device checkin, the fleet server merges all assigned policies (by priority) and returns the result
- The device's
freezeos-policy-enforce.shapplies the merged settings
API Reference
The fleet server exposes a REST API for device management.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/fleet/enroll | Enroll a new device |
| POST | /api/fleet/login-enroll | Enroll with existing account |
| POST | /api/fleet/checkin | Device checkin, token refresh |
| GET | /api/fleet/images/latest | Get latest system image metadata |
| GET | /api/fleet/images/download/{version} | Download system image |
| GET | /api/fleet/policies?node_id={id} | Get merged policies for a device |
| POST | /api/fleet/update-report | Report update status |
| POST | /api/fleet/submit-log | Submit diagnostic logs |
| GET | /api/fleet/recovery/latest | Get recovery image metadata |
| GET | /api/fleet/scripts/latest | Get latest scripts package |
| POST | /api/fleet/re-provision | Re-provision a device |
| POST | /api/fleet/deauth | Deauthorize a device |
| GET | /health | Server health check |