This commit is contained in:
Milan Martin Jäckel 2026-07-17 20:02:49 +02:00
parent 47d33a59a9
commit 845567d1f5
15 changed files with 635 additions and 79 deletions

3
.gitignore vendored
View File

@ -9,3 +9,6 @@ Thumbs.db
node_modules/ node_modules/
__pycache__/ __pycache__/
# Local machine secrets and filled-in templates
smb/fstab.fragment

View File

@ -1,14 +1,21 @@
# Milan's Omarchy Config # Milan's Omarchy Config
## Install This repository is the source of truth for Milan's Omarchy workstation.
Configs are restored with symlinks so future edits should happen here.
## Fresh install
```bash ```bash
git clone https://git.ta52.dk/milan/omarchy-config.git git clone https://git.ta52.dk/milan/omarchy-config.git
cd omarchy-config cd omarchy-config
chmod +x install.sh ./bootstrap.sh
```
## Restore on an existing install
```bash
./install.sh ./install.sh
``` ```
@ -25,3 +32,16 @@ git commit -m "Update"
git push git push
``` ```
## Structure
- `tracked-configs.txt` lists every managed config symlink.
- `configs/` stores files that restore into `~/.config`.
- `bash/` can store `.bashrc` and `.bash_aliases` when enabled in `tracked-configs.txt`.
- `scripts/` restores executable helpers into `~/.local/bin`.
- `applications/` restores custom launchers into `~/.local/share/applications`.
- `fonts/` restores into `~/.local/share/fonts/omarchy-config`.
- `system/` stores exported service and system package metadata.
- `smb/` stores SMB automount templates without credentials.
Set `ENABLE_SYSTEM_SERVICES=1` to restore system services and `INSTALL_SMB=1` to run the SMB installer.

1
applications/.gitkeep Normal file
View File

@ -0,0 +1 @@

103
backup.sh Normal file → Executable file
View File

@ -2,36 +2,109 @@
set -euo pipefail set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TRACKED_CONFIGS="$REPO_DIR/tracked-configs.txt"
copy_path() {
local source="$1"
local destination="$2"
if [[ ! -e "$source" && ! -L "$source" ]]; then
echo "Skipping missing source: $source"
return 0
fi
if [[ -e "$destination" || -L "$destination" ]]; then
if [[ "$(readlink -f "$source")" == "$(readlink -f "$destination")" ]]; then
echo "Already tracked: ${destination#$REPO_DIR/}"
return 0
fi
rm -rf "$destination"
fi
mkdir -p "$(dirname "$destination")"
cp -a "$source" "$destination"
echo "Copied $source -> ${destination#$REPO_DIR/}"
}
read_list() {
local file="$1"
[[ -f "$file" ]] || return 0
sed 's/#.*//' "$file" | awk 'NF {print $1}'
}
write_version_file() {
{
echo "Generated: $(date -Is)"
echo "Kernel: $(uname -r)"
if command -v hyprctl >/dev/null 2>&1; then
hyprctl version | sed -n '1p' | sed 's/^/Hyprland: /'
fi
if command -v omarchy >/dev/null 2>&1; then
omarchy version 2>/dev/null | sed 's/^/Omarchy: /' || true
fi
} > "$REPO_DIR/version.txt"
}
cd "$REPO_DIR"
echo "Updating package lists..." echo "Updating package lists..."
pacman -Qqe > packages.txt pacman -Qqe > packages.txt
pacman -Qqem > aur-packages.txt pacman -Qqem > aur-packages.txt
pacman -Qe > installed-packages-full.txt pacman -Qe > installed-packages-full.txt
echo "Updating configs..." if command -v flatpak >/dev/null 2>&1; then
flatpak list --app --columns=application > flatpaks.txt
fi
rm -rf configs echo "Updating version info..."
write_version_file
mkdir configs echo "Updating tracked configs..."
cp -r ~/.config/omarchy configs/ if [[ ! -f "$TRACKED_CONFIGS" ]]; then
cp -r ~/.config/hypr configs/ echo "Missing tracked-configs.txt"
cp -r ~/.config/waybar configs/ exit 1
cp -r ~/.config/walker configs/ fi
cp -r ~/.config/ghostty configs/
cp -r ~/.config/kitty configs/
cp -r ~/.config/mako configs/
cp -r ~/.config/nvim configs/
cp -r ~/.config/fastfetch configs/
cp ~/.config/starship.toml configs/ while read -r destination source; do
cp ~/.config/mimeapps.list configs/ [[ -n "${destination:-}" ]] || continue
[[ "$destination" != \#* ]] || continue
[[ -n "${source:-}" ]] || source="$destination"
destination="${destination/#\~/$HOME}"
source="${source/#\~/$HOME}"
[[ "$destination" = /* ]] || destination="$REPO_DIR/$destination"
[[ "$source" = /* ]] || source="$HOME/$source"
copy_path "$source" "$destination"
done < "$TRACKED_CONFIGS"
echo "Updating scripts, launchers, and fonts..."
if [[ -d "$HOME/.local/bin" ]]; then
mkdir -p scripts
fi
if [[ -d "$HOME/.local/share/applications" ]]; then
mkdir -p applications
fi
if [[ -d "$HOME/.local/share/fonts/omarchy-config" ]]; then
copy_path "$HOME/.local/share/fonts/omarchy-config" "$REPO_DIR/fonts"
fi
echo "Updating services..." echo "Updating services..."
systemctl --user list-unit-files --state=enabled > system/user-services.txt systemctl --user list-unit-files --state=enabled > system/user-services.txt
sudo systemctl list-unit-files --state=enabled > system/system-services.txt if command -v sudo >/dev/null 2>&1; then
sudo -n systemctl list-unit-files --state=enabled > system/system-services.txt 2>/dev/null || true
fi
echo echo
echo "Done!" echo "Done!"

1
bash/.gitkeep Normal file
View File

@ -0,0 +1 @@

31
bootstrap.sh Executable file
View File

@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
require_command() {
local command_name="$1"
if ! command -v "$command_name" >/dev/null 2>&1; then
echo "Missing required command: $command_name"
exit 1
fi
}
echo "========================================"
echo " Milan's Omarchy Bootstrap"
echo "========================================"
echo
require_command yay
require_command systemctl
require_command fc-cache
if [[ ! -f "$REPO_DIR/tracked-configs.txt" ]]; then
echo "Missing tracked-configs.txt"
exit 1
fi
chmod +x "$REPO_DIR/install.sh"
"$REPO_DIR/install.sh"

1
flatpaks.txt Normal file
View File

@ -0,0 +1 @@
# Add one Flatpak application ID per line.

1
fonts/.gitkeep Normal file
View File

@ -0,0 +1 @@

205
install.sh Normal file → Executable file
View File

@ -3,98 +3,179 @@
set -euo pipefail set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIGS_DIR="$REPO_DIR/configs" TRACKED_CONFIGS="$REPO_DIR/tracked-configs.txt"
BACKUP_DIR="$HOME/.local/state/omarchy-config/backups/$(date +%Y%m%d-%H%M%S)"
echo "========================================" echo "========================================"
echo " Milan's Omarchy Setup Installer" echo " Milan's Omarchy Setup Installer"
echo "========================================" echo "========================================"
echo echo
# ensure_dir() {
# Update system mkdir -p "$1"
# }
echo "[1/5] Updating system..."
read_list() {
local file="$1"
[[ -f "$file" ]] || return 0
sed 's/#.*//' "$file" | awk 'NF {print $1}'
}
backup_target() {
local target="$1"
local backup
[[ -e "$target" || -L "$target" ]] || return 0
ensure_dir "$BACKUP_DIR"
backup="$BACKUP_DIR/${target#$HOME/}"
ensure_dir "$(dirname "$backup")"
echo "Backing up $target"
mv "$target" "$backup"
}
link_path() {
local source="$1"
local target="$2"
if [[ ! -e "$source" ]]; then
echo "Skipping missing source: ${source#$REPO_DIR/}"
return 0
fi
ensure_dir "$(dirname "$target")"
if [[ -L "$target" && "$(readlink -f "$target")" == "$(readlink -f "$source")" ]]; then
echo "Already linked: $target"
return 0
fi
backup_target "$target"
ln -s "$source" "$target"
echo "Linked $target -> ${source#$REPO_DIR/}"
}
install_packages() {
local file="$1"
[[ -s "$file" ]] || return 0
mapfile -t packages < <(read_list "$file")
((${#packages[@]} > 0)) || return 0
yay -S --needed --noconfirm "${packages[@]}"
}
echo "[1/8] Updating system..."
yay -Syu --noconfirm yay -Syu --noconfirm
#
# Install packages
#
echo echo
echo "[2/5] Installing packages..." echo "[2/8] Installing packages..."
install_packages "$REPO_DIR/packages.txt"
install_packages "$REPO_DIR/aur-packages.txt"
if [[ -f "$REPO_DIR/packages.txt" ]]; then if [[ -s "$REPO_DIR/flatpaks.txt" ]] && command -v flatpak >/dev/null 2>&1; then
yay -S --needed --noconfirm $(<"$REPO_DIR/packages.txt") while read -r app; do
[[ -n "$app" ]] || continue
flatpak install --user --noninteractive flathub "$app" || true
done < <(read_list "$REPO_DIR/flatpaks.txt")
fi fi
if [[ -s "$REPO_DIR/aur-packages.txt" ]]; then echo
yay -S --needed --noconfirm $(<"$REPO_DIR/aur-packages.txt") echo "[3/8] Linking tracked configs..."
if [[ ! -f "$TRACKED_CONFIGS" ]]; then
echo "Missing tracked-configs.txt"
exit 1
fi fi
# while read -r source target; do
# Symlink configs [[ -n "${source:-}" ]] || continue
# [[ "$source" != \#* ]] || continue
[[ -n "${target:-}" ]] || target="$source"
source="${source/#\~/$HOME}"
target="${target/#\~/$HOME}"
[[ "$source" = /* ]] || source="$REPO_DIR/$source"
[[ "$target" = /* ]] || target="$HOME/$target"
link_path "$source" "$target"
done < "$TRACKED_CONFIGS"
echo echo
echo "[3/5] Linking configs..." echo "[4/8] Linking scripts..."
mkdir -p "$HOME/.config" if [[ -d "$REPO_DIR/scripts" ]]; then
ensure_dir "$HOME/.local/bin"
find "$REPO_DIR/scripts" -maxdepth 1 -type f -executable | sort |
while read -r script; do
link_path "$script" "$HOME/.local/bin/$(basename "$script")"
done
fi
for item in "$CONFIGS_DIR"/*; do
name="$(basename "$item")"
target="$HOME/.config/$name"
# Skip if already linked correctly
if [[ -L "$target" ]]; then
if [[ "$(readlink -f "$target")" == "$(readlink -f "$item")" ]]; then
echo "$name already linked"
continue
fi
fi
# Backup existing config
if [[ -e "$target" && ! -L "$target" ]]; then
backup="${target}.backup.$(date +%Y%m%d-%H%M%S)"
echo "Backing up $name -> $(basename "$backup")"
mv "$target" "$backup"
fi
rm -rf "$target"
ln -s "$item" "$target"
echo "Linked $name"
done
#
# Enable user services
#
echo echo
echo "[4/5] Enabling user services..." echo "[5/8] Linking desktop launchers..."
if [[ -d "$REPO_DIR/applications" ]]; then
ensure_dir "$HOME/.local/share/applications"
find "$REPO_DIR/applications" -maxdepth 1 -type f -name '*.desktop' | sort |
while read -r launcher; do
link_path "$launcher" "$HOME/.local/share/applications/$(basename "$launcher")"
done
fi
echo
echo "[6/8] Linking fonts..."
if [[ -d "$REPO_DIR/fonts" ]]; then
ensure_dir "$HOME/.local/share/fonts"
link_path "$REPO_DIR/fonts" "$HOME/.local/share/fonts/omarchy-config"
fc-cache -fv >/dev/null 2>&1 || true
fi
echo
echo "[7/8] Enabling user services..."
if [[ -f "$REPO_DIR/system/user-services.txt" ]]; then if [[ -f "$REPO_DIR/system/user-services.txt" ]]; then
awk '{print $1}' "$REPO_DIR/system/user-services.txt" | read_list "$REPO_DIR/system/user-services.txt" |
while read -r service; do while read -r service; do
[[ -z "$service" ]] && continue
systemctl --user enable "$service" >/dev/null 2>&1 || true systemctl --user enable "$service" >/dev/null 2>&1 || true
done done
fi fi
# if [[ -f "$REPO_DIR/system/system-services.txt" ]]; then
# Font cache if [[ "${ENABLE_SYSTEM_SERVICES:-0}" == "1" ]]; then
# read_list "$REPO_DIR/system/system-services.txt" |
while read -r service; do
if systemctl list-unit-files "$service" >/dev/null 2>&1; then
sudo systemctl enable "$service" >/dev/null 2>&1 || true
fi
done
else
echo "Skipping system services. Run with ENABLE_SYSTEM_SERVICES=1 to enable them."
fi
fi
echo echo
echo "[5/5] Refreshing font cache..." echo "[8/8] Running optional installers..."
fc-cache -fv >/dev/null 2>&1 || true
if [[ -x "$REPO_DIR/smb/install.sh" ]]; then
if [[ "${INSTALL_SMB:-0}" == "1" ]]; then
"$REPO_DIR/smb/install.sh"
else
echo "Skipping SMB installer. Run with INSTALL_SMB=1 to enable it."
fi
fi
echo echo
echo "========================================" echo "========================================"
echo " Finished!" echo " Finished!"
echo "========================================" echo "========================================"
echo echo
echo "You may want to:" echo "Backups were written to: $BACKUP_DIR"
echo " • Log out and back in" echo
echo " • Run: omarchy-theme (if needed)" echo "You may want to log out and back in, or restart Waybar/Hyprland if configs changed."
echo " • Restart Waybar/Hyprland if configs changed"
echo echo

283
smb-setup.md Normal file
View File

@ -0,0 +1,283 @@
# SVR52 Samba Client Setup (Omarchy / Arch Linux)
## Purpose
This document describes the complete client-side configuration for automatically connecting to the Samba share hosted on **svr52** (a Raspberry Pi server) from another Linux machine running Omarchy/Arch.
The server is accessed primarily over **Tailscale**, meaning the machine may not be on the same LAN.
The goal is:
* Automatically access the Samba share after boot.
* Do **not** fail boot if the server is unavailable.
* Wait until the share is actually accessed before attempting to connect.
* Work reliably with Tailscale's startup delay.
---
# Server Information
Hostname:
```text
svr52
```
Samba user:
```text
ta52
```
Primary share:
```text
smb
```
Mount point on client:
```text
/home/milan/svr52
```
---
# Required packages
Arch:
```bash
sudo pacman -S cifs-utils smbclient
```
---
# Verify connectivity
List available shares:
```bash
smbclient -L //svr52 -U ta52
```
Expected shares:
```
smb
ta52
print$
IPC$
```
---
# Credentials file
Create:
```bash
mkdir -p ~/.smb
nano ~/.smb/svr52
```
Contents:
```text
username=ta52
password=costarica
```
Protect it:
```bash
chmod 600 ~/.smb/svr52
```
---
# Create mountpoint
```bash
mkdir -p ~/svr52
```
---
# /etc/fstab
Append:
```fstab
//svr52/smb /home/milan/svr52 cifs credentials=/home/milan/.smb/svr52,uid=1000,gid=1000,_netdev,nofail,x-systemd.automount,x-systemd.idle-timeout=10min 0 0
```
### Explanation
* `credentials=...`
Uses the credentials file.
* `uid=1000,gid=1000`
Files appear owned by the normal user.
* `_netdev`
Marks this as a network filesystem.
* `nofail`
Boot continues even if the server is unreachable.
* `x-systemd.automount`
Do **not** mount during boot.
Mount only when the directory is first accessed.
* `x-systemd.idle-timeout=10min`
Automatically unmount after 10 minutes of inactivity.
---
# Reload systemd
```bash
sudo systemctl daemon-reload
```
---
# Test
Unmount if currently mounted:
```bash
sudo umount ~/svr52
```
Start automount:
```bash
sudo systemctl start home-milan-svr52.automount
```
Status should show:
```
Active: active (waiting)
```
---
# Verify automount
Before accessing:
```bash
findmnt ~/svr52
```
Expected:
```
autofs
```
Access the folder:
```bash
ls ~/svr52
```
Then verify:
```bash
findmnt ~/svr52
```
Expected:
```
autofs
└── cifs //svr52/smb
```
This confirms the automount triggered successfully.
---
# Why automount is required
A normal fstab mount fails because:
1. systemd processes `/etc/fstab`
2. Tailscale has **not yet connected**
3. `svr52` cannot be reached
4. Samba mount fails
Automount fixes this because:
1. Boot finishes normally.
2. Tailscale connects.
3. User later opens:
```
~/svr52
```
4. systemd performs the mount only then.
This completely avoids boot-time race conditions.
---
# Useful commands
List shares:
```bash
smbclient -L //svr52 -U ta52
```
Manual mount:
```bash
sudo mount -a
```
Unmount:
```bash
sudo umount ~/svr52
```
Status:
```bash
systemctl status home-milan-svr52.automount
```
Verify mount:
```bash
findmnt ~/svr52
```
Reload systemd after editing fstab:
```bash
sudo systemctl daemon-reload
```
---
# Current Working Configuration
* Client OS: Omarchy (Arch Linux)
* Transport: Tailscale
* Hostname: `svr52`
* Share: `smb`
* Credentials file: `~/.smb/svr52`
* Mount point: `/home/milan/svr52`
* Mount type: CIFS
* Mount strategy: `systemd` automount
* Idle timeout: 10 minutes
This configuration has been tested and confirmed working. The Samba share mounts automatically on first access after Tailscale is connected, eliminating boot-time failures caused by network startup timing.

10
smb/README.md Normal file
View File

@ -0,0 +1,10 @@
# SMB Automount
This directory stores the non-secret pieces needed to restore SMB mounts.
1. Copy `fstab.fragment.example` to `fstab.fragment`.
2. Edit the server, share, mountpoint, and credentials path.
3. Store credentials outside this repository.
4. Run `INSTALL_SMB=1 ./install.sh` from the repository root.
Never commit Samba credentials.

View File

@ -0,0 +1,2 @@
# Example only. Copy to smb/fstab.fragment and edit locally.
# //server/share /mnt/share cifs credentials=/home/milan/.smbcredentials,uid=1000,gid=1000,iocharset=utf8,nofail,x-systemd.automount 0 0

32
smb/install.sh Executable file
View File

@ -0,0 +1,32 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
FSTAB_FRAGMENT="$REPO_DIR/smb/fstab.fragment"
echo "Installing SMB support..."
yay -S --needed --noconfirm cifs-utils smbclient
if [[ ! -f "$FSTAB_FRAGMENT" ]]; then
echo "No smb/fstab.fragment found. Copy smb/fstab.fragment.example and edit it first."
exit 0
fi
while read -r device mountpoint rest; do
[[ -n "${device:-}" ]] || continue
[[ "$device" != \#* ]] || continue
[[ -n "${mountpoint:-}" ]] || continue
sudo mkdir -p "$mountpoint"
if ! grep -Fq "$device $mountpoint " /etc/fstab; then
echo "$device $mountpoint $rest" | sudo tee -a /etc/fstab >/dev/null
echo "Added fstab entry for $mountpoint"
else
echo "fstab already contains $mountpoint"
fi
done < "$FSTAB_FRAGMENT"
sudo systemctl daemon-reload
echo "SMB setup complete."

16
tracked-configs.txt Normal file
View File

@ -0,0 +1,16 @@
# Repository path Home path
configs/omarchy .config/omarchy
configs/hypr .config/hypr
configs/waybar .config/waybar
configs/walker .config/walker
configs/ghostty .config/ghostty
configs/kitty .config/kitty
configs/mako .config/mako
configs/nvim .config/nvim
configs/fastfetch .config/fastfetch
configs/starship.toml .config/starship.toml
configs/mimeapps.list .config/mimeapps.list
# Uncomment after adding the matching files:
# bash/.bashrc .bashrc
# bash/.bash_aliases .bash_aliases

1
version.txt Normal file
View File

@ -0,0 +1 @@
# Generated by ./backup.sh