β οΈ Do not run this on a system you're already using.privacyos.shreconfigures package sources, purges packages, rewrites/etc/hosts, and overwrites browser profiles β it's built for a fresh Debian 13 (Trixie) install with nothing on it you care about yet, not your daily driver. The script itself asks you to typeyesto confirm this before it changes anything, but you should know that going in, not find out at that prompt.
π§ Work in progress β actively in testing. The core install has completed successfully, repeatedly, end-to-end β packages, DNS, hosts blocklist, browser hardening, default browser and search engine, all confirmed working on a real install. A couple of pieces (automatic security updates, the firewall) were just added and haven't been through that same testing yet, and it's only been run on one setup so far, not a range of real hardware. You're welcome to try it and report anything that breaks β that's genuinely useful right now.
A single script that turns a fresh Debian 13 (Trixie) install into a hardened, privacy-first desktop β get networking working, run the script, done.
Everything it installs comes through apt: Debian's own repositories, or a
vendor repository added the same way LibreWolf's/Waterfox's/Mozilla's/
VSCodium's are. Nothing here is a one-off .deb download, a tarball, an
AppImage, or a Flatpak β one update mechanism (apt update && apt upgrade)
covers everything, and nothing sits around unmanaged outside the package
manager's tracking.
Read the script before you run it. That's the point β there's nothing here you can't see for yourself.
Both are themselves built on Debian β Ubuntu is a Debian derivative, and Mint is built on top of Ubuntu, so it's two layers removed from Debian itself. This project builds directly on Debian instead, deliberately, for reasons that matter specifically for a hardening project rather than being a knock on either:
- Fewer layers between an upstream security fix and your machine β packages come from Debian's own archive or a vendor's own repo, not a derivative's repackaging of one.
- Debian doesn't carry Ubuntu's Snap-by-default packaging or its history of bundling things like commercial search integration β starting from the plainer, more scrutinized base means less to audit and undo before any hardening even starts.
- It matches this project's own APT-only rule: everything stays one hop from upstream, not two.
- A fresh install of Debian 13 (Trixie) with the Cinnamon desktop already installed. This is a real requirement, not a suggestion β the Nemo file-manager integration and the bloat-purge list are both written specifically for what a Cinnamon install includes. Other desktops aren't supported.
- Easiest way to get there: Debian publishes an official live image with
Cinnamon already on it, installed via Calamares (the same graphical
installer Linux Mint itself uses) β boot it, connect to Wi-Fi through its
normal desktop applet if you need to, install to disk from there. No
separate desktop-selection step, no
apt installafterward. - This project is currently verified against Debian 13.6.0, released
2026-07-11.
- Cinnamon live image: debian-live-13.6.0-amd64-cinnamon.iso (~3.8 GB) β links straight to the file itself, not the folder, so there's no risk of grabbing the GNOME/KDE/XFCE/etc. image by mistake. Debian also publishes a .torrent for it β often faster than downloading straight from Debian's own server, since you're pulling pieces from everyone else currently sharing the file at the same time instead of one single source. Any torrent client (Deluge, qBittorrent, Transmission, etc.) opens it directly.
- Prefer a minimal/manual install instead? The plain
debian-13.6.0-amd64-netinst.iso (~755 MB,
.torrent)
works too β just make sure to select Cinnamon in the installer's software
selection screen (or run
sudo apt install task-cinnamon-desktopafterward if you didn't). Unlike the Cinnamon live link above, both of these are on Debian's "current" path, so they'll silently serve whatever point release is newest by the time you click them, not necessarily 13.6.0. - Checksums:
SHA256SUMS/SHA512SUMS(+.signfiles) sit in the same directory as whichever image you pick β verify before you install. - Newer Debian point releases should work fine β this project is pinned to
the
trixiecodename, not a specific point release, and it runsapt update && apt upgradeas its first real step regardless of which point release you installed from.
Do this during Debian's own installer, before privacyos.sh ever enters the
picture β it's the one piece of real protection that has to happen at
install time, not something the script can add afterward.
Full-disk encryption protects everything β not just your personal files, but the operating system itself: browser caches, swap, temp files, system logs, all of it. Without it, someone with physical access to a powered-off machine (lost, stolen, seized, whatever) can just pull the drive and read everything on it directly. With it, none of that is readable without the passphrase, full stop.
- Using the Cinnamon live image (the recommended path above, installed via Calamares): when you get to partitioning, choose Erase disk, then enable the Encrypt system option before continuing. LVM gets set up underneath automatically as part of that same flow β nothing else to configure.
- Using the netinst image (the classic Debian installer): on the Partition disks screen, choose Guided β use entire disk and set up encrypted LVM.
Either way, you'll be asked to set an encryption passphrase during this step. Write it down somewhere safe before you forget it β this isn't a login password, it's what makes the entire disk readable at all, asked for on every single boot before the system even starts. There is no recovery option and no "forgot password" flow. Lose the passphrase and everything on the disk is gone, permanently, by design β that's the same property that makes it real protection in the first place.
Debian's installer separately asks whether to set a root password. This
one's optional either way β privacyos.sh handles it automatically no
matter what you choose β but knowing the tradeoff now saves a step later:
- Leave it blank and Debian adds your regular user to the
sudogroup automatically (this is Ubuntu's default behavior, for comparison). Your user already hassudoby the timeprivacyos.shruns, so it skips straight past the sudo-fix step entirely β one less reboot. - Set a root password (the traditional Debian way) and your user
isn't added to
sudoautomatically. Nothing's broken βprivacyos.shdetects this, walks you through fixing it, and reboots once to make it take effect β just an extra step compared to leaving it blank.
Neither choice is wrong. If you don't have a specific reason to want a separate root account, leaving the password blank gets you through the install with one fewer reboot.
One file, fetched with curl (present by default where git and wget
usually aren't), run from one terminal:
curl -fsSLO https://raw.githubusercontent.com/rjc3rd/PrivacyOS/main/privacyos.sh
chmod +x privacyos.sh
./privacyos.shThat's genuinely it β privacyos.sh is fully self-contained, no sibling
files it depends on, nothing else to download first. It checks whether
your user actually has sudo yet and walks you through fixing it if
not (a fresh Debian install doesn't always grant that automatically β
depends on a choice made in Debian's own installer), installs a small set
of basic tools it needs (wget, gnupg, git, curl), then goes
straight into the actual PrivacyOS install this README describes below.
If your user wasn't a sudoer yet, fixing that needs a real reboot β
tested directly, logging out and back in isn't reliably enough, so the
script doesn't leave that to chance; it'll ask before rebooting, not just
do it. Once it's back up, run ./privacyos.sh again β apt/package steps
are idempotent, so it picks back up quickly rather than needing to resume
from some exact point.
Prefer to do each step yourself instead of running a script you haven't
read line by line first? Totally reasonable, and the point of this
project is that you can β read it, then either run it as-is or do its
steps by hand. git clone https://github.com/rjc3rd/PrivacyOS.git works
fine too if you'd rather have the whole repo locally (e.g. you're
planning to contribute back).
Run it as your normal user, not root β it calls sudo itself wherever it
needs to.
Before it changes anything, privacyos.sh asks you to type yes to
confirm this is actually a fresh install β same pattern installers like
ISPConfig's use, on purpose: this reconfigures package sources, installed
software, /etc/hosts, and browser profiles, and it's built for a machine
with nothing on it you care about yet, not one you're already using.
Every optional choice is a command-line flag, so you can pre-decide exactly
what you want (and script/document it, or eventually generate the command
from a checkbox picker on privacyos.dev) instead of answering prompts.
Anything you don't pass a flag for gets asked interactively β as a graphical
dialog if available, a plain terminal prompt otherwise. E.g.
./privacyos.sh --theme --dns=quad9.
--dns=PROVIDER quad9 (default) | nextdns | opendns | none
--theme / --no-theme desktop theming extras (asks if omitted)
--apps / --no-apps creative/media/dev app bundle (asks if omitted)
--no-librewolf skip LibreWolf (included by default)
--no-firefox skip Firefox (included by default)
--no-tor skip Tor Browser (included by default)
--no-waterfox skip Waterfox (included by default)
--no-chromium skip Chromium (the no-extensions fallback browser)
--yes non-interactive: accept defaults for anything
not given an explicit flag (theme=no, apps=no)
-h, --help show help and exit
Once every prompt is answered and it actually starts making changes, expect
it to take 15-20 minutes, depending on your connection and hardware β
it's genuinely doing a lot (packages, repos, DNS, the hosts file, browser
hardening), not stuck. Long quiet stretches while apt or a download works
in the background are normal.
- Points
/etc/apt/sources.listat Debian 13/Trixie explicitly (not the genericstablealias, so this keeps targeting Trixie even after the next Debian release ships). - Removes a set of default desktop apps this project doesn't need.
- Installs core privacy/security tooling:
secure-delete,wipe,bleachbit,riseup-vpn,tor,keepassxc,wireshark(plus a right-click "Secure Delete" action in the Nemo file manager).toris the standalone background proxy daemon (distinct from Tor Browser, installed separately below) β it just runs, quietly, always available on127.0.0.1:9050for anything that wants to use it. - Installs a privacy-focused browser set β LibreWolf (primary), Firefox (fallback), Tor Browser, Waterfox β plus a deliberately bare, no-extensions Chromium kept entirely separate. Chromium isn't just a compatibility fallback for sites a hardened browser breaks; it's deliberate browser isolation β for sites you have to use but don't trust (job sites, Microsoft properties, etc.), using a completely separate, unlinked browser means whatever they collect there can't be correlated with anything in your real, hardened browsing identity. Each browser is individually skippable via flag.
- Installs Thunderbird for mail.
- Configures an encrypted DNS resolver (Quad9 by default) via
systemd-resolved. - Installs and enables
unattended-upgradesfor automatic security updates specifically β Debian's own shipped default config already restricts to security-only, nothing else gets silently auto-installed. This doesn't replaceupgrade(below) β it handles routine background security patching,upgradeis still how you refresh the hosts list and browser hardening, and do a full package upgrade whenever you want one. - Installs and enables ufw with the simplest correct desktop posture: deny all incoming, allow all outgoing. Nothing on this machine is meant to be reachable from the network, and everything an actual user does β browsing, email, messaging β is a connection this machine starts outward, so nothing here needs to be specially allowed.
- Builds
/etc/hostsfrom the StevenBlack list plus your own custom.hosts (see below). - Builds hardened browser preferences from
Arkenfox +
Betterfox plus this project's own
small
overrides-user.js, applied to Firefox/Waterfox. LibreWolf gets just the overrides file, since it already hardens its own defaults β layering the full Arkenfox/Betterfox set on top would fight settings it made on purpose. - Force-installs a standard extension set into Firefox, Waterfox, and
LibreWolf via
policies.json(Mozilla's own enterprise mechanism for this) β each extension with its own out-of-the-box defaults, no custom rules or filters layered in: uBlock Origin (Firefox and LibreWolf only β see notes below), ClearURLs, Don't track me Google, KeePassXC-Browser, LocalCDN, Onion Browser Button (see note below), Port Authority, SponsorBlock for YouTube. - Sets LibreWolf as the system default browser, and adds ProxySearch.org as an available and default search engine in Firefox, Waterfox, and LibreWolf β see Default browser and search engine below.
- Sets the hostname to
privacyos. - Finishes with
apt update && apt upgradeand a reboot.
Neither of these is "hardening" β they're kept separate so installing them isn't forced on anyone who just wants the core setup.
--theme: Cinnamon config, Mint-Y-Dark theme, icons, wallpapers. Not yet built β tracked for a future update.--apps: GIMP, Inkscape, darktable, RawTherapee, Scribus, Flowblade, Audacity, Audacious, mpv, Celluloid, Deluge, FileZilla, SimpleScreenRecorder, VSCodium, Terminator, mintstick, dconf-editor, gnome-clocks, plus a small, deliberately curated set of basic games β Mahjongg, Mines, Moonlander, Reversi, Solitaire, Sudoku, Yahtzee β chosen specifically instead of reintroducing the old bundledgnome-gamespackage this project already purges from core.
/etc/hosts is built from exactly one list β
StevenBlack/hosts β plus
custom.hosts, a plain local file in this repo for your own
additions. This project used to stack several different lists from several
maintainers; real, repeated experience was that it caused more site breakage
(an overzealous or stale entry in one of them blackholing a domain some site
actually needed) than it was worth. StevenBlack alone is well-maintained and
strikes a better balance β one source is also just one thing that can go
stale or move.
custom.hosts is merged in before StevenBlack's list, which matters if
you ever want to override an entry: for a given hostname, the first matching
line in /etc/hosts wins, so anything you put in custom.hosts takes
priority over the downloaded list β useful both for adding your own blocks
and for un-blocking something StevenBlack catches that you actually need.
- uBlock Origin is excluded from Waterfox on purpose. Waterfox has its own native ad-blocking engine built in (Brave's open-source adblock engine, using uBlock Origin's own filter lists β EasyList, EasyPrivacy, and more), running in the browser process rather than as an extension. Installing the actual extension on top would just be redundant with what's already running.
- LibreWolf gets a merge, not a fresh file. Firefox-family browsers use
exactly one
policies.jsonβ picked by priority, never merged with any other β and LibreWolf ships its own, which does a lot more than extensions (disables telemetry/studies, forces HTTPS-Only, blocks local- network tracking, strips sponsored content, and more). Overwriting it blindly would have silently undone all of that. Instead, LibreWolf's real current defaults (pulled from their own settings repo) are reproduced here with this project's extensions added into the existing list β nothing else touched. If LibreWolf changes their own defaults later this copy won't automatically follow, so it's worth re-diffing against their repo occasionally rather than trusting it as a one-time copy. LibreWolf already installs uBlock Origin itself (removable, not locked) β left exactly as-is, not force-installed or duplicated. - Privacy Possum was considered and deliberately left out β its last release was 2019. Not something to include in a privacy-hardening tool without active maintenance behind it.
- Onion Browser Button is not affiliated with the Tor Project β it's an
independently-developed convenience extension, unrelated to Tor Browser
itself (which this project already installs separately, properly
isolated). Its actual purpose here: this project also installs the
torpackage itself, which runs a local Tor SOCKS proxy in the background all the time β this extension is a one-click way to route regular browser traffic through that already-running local proxy for something quick, without launching the full, heavier, more isolated Tor Browser every time. Checked its actual source rather than just trusting the listing (it's open source: github.com/jeremy-jr-benthum/onion-browser-button): permissions are minimal (proxy,storage,notificationsβ nothing broader), toggling it on points Firefox's proxy settings at127.0.0.1:9050(the standard local Tor SOCKS port β not some third party's server) and verifies the connection against Tor Project's own officialcheck.torproject.org, exactly matching what it claims to do. The one thing worth knowing: on install/update it opens a changelog tab on the developer's own site with the version number in the URL (visible, low-sensitivity β you'd see the tab open, it's not hidden) β and that tab doesn't open when it detects an automated testing environment. Common, usually-benign pattern for not spamming testers with tabs, but also the kind of "behaves differently under review" detail worth knowing about rather than glossing over. Nothing else in the code goes beyond its stated purpose β this was independently verified for this project by reading the extension's actual shipped source, not just its store listing, so it's included here on that basis, not blind trust. If you'd still rather not run a third-party extension for this at all, the extension isn't doing anything you can't do yourself by hand: in any Firefox-based browser, Settings β Network Settings β Manual proxy configuration β SOCKS Host127.0.0.1, Port9050, SOCKS v5 β that's the entire mechanism, one click or typed in by hand.
- LibreWolf is set as the system default browser (
xdg-settings set default-web-browser librewolf.desktop) β it's the browser this project hardens the most conservatively (its own upstream defaults, not layered Arkenfox/Betterfox), so it's the one meant for everyday use. Skipped automatically if you installed with--no-librewolf. - ProxySearch.org β a privacy-respecting meta
search engine β is added as an available search engine and set as the
default in Firefox, Waterfox, and LibreWolf, via each browser's
policies.json. None of the built-in engines (Google, DuckDuckGo, etc.) are removed β ProxySearch is just what a fresh search starts with; switch back to any of them in Settings β Search any time. - The "make this your default browser" startup nag is suppressed on
Firefox and Waterfox (
browser.shell.checkDefaultBrowserset tofalseinoverrides-user.js) β there's no need for either to keep asking when LibreWolf is already set as the actual default. LibreWolf never showed this prompt in the first place (DontCheckDefaultBrowseris already part of its own upstreampolicies.json, reproduced as-is here).
- Quad9 (default) β free, unlimited, no account, run by the nonprofit Quad9 Foundation. Configured via DNS-over-TLS.
- OpenDNS β configured as plain DNS only; its DNS-over-TLS support isn't well established enough to enable encryption automatically here.
- NextDNS β uses a personal per-account config ID rather than a shared address, so it can't be wired in generically. The script prints a pointer to my.nextdns.io instead of guessing.
- none β leaves DNS at whatever the network provides.
(Mullvad's public DNS service was considered but is being shut down by Mullvad itself, with users migrated to Quad9 β not included here for that reason.)
Installing drops an upgrade command into ~/.local/bin/ (already on your
PATH) β run it whenever you'd otherwise run apt update && apt upgrade by
hand. It asks for your sudo password once, then: upgrades all packages,
removes old kernels that pile up along the way, cleans up, rebuilds
/etc/hosts from a fresh StevenBlack list plus your custom.hosts, and
rebuilds Firefox/Waterfox/LibreWolf's hardened preferences from a fresh
Arkenfox + Betterfox. One command, meant to become part of your normal
routine rather than something you reach for occasionally.
Your own additions β custom.hosts and overrides-user.js β live in
~/.config/privacyos/ once installed, not in the cloned repo folder, so
upgrade still works even if you delete that folder afterward. Edit them
there; upgrade only ever reads them, never overwrites them.
- This script. β (first draft β needs real-hardware testing; see below)
- A Debian preseed file that fully automates the official Debian installer and runs this script automatically as its last step, so installing PrivacyOS is closer to one step instead of two. Planned next, not yet built.
- A small companion site at
privacyos.devpointing here.
A full custom pre-built ISO was considered and set aside for now β a frozen image goes stale in a way this script doesn't (it always installs current packages at run time), and the preseed approach above gets most of the same benefit without that trade-off.
Core install (packages, DNS, hosts blocklist, browser hardening/extensions,
default browser, default search engine) has been tested end-to-end multiple
times and completes successfully, including a full reboot into a working
system. Automatic security updates and the firewall are newly added and
haven't been through that same real-install testing yet. --theme is wired
into the flag/prompt system but has no implementation behind it yet. All of
this has only run on one testing setup so far β not yet tried across a range
of real hardware or network configurations, so still expect the occasional
rough edge outside what's been directly exercised, particularly around the
DNS/NetworkManager interaction on hardware this hasn't been tried on.
MIT β see LICENSE.