# Ubuntu / Debian Setup Manager A collection of hardened install and maintenance scripts for a fresh Ubuntu / Debian desktop, driven by an interactive `menu.sh`. Each installer auto-detects the distro, uses `signed-by` APT keyrings where applicable (no `apt-key`), and is idempotent (safe to re-run). ## Quick start — run the menu One-liner — fetches `menu.sh` and runs it. You'll see a numeric picker and can select one option, several, or all: ```bash bash -c "$(curl -fsSL https://tinyurl.com/bdddmxc4)" ``` How to use the picker: - Enter one or more numbers separated by spaces, e.g. `1 6 11` - `0` runs setup options 1-23 in order - `-1` exits The menu caches `sudo` credentials up-front so multi-task runs don't keep re-prompting, and falls back to per-user execution for scripts that must not run as root (JetBrains Toolbox, IBus Pinyin, Nerd Fonts, screenshots cleanup, Thunderbird backup, CCUsage sync). ## Available scripts | # | Category | Script | Runs as | What it does | |---|---|---|---|---| | 1 | Browsers & Mail | [`install-chrome.sh`](install-chrome.sh) | sudo | Installs Google Chrome Stable from Google's official APT repo using a `signed-by` keyring. | | 2 | Browsers & Mail | [`install-firefox.sh`](install-firefox.sh) | sudo | Removes the Firefox Snap and installs Firefox from Mozilla's official APT repo, with APT pinning so it stays on the Mozilla build. Verifies the Mozilla signing-key fingerprint. | | 3 | Browsers & Mail | [`install-thunderbird.sh`](install-thunderbird.sh) | sudo | Ubuntu: removes the Snap, adds the Mozilla Team PPA, and pins it. Debian: installs from the standard repos. | | 4 | Communication | [`install-telegram.sh`](install-telegram.sh) | sudo | Installs the latest official Telegram Desktop Linux build from Telegram's latest download endpoint. Adds launcher and `tg:` URL handler. | | 5 | Communication | [`install-discord.sh`](install-discord.sh) | sudo | Installs the latest official Discord Linux `.deb` from Discord's latest download endpoint. | | 6 | Files, Downloads & Storage | [`install-localsend.sh`](install-localsend.sh) | sudo | Installs the latest official LocalSend `.deb` from `localsend/localsend`. SHA-256 verified against the GitHub release asset digest when available. | | 7 | Files, Downloads & Storage | [`install-qbittorrent.sh`](install-qbittorrent.sh) | sudo | Installs the latest official qBittorrent x86_64 AppImage from `qbittorrent/qBittorrent`. SHA-256 verified against the GitHub release asset digest when available. Installs launcher, icons, and torrent/magnet handlers. | | 8 | Files, Downloads & Storage | [`install-network_drive.sh`](install-network_drive.sh) | sudo | Discovers SMB shares on a Synology NAS and adds them to `/etc/fstab` under `/mnt/Synology` with `x-systemd.automount`. fstab block is managed via begin/end markers so re-runs replace rather than duplicate. Credentials file is `0600`. Best-effort GNOME Dock pin. | | 9 | Productivity & Security | [`install-libreoffice.sh`](install-libreoffice.sh) | sudo | Detects the latest stable release on documentfoundation.org, downloads the matching `.deb` tarball, verifies the published MD5, and installs. Purges the distro's `libreoffice*` first to avoid library conflicts (opt-out with `--keep-distro-libreoffice`). | | 10 | Productivity & Security | [`install-obsidian.sh`](install-obsidian.sh) | sudo | Installs the latest official Obsidian amd64 `.deb` from `obsidianmd/obsidian-releases`. SHA-256 verified against the GitHub release asset digest when available. Honors `$GITHUB_TOKEN` to avoid API rate limits. | | 11 | Productivity & Security | [`install-marktext.sh`](install-marktext.sh) | sudo | Installs the latest official MarkText amd64 `.deb` from `marktext/marktext`. SHA-256 verified against the GitHub release asset digest when available. Honors `$GITHUB_TOKEN` to avoid API rate limits. | | 12 | Productivity & Security | [`install-drawio.sh`](install-drawio.sh) | sudo | Installs the latest official draw.io Desktop `.deb` from `jgraph/drawio-desktop`. SHA-256 verified against the GitHub release asset digest when available. Honors `$GITHUB_TOKEN` to avoid API rate limits. | | 13 | Productivity & Security | [`install-espanso.sh`](install-espanso.sh) | sudo | Installs Espanso. Auto-detects Wayland vs X11 from `$XDG_SESSION_TYPE` and registers the systemd-user service as the invoking desktop user (not root). | | 14 | Productivity & Security | [`install-1password.sh`](install-1password.sh) | sudo | Configures the 1Password APT repo with `debsig` signature policy. Arch-aware (amd64 / arm64). | | 15 | Development Tools | [`install-vscode.sh`](install-vscode.sh) | sudo | Microsoft's official `code` APT repo, signed-by keyring. `--insiders` flag installs `code-insiders` instead. | | 16 | Development Tools | [`install-jetbrains-toolbox.sh`](install-jetbrains-toolbox.sh) | **user** | Per-user install into `~/.local/share/JetBrains/Toolbox`. SHA-256 verified against JetBrains' release feed. x86_64 + aarch64. Drops a `.desktop` launcher. | | 17 | Development Tools | [`install-bruno.sh`](install-bruno.sh) | sudo | Bruno API client from the official APT repo. Keyserver fetch is wrapped in a 5-attempt retry/backoff because `keyserver.ubuntu.com` is occasionally flaky. | | 18 | Development Tools | [`install-ipatool.sh`](install-ipatool.sh) | sudo | Installs the latest release of `majd/ipatool` from GitHub. SHA-256 verified against the release `checksums.txt`. Honors `$GITHUB_TOKEN` to avoid API rate limits. | | 19 | Desktop & Localization | [`install-ibus-pinyin.sh`](install-ibus-pinyin.sh) | **user** | Installs `ibus-libpinyin` and Simplified Chinese language packs, restarts the IBus daemon, and idempotently adds `('ibus', 'libpinyin')` to GNOME's input sources via `gsettings`. | | 20 | Desktop & Localization | [`install-font.sh`](install-font.sh) | **user** | Installs the latest Ubuntu Sans Nerd Font and JetBrains Mono Nerd Font to `~/.local/share/fonts`, then refreshes the font cache. No sudo needed. | | 21 | System & Maintenance | [`install-screenshot-cleanup-cron.sh`](install-screenshot-cleanup-cron.sh) | **user** | Installs an idempotent per-user cron job that clears `$HOME/Pictures/Screenshots` every 5 minutes while preserving the directory itself. | | 22 | System & Maintenance | [`timedatectl-fix.sh`](timedatectl-fix.sh) | sudo | Sets the hardware clock to UTC to avoid time drift when dual-booting Linux and Windows. | | 23 | System & Maintenance | [`disable-grub-countdown.sh`](disable-grub-countdown.sh) | sudo | Configures GRUB to show the dual-boot menu with no countdown by setting `GRUB_TIMEOUT_STYLE=menu` and `GRUB_TIMEOUT=-1`, then regenerates the GRUB config. | | 24 | Backup | [`backup-thunderbird-to-synology.sh`](backup-thunderbird-to-synology.sh) | **user** | Backs up `/home/vernon/.thunderbird/` to a configurable Synology NAS destination using `rsync -a --delete`, mountpoint checks, and `flock`. Not included in menu option `0`; run it explicitly. | | 25 | Backup | [`install-ccusage-sync.sh`](install-ccusage-sync.sh) | **user** | Installs and verifies five-minute multi-device usage synchronization for Claude Code, Codex CLI, and OpenCode through a preconfigured Hetzner Storage Box. Not included in menu option `0`; select it explicitly. | "Runs as **user**" entries must be invoked as your normal desktop user, not via `sudo`. The other entries elevate via `sudo` internally and the menu primes `sudo -v` up-front, so you'll only be prompted once. ## Running a single script directly If you'd rather skip the menu, each script can be run on its own. Use the right invocation pattern for that script's privilege mode: ```bash # sudo scripts (1-15, 17-18, 22-23) — pipe through sudo bash curl -fsSL https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/install-firefox.sh | sudo bash # user scripts (16, 19-21, 24-25) — DO NOT use sudo; they install or run per-user bash -c "$(curl -fsSL https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/install-font.sh)" ``` Most installers and utilities accept `--help` and `--dry-run` (the latter prints what would happen without executing). For example: ```bash curl -fsSL https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/install-libreoffice.sh \ | bash -s -- --help ``` ## CCUsage Multi-Device Sync Menu option `25` downloads and validates the canonical public installer from: ```text https://opengist.resetrix.work/weehong/ai-coding-agent ``` It installs dependencies, deploys `~/sync-ccusage.sh`, runs an initial push and pull, and installs a five-minute user cron job. The sync includes Claude Code, Codex CLI, and OpenCode data. The complete cloud tree is pulled into `~/.ccusage-synced-logs/`. Before selecting option `25`, configure passwordless SSH for the alias `hetzner-ccusage-storage-box`. The installer does not create, copy, or replace SSH private keys. If SSH or the initial rsync fails, it does not install the cron entry. Run option `25` directly without the menu: ```bash bash -c "$(curl -fsSL https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/install-ccusage-sync.sh)" ``` Validate the wrapper without installing: ```bash curl -fsSL https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/install-ccusage-sync.sh \ | bash -s -- --dry-run ``` ## Thunderbird to Synology Backup The Thunderbird backup utility reads its default config from this gist: ```bash https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/thunderbird-backup.conf ``` Run it manually: ```bash bash -c "$(curl -fsSL https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/backup-thunderbird-to-synology.sh)" ``` Preview changes without writing files: ```bash curl -fsSL https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/backup-thunderbird-to-synology.sh \ | bash -s -- --dry-run ``` To change the backup location for every machine using the hosted config, edit `thunderbird-backup.conf` in this gist and update `DESTINATION`; if the backup location is on a different mounted drive or NAS share, update `MOUNTPOINT` too. The script parses only `SOURCE`, `DESTINATION`, `MOUNTPOINT`, `LOG_FILE`, and `LOCK_FILE`; unsupported keys or invalid lines stop the run. For hourly backups, install the script locally and add it to the current user's crontab: ```bash mkdir -p /home/vernon/bin curl -fsSL https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/backup-thunderbird-to-synology.sh \ -o /home/vernon/bin/backup-thunderbird-to-synology.sh chmod 755 /home/vernon/bin/backup-thunderbird-to-synology.sh ``` ```cron 0 * * * * /home/vernon/bin/backup-thunderbird-to-synology.sh ``` ## What "hardened" means here The hardened installers generally share this robustness baseline: - `set -euo pipefail` + IFS hygiene + `ERR` trap reporting the failing line number - `/etc/os-release` distro auto-detection (no hardcoded codenames) - `dpkg --print-architecture` / `uname -m` for architecture (amd64 / arm64 / armhf / x86_64 / aarch64 as applicable to each upstream) - Idempotent — re-running a script does not duplicate APT sources, fstab entries, gsettings entries, or `.desktop` files - `signed-by` keyrings in `/etc/apt/keyrings` (no deprecated `apt-key add`) - Checksum verification where the upstream publishes one (JetBrains SHA-256, LibreOffice MD5, Obsidian SHA-256, MarkText SHA-256, ipatool SHA-256, draw.io SHA-256, qBittorrent SHA-256, LocalSend SHA-256) - Per-user installers refuse to run as root; system installers refuse to run as non-root ## Hide Drive from the Dock ```bash gsettings set org.gnome.shell.extensions.dash-to-dock show-mounts false ``` ## Supported distros - Ubuntu (any modern release; some scripts target Ubuntu 25.10 specifically but work elsewhere) - Debian (most scripts; `install-thunderbird.sh` takes a different code path since Debian has no PPAs) Other distros are rejected up-front rather than failing later in unpredictable ways.