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, though, as it has for me, and them, and maybe you, too. Get there from here.
**Stealth edit heads-up because I am lousy with taken for granted stuff**
DORiS absolutely replaces your: **~/.bashrc, .bash_aliases, and .bash_functions** files.
I mean, of course it does, DORIS is bash heavy and it's a setup, restoration of digs,
so, it forcefully carries and plants those files. It backs everything up, of course, and
you can find anything it replaces backed up to **~/DORiS/backups**
Also, if you're adding your ~/.bashrc file back after installing DORiS
then you are not really using DORiS. :)
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.
DORiS desktop — Openbox, keyboard-driven, tuned. Gruvbox-dark shown, nord is in there, too, gnome apps cooperate; it's all good. In fact, hit c'tarl+shift+t one time.
DORiS is a disposition, I think: a humanist's way of computing, and the machine bends to how you or I think, not the other way around. The hundred(s) hours of "how I like my box" finally codified, so a fresh install comes out the other side done and done. Really, it's just digs on Debian, but, they's good digs. I mean, why build a distro when you can just Debian, whiff?
What you get is a solid, reliable 'workstation' already well provisioned with a butt-load of handy function at the ready — a keybind or a handy alias or a script away. Add or remove what you like to make DORiS even better for you, if you like, and it's easy to do so. Everything works every time, all of the time, the way you actually want it to. This is a proper desktop paradigm. Robust. Reliable. The kind you can be productive on all day because I am becuase DORiS is my desktop on Debian Linux that I have been using reliably for...decades, small tweaks notwithstanding.
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 + Hack fonts → /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; the timezone is not baked — .bashrc reads the box's own /etc/timezone (or localtime) at shell start, so any coast works |
| 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 and it's silly and noboody asked for it, ever, and it's awesome.
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).
Ctrl+Shift+T (or right-click menu → "looker", right beneath Pianobar) flips the whole desk between gruvbox and nord in one shot with a small confirm: GTK3 + GTK4 themes, the Openbox window theme, geany's colorscheme, alacritty, mc's skin, btop's theme, the wallpaper (gruvbox wears the painting, nord wears palaver), and even the GTK2 include — dressing the logout dialog and the panel too. Already-open apps pick it up for new windows; geany repaints on restart, and mc/btop likewise take the new suit the next time you open them. One habit to know: close mc before flipping — when mc quits it rewrites its own config, so an mc born in the old theme will paint the old skin back when it exits.
The tool is ~/bin/doris-theme — it reads the current theme back out of your
config (no state file to go stale) and backs up every file it touches as
*.bak-doris-theme. --selftest reports what's present; --flip-to nord
flips without the popup. Both theme sets ship in the kit, so the flip works
on a fresh install before you've touched anything.
DORiS is a decision, not an app: it replaces your shell files, sets
system defaults, and plants handy things. Everything it touched is backed
up first, into <kit>/backups/<timestamp>/ — and backing OUT is one
command now, shipped as doris-backout (installed to ~/bin):
doris-backout # dry run - shows the plan, moves nothing
sudo doris-backout --apply # full restore, including system defaults (root)
doris-backout --apply --quiet # non-interactive: newer-file conflicts get
# deferred to a list, never clobbered silently
It restores the backed-up originals (oldest snapshot first - that one holds
the true pre-restore state), asks before overwriting anything newer than
the backup copy (protects the work you did since testing - a tty-less run
defers those to a list instead), lists everything DORiS delivered that had
no original (watch-list: nothing auto-deleted), and - with root rights -
undoes the system-state defaults (file-manager/text-editor alternatives,
the xdg-mime handler) back to values the kit captured before altering
them. Nothing gets deleted by backout itself; the backup stays until you
personally shred it. See doris-backout --help for knobs.
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, fonts, 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. I built-up a labwc desktop tjhis summer and it was fine and it was also a pain in the ass; currently. Will revisit.
- amd64 Debian trixie only — that's the supported surface; Debian stable.
- 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 and runtime junk - and stops you cold if a
real key (weather, pianobar, nextdns) is still in there. 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!