| Filename | Latest commit message | Latest commit date |
|---|---|---|
| control@0f7ddeae55 | ||
| debian | ||
| docs | ||
| kiosk@5f4d221ffa | ||
| .env.example | ||
| .gitignore | ||
| .gitmodules | ||
| LICENSE | ||
| README.md | ||
KioskOS
A minimal Linux distribution that boots directly into a web browser kiosk mode, managed centrally via a Django control server. Supports x86_64 (PCs, VMs) and ARM64 (Raspberry Pi 4/5) platforms. Ships as a bootable ISO built from Debian Bookworm.
[Download] <> [License] <> [AI Involvement Disclosure]
Features
- Bootable ISO built from Debian Bookworm via Docker + debootstrap + xorriso
- Full-screen Chromium kiosk mode — XFCE4 autostart launches Chromium in kiosk mode
- Direct X session — autologin on tty1 → startx → XFCE4 (no display manager)
- Centralized management via Django control server with REST API
- Zero-touch deployment — pre-load
config.jsonon USB to skip setup wizard - WiFi/LAN configuration via interactive setup wizard on first boot (or pre-configured)
- Remote configuration updates — change target URL, refresh intervals, and more
- System monitoring — uptime, memory, and disk usage reported to the control server
- Multi-architecture support — x86_64 (PCs, VMs) and ARM64 (Raspberry Pi 4/5)
- Hybrid BIOS + UEFI boot (amd64) / UEFI boot (aarch64)
- Docker-based control server deployment with PostgreSQL and Nginx
- REST API for full kiosk lifecycle management
- Administrator-issued enrollment — a one-time code binds each device to a kiosk an admin created (2.0.0; devices no longer self-register)
- Install option — Calamares installer included on the ISO for permanent installation
Architecture Overview
KioskOS consists of three main components that work together:
| Component | Directory | Description |
|---|---|---|
| Control Server | control/ |
Django + Django REST Framework API server |
| Kiosk Agent | kiosk/ |
Python agent running on each kiosk device |
| Build System | debian/ |
Debian-based bootable ISO builder |
For a detailed architecture diagram and data flow, see docs/ARCHITECTURE.md.
Quick Start
1. Control Server Setup
# Clone the repository
git clone https://github.com/your-org/kioskOS.git
cd kioskOS
# Configure environment
cp .env.example control/.env
# Edit control/.env with your settings
# Start the server stack (PostgreSQL + Django + Nginx)
cd control
docker-compose up -d
# Create an admin user
docker-compose exec server python manage.py createsuperuser
The control server will be available at http://localhost (Nginx on port 80).
2. Building the Kiosk ISO
Prerequisites: Docker Desktop (macOS/Linux) or Docker Engine (Linux), ~10 GB free disk, Make
cd debian
# Build x86_64 ISO (PCs, VMs)
make amd64
# Build ARM64 ISO (Raspberry Pi 4/5)
make aarch64
Output ISO: debian/output/kioskos-amd64.iso
Write ISO to USB:
# Linux
sudo dd if=output/kioskos-amd64.iso of=/dev/sdX bs=4M status=progress && sync
# macOS
diskutil list
diskutil unmountDisk /dev/diskN
sudo dd if=output/kioskos-amd64.iso of=/dev/rdiskN bs=4m
3. First Boot
- Write the ISO to a USB drive and boot from it.
- Two boot options are available: "Run KioskOS (Live)" and "Install KioskOS" (via Calamares).
- On live boot, the setup wizard appears automatically.
- Follow the dialog-based TUI to configure:
- Network — WiFi SSID/passphrase or LAN
- Server URL — address of your control server
- Enrollment code — the one-time code an administrator issued for this kiosk
- Target URL — the webpage to display in kiosk mode
- The device redeems the code, receives its token, and opens the browser in full-screen kiosk mode.
Project Structure
kioskOS/
├── control/ # Django control server (API + admin)
│ ├── api/ # REST API app (models, views, serializers)
│ ├── kioskos/ # Django project settings
│ ├── nginx/ # Nginx reverse-proxy config
│ ├── Dockerfile # Server container image
│ └── docker-compose.yml
├── kiosk/ # Kiosk agent + setup scripts
│ ├── agent/ # Python agent (check-in, config, display control)
│ └── setup/ # First-boot setup wizard (dialog-based TUI)
├── debian/ # Debian-based OS build system (primary)
│ ├── docker/ # Docker build environments (amd64, aarch64)
│ ├── scripts/ # Provisioning, ISO creation, build orchestration
│ ├── configs/ # GRUB config, package list
│ ├── overlay/ # Root filesystem overlay
│ └── Makefile # Build targets (amd64, aarch64, all)
├── docs/ # Documentation
└── README.md
Control Server
API Endpoints
All API endpoints are prefixed with /api/v1/.
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/api/v1/register/ |
Enrollment code | Redeem a one-time code for a device token |
POST |
/api/v1/browser-grant/ |
Token | Mint a single-use URL that gives the browser a device session |
POST |
/api/v1/kiosks/{uid}/enrollment-code/ |
Admin | Issue a fresh one-time enrollment code |
POST |
/api/v1/checkin/ |
Kiosk Token | Kiosk periodic check-in with system stats |
GET |
/api/v1/config/ |
Kiosk Token | Retrieve current kiosk configuration |
GET |
/api/v1/kiosks/ |
Admin | List all registered kiosks |
GET |
/api/v1/kiosks/<uid>/ |
Admin | Retrieve kiosk details |
PATCH |
/api/v1/kiosks/<uid>/ |
Admin | Update kiosk settings |
GET |
/api/v1/kiosks/<uid>/events/ |
Admin | Retrieve kiosk event history |
Docker Deployment
The control server is deployed with Docker Compose (PostgreSQL + Gunicorn + Nginx):
cd control
cp .env.example .env # Configure environment
docker-compose up -d # Start all services
docker-compose exec server python manage.py createsuperuser # Create admin
The admin panel is available at http://localhost/admin/.
Building Kiosk Images
Prerequisites
- Docker Desktop (macOS/Linux) or Docker Engine (Linux)
- ~10 GB free disk space
- Make
Build Commands
cd debian
# Build x86_64 ISO (PCs, VMs) — hybrid BIOS + UEFI boot
make amd64
# Build ARM64 ISO (Raspberry Pi 4/5) — UEFI boot
make aarch64
# Clean build artifacts
make clean
How It Works
The build pipeline runs entirely inside Docker containers, so it works on macOS and Linux without native build dependencies. A build container is launched with the appropriate architecture (native for amd64, QEMU-emulated for aarch64), then the base system is bootstrapped via debootstrap. The rootfs is provisioned with kiosk packages and overlay files via chroot, packaged into a squashfs, and assembled into a bootable ISO with xorriso.
Output
debian/output/kioskos-amd64.iso— x86_64 bootable ISO (hybrid BIOS + UEFI)debian/output/kioskos-aarch64.iso— ARM64 bootable ISO (UEFI)
Boot Options
The ISO provides two boot options via GRUB:
- Run KioskOS (Live) — Boot directly into the live kiosk environment
- Install KioskOS — Launch the Calamares graphical installer for permanent installation
Write ISO to USB
# Linux
sudo dd if=output/kioskos-amd64.iso of=/dev/sdX bs=4M status=progress && sync
# macOS
diskutil list
diskutil unmountDisk /dev/diskN
sudo dd if=output/kioskos-amd64.iso of=/dev/rdiskN bs=4m
Desktop / Display Stack
KioskOS uses a direct X session with no display manager:
- Autologin — The
kioskuser is automatically logged in on tty1 via a systemd getty override - X launch —
.bash_profiledetects VT1 and runsexec startx - XFCE4 session —
.xinitrcdisables screen blanking and runsexec startxfce4 - Kiosk browser — XFCE4 autostart launches Chromium in full-screen kiosk mode
LightDM is masked and not used.
Kiosk Setup
First-Boot Setup Wizard
On first boot, the kiosk launches a dialog-based TUI setup wizard that guides you through:
- Network configuration — Connect to WiFi (SSID + passphrase) or use wired LAN
- Server URL — Enter the address of your control server (e.g.,
http://192.168.1.100) - Enrollment code — The one-time code for this kiosk, e.g.
ABCD-EFGH-JKLM. Dashes and letter case are ignored. - Target URL — The webpage to display in kiosk mode (e.g.,
https://example.com/display)
Once complete, the device redeems the code with the control server and launches Chromium in full-screen kiosk mode.
Getting an Enrollment Code
Since 2.0.0 a device cannot register itself. Before setting up a device:
- In the control server, create the kiosk (name it after where it will live).
- The server shows a one-time code once — write it down or copy it.
- Type it into the setup wizard on the device.
Codes are single-use and expire after seven days. If one is lost or expires, issue a new one from the kiosk's row; that does not disturb any device already enrolled against it. To move a kiosk to replacement hardware, issue a fresh code and set up the new device — then regenerate the token to cut the old one off.
Zero-Touch Deployment (Pre-loaded Config)
For bulk deployments, you can skip the setup wizard entirely by pre-loading a
config.json file onto the USB drive before booting the kiosk.
How It Works
- The ISO includes a small FAT32 partition labeled
KIOSKOS-CONFIG - On first boot, the
kioskos-preloadservice searches forconfig.jsonon:- The
KIOSKOS-CONFIGpartition (recommended) /boot/config.jsonor/boot/efi/config.json(boot/EFI partition)/config.json(root filesystem)
- The
- If a valid config is found, it is copied to
/etc/kioskos/config.json, network settings are applied, and the setup wizard is skipped.
Preparing a USB Drive
The config partition works with the ISO image. A FAT32 config partition is
automatically included during the build — just burn the ISO and drop
config.json onto the partition.
Manual (any OS — macOS, Windows, Linux):
- Burn the KioskOS ISO to the USB drive
- The USB will show a small FAT32 volume named
KIOSKOS-CONFIG- On macOS: it appears in Finder as a removable drive
- On Windows: it appears in Explorer with its label
- On Linux: it auto-mounts or use
udisksctl mount -b /dev/sdX3
- Copy your
config.jsonto the root of that partition - Eject / unmount and boot the kiosk
Config File Format
The config.json must contain at least server_url, enrollment_code and
target_url:
{
"server_url": "https://control.example.com",
"enrollment_code": "ABCD-EFGH-JKLM",
"target_url": "https://display.example.com",
"refresh_interval": 300,
"checkin_interval": 60,
"network": {
"type": "wifi",
"wifi_ssid": "MyNetwork",
"wifi_password": "MyPassword"
}
}
Network type can be dhcp, wifi, or static. For static IP, include
static_ip (with CIDR), static_gateway, and static_dns in the network object.
Because enrollment codes are single-use, zero-touch deployment needs one code
per device — a shared config.json will enroll the first device to boot and
be rejected by the rest. The file also carries a credential: keep the USB drive
with the same care as the device, and note that /etc/kioskos/config.json is
written 0600 on the kiosk.
Re-Running Setup
To reconfigure a kiosk, SSH into the device (or connect a keyboard) and run:
sudo /opt/kioskos/setup/setup.sh
To force reconfiguration, remove the setup marker first:
sudo rm /etc/kioskos/.setup-complete
sudo systemctl restart kioskos-setup.service
Development
Running the Control Server Locally
cd control
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver
The development server will be available at http://localhost:8000.
Running Tests
cd control
python manage.py test
Configuration
- Control Server: Copy
.env.exampletocontrol/.envand adjust values for your environment (database, secret key, CORS, etc.). - Kiosk Agent: See
kiosk/config.json.examplefor the agent configuration format.
AI Involvement Disclosure
This project uses Kilocode and GLM-5 by Z.ai as part of the dev chain. All code generated by GLM-5 was manually reviewed by a human before deployment.
Documentation is still scrappy, AI generated in some places, and needs some review before considering it stable as well.
DO YOUR DUE DILIGENCE!!!! Validate this codebase before blindly trusting it with your production systems.
License
This project is licensed under the MIT License. See LICENSE for details.