Go to file
2026-07-28 04:32:38 +03:00
config/zsh zsh config: zshrc, path, aliases (ported from fish), extras, functions, plugins 2026-07-28 04:32:38 +03:00
lib skeleton: launcher, entrypoint, distro/log/prompt libs 2026-07-28 04:32:38 +03:00
modules modules: hardening (ssh/ufw/updates/tz/hostname/swap/locale/fail2ban) + sanity report 2026-07-28 04:32:38 +03:00
.gitignore docs: README + gitignore 2026-07-28 04:32:38 +03:00
install.sh skeleton: launcher, entrypoint, distro/log/prompt libs 2026-07-28 04:32:38 +03:00
README.md docs: README + gitignore 2026-07-28 04:32:38 +03:00
setup.sh skeleton: launcher, entrypoint, distro/log/prompt libs 2026-07-28 04:32:38 +03:00

bootstrap

Turn a fresh Debian/Ubuntu/Arch VPS into a familiar workstation in one command. Detects the distro, installs a curated CLI package set, sets up zsh + oh-my-zsh with your ported config, brings your nvim config, hardens sane system defaults, and reports state.

Usage

curl -fsSL <shortener> | bash
# run everything non-interactively:
curl -fsSL <shortener> | bash -s -- --yes
# run a single step:
curl -fsSL <shortener> | bash -s -- --only packages

The shortener points at the raw install.sh in this repo, which clones the full repo to ~/.bootstrap and runs setup.sh. To update: cd ~/.bootstrap && git pull (or just re-run the one-liner — it pulls existing clones).

Re-run individual steps locally after the initial bootstrap:

bash ~/.bootstrap/setup.sh --only shell-zsh
bash ~/.bootstrap/setup.sh --only hardening

Steps

# step what it does
0 preflight verify distro + network + privileges
1 packages git, byobu, ufw, mosh, btop, eza, fzf, ripgrep, bat, zoxide, jq, fd, tree, ncdu, lazygit, starship, … (+ yay on Arch)
2 docker Docker engine + compose v2 plugin, $USER in docker group
3 angie Angie (nginx fork) web server
4 shell-zsh zsh + oh-my-zsh + plugins, set default shell, ship config
5 nvm nvm → ~/.nvm + Node LTS
6 nvim clone g.mk.fo/bootstrap/nvim-minimal~/.config/nvim
7 hardening ssh (key-only root), ufw, updates, unattended-upgrades, tz, hostname, swapfile, locale, fail2ban
8 sanity read-only report + recommended manual follow-ups

Every step is idempotent — re-running is safe.

Zsh plugins enabled (oh-my-zsh)

git sudo command-not-found colored-man-pages extract copypath dirhistory plus, cloned into $ZSH_CUSTOM: zsh-autosuggestions, zsh-syntax-highlighting (loaded last), zsh-completions, history-substring-search, fzf-tab. Prompt: starship.

Config layout (shipped to ~/.config/zsh)

config/zsh/
  zshrc              # main config (sources the pieces below)
  path.zsh           # PATH + env (XDG, EDITOR, LANG, nvm, pnpm)
  aliases.zsh        # ported from fish + curated defaults
  aliases-extras.zsh # your personal additions (preserved across re-runs)
  functions.zsh      # mcd, conf, so, ssh-wrapper, dot-expansion
  plugins.zsh        # omz plugin list + load oh-my-zsh

~/.zshrc is a tiny shim that sets ZDOTDIR=~/.config/zsh and sources the real config there — keeps omz "happy" while your config lives under XDG.

Hardening choices

  • SSH: PermitRootLogin prohibit-password + PasswordAuthentication no. Root key login stays available; password login is disabled. A backup is made and sshd -t runs before reload. Always keep your current session open and test a new login before closing it.
  • ufw: deny incoming, allow 22/tcp, 60000:61000/udp (mosh), 80,443/tcp (angie).
  • updates + unattended-upgrades (Debian), system upgrade on Arch.
  • timezone (default UTC), hostname (optional).
  • swapfile 2G if RAM < 2G and no swap present.
  • locale en_US.UTF-8.
  • fail2ban with an sshd jail.

Supported hosts

  • Debian / Ubuntu (via apt)
  • Arch (via pacman + yay for AUR)
  • Architectures: amd64, arm64

Notes

  • aliases-extras.zsh is seeded once and then left alone — re-running the shell-zsh step won't clobber your personal aliases.
  • On Debian, fd/bat ship as fdfind/batcat; symlinks to the canonical names are created in ~/.local/bin (which is on PATH via path.zsh).
  • Some Go/Rust CLIs (dust, duf, procs, lazygit) are fetched from the latest GitHub release tarball when the distro package is missing; this is best-effort and warned (not fatal) on failure.