Skip to content

User guide ​

This is the day-to-day reference for using Airlock. For first-time installation see Installation; for release notes see the Changelog.

Overview ​

Airlock exposes USB storage (thumb drives, SD-in-USB-reader, external SSD) plugged into a Raspberry Pi to your local network. The Pi does the mounting; every client uses either:

  • The web UI at http://<host>.local/ — the same set of tools this guide covers.
  • SMB at smb://<host>.local/<label> — normal file-manager access from macOS Finder, Windows Explorer, Linux Files, etc.

Everything is guest-access by design — the appliance trusts your LAN. See the security posture section below for the honest scope of what that means.

Accessing airlock ​

From the web UI ​

Open http://<host>.local/ in any browser on the same network. If mDNS is filtered on your network (rare at home, common on corporate Wi-Fi), use the Pi's IP directly.

The UI has two tabs:

  • Mounts — what's currently shared. Day-to-day browsing.
  • Devices — physical devices attached. Everything destructive lives here.

From macOS Finder ​

⌘K → smb://<host>.local → Connect As: Guest. Or from the CLI:

sh
mount_smbfs //guest@<host>.local/<share> /Volumes/<share>

Empty password — just press return. If Finder ever asks for credentials, you selected "Registered User" by mistake; back out and pick Guest.

From Windows Explorer ​

Type \\<host>\<share> into Explorer's address bar. Modern Windows disables anonymous / guest SMB by default; if it prompts and no credential works you need to enable insecure guest logons:

Group Policy → Computer → Administrative Templates → Network →
Lanman Workstation → "Enable insecure guest logons" → Enabled

If you can't change GPO, use the web UI instead — HTTP has no such lockdown.

From Linux ​

Nautilus / Dolphin: sidebar → Other Locations → smb://<host>.local/. CLI:

sh
smbclient -N //<host>.local/<share>

The Mounts tab ​

Each row is a partition that is currently mounted and shared.

ElementWhat it does
Drive name (linked)Click to open the file browser at that share
Filesystem · sizeRead-only info
smb://host/share (linked)Click to open your OS's file manager on that share (works on macOS/Linux/Firefox; Chrome/Edge may prompt or block on Windows)
Copy buttonCopies the platform-appropriate path — \\host\share on Windows, smb://host/share elsewhere
EjectUnmounts every partition of the same physical device (safe to yank after it disappears)
Eject all (top)Same, but for every mounted drive

Ejecting withdraws the SMB share first, then unmounts. Client sessions see the share disappear and can reconnect once you (re)plug the drive. If a file on the drive is still open — an SMB client mid-copy, a download in progress — the unmount fails with a busy error and the drive stays mounted (Airlock never lazy-unmounts, which would report success while data is still in flight). Finish or cancel the transfer and eject again.

The Devices tab ​

Every USB-attached block device shows up here, whether mounted or not. Rows show the vendor / model / serial, size, partition-table type, and transport (always USB).

Device-level actions ​

ButtonEffect
EjectUnmount every mounted partition of this device
Format…Wipe partition table, create a fresh single-partition FS
Flash…Overwrite the whole device with an image (.img / .img.xz / .img.gz)
Dump…Download the whole device as a disk image, compressed on the fly

Partition rows (nested under each device) ​

Every partition — mounted or not — appears as a nested row with its kernel name (sdb1), filesystem, size, and label. Depending on state, per-partition actions appear:

ButtonAppears whenEffect
MountPartition has a supported FS but isn't currently mounted by airlockTriggers a mount so the partition becomes a share
RenameFS is FAT / exFAT / NTFS / ext2/3/4 and drive is writableChange the volume label
CheckFS has a fsck tool we knowRun a filesystem consistency check

Partitions with unsupported filesystems (UFS, HFS+ RW, LUKS, etc.) show up with their metadata but no per-partition actions.

File browser ​

Open a share by clicking its name in the Mounts tab, or by navigating to http://<host>.local/drives/<share>/.

  • Breadcrumbs at the top for the current path.
  • Directories are listed first, then files, both alphabetical.
  • Click a directory name to descend, breadcrumbs to jump up, or the browser's Back button.

Downloading ​

Click any file to download it. Each row also has a Download button (same effect). Big files stream — no client-side buffer.

Uploading ​

The toolbar has:

  • Upload files — pick individual files
  • Upload folder — pick a whole folder (Chrome / Firefox / Edge / Safari all support this)
  • Drag-and-drop — either files or folders anywhere on the file list. Folders are walked recursively; the directory tree on the drive matches what you dropped.

Uploads run one request per file so a hiccup on one file doesn't abort the batch. The bottom-right progress card has:

  • Aggregate progress bar and current-file counter (Uploading 3 of 12)
  • A Details toggle showing every file with its own progress: ○ queued, ↑ 45 % (in flight), ✓ done, ✗ error
  • Auto-opens on the first failure so you see what broke; auto-hides after successful completion.

Rename / delete / new folder ​

  • Rename on any row: modal with a text input. Applies immediately.
  • Delete on any row: confirm() dialog first (file or whole folder).
  • New folder in the toolbar: modal with a name input; created at the current path.

Read-only drives (write-protect switch, iso9660, hybrid ISOs) hide the upload / rename / delete / mkdir actions and show a banner at the top of the browser explaining why.

Formatting a drive ​

Destructive — erases every partition on the target device.

Devices tab → Format…. The modal shows:

  • The target device and its total size
  • Every partition on the device with its label + FS + size (so you know exactly what disappears)
  • Filesystem picker: FAT32, exFAT, NTFS, or ext4 — auto-selected by size (FAT32 <32 GB, exFAT ≥32 GB)
  • New volume label (optional)
  • Type-to-confirm — must type the drive's current label, or the word FORMAT if the drive is unlabeled

Progress is streamed live from the daemon:

unmount → wipe → partition → rescan → mkfs → done

When done the modal closes; the fresh partition shows up as a new share on the Mounts tab within a couple of seconds.

Safety guards:

  • Only USB-attached devices can be targeted — the Pi's own boot SD can never appear here, and neither can a USB disk the OS itself runs from (anything backing /, /boot/firmware or swap).
  • One operation per device at a time: a second format / flash / dump / fsck on the same device is refused as busy.
  • Refused if any partition is currently marked read-only (write-protect switch tripped, etc.).
  • During the format the daemon quarantines the target, so a race where it tries to auto-mount the fresh partition mid-mkfs can't happen.

Renaming a volume ​

Devices tab → per-partition Rename. Modal has a text input with the correct max length for the filesystem (11 for FAT32, 15 for exFAT, 32 for NTFS, 16 for ext*).

Under the hood: the partition is unmounted, fatlabel / exfatlabel / ntfslabel / e2label runs, then udev re-fires so the daemon re-mounts under the new label. SMB clients need to reconnect using the new share name.

Mounting an unmounted partition ​

Devices tab → per-partition Mount. Fires udevadm trigger --action=add for that partition; the daemon's normal event handler picks it up.

Useful when:

  • You ejected a partition earlier and want it back without unplugging.
  • A hybrid layout means one partition was skipped (e.g. the ISO parent claimed the whole disk).
  • You just formatted and the automatic re-mount didn't fire for some reason.

Running fsck ​

Devices tab → per-partition Check. Modal offers:

  • Check only — read-only pass, no changes (-n for e2fsck / fsck.vfat / fsck.exfat; --no-action for ntfsfix)
  • Repair — safe auto-fix (-p preen for e2fsck; -a for fsck.vfat; -y for fsck.exfat / ntfsfix)

The panel below shows the tool's stdout / stderr live as it runs. Exit codes are interpreted:

CodeMeaning
0Clean
1–2Errors corrected
4Errors remain — try Repair mode
≥8Tool failure

Caveats per filesystem:

  • NTFS: ntfsfix is not a full chkdsk — it fixes only a few common issues. For deep repair, run chkdsk from Windows.
  • HFS+: fsck.hfsplus is check-only in Airlock — no repair mode.
  • exFAT: modern fsck.exfat (from exfatprogs) supports both check and repair. Older versions may not.

Backing up: dump a device to an image ​

Devices tab → Dump…. Choose compression:

  • xz (default) — best ratio, fully-empty regions compress massively. A 32 GB SD with 500 MB of data typically produces a 100–200 MB .img.xz. Multi-threaded (-T 0) so all cores help.
  • gzip — faster, decent ratio.
  • none — raw .img. Fastest, biggest file.

The browser starts a normal download. Filename is auto-generated from the partition label + date:

airlock-<label>-<yyyy-mm-dd>.img[.xz|.gz]

Read-only operation — Airlock calls sync() before opening /dev/<parent> for read but does not unmount. SMB clients keep their sessions.

For a bit-perfect dump (e.g. forensics or a card you plan to restore via dd), eject the drive first, then dump, then plug back in. Otherwise fs-buffered writes in flight during the dump could produce a slightly-inconsistent snapshot.

Flashing an OS image to a drive ​

Destructive — overwrites the whole device.

Devices tab → Flash…. Pick an image file:

  • .img — raw, no decompression
  • .img.xz — decompressed on the Pi via xz -dc
  • .img.gz — decompressed via stdlib gzip
  • .zip — not supported yet; extract locally first

Airlock detects compression from the filename. The dialog shows the target device, the picked file, its size, and a warning if a raw image is bigger than the target.

Type the confirmation word (drive label, or FLASH for unlabeled media) to enable the Flash button.

What happens during flash ​

  1. Upload streams over HTTP from browser → server
  2. Server pipes: request body → xz -dc / gzip.Reader / passthrough → /dev/<parent> in 4 MB chunks
  3. Progress bar tracks the higher of (upload %, bytes written / device size)
  4. Once the write finishes: sync, partprobe, udevadm trigger
  5. The daemon picks up any new partitions and remounts them as shares

Zero intermediate storage — a 3 GB Pi OS image never lands on the Pi's boot SD, only on the target USB drive.

Progress display ​

Two counters appear during flash:

  • uploaded — bytes the browser has sent (still compressed for .xz)
  • written — bytes actually landed on the target device (raw, post-decompress)

For .img.xz uploads, the "written" number will typically be 3–5× the "uploaded" one because Pi OS images decompress massively. This is normal.

Safety guards ​

  • Only USB devices can be targeted (never the Pi's own SD, nor a USB disk the OS boots from)
  • Refused if any partition on the device is read-only
  • Refused if the raw (uncompressed) upload is bigger than the target
  • Device is quarantined during the flash so partial partition tables don't fire race-conditions on the daemon

Physical eject button + LED (optional) ​

If you wired the reference hardware from the install guide:

  • Button on GPIO 17 (physical pin 11): pressing it triggers Eject all — every mounted drive is unmounted.
  • LED on GPIO 27 (physical pin 13):
LED stateMeaning
offNo drives mounted — safe to yank anything
solidDrives mounted, nothing busy — safe to press the button
fast blink (~4 Hz)Eject / format / flash / dump in progress — do NOT yank

The daemon runs fine without any GPIO wiring. If the button and LED aren't connected, the physical eject path just doesn't exist; the web UI's eject still works.

Security posture ​

The whole point of the appliance is to isolate untrusted USB media from your primary machine. In practice:

  • Every mount uses nosuid,nodev,noexec — no binary on the drive can execute, gain privileges, or open a device node on the Pi. And it never runs on your laptop directly.
  • Airlock never auto-runs anything from the media.
  • The disk the OS runs from is off-limits: the daemon refuses to list, format, flash, dump or mount anything backing /, /boot/firmware or swap.
  • The web UI has no login, so it rejects cross-site POST / DELETE requests (a web page you visit can't format a drive) and requests with an unexpected Host header (DNS rebinding). SMB is limited to LAN address ranges.
  • BadUSB / USB Rubber Ducky devices (a stick that pretends to be a keyboard) plug into a headless Pi with no interactive session to type into. On your laptop the same device would type into whatever window has focus.
  • Kernel filesystem-parser CVEs (rare but real for FAT / NTFS / exFAT / HFS+) land on the Pi, not on the trusted machine.

You still have to be careful about file content. A booby-trapped PDF or macro-laden Office document is Airlock's cargo, not its concern. Endpoint hygiene (AV, Gatekeeper on macOS, SmartScreen on Windows, whatever's on your machine) still matters.

For the full list, and the two optional tightening layers — USB device-class blocklist and read-only root — see the installation guide.

Troubleshooting ​

airlock.local doesn't resolve ​

Confirm Avahi is running: systemctl status avahi-daemon on the Pi. If your network filters mDNS (some corporate Wi-Fi does), use the IP directly: http://192.168.x.y/. Find it with hostname -I on the Pi, or in your router's DHCP client list. (The daemon's startup log only shows the listen address, addr=":80", not the IP.)

Web UI says 421 or 403 ​

  • 421 unrecognised Host header — you reached the Pi via a DNS name that isn't .local / .lan / .home.arpa / … or an IP. Add it to AIRLOCK_ALLOWED_HOSTS (see the installation guide).
  • 403 cross-origin request refused — the browser flagged the request as coming from another site. Open the UI directly at http://<host>.local/ and retry.

Web UI works but SMB shows no shares ​

  • Check sudo testparm -s on the Pi for Samba syntax errors.
  • Confirm smbd is running: systemctl status smbd.
  • On Windows, the "insecure guest logons" GPO must be enabled (Microsoft KB4046019 — this is a Windows client-side setting, not something Airlock controls).
  • On macOS, make sure you selected Connect As Guest, not Registered User.

USB drive not appearing after plug-in ​

  • Verify with lsblk on the Pi that the kernel sees it.
  • If it's a whole-disk filesystem or has partitions we don't auto-mount (UFS, LUKS, etc.), it will still show up on the Devices tab — just with no per-partition actions. Format or Flash still work at the device level.
  • If it's a native SD in the Pi's built-in slot, we intentionally don't touch it — that's the boot media.

Flash or format hangs ​

  • Client-side hangs are usually the browser timing out. Check the daemon log: journalctl -u airlockd -f.
  • If the device gets physically unplugged mid-flash you'll see input/output error from the kernel. The daemon lifts the quarantine and reports "flash failed". Re-plug and retry.
  • xz decompression can take a while after the upload finishes — the progress bar stays at 100 % for the upload phase while the server drains its buffer. That's expected.

Where to look for logs ​

sh
journalctl -u airlockd -f            # daemon
journalctl -u smbd -f                # Samba
journalctl -u avahi-daemon -f        # mDNS / discovery

For faster boot / less-noisy log volume, see the installation guide.