Wren Linux

wren-linux / docs / install-base.md (as plain text)

What install-base.sh does

install-base.sh turns a bare Debian 13 into the Wren Linux desktop, in six steps:

  1. It explains and asks. Nothing changes until you agree.
  2. You pick your extras. They install at the end, so you answer everything up front.
  3. It installs the core packages: sway, a terminal, and a few tools.
  4. It sets up the desktop: sway, the bar and the key cheat sheet.
  5. It runs every base part: the firewall, the screen lock, kernel hardening and the rest.
  6. It installs the extras you picked.

The rest of this page goes through each step, then each part, one at a time.

1. It explains and asks

prep/intro.sh says what is about to happen, shows a disclaimer, and asks whether to go on. bash install-base.sh --yes skips it.

2. You pick your extras

Right after you agree, it shows the list of optional extras (install-extras.sh --choose). Nothing is checked for you. What you pick is installed once the base is done.

wrenctl --apps shows the list again whenever you like, and wrenctl --apps --list only prints it.

There is no web browser until you pick one: Firefox and w3m are in the list.

3. It installs the core packages

First, online, Debian's updates since the image was made (apt update, then apt upgrade, asking nothing: a settings file you changed is kept). A fresh install is as old as its image. Offline, or if the lists can't be fetched, it says so and goes on. A newer kernel than the running one means a reboot, which it reminds you of at the end.

The core packages are all with --no-install-recommends: sway foot libgl1-mesa-dri gpg age diceware. Every part then installs its own packages, listed below.

ToolWhat it's for
gpgChecks downloads
ageEncrypts a file to a password or a key: age -p file >file.age, and age -d file.age decrypts it
dicewarediceware -n 6 makes a passphrase of six random words, from the system's secure random source

4. It sets up the desktop

sway: a copy of the stock config, plus one include line for ~/.config/sway/config.d/. An existing sway config is kept: only the include line is added. Every snippet is checked with sway -C before it's kept. Tiled windows have no borders, floating ones 1 pixel in the theme's color (appearance.conf).

Starting it: sway starts when you log in on tty1, from a marked block in ~/.profile.

The login: at its first run on an encrypted disk, it also sets up the login without your password on tty1 (extras/autologin.sh --encrypted-only). The disk passphrase at boot is the lock then, and the screen lock and sudo still ask for yours. On a disk that isn't encrypted it doesn't. wrenctl remove autologin takes it out, and later runs leave that alone.

The bar is see-through black, and it's only changed if it's still the stock one. It has:

The key cheat sheet: Super+?, the keys command, or ~/KEYS.txt (a link to the one copy). The first time sway starts, it asks whether sway's shortcuts use Super, the Windows key, or Alt. keys --mod alt and keys --mod super switch later, and the sheet shows whichever you use. Plain text consoles get a one-line hint.

Screens: display-scale sets the text size of each screen, remembered per screen (display.conf). A watcher started by sway says once, in a notification, when a sharp screen is still at scale 1, also when you plug one in later. A screen's size comes from its own data in /sys/class/drm. Without it, the sharpness is unknown and nothing is said.

Timers and alarms

timer (Super+t, or a click on the time in the bar) uses systemd user timers and no extra package. The next one shows in the bar.

CommandWhat it does
timer 10m teaA timer
timer at 7:30An alarm
timer listWhat is running
timer cancelCancels one
timer stopEnds the ringing. Clicking the notification or dismissing it does too
timer lock 10Minutes idle before the screen turns off (or l in the timer menu). It locks a minute later
timer soundHear and choose what it rings with (or a in the timer menu): the wren, unless you choose another. The sounds are made on your computer by lib/alarm-sounds.py
timer clockWhether the bar shows the date (~/.config/wren/clock). The time is always am/pm

An alarm repeats its sound for up to 5 minutes, to wake you, and a timer rings for about 20 seconds. Timers last until logout or reboot, and a laptop that is asleep does not wake for them.

5. It runs every base part

It runs every script in the base list (PARTS in packages.sh). If one fails, the rest still run, and it tells you which to re-run.

A few only run where the computer has the hardware, and otherwise say so and are skipped. Run by hand, a part always installs.

PartNeeds
brightnessctlA screen backlight
power-profiles-daemonA battery or power profiles
network-manager, random-macA Wi-Fi adapter

6. It installs the extras you picked

install-extras.sh --install installs what you chose in step 2.

The parts

Each is one script in parts/, and its --remove undoes it.

Updates

unattended-upgrades.sh installs unattended-upgrades.

needrestart.sh installs needrestart and libnotify-bin. After every update, it lists the running programs that still use outdated libraries. It only lists: it never restarts anything. Check any time with sudo needrestart.

Networks and DNS

ufw.sh installs ufw, the firewall. It blocks incoming connections and allows outgoing. Debian's own ufw rules (/etc/ufw/before.rules, left as they are) still let in ping and local service-discovery messages (mDNS and UPnP); sysctl-hardening.sh keeps the laptop from answering pings, and nothing Wren Linux installs listens for the other two.

secure-dns.sh installs unbound, dns-root-data and nftables. Unbound on this computer checks every answer with DNSSEC and asks the resolver you pick (Enter: Quad9) over DNS over TLS. A firewall rule lets only Unbound send DNS out. There's a switch for Wi-Fi sign-in pages: the Wren menu's Secure DNS line, or secure-dns on/off. See Encrypted DNS.

sandbox-dns.sh sends DNS from Wren Linux's sandbox users only to the resolver this computer uses, not to any address. That covers the sandboxed Firefox, incognito, the Wi-Fi sign-in window, yt-dlp, Claude's own user and the VMs.

network-manager.sh installs network-manager, wpasupplicant, wireless-regdb and polkitd. It moves the Wi-Fi from the installer or wifi.sh into NetworkManager. nmtui switches networks, in Wren Linux's white-on-black colors, like the install list. Your own NEWT_COLORS wins.

random-mac.sh (with NetworkManager) means a made-up Wi-Fi MAC address on every connection and while scanning, no computer name sent to the network, and temporary IPv6 addresses. Networks can't recognise the laptop from place to place.

dhcp-no-name.sh stops dhcpcd and dhclient sending this computer's name to each network, on a cable or through wifi.sh.

tether.sh adds tether: a phone's mobile data through its USB cable, with or without NetworkManager. While you are offline, a window asks when a phone appears, and it connects only if you say so. See phone tethering.

no-live-extras.sh takes out what Debian's live image installs and Wren Linux doesn't use. A DVD or netinst install doesn't have it. It shows what goes first.

Kernel and boot

sysctl-hardening.sh applies kernel and network settings in the spirit of Kicksecure (data/sysctl-hardening.conf), now and at every boot: kernel addresses hidden, only your own child programs can be traced, no kexec, SysRq limited, no io_uring, and stricter file and network defaults. See Kernel hardening.

hidepid.sh mounts /proc so that each user sees only its own programs, from the next boot on (a small service, wren-hidepid.service). Without it, the sandboxed browsers and every other user on the computer can read the command line of every program: the sites you have profiles for, the files you opened. ps, top and pgrep show only your own programs; use sudo to look further. systemd-logind and polkit keep the group wren-proc, which still sees all of them.

startup-watch.sh notices changes to what starts at your login: your shell's startup files, sway's config, autostart, systemd user units, ~/.local/bin and a few more. Their fingerprints are root's, compared at boot and every 15 minutes, and a change shows as "startup changed" in the bar until you accept it (wren-watch). It is the last part, so its first record holds what the others wrote; the extras you pick go in after it, through wrenctl, which tells it what their run changed. See the startup watch.

module-blacklist.sh blocks rare network protocols, old filesystems and FireWire from loading (data/module-blacklist.conf).

boot-hardening.sh adds Kicksecure's boot parameters to GRUB, and they apply after a reboot: slab_nomerge init_on_alloc=1 init_on_free=1 page_alloc.shuffle=1 randomize_kstack_offset=on vsyscall=none debugfs=off intel_iommu=on iommu.passthrough=0 iommu.strict=1

grub-colors.sh changes GRUB's boot menu to a red box with white text, the chosen entry yellow, and black around it (/etc/grub.d/06_wren_colors). Colours only.

Your account

sudo-timeout.sh makes sudo remember your password for 60 seconds, in the terminal it was typed in, instead of Debian's 15 minutes (timestamp_timeout=1). A program waiting for you to use sudo gets a minute, not a quarter of an hour. Wren Linux's scripts refresh it every 50 seconds while they run, so a long install still asks once.

home-private.sh keeps your home private to you, also from Wren Linux's sandbox users. The sandboxed Firefox and Claude pass through your home to their shared folder, and could otherwise open any world-readable file in it by name.

clock.sh installs systemd-timesyncd. The clock is set over the network (NTP, from debian.pool.ntp.org) and kept right, which Tor needs. While the time zone is UTC it asks for yours (Enter keeps UTC), so the bar shows your local time. Run it again to change it: timedatectl list-timezones lists them.

Locking the screen, and power

swaylock.sh installs swaylock. Super+Escape locks.

swayidle.sh installs swayidle and swaylock.

power-menu.sh installs wmenu. powermenu locks, suspends, logs out, reboots or powers off, from a small menu on Super+Shift+Escape.

power-profiles-daemon.sh installs power-profiles-daemon: powerprofilesctl set power-saver | balanced | performance. It skips itself if tlp is installed.

brightnessctl.sh installs brightnessctl: brightness up|down [STEP], never below 5%, on the brightness keys and Super+F1/F2.

USB

usb.sh installs udisks2 and polkitd, for the usb command. Nothing mounts by itself: you ask, with usb mount.

CommandWhat it does
usbLists sticks
usb mount [NAME]Mounts one as you, under /media/$USER/, with nosuid,nodev,noexec. FAT, exFAT and NTFS are readable by you alone. An encrypted one asks for its passphrase
usb unmountUnmounts, locks and switches it off

A FAT stick mounted with sudo mount is root's, so you can't write to it: usb mount offers to mount it again as you.

USB drives and noexec: a drive can't run programs from itself (bash script.sh and mpv file work; ./program doesn't). To run a program from a stick, copy it somewhere else first.

The Wren menu

wren-menu.sh installs wmenu and rfkill, for wren-menu. Click "wren" at the left of the bar, or press Super+m (again closes it), for a black-and-gray menu in a floating window over what you were doing.

Its first screen names what you want to do, not the program; the program's name shows in the list it opens. Each line shows only when there is something behind it:

To learn bash from Wren Linux itself: wrenctl learn lists every one of its bash scripts, the smallest first, numbered down the list with each one's length. Space checks off one you have read and understood, Enter (or a click) opens it read-only, n goes to the next unread one and / searches. Greg's BashGuide (online, opened in Firefox) and bash's own manual are at the top. Your progress is in ~/.local/share/wren/bash-learning.progress, in your home folder, so your backup keeps it.

The Privacy line shows the microphone, webcam and secure DNS at a glance.

Each first-screen line has an icon only where it can show as a picture: in a window, with a color emoji font (wrenctl install emoji-font). Without one there are none, rather than empty boxes.

The lists, each with only what is here:

The desktop

core-commands.sh installs ncal and bash-doc (the Bash Reference Manual, for wrenctl learn), and puts the base desktop's own commands in ~/.local/bin (keys, wren-welcome, timer, display-scale, sway-status), with the key cheat sheet and the alarm sound. install-base.sh puts them in place too. This part does it again so that wrenctl --update brings them up to date when they change.

wmenu.sh installs wmenu, the launcher on Super+d, in the bar's black and white. It's opaque (the bar is see-through), with a font a little bigger than the bar's, so it covers the bar. If a strip of the bar still shows, raise the 12 in the set $menu line of ~/.config/sway/config.

autostart.sh sets what opens when you log in, and on which workspace, in one file: ~/.config/wren/autostart, a workspace and a command on each line. It starts empty: nothing opens until you add it. Change it there, with the Wren menu's Settings > Startup programs, or with wren-autostart edit. Yours is never replaced.

mako.sh installs mako-notifier. Notifications close after 5 seconds, and Super+n and Super+Shift+n dismiss.

wl-clipboard.sh installs wl-clipboard: wl-copy and wl-paste.

command-hints.sh helps when you type a Wren Linux extra's command that isn't installed (claude-vm, gimp...): the terminal says which script installs it. It only prints, and bash asks it only when no program of that name exists. It's a root-owned file (data/command-hints.bash), loaded by one marked block in ~/.bashrc.

foot-config.sh installs fonts-dejavu-mono, and sets the terminal's look (data/foot.ini): DejaVu Sans Mono at size 14 instead of foot's small default, a black background and readable colors.

console-tmux.sh installs tmux, dressed like the desktop, always. ~/.config/tmux/tmux.conf (plain settings) loads console.conf only on a text console, so a tmux in a foot window under sway stays plain. console-click handles the bar clicks, and the console-only extra starts it at login.

Wallpaper and theme

wallpaper.sh is your own wallpaper: the newest JPEG or PNG in ~/Pictures/wren/desktop goes up at every login and sway reload (Super+Shift+c). With the folder empty you get the default, a wren for the theme in use, which swaps when the theme does. Your sway config's own output * bg line stays instead, if it has one.

Key or commandWhat it does
Super+] and Super+[Step through ~/Pictures/Wallpapers as the wallpaper
Super+Shift+wLists it by name, with "0 No wallpaper" first (wmenu). The one chosen is copied into the desktop folder, so it stays
Super+\No wallpaper, not even a wren: the theme's plain background, until you choose one or copy in a newer picture
wallpaper statusWhich picture is used, and why a file isn't (a file that only says it is a JPEG or PNG, over 50 MB)

theme.sh is light or dark, from one place: theme light, theme dark, theme toggle, or the Wren menu's Theme line. Dark is the default, and Wren Linux's look as before. Light has warm light backgrounds (#f2efe9) and dark text.

Encrypted DNS, with a switch (parts/secure-dns.sh)

Without it, every name the computer looks up goes unencrypted to the DNS server the network hands out (usually the router): the network and your ISP see each one and anyone on the way can answer falsely. With it:

It is part of the base install and switches on the first time. Something else running DNS here (systemd-resolved, resolvconf, another server on port 53) makes it skip itself with a note. Run it again to pick another resolver; a re-run keeps the switch where you left it. bash status.sh shows whether it is on and which resolver is in use. --remove takes it out.

LIMITS: the resolver you choose sees every name you look up, from your address; the sites you then connect to are still seen by your network (by address, and usually by name in the TLS handshake); a computer whose clock is far off can't check DNSSEC, so names stop resolving until the clock is right.

Kernel hardening

Three parts follow Kicksecure's approach, with what it does by default checked against this Debian:

Not taken from Kicksecure: security-misc, hardened-malloc and kloak are not in Debian, and using them means trusting another apt repository.

apt through Tor

install-base.sh asks first, under "Network privacy" and before anything is downloaded, whether apt should fetch Debian's packages through Tor (the default is no), saying what that changes and what it doesn't. Say yes, tick it in the Install apps list, or run wrenctl install apt-tor any time, and it:

  1. asks whether you need a bridge to reach Tor (see Bridges); obfs4 or webtunnel lines, or Snowflake, are offered here (there is no client program for meek); the choice goes into /etc/tor/torrc;
  2. installs tor, apt-transport-tor and the bridge's program in the normal way (once), with Tor kept from starting until your bridges are in place;
  3. starts Tor and waits for it to connect; if it doesn't in 3 minutes, apt is left alone;
  4. changes deb.debian.org and security.debian.org (and deb.torproject.org, for webtunnel) in your apt sources to tor+https://… (originals saved as *.wren-tor.bak) and runs apt-get update through Tor; if that fails, the sources are put back.

apt still checks every package's signature as always; this hides who downloads what from your network and your address from the mirrors. It is slower, and other repositories you added (Mullvad, Claude Code) are still fetched directly. wrenctl remove apt-tor puts it all back. It is an extra now: its page.

Bridges

Everything in Wren Linux that connects to Tor (Tor Browser, Whonix, OnionShare, and the system Tor that apt over Tor, remote access and the onion site share) asks the same way. First: **do you need a bridge to reach the Tor network?** A bridge is a relay that isn't listed publicly; you need one if your network blocks Tor or you don't want it to see that you use Tor. The default is no. If you say yes, you get the kinds that work in that place:

KindWhat it isTor BrowserWhonix GatewayOnionSharesystem Tor
obfs4, built-inTor's own public list; nothing to fetch; often blocked where Tor isyesnoyesno
obfs4, your linesMakes Tor look like random data; fastyesyesyesyes
webtunnelLooks like a visit to a website; good against blockingyesnonoyes
SnowflakeNo lines needed; borrows volunteers' browsers; sloweryesyesyesyes
meek (Azure)Looks like a visit to Microsoft's cloud; slowest, a last resortyesnonono

The "no" entries are real limits: the Whonix Gateway ships only the obfs4 and Snowflake programs (I checked its package list), there is no client for meek outside Tor Browser, and OnionShare can't use webtunnel or meek. The menu says what is left out, and why. The system Tor is shared, so its bridge is asked for once, by whichever of apt over Tor, remote access and the onion site comes first.

webtunnel for the system Tor

Debian has no webtunnel client. The Tor Project's own bridge program, lyrebird (the one Tor Browser carries; it speaks obfs4, webtunnel, Snowflake and meek), comes from the Tor Project's apt repository, deb.torproject.org, and Wren Linux takes only lyrebird from it:

When the last script using it is removed, lyrebird and the repository go too. Building webtunnel from its git source as root, and editing the system_tor AppArmor profile by hand, as some guides say, is not done: its releases aren't signed, and Debian's profile is overwritten by updates.

By hand:

# the key: check gpg prints exactly the TORPROJECT_FPR of pins.sh
wget -O /tmp/tpo.asc "$(. ~/wren/pins.sh; echo "$TORPROJECT_KEY_URL")"
gpg --show-keys /tmp/tpo.asc
sudo install -D -m 0644 /tmp/tpo.asc /usr/share/keyrings/wren-torproject.asc
# lyrebird only, from that repository
printf '%s\n' 'Package: lyrebird' 'Pin: origin deb.torproject.org' 'Pin-Priority: 500' '' \
    'Package: *' 'Pin: origin deb.torproject.org' 'Pin-Priority: -1' |
    sudo tee /etc/apt/preferences.d/wren-torproject.pref
echo "deb [signed-by=/usr/share/keyrings/wren-torproject.asc arch=amd64] https://deb.torproject.org/torproject.org trixie main" |
    sudo tee /etc/apt/sources.list.d/wren-torproject.list
sudo apt update
# tor's Candidate must be Debian's version (not one ending in ~d13.trixie+1),
# and the deb.torproject.org lines under tor must show -1
apt-cache policy tor lyrebird
sudo apt install lyrebird
# at the end of /etc/tor/torrc:
#   UseBridges 1
#   ClientTransportPlugin webtunnel exec /usr/bin/lyrebird
#   Bridge webtunnel [ADDRESS]:443 FINGERPRINT url=https://... ver=0.0.3

For obfs4 and webtunnel lines you get yourself, from Tor's BridgeDB:

Snowflake needs nothing from you. Tor Browser has it built in; for the others data/snowflake-bridges.txt has Tor Browser's own Snowflake lines, adjusted for Debian's snowflake-client (one front= instead of fronts=). I have not connected through these Snowflake lines from Debian's client, so if one fails, try another kind.