Skip to content
NAILS on GitHub
These docs describe NAILS 0.3, published so far as the release candidate v0.3.0-rc.3. They do not apply to v0.2.0, the latest stable release. Download and verify NAILS 0.3

Your first session

This page walks through one session. It assumes the decoy is prepared, the hidden volume exists and NAILS is installed on it, for example from Tails. The examples use the hidden volume at /mnt/data.

Terminal window
# On the decoy, in a shell with history off
set +o history
# unlock and mount the hidden volume at /mnt/data, then:
sudo /mnt/data/nails check
sudo /mnt/data/nails activate
# Inside the hidden session, when you are done
sudo /mnt/data/nails verify --deep
sudo /mnt/data/nails deactivate --poweroff

Type as little as possible on the decoy. Use NAILS there only for init once, the steps below, and recover or reset-upper when you need them. Do not edit the NAILS configuration there, and do not name the hidden volume, its mapping, its mount point or the tool in any other command.

  1. Turn shell history off for this terminal.

    Terminal window
    set +o history
  2. Unlock and mount the hidden volume with the commands for your backend.

  3. Check readiness. check runs the same pre-flight checks as activation and changes nothing.

    Terminal window
    sudo /mnt/data/nails check

    A failing check prints a hint that names the fix. The platform row names the host NAILS detected. It warns on a Debian or Ubuntu release that NAILS has not been tested on, and fails on a host that activation refuses.

    Also review what check reports about the session: which decoy filesystems are overlaid, bound read-only or masked, and which inherited decoy state needs review. It lists the autostart entries and services that you or other software added, lingering, autologin, and the clients on a list of known trace writers, such as sync and messaging clients.

  4. Activate.

    Terminal window
    sudo /mnt/data/nails activate

    Activation asks for confirmation. Without a configuration file, it says before the prompt that it uses the built-in defaults. It then writes a read-only baseline scan of the decoy to the hidden volume, runs the pre-flight checks, prepares the overlay and, on NixOS, builds the hidden system. The first NixOS activation also copies the hidden system’s whole closure onto the hidden volume: several GB for a desktop, and minutes on a slow or encrypted backend. As its last step, activation kills the decoy’s interactive shells, so none of them writes the activation command to a history file, and soft-reboots.

    Ctrl+C cancels the activation at any point before the switch. It stops at the next step, removes everything it built and exits with status 130. A step that runs a program to its end, such as the activation of the hidden NixOS system, finishes first.

  5. Log in again. Your terminal closes and the screen shows a text console for a few seconds. Then the hidden session starts at its own login screen. NAILS logs nobody in, but a display manager set to log an account in automatically logs it in again, as at boot. See Autologin.

The hidden volume is at the same path as on the decoy. Work as usual. Changes land in the upper layer on the hidden volume. A disk you mount yourself is the exception, as described below. sudo /mnt/data/nails status shows the session and the space left on the hidden volume.

  • NixOS. nixos-rebuild test applies a change to the running session. Give it the target that activation builds:

    • Without a hidden flake or nixos_flake, run sudo nixos-rebuild test. Here /etc/nixos is the hidden configuration.
    • With a hidden flake, run sudo nixos-rebuild test --flake /mnt/data/nixos#<host> --impure, where <host> is the decoy’s hostname, not the hidden name that the network-identity module sets. For a flake named with nixos_flake, pass that reference instead.

    On a decoy whose /etc/nixos is a flake, a plain nixos-rebuild test builds that decoy flake. It fails, or it puts the decoy’s own system into the session without the hidden module, so always name the hidden flake there. Never use switch or boot, which try to install a bootloader into the read-only ESP and fail. The next activation builds the hidden system again from /mnt/data/config/nixos/ or your flake, so keep that source in step with what you test.

  • Debian and Ubuntu. Use apt, edits in /etc and systemctl enable as on any system. Every change lands in the upper layer and stays the hidden configuration from then on.

Activation refuses to build a decoy’s own /etc/nixos flake, also with --no-preflight, because that build would leave out the hidden module and the hidden hardware configuration. Such a decoy needs a self-contained hidden flake in /mnt/data/nixos. Write it in a hidden session:

  1. On the decoy, check and enter a session with the decoy’s own system.

    Terminal window
    sudo /mnt/data/nails check --overlay-only
    sudo /mnt/data/nails activate --overlay-only
  2. In that session, /etc/nixos shows the decoy’s configuration beside the hidden hardware configuration. Copy what the hidden system needs into /mnt/data/nixos. Write a flake.nix there that builds this machine’s hostname from those copies and imports the hidden module /mnt/data/config/nixos/configuration.nix by its absolute path.

  3. Lock it with nix flake lock in the same session. Activation never updates flake.lock, so it must exist.

  4. Build it there before you rely on it, with the decoy’s hostname as <host>. --impure lets the flake import the hidden module by its absolute path.

    Terminal window
    sudo nixos-rebuild build --flake /mnt/data/nixos#<host> --impure
  5. End the session with deactivate. The next activation builds the hidden flake.

Never write or lock the flake on the decoy, where the editor’s files, root’s Nix cache and the nixpkgs the lock fetches would land on the decoy disk. Keep it self-contained. A flake that imports the decoy’s /etc/nixos/configuration.nix reads the decoy’s own files at every activation, which updates their access times on a relatime decoy, and the ./hardware-configuration.nix it then imports is the decoy’s, swap included.

The overlay copies a decoy file to the hidden volume in full the first time you change it. The first write to a large file, such as a browser profile or a VM image, can stall on a slow or encrypted backend. The upper layer only grows.

  • Watch free space with df -h /mnt/data. nails check fails when it drops below minimum_space_mb.
  • Clear caches inside the session. On NixOS, run nix-collect-garbage -d there.
  • A file copied up earlier hides later decoy updates of that file. To drop a path’s hidden copy, run sudo /mnt/data/nails reset-upper <PATH> on the decoy, with the hidden volume mounted. It lists what it deletes and asks first.

Accounts, sync clients and network identity

Section titled “Accounts, sync clients and network identity”
  • By default the hidden session runs as the decoy user, in the decoy home. The decoy’s browser profiles, keys and signed-in accounts are live there. Sign in to the hidden session’s own accounts for sensitive work, or use the fresh-home persona.
  • Do not start the decoy’s sync, cloud, mail or messaging clients for sensitive work. What they send stays on the remote side, and a decoy client can pull it back onto the decoy disk after the session. Mask them inside the hidden session, for example with systemctl --user mask syncthing.service.
  • The hidden session keeps the decoy’s machine ID, hostname, MAC addresses and network profiles, including VPN autoconnect. NAILS ships optional snippets that give the hidden session its own MAC addresses and hostname. The way back does not undo them, so end a session that used them with deactivate --poweroff or emergency --poweroff.

A display manager set to log an account in automatically does so after every switch, as at boot. After activate the hidden desktop then opens without a password, and after deactivate or emergency the decoy’s desktop does. NAILS logs nobody in and leaves the setting alone. check lists an autologin it finds in the decoy’s GDM, LightDM or SDDM configuration.

To keep autologin on the decoy but have the hidden session start at its login screen, turn it off in the hidden session only:

  • NixOS. Inside a hidden session, add this line to the hidden module /mnt/data/config/nixos/configuration.nix or to your hidden flake. The next activation builds it in.

    services.displayManager.autoLogin.enable = lib.mkForce false;
  • Debian and Ubuntu. Inside a hidden session, edit the file that sets the display manager’s autologin. For GDM, set AutomaticLoginEnable=false in the [daemon] section of /etc/gdm3/daemon.conf on Debian or /etc/gdm3/custom.conf on Ubuntu. For LightDM, empty autologin-user= in its [Seat:*] section. For SDDM, empty User= under [Autologin]. The edit lands in the upper layer, so it applies from the next activation and the decoy keeps its own setting.

check keeps listing the decoy’s autologin even after the hidden session turns it off.

A disk you mount yourself, such as an automounted USB drive or a decoy partition, is outside every overlay. A read-write mount writes to it directly, and mounting it read-write already writes its superblock.

  • The session watcher shows a desktop alert, “Disk mounted with write access”, for every read-write mount of a disk outside the hidden volume. Alerts appear on the desktop of the account logged in on the machine’s own screen. While nobody is logged in there, none can be shown.
  • A disk mounted over the hidden volume, at /mnt/data or at a parent such as /mnt, hides it. Every file saved under that path from then on goes to that disk. The watcher shows a separate alert, “Disk mounted over a folder in use”, and nails status names the disk. Unmounting it, for example with sudo umount /mnt, takes it off. NAILS writes nothing there meanwhile, and deactivate refuses until it is gone.
  • session_mounts.read_only = true makes every disk the session does not use read-only for the session. Turn it on unless you need to write to an external disk. See Backend watcher and disks.
  • nails deactivate unmounts these disks before the way back.

Suspend keeps the whole hidden session and the volume’s key in RAM, behind the hidden lock screen. Set the decoy’s lid switch to lock as described in Prepare the decoy, and consider a sleep policy.

  1. Look for known artifacts.

    Terminal window
    sudo /mnt/data/nails verify --deep

    Inside the session, what belongs to the session is not reported as residue. One note says that the session’s runtime files in /run, the mounted hidden volume and its active state are expected, and the header counts only warnings and critical findings. With --deep, verify also searches the journal and names sudo’s records of your own commands as such.

    A clean result is evidence against known artifacts, not proof. To check the decoy itself, scan an image of it offline, as Check your setup describes.

  2. End the session and power off.

    Terminal window
    sudo /mnt/data/nails deactivate --poweroff

    deactivate asks for confirmation. Programs then close as at a logout. Powering off is what clears RAM, so leave the machine off for a few minutes before anyone else handles it. Without --poweroff, the machine returns to the decoy’s login screen, or to its desktop if the display manager logs an account in automatically, and the hidden volume is closed on the way.

    The way back keeps the network links, addresses, routes and VPN tunnels that the session set up, and they stay up until power-off. If you return to the decoy without powering off, first take down the connections and tunnels you brought up and delete the links you created. Ending a session lists what else the way back leaves.

Before you rely on NAILS, rehearse a whole session on the real machine with nails rehearse.