A pair of bash scripts to save how your Linux is set up and put it back after a clean install. It works on Ubuntu and distros based on it (Linux Mint, Pop!_OS, Zorin, elementary...).
It handles:
- apt, Flatpak and Snap packages, including third-party apt repositories like Brave or Docker
- desktop settings (through dconf)
- dotfiles like
.bashrcand.gitconfig - a few system tweaks (swappiness, TRIM)
- anything else you want, through your own scripts ("hooks")
The scripts are the same for everyone. Your own data lives in a profile, a folder inside profiles/.
You need your own copy of this repo on GitHub, to push your profile to. There are two ways:
- Fork it. Quick, but a fork of a public repo is always public, and so is everything you push to it, dotfiles included.
- Make a private copy. Click Use this template at the top of this page and choose Private. Your profile stays visible only to you.
In the commands below, replace AndreMel-30 with your GitHub username and linux-setup with the name of your copy. If your copy is private, git clone on the new system needs you to log in to GitHub (with an SSH key or a token), so have that ready before you reinstall.
On the system you have now, before reinstalling:
git clone https://github.com/AndreMel-30/linux-setup.git
cd linux-setup
./backup.sh myname # saves everything into profiles/myname
git status # see what was saved, especially the dotfiles
git add -A && git commit -m "backup" && git pushOn the fresh install:
sudo apt install -y git
git clone https://github.com/AndreMel-30/linux-setup.git ~/linux-setup
cd ~/linux-setup && ./install.sh mynameBefore changing anything, install.sh shows a summary of what it is going to do (repositories, packages, settings, which files in your home will be replaced) and asks you to confirm. When it is done, reboot. At the end, install.sh lists anything it could not do (and exits with an error code if there is something). You can run it again as many times as you like.
If you leave out the name, the profile is called default. example is the template, so you can't back up into it.
A profile is just a folder. Its name is whatever you type after the script name; it is not taken from your username or your computer.
profiles/myname/
├── setup.conf what to do (see below)
├── packages/ apt.txt, flatpak.txt, snap.txt, one entry per line
├── apt-repos/ third-party apt repositories and their keys
├── dconf/ desktop settings, one .ini file per dconf branch
├── dotfiles/ copies of your config files
└── hooks/ your own scripts
profiles/example/ is the starting point. The first time you run backup.sh with a new name, it creates the folder and copies setup.conf from the example. After that, setup.conf is yours to edit. The scripts read it but never change it.
This is where you decide what the scripts do. It is a normal bash file with a few variables. Because it is bash, the scripts run it as code every time they load the profile, even backup.sh: only use profiles you trust.
| Variable | What it does |
|---|---|
DO_UPGRADE |
Update the whole system (apt full-upgrade) before installing anything. Turn it off if you only want to restore, say, your dotfiles. |
DO_APT, DO_FLATPAK, DO_SNAP |
Turn each package manager on or off. Set DO_SNAP=false on Mint, which has snap disabled. |
DO_DCONF, DO_DOTFILES, DO_HOOKS |
Same idea for desktop settings, dotfiles and hooks. |
SWAPPINESS |
How eagerly the kernel uses swap. Ubuntu and Mint use 60; lower values keep more in RAM. Leave empty to skip. |
ENABLE_TRIM |
Turn on the weekly TRIM timer for SSDs. |
DOTFILES |
Which files or folders in your home folder to save. |
DCONF_PATHS |
Which dconf branches to save. Empty means it picks them from your desktop. |
It reads your system and writes the result into the profile. It does not change anything on the system itself.
- apt: lists the packages you installed by hand. It subtracts the list from the moment the system was installed, so you only get your own packages and not the hundreds that came with the distro. Old kernel versions are left out.
- third-party repositories: copies the repository files from
/etc/apt/sources.list.d/and the keys they are signed with intoapt-repos/. The distro's own repositories are skipped. - Flatpak and Snap: lists the apps you have installed. For Flatpak only the app IDs are saved, and
install.shinstalls them all from Flathub, system-wide.backup.shwarns you about apps that came from another source or are installed for your user only. - dconf: dumps the desktop settings to text files. Some settings only store the path of a file, like your wallpaper; if that file is in your home folder and not in
DOTFILES,backup.shtells you, so you can copy it over yourself. - dotfiles: copies the files listed in
DOTFILES, and warns you if one looks like it contains a token or password. If one is a symlink, the file it points to is copied. A file you delete from your home folder is not deleted from the profile; remove it there by hand.
It reads the profile and applies it to the new system. Run it as a normal user, not with sudo; it asks for your password once.
First it prints a plan, for example:
==> Plan
Packages
apt repositories 5 to add: brave-browser-release, claude-desktop, docker, tailscale, vscodium
System upgrade yes (apt full-upgrade)
apt packages 96 to install
Flatpak apps 2 to install: com.rustdesk.RustDesk, org.localsend.localsend_app
Snap apps skipped (DO_SNAP=false)
System
Swappiness 10
TRIM weekly timer on
Desktop and home folder
Desktop settings 4 dconf branches: /org/cinnamon/, /org/gnome/terminal/, /org/nemo/, /org/x/
Dotfiles 3 to link, 0 already linked
2 existing file(s) in your home will be renamed to .bak.<date>
Your own scripts
Hooks none
Nothing has been changed yet. If you continue, you will be asked for your password.
Continue? [y/N]
Nothing happens until you answer y. To skip the question (for example when another script runs it), use ./install.sh --yes myname. Without a terminal and without --yes, it stops instead of guessing.
Then:
- Runs
hooks/pre-*.sh - Puts back the third-party repositories and their keys from
apt-repos/ - Updates the system, unless
DO_UPGRADE=false. If the upgrade fails the script stops, because installing more on top of a broken apt only makes things worse. - Installs the apt, Flatpak and Snap packages. A package that can't be found is skipped and reported, it doesn't stop the rest. Packages that ask a question while installing (wireshark, for example) get their default answer, so the script never stops to wait for you.
- Sets swappiness and TRIM
- Loads the dconf settings
- Links the dotfiles into your home folder. They are symlinks, so editing
~/.bashrcedits the file in the repo. If a file is already there, it is renamed to.bak.<date>, never deleted. Because of the links, keep the repo in a fixed place (like~/linux-setup): if you move or delete it, those files stop working. - Runs
hooks/post-*.sh
lib/common.sh has the small functions both scripts share.
For things that aren't a normal package: a pre-*.sh script runs before the packages (good for adding a PPA or repository), a post-*.sh script runs at the end (good for tools with their own installer, like Tailscale). There are two examples in profiles/example/hooks/.
You usually don't need a hook for apt repositories: backup.sh already saves the ones you have.
Packages like brave-browser or docker-ce don't come from your distro but from the developer's own apt repository. backup.sh saves those repositories, together with the key each one is signed with, and install.sh puts them back before installing packages. apt then checks every package against those keys, as it does on your current system.
Nothing is searched for or downloaded: the new system trusts exactly the same sources as the old one. A few things to keep in mind:
- If you don't want a repository anymore, remove it from your current system (or delete its files from
apt-repos/) before you runinstall.sh. - Developers sometimes change their key. If a saved key is out of date,
apt-get updatecomplains about that repository;install.shreports it at the end and goes on with the rest. Re-add the repository by following the developer's instructions. - The repositories are saved for one Ubuntu release (
apt-repos/codename, for examplenoble). If you install a newer release,install.shtells you and puts them back as they are. That usually works: most developers keep publishing for the older release too. (I tried a profile saved on Mint 22.3 on Ubuntu 26.04: Brave, Docker, Tailscale, VSCodium and Claude Desktop all installed fine.) When you have time, switch them to the new release by following each developer's instructions. - Anyone who can change your profile can add a repository and a key, and so install software as root. The same is true for hooks. Keep your profile somewhere only you can write to.
- Try it in a virtual machine first.
backup.shis safe to run any time, butinstall.shchanges the system. - Other desktops (KDE, XFCE...) are not recognised for dconf. You can still save their config folders by adding them to
DOTFILES, for example.config/xfce4. - Distros that are not Ubuntu-based are refused.
FORCE=1 ./install.sh mynamelets you try anyway. - If you keep your profile in a public repo, read your dotfiles first.
backup.shwarns about lines likepassword = ..., but that is only a hint: it can't recognise every secret. A private repo is safer. A profile can also live outside this folder: any argument with a/is used as a path, for example./install.sh ~/my-profile.
tests/run.sh checks the shared functions and runs backup.sh against a fake home folder. It changes nothing on your system, so you can run it any time. tests/install-smoke.sh runs install.sh for real, twice, so it only runs on GitHub's throwaway machines, together with ShellCheck, on every push.
MIT
