A Personal Git-Based Backup & Replication System for my new Omarchy setup
As an Arch Linux user (btw), you know the power of granular control – and the pain of starting from scratch. While tools like omarchy offer snapshot capabilities, I wanted a robust, version-controlled system for my personal configuration (“dotfiles”) that lives alongside my data backups and makes reproducing my exact setup on any new machine incredibly easy.
This tutorial will walk you through setting up a powerful, private Git-based backup and replication system for your Arch Linux dotfiles, securely hosted on your Synology NAS using Gitea.
Note: This guide focuses solely on backing up configuration files and application lists. Your personal data like Pictures, Documents, and Music should be handled by a dedicated sync solution, such as Synology Drive, as I do.
The Core Concept
We will use a “bare” Git repository to track config files (dotfiles) scattered across our home directory. We’ll host this repository on a private Gitea server, which will run in a Docker container on a Synology NAS. We’ll even automate the backup process using systemd.
Part 1: Set Up Your Private Gitea Server on Synology NAS
This will be the central hub for your backups.
-
Prepare Synology NAS Storage:
- Open File Station and create a new folder at
/volume1/docker/gitea-data. This will permanently store all your Git repositories. - Find your User ID (UID/GID) by SSH-ing into your NAS and running
id your_username. Note theuid(e.g.,1026) andgid(e.g.,100).
- Open File Station and create a new folder at
-
Add Gitea to
docker-compose.yml:- Open your NAS’s
docker-compose.ymlfile and add the following service block.
# --- Gitea Git Server --- gitea: image: gitea/gitea:latest container_name: gitea-server restart: unless-stopped networks: - nas-network # Or your existing Docker network ports: - "3000:3000" # Gitea Web UI - "2222:22" # Gitea SSH (Cannot use 22, as the NAS host uses it!) volumes: - /volume1/docker/gitea-data:/data environment: - TZ=${TZ} - USER_UID=1026 # <-- Change to your UID - USER_GID=100 # <-- Change to your GID - Open your NAS’s
-
Deploy and Configure Gitea:
- Run
docker-compose up -dto start the new container. - Find your NAS’s Tailscale IP (or local IP if you’re on the LAN, e.g.,
192.168.10.98). - Open a browser and go to
http://<YOUR_NAS_IP>:3000. - On the “Initial Configuration” page, set the following:
- Database Type:
SQLite3(perfectly fine for this). - Server Domain: Your NAS IP (e.g.,
192.168.10.98or your Tailscale IP). - SSH Server Port:
2222(This is critical). - Gitea Base URL:
http://<YOUR_NAS_IP>:3000/.
- Database Type:
- Create your admin account and complete the installation.
- Log in and create a new private repository (e.g.,
omarchy-system-config).
- Run
Part 2: Configure Your MAIN Machine (The Backup Source)
This is the most important part, where we set up the backup system correctly from the start.
-
Install Tools:
sudo pacman -S git lazygit -
Set Up SSH Key:
- Generate a new key:
ssh-keygen -t ed25519 -C "main-arch-machine" - Copy the public key:
cat ~/.ssh/id_ed25519.pub - In Gitea, go to Settings > SSH / GPG Keys and paste your public key.
- Generate a new key:
-
Create the Bare Repository:
git init --bare $HOME/.dotfiles -
Create Your Shell Aliases (The Correct Way):
- Add these aliases to your shell’s config file (
~/.bashrcor~/.zshrc). This command block handles special characters and uses the portable$HOMEvariable.
cat << 'EOF' >> ~/.bashrc # --- Custom Aliases for Dotfiles Backup --- # Use the bare repo for dotfiles alias config='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' # Use lazygit with the bare repo alias lazydots='lazygit --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' # Update package lists (no version numbers, 'q' flag) alias update-pkgs='pacman -Qenq > $HOME/.local/state/pkglist_pacman.txt && pacman -Qemq > $HOME/.local/state/pkglist_aur.txt && echo "✅ Package lists updated!"' EOF- Reload your shell to activate them:
source ~/.bashrc
- Add these aliases to your shell’s config file (
-
Connect to Gitea:
- Get the SSH URL from your Gitea repository page.
config remote add origin ssh://git@<YOUR_NAS_IP>:2222/your_user/your_repo.git -
Create the Perfect
.gitignore:- We will use the
info/excludefile for our rules. This is the key to making the system work recursively.
nano ~/.dotfiles/info/exclude- Paste the following complete ruleset. This tells Git to ignore everything by default, then makes specific, recursive exceptions for what we want to back up.
# --- Main Rules --- # 1. For security, always ignore all .env files. *.env # 2. Ignore everything in the home directory by default. * # --- EXCEPTIONS --- # Now, explicitly UN-ignore the specific files and folders we want to track. # Individual dotfiles !/.bash_profile !/.bashrc !/.gitconfig !/.gitignore # Main .config directory and its contents recursively !/.config/ !/.config/** # .local directory structure and its contents recursively !/.local/ !/.local/bin/ !/.local/bin/** !/.local/share/ !/.local/share/applications/ !/.local/share/applications/** !/.local/share/fonts/ !/.local/share/fonts/** !/.local/share/icons/ !/.local/share/icons/** !/.local/state/ !/.local/state/pkglist_pacman.txt !/.local/state/pkglist_aur.txt- Save the file.
- We will use the
-
Do the First Push:
- Copy the rules to a tracked
.gitignorefile:cp ~/.dotfiles/info/exclude ~/.gitignore - Generate your package lists:
update-pkgs - Add all your tracked files:
config add -A - Commit your files:
config commit -m "Initial commit of dotfiles" - Push and set the upstream branch. Note: Your Gitea branch is likely named
master.config push --set-upstream origin master - When prompted to trust the SSH key, type
yesand press Enter.
- Copy the rules to a tracked
Part 3: Automate Daily Backups
Now, let’s set up the systemd timer for your daily “safety net” backup.
-
Create the Backup Script:
nano ~/.local/bin/backup-system-config.sh- Paste this content (note the
Qenq/Qemqflags):
#!/bin/bash cd "$HOME" || exit alias config='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' STATE_DIR="$HOME/.local/state" mkdir -p "$STATE_DIR" # Update package lists (quiet, no versions) pacman -Qenq > "$STATE_DIR/pkglist_pacman.txt" pacman -Qemq > "$STATE_DIR/pkglist_aur.txt" # Add lists and any other modified files config add "$STATE_DIR/pkglist_pacman.txt" config add "$STATE_DIR/pkglist_aur.txt" config add -u # Commit and push only if there are changes if ! config diff-index --quiet HEAD --; then config commit -m "chore(backup): automated system sync" config push origin main fi- Save and make it executable:
chmod +x ~/.local/bin/backup-system-config.sh
- Paste this content (note the
-
Create the
systemdService:mkdir -p ~/.config/systemd/user/ nano ~/.config/systemd/user/system-backup.service- Paste this:
[Unit] Description=Backup system dotfiles to Gitea [Service] Type=oneshot ExecStart=%h/.local/bin/backup-system-config.sh -
Create the
systemdTimer:nano ~/.config/systemd/user/system-backup.timer- Paste this (runs daily at midnight):
[Unit] Description=Run system dotfiles backup daily [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target -
Add the Timer to Git & Activate:
- Crucial Step: Add your new
systemdfiles to the backup!config add ~/.config/systemd/ config commit -m "feat: add systemd automation files" config push - Enable the timer on your main machine:
systemctl --user daemon-reload systemctl --user enable --now system-backup.timer
- Crucial Step: Add your new
Part 4: The Payoff! Replicating on a NEW Machine
This is the moment of truth. On a fresh Arch Linux installation, follow these steps.
-
Initial Setup:
sudo pacman -S git git init --bare $HOME/.dotfiles # Add the aliases to .bashrc (or .zshrc) cat << 'EOF' >> ~/.bashrc alias config='/usr/bin/git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' alias lazydots='lazygit --git-dir=$HOME/.dotfiles/ --work-tree=$HOME' alias update-pkgs='pacman -Qenq > $HOME/.local/state/pkglist_pacman.txt && pacman -Qemq > $HOME/.local/state/pkglist_aur.txt && echo "✅ Package lists updated!"' EOF source ~/.bashrc -
Connect to Gitea:
- Generate a new SSH key:
ssh-keygen -t ed25519 - Copy the public key:
cat ~/.ssh/id_ed25519.pub - Add this new key to your Gitea account settings.
- Connect the remote:
config remote add origin ssh://git@<YOUR_NAS_IP>:2222/your_user/your_repo.git
- Generate a new SSH key:
-
Force Checkout Your Config:
- A new system has default dotfiles. Git will complain. We’ll forcefully overwrite them with our backed-up versions.
config checkout -f master(Use
masteror whatever your branch name is. All your custom files, fonts, and icons will now appear!) -
Restore All Your Software:
- Sync Repos: First, sync your new machine’s package database.
sudo pacman -Syu - Install
yay:sudo pacman -S --needed base-devel git git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si && cd .. - Install from Lists: We use
awkto strip version numbers, just in case your old lists still have them. This is the most robust command.# Install official packages awk '{print $1}' ~/.local/state/pkglist_pacman.txt | sudo pacman -S --needed - # Install AUR packages awk '{print $1}' ~/.local/state/pkglist_aur.txt | yay -S --needed -
- Sync Repos: First, sync your new machine’s package database.
-
Activate Automated Backup:
- Your timer files were restored, but they aren’t active. Let’s enable them.
systemctl --user daemon-reload systemctl --user enable --now system-backup.timer- Verify it’s running:
systemctl --user list-timers
Part 5: Living With Your System (Maintenance)
-
How to Add New Software:
- Install it:
sudo pacman -S new-app - Update your list:
update-pkgs - Back it up:
lazydots, stage thepkglistfiles, commit, and push.
- Install it:
-
How to Add a New Webapp:
- Create the webapp in your browser.
- Back it up:
lazydots, stage the new.desktopfile, commit, and push.
-
Handling Missing Icons:
- Your webapp shortcuts (
.desktopfiles) may link to icons. - Solution: Place all your custom icon files in
~/.local/share/icons/. Our.gitignoreis already set up to find them. Just runlazydotsto add, commit, and push them.
- Your webapp shortcuts (
-
What About Deleted Apps?
- This backup is additive. If you restore to a new machine, it won’t uninstall default apps (like
nanoorvi) that aren’t in your list. - Solution: This is a minor, one-time manual cleanup.
sudo pacman -Rns unwanted-package.
- This backup is additive. If you restore to a new machine, it won’t uninstall default apps (like
You now have a complete, secure, and automated system for replicating your perfect Arch Linux environment anywhere. Congratulations!
