Newcomers don't usually land on Debian + Openbox — that's a choice people make after they've been burned by a desktop war, or fallen for the blank-canvas minimalism. DORiS won't mint that taste; it will meet it, perfectly, the moment someone has it. Get there from here.
DORiS is a desktop restoration system for any amd64 machine running Debian
trixie. It was initially a handy way for me to restore my own setup after a net-install, and it still is, but, being machine agnostic makes it a cool thing to share. Run it after a fresh net-install and it recreates the "DORiS" desktop —
Openbox/X11, keyboard-driven, hardened — from one kit. Everything the restore
needs is vendored inside this repo, so it works offline: the only network it
needs is apt.
Menus, keys, firewall, welcome screen. It's a whole 'nother level, right in
your pocket. Heh, or, at least I think so. I have been running the fastcompmgr compositor for some years and it's been great so it's included in DORiS run from ~/bin.
The doris desktop — Openbox, keyboard-driven...colorful.
DORiS is a disposition: a humanist's way of computing, where the machine bends to how you think, not the other way around. The hundred hours of "how I like my box" written down, so a fresh install comes out the other side already home.
Everything you need is at the ready — a keybind or a handy alias or a script away. All your keys work before you even learn they exist. Everything works every time, all of the time, the way you actually want it to. Security is built in. Automagic is built in. Of course it is — this is a power user's machine. Robust. Reliable. The kind you can be productive on all day.
Whaddya want for nuthin'?
Don't want to touch your daily driver? Restore a disposable QEMU guest and watch the kit work end to end.
-
Grab the Debian trixie netinst ISO.
-
Create a disk and boot the installer with KVM:
qemu-img create -f qcow2 doris-test.qcow2 20G qemu-system-x86_64 -enable-kvm -m 4096 -cpu host \ -cdrom debian-trixie-netinst.iso \ -hda doris-test.qcow2 \ -netdev user,id=n0 -device e1000,netdev=n0 -boot d
No KVM? Swap
-enable-kvm -cpu hostfor-accel tcg— slower, works anywhere. -
Net-install as normal: a root password, your user added to sudo, "standard system utilities" only. Reboot — this time boot the disk (
-boot c, no-cdrom). -
As your new user:
sudo apt-get install -y git git clone https://github.com/rabmach/DORiS ~/DORiS cd ~/DORiS sudo ./restore.sh # system half ./user-setup.sh # per-user half
-
startxand meet your new desktop. QEMU's user-network gateway (10.0.2.2) counts as a trusted LAN, so the kit picks the router DNS posture automatically.
- 00 — The Big Picture — quick version first, then the architecture exploded: the two halves, the restore flow, task by task, the supporting machinery, and the honest limits.
- 01 — The Path — what you need, the concepts, and the step-by-step from fresh net-install to running DORiS.
- 03 — The Decision Journal — every real decision in the kit, with the if/then/buts: why Openbox, why bash, why the firewall has an all-TCP outbound, why the kit split in two.
- 04 — The Bug Log — the bugs that survived to a real machine: fresh-install ownership, the invisible task failure, the stale key pin. Each with root cause and fix, kept as a teaching record.
-
Net-install Debian trixie. Create a root password and standard system utilities only (Software).
-
As root, prepare your user:
apt-get update && apt-get install -y git sudo adduser <youruser> adduser <youruser> sudo echo '<youruser> ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/<youruser> reboot
-
Get the kit onto the machine either way:
cloned repo:
git clone https://github.com/rabmach/DORiS ~/DORiS cd ~/DORiS
backup drive:
sudo mount /dev/<backupdrive> /mnt cd /mnt/DORiS
Then run the two halves:
sudo ./restore.sh # system half (needs root) ./user-setup.sh # per-user half (bakes $USER/$HOSTNAME into configs)
-
Reboot.
startx(or configure auto-login). The first-login welcome screen greets you with keybinds, aliases, timers and the one-time credential chores. DORiS also creates a handy what-it-is doc for every new user on the box. It's called, clears throat, what-it-is.
The kit can live anywhere and DORiS doesn't care: ~/DORiS from a git clone, a mounted backup drive (/mnt/…), a USB stick, whatever. You just
run it from wherever it is. ($DORIS_DIR is resolved from the script's own
location, never from a hardcoded path.)
Machine-agnostic by design: vendor firmware (Intel/AMD microcode, VA-API
drivers) is auto-detected at install time, and hardware-specific extras are
optional overlays that never touch the core kit. Wifi works out of the box
on the common laptop cards — NetworkManager runs the wires and the airwaves,
firmware for Intel/Realtek/Atheros/Broadcom/MediaTek is in the core list,
and joining a network is nmtui in any terminal (or the panel applet).
DORiS splits into two halves:
| half | script | when | does what |
|---|---|---|---|
| system | sudo ./restore.sh |
once per machine | repos, packages, system-wide icons+themes, firewall, DNS strategy, logs, timers |
| per-user | sudo ./user-setup.sh |
once per user | dotfiles, ~/bin, films.txt, wallpapers, first-login welcome |
Run the system half once, then the per-user half for every user who logs in on that machine. Both are idempotent and back up before they touch a file, so a second user — or a re-run — is safe.
| task | what |
|---|---|
| 00-check | root, amd64, networking (dies without it), Wayland detection (warns, stays X11), kit self-test |
| 01-connection | auto-detects trusted-LAN vs direct-ISP and picks the DNS strategy (see Security) |
| 02-repos | apt repos: Mozilla (Firefox), Helium, Sublime Text; key fingerprints verified |
| 03-packages | full core package list (see packages/core.list) + stock kernel + vendor microcode (auto-detected) + optional extras |
| 04-assets | icons + themes → /usr/share so root apps match; icon caches rebuilt; nothing in ~/.local |
| 05-hardening | nftables, DNS (router pin; direct links get a plain warning), journald caps, debsecan cron, ramdisk tmpfs, CPU governor, sysctl drop-ins (hardening/sysctl.d/60-doris-*.conf) |
| 05-tweaks | loginfetch tty banner (dynamic /etc/issue on every tty login), Ctrl+Alt+Backspace kill-X, boot to multi-user + tty1 autostart X |
| 06-verify | confirms the important bits took, writes the install marker |
| task | what |
|---|---|
| 10-config | config/ → ~/.config, bin/ → ~/bin, home/ → ~/ (dotfiles + films.txt), Thunar scripts, Pictures/; $USER/$HOSTNAME tokens baked in |
| 12-welcome | generates the first-login welcome from the kit (keybinds, aliases, timers, admin apps, credential nags, dad joke) |
| 13-lockd | wires lockd — one-word encryption (age underneath): Thunar right-click family, *.age double-click unlock, Apps-menu launcher, Ctrl+Alt+E quick-lock. Originals wiped after byte-verification (--keep opts out); your key is born on your first run |
DORiS is the foundation; the handy tools are the family that lives on it. Two ship in the kit:
- lockd — one-word file/directory encryption, right-click to keybind. On by default: it's a function, not a taste. Standalone repo: rabmach/lockd (DORiS embeds a snapshot; the repo is upstream-of-record).
Others (brenda, nina, RandomLitB, george) live on their own — clone what you want. brenda can be pretty handy; george (keyboard-first dashboard/command center) is all-inclusive at rabmach/george.
git pull only downloads the new scripts — it changes nothing on your box.
To apply a kit update, re-run the half that owns the changed task:
- system-level changes (
tasks/system/*, e.g.update-alternatives, nftables, sysctl, packages) →sudo ./restore.sh - user-level changes (
tasks/user/*,config/,bin/) →./user-setup.sh
Backups go to <kit>/backups/ first, already-
done steps are skipped, and nothing is re-downloaded. If in doubt, run the
system half too — it re-verifies what matters (task 06) rather than
wrecking anything.
Two postures, decided automatically at runtime:
- Behind a router (default gateway is RFC1918/link-local/ULA): that
router is trusted — DNS is pinned to it (default
192.168.1.1, override withDNS_SERVER=…). Guest wifi profiles are skipped. - Straight into the ISP's router (public/CGNAT gateway): the link is
not trusted. DORiS says so plainly: DNS rides DHCP (plaintext) there.
For encrypted DNS on the road, use browser-level DoH (e.g.
dns.nextdns.ioin Firefox/Chromium) or your own DoT client — the old stubby (laptop-side DoT daemon) layer is retired. - Unknown → treated as untrusted. If it misdetects, set it by hand:
echo router > /etc/doris/modeand rerun task 05.
The rest, regardless of posture:
- nftables: default-deny inbound and outbound. Outbound allows
loopback, ICMP, DHCP, NTP, DNS (family-agnostic), mDNS, and all TCP
(FTPS/FTP passive data channels need an arbitrary port revealed inside
TLS).
nf_conntrack_ftpcovers FTP active mode. Inbound stays default-deny. - AppArmor: reverted back to stock Debian default, the security posture hangs on nftables + DNS + sysctls + debsecan.
- journald capped (64M/16M rotate, 1 month retention), debsecan weekly CVE scan cron.
- CPU governor powersave by default (
~/bin/govtoggles performance). - /mnt/ramdisk tmpfs — general-purpose temp cache.
Everything is reversible; originals back up to <kit>/backups/ before
changes (cp -a copies, nothing is deleted until you are happy).
The first-login welcome is generated from the kit itself
(tools/mkwelcome.sh): keybinds come out of config/openbox/rc.xml,
aliases out of home/.bash_aliases, timers out of hardening/. Add a
keybind or alias, re-run ./user-setup.sh, and the welcome updates. It
also lists the one-time credential chores that you may ignore completely:
- pianobar — your PANDORA account in
~/.config/pianobar/config(uncommentpassword_command). - weather — your OpenWeatherMap key in
~/.config/weather_sh.rc. - keepassxc, claws-mail accounts, filezilla sites.
~/bin/nbpneeds a gpg secret key set as your default (nbp encrypts to your default secret key automatically — no key name hardcoded anymore).
sudo ./restore.sh # full system restore
sudo ./restore.sh --list # show system tasks
sudo ./restore.sh --only 03 # run just one task
sudo ./restore.sh --skip 05 # skip a task (repeatable)
sudo ./restore.sh --dry-run # print what would run
sudo ./restore.sh --ask # confirm each task
sudo ./restore.sh --extras # also install packages/extras.list
./user-setup.sh # set up the invoking user
sudo ./user-setup.sh --user bob # set up another user
./user-setup.sh --list # show per-user tasks
./user-setup.sh --dry-run # print what would run
Env vars: DORIS_ASK=1, DORIS_EXTRAS=1, DNS_SERVER=….
DORiS/
├── restore.sh system runner (root)
├── user-setup.sh per-user runner
├── lib.sh shared library (network/dns/backup/token helpers)
├── packages/ core.list + extras.list
├── tasks/
│ ├── system/ 00-check … 06-verify
│ └── user/ 10-config, 12-welcome
├── config/ ~/.config (tokenized with $USER / $HOSTNAME)
├── home/ dotfiles + films.txt
├── bin/ ~/bin scripts (incl. doris-welcome)
├── local/share/ icons, themes, Thunar scripts (→ /usr/share)
├── Pictures/backgrounds/ wallpapers
├── hardening/ nftables, journald, udev, systemd, cron, sysctl.d, loginfetch
└── tools/ selftest.sh, mkwelcome.sh, capture.sh, scrub.sh
$USER and $HOSTNAME are baked into config files at restore time; executables
resolve $HOME in config files at runtime, so the kit ships no hardcoded usernames or hostnames
(hostnames change between installs — they're tokenized, not captured).
tools/selftest.sh checks that before every restore (and you can run it by hand).
- Openbox/X11 only — no Wayland configuration. DORiS detects a Wayland session and warns, then stays X11.
- amd64 Debian trixie only — that's the supported surface, on purpose for right now.
- Opinionated by design — it recreates this way of computing, not a menu of desktop choices. Your keys, your panel, your wallpapers, a config'd reliable setup.
- Outbound firewall is all-TCP — FTPS passive data channels negotiate their port inside TLS, so they can't be allowlisted; filtering is enforced at the DNS layer instead (decision journal, D11).
- AppArmor is stock Debian — the distro's profiles load as shipped; DORiS adds no profiles and no audit layer (decided 2026-09-14; see the decision journal).
Feedback, ideas, bugs: open an issue, or tell me where you'd have decided differently — the decision journal lists every trade-off I made, and I'd genuinely like yours.
cd ~/DORiS && tools/capture.sh && tools/scrub.shcapture.sh re-vendors ~/.config, ~/bin, ~/.local, ~/Pictures,
~/home dotfiles and the /etc hardening files. scrub.sh walks the
result and strips usernames, keys, and runtime junk. Review the diff before
committing.
Why did the doris restore script break up with the live distro?
Because it was too easy to boot!
startx, and press all the keys. Later, bitches!