# 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 - `26` updates all software by re-running installers 1-7 and 9-20 - `-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, and Thunderbird backup). ## 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 | [`install-thunderbird-backup-cron.sh`](install-thunderbird-backup-cron.sh) | **user** | Installs an hourly cron job that fetches and runs the hosted Thunderbird-to-Synology backup script without storing it locally. Not included in menu option `0`; select it explicitly. | | 26 | System & Maintenance | Built into [`menu.sh`](menu.sh) | mixed | Updates all software by re-running the idempotent installers for options 1-7 and 9-20. Excludes network-drive, cron, system configuration, backup, and sync tasks. | "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) — 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 ``` ## 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 a backup 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. Menu option `24` installs this hourly user cron job idempotently and removes legacy entries that invoke a locally stored backup script: ```cron 0 * * * * /usr/bin/bash -o pipefail -c '/usr/bin/curl --proto "=https" --tlsv1.2 -fsSL --max-time 60 "https://opengist.resetrix.work/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/backup-thunderbird-to-synology.sh" | /usr/bin/bash' >> "$HOME/.local/state/thunderbird-cron.log" 2>&1 # thunderbird-synology-backup ``` The current hosted script is downloaded on every run and executes locally because the Thunderbird profile and Synology mount are local. Changes pushed to the hosted script therefore take effect on the next hourly run. ## 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.