# Ubuntu / Debian Setup Manager A collection of hardened install scripts for a fresh Ubuntu / Debian desktop, driven by an interactive `menu.sh`. Each script 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://opengist.rmrf.online/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/menu.sh)" ``` How to use the picker: - Enter one or more numbers separated by spaces, e.g. `1 6 11` - `0` runs every option 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 the three scripts that must not run as root (JetBrains Toolbox, IBus Pinyin, Nerd Fonts). ## Available scripts | # | Script | Runs as | What it does | |---|---|---|---| | 1 | [`install-chrome.sh`](install-chrome.sh) | sudo | Installs Google Chrome Stable from Google's official APT repo using a `signed-by` keyring. | | 2 | [`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 | [`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 | [`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. | | 5 | [`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. | | 6 | [`install-discord.sh`](install-discord.sh) | sudo | Installs the latest official Discord Linux `.deb` from Discord's latest download endpoint. | | 7 | [`install-1password.sh`](install-1password.sh) | sudo | Configures the 1Password APT repo with `debsig` signature policy. Arch-aware (amd64 / arm64). | | 8 | [`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). | | 9 | [`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 | [`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 | [`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. | | 12 | [`install-vscode.sh`](install-vscode.sh) | sudo | Microsoft's official `code` APT repo, signed-by keyring. `--insiders` flag installs `code-insiders` instead. | | 13 | [`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. | | 14 | [`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. | | 15 | [`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. | | 16 | [`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. | | 17 | [`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. | | 18 | [`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`. | | 19 | [`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. | | 20 | [`timedatectl-fix.sh`](timedatectl-fix.sh) | sudo | Sets the hardware clock to UTC to avoid time drift when dual-booting Linux and Windows. | "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-12, 14-17, 20) — pipe through sudo bash curl -fsSL https://opengist.rmrf.online/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/install-firefox.sh | sudo bash # user scripts (13, 18, 19) — DO NOT use sudo; they install per-user bash -c "$(curl -fsSL https://opengist.rmrf.online/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/install-font.sh)" ``` Most installers accept `--help` and `--dry-run` (the latter prints what would happen without executing). For example: ```bash curl -fsSL https://opengist.rmrf.online/weehong/2de15ba0106a475fa41215159203a63b/raw/HEAD/install-libreoffice.sh \ | bash -s -- --help ``` ## 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, 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 ## 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.