Personal machine setup scripts for macOS, Linux servers, and Proxmox VMs. Scripts are organised by platform and numbered by phase so you always know what to run and in what order.
graph TD
repo["setup/"] --> mac["mac/<br/>Mac bootstrap"]
repo --> linux["linux/<br/>Linux / server bootstrap"]
repo --> tools["tools/<br/>Cross-platform dev tools"]
repo --> proxmox["proxmox/<br/>Proxmox VM provisioning"]
mac --> m1["00_sshkey.sh — SSH key<br/>01_basics.sh — Homebrew"]
linux --> l1["00_bootstrap.sh — one-shot server hardening<br/>01–03_*.sh — baseline + dotfiles + shell<br/>10_neovim, 11_docker_tools, 20_restic"]
tools --> t1["10_* — kubectl, helm, lazygit, Claude Code…<br/>20_* — atuin, uv, conda, coder…"]
proxmox --> px1["provision.sh — main entrypoint<br/>vms/ · profiles/ · apps/ · cloudinit/"]
cp .env.example .env
# fill in SETUP_USER, SETUP_HOST, DOTFILES_REPO, GH_TOKEN.env is sourced automatically by all scripts — no hardcoded usernames or tokens.
Run from your local machine — handles user creation, key upload, and SSH hardening in one step:
bash linux/00_bootstrap.sh <HOST_IP>
bash linux/00_bootstrap.sh <HOST_IP> --root-pass 'password'Then SSH in as your user and continue:
bash linux/01_basics.sh
bash linux/02_dotfiles.sh
bash linux/03_shell.sh
exec zsh && p10k configureRun as root on the fresh server:
bash linux/00_adduser.sh # create user (SETUP_USER) + add to sudo & docker groups
bash linux/00_sudoers.sh # passwordless sudo for userFrom your local machine — copy your SSH key over while password auth is still on:
bash mac/00_sshkey.sh user@<host>Back on the server as root — lock down SSH once the key is confirmed working:
bash linux/00_sshd.sh # key-only auth, no root login, restart sshdThen SSH in as your user and continue with Phase 1:
bash linux/01_basics.sh
bash linux/02_dotfiles.sh
bash linux/03_shell.sh
exec zsh && p10k configurebash linux/01_basics.sh # baseline apt packages
bash linux/02_dotfiles.sh # chezmoi dotfiles + tmux plugins
bash linux/03_shell.sh # oh-my-zsh + powerlevel10k + plugins
exec zsh && p10k configurebash mac/01_basics.sh # Homebrew + baseline packages
bash linux/02_dotfiles.sh # chezmoi dotfiles + tmux plugins
bash linux/03_shell.sh # oh-my-zsh + powerlevel10k + plugins
exec zsh && p10k configureProvision a VM from any machine (Mac, Linux, MobaXterm):
cp proxmox/.env.example proxmox/.env # fill in once
./proxmox/provision.sh --dry-run proxmox/vms/ragflow.yaml
./proxmox/provision.sh proxmox/vms/ragflow.yamlSee proxmox/README.md for full documentation, including Mermaid diagrams of the provisioning flow, VM model, and bootstrap sequence.
| Script | What it does | Linux | macOS |
|---|---|---|---|
| mac/ — Mac bootstrap | |||
mac/00_sshkey.sh |
Generate ED25519 key pair + copy to server | — | ✓ |
mac/01_basics.sh |
Homebrew + baseline packages | — | ✓ |
mac/mx-keys-fix.sh |
Logitech MX Keys Fn-key fix (macOS) | — | ✓ |
mac/quickemu_install.sh |
quickemu + quickget — run lightweight VMs | — | ✓ |
mac/quickgui_install.sh |
quickgui — GUI front-end for quickemu | — | ✓ |
| linux/ — Server bootstrap | |||
linux/00_bootstrap.sh |
One-shot: create user, upload key, harden SSH | ✓ | — |
linux/00_adduser.sh |
Create user (SETUP_USER), sudo + docker groups |
✓ | — |
linux/00_sudoers.sh |
Passwordless sudo for user | ✓ | — |
linux/00_sshd.sh |
Key-only auth, disable password + root login | ✓ | — |
linux/01_basics.sh |
apt baseline: git, zsh, eza, ripgrep, fd, node… | ✓ | — |
linux/02_dotfiles.sh |
chezmoi dotfiles (DOTFILES_REPO) + tpm |
✓ | ✓ |
linux/03_shell.sh |
oh-my-zsh, powerlevel10k, autosuggestions, syntax-hl | ✓ | ✓ |
linux/10_neovim.sh |
Neovim AppImage → ~/.local/bin/nvim |
✓ | — |
linux/11_docker_tools.sh |
ctop, dive, lazydocker | ✓ | — |
linux/20_restic.sh |
restic — fast, encrypted backups | ✓ | — |
| tools/ — Cross-platform dev tools | |||
tools/10_lazygit.sh |
lazygit (latest GitHub release) | ✓ | ✓ |
tools/10_kubectl.sh |
kubectl (latest stable) | ✓ | ✓ |
tools/10_helm.sh |
Helm 3 (official installer) | ✓ | ✓ |
tools/10_k3d.sh |
k3d — k3s in Docker | ✓ | ✓ |
tools/10_claude.sh |
Claude Code CLI (native installer) | ✓ | ✓ |
tools/10_ai_tools.sh |
Gemini CLI, Codex CLI, GH Copilot CLI, Pi | ✓ | ✓ |
tools/10_llm_tools.sh |
llm, files-to-prompt, ttok, strip-tags, aider | ✓ | ✓ |
tools/20_atuin.sh |
atuin shell history (replaces mcfly) | ✓ | ✓ |
tools/20_uv.sh |
uv — fast Python package + project manager | ✓ | ✓ |
tools/20_conda.sh |
Miniconda (default) or Anaconda | ✓ | ✓ |
tools/20_kind.sh |
kind — Kubernetes IN Docker (latest) | ✓ | ✓ |
tools/20_minikube.sh |
minikube — local Kubernetes cluster | ✓ | ✓ |
tools/20_coder.sh |
Coder — self-hosted dev environments | ✓ | ✓ |
tools/20_teleport.sh |
Teleport v17 — zero-trust access | ✓ | ✓ |
tools/20_fonts.sh |
Nerd Fonts: JetBrainsMono + Meslo | ✓ | ✓ |
tools/yabs.sh |
Server benchmark (Yet Another Bench Script) | ✓ | — |
Generates an ED25519 key pair (if one doesn't already exist at the given path)
and copies the public key to a remote server using ssh-copy-id. Run this
before linux/00_sshd.sh locks out password auth.
bash mac/00_sshkey.sh # uses SETUP_HOST from .env or prompts
bash mac/00_sshkey.sh user@1.2.3.4 # specify host
bash mac/00_sshkey.sh user@1.2.3.4 ~/.ssh/id_myserver # custom key pathDefault key path: ~/.ssh/id_ed25519
Installs Homebrew if not present, then installs an equivalent set of tools.
bash mac/01_basics.sh| Group | Tools |
|---|---|
| Core | git gh vim wget |
| Shell | zsh tmux fzf zoxide |
| Files | eza bat fd ripgrep lazygit |
| Monitor | btop ncdu hyperfine mactop viddy |
| Data | jq yq glow lnav csvlens jless tldr |
| Dev workflow | git-delta direnv watchexec |
| Network | httpie rsync |
| AI / LLM | models llmfit gemini-cli codex |
| Terminal extras | taproom timg |
| Runtime | Node.js LTS (via nvm) |
Note: Docker Desktop must be installed manually from docker.com.
The recommended starting point for any fresh host. Runs from your local machine, SSHes in as root, and performs all hardening steps non-interactively.
bash linux/00_bootstrap.sh 192.168.1.50
bash linux/00_bootstrap.sh 192.168.1.50 --root-pass 'password'Steps performed:
- Create user (
SETUP_USERfrom.env) with sudo + docker groups - Add passwordless sudo via
/etc/sudoers.d/ - Upload
SSH_PUBLIC_KEYfrom.envto~/.ssh/authorized_keys - Harden sshd: key-only auth, no root login, no passwords
- Report:
Host secured. Connect with: ssh <user>@<host>
Reads credentials from proxmox/.env → .env → linux/.env (first found wins).
Creates the user (SETUP_USER from .env) and adds them to the sudo and docker groups.
bash linux/00_adduser.shWrites /etc/sudoers.d/<user>-nopasswd granting NOPASSWD: ALL to the
specified user, then validates it with visudo -c before saving so a broken
sudoers file can never land.
sudo bash linux/00_sudoers.sh # defaults to SETUP_USER
sudo bash linux/00_sudoers.sh alice # explicit overrideEdits /etc/ssh/sshd_config to enforce key-based authentication and restarts
sshd. Run this only after your SSH key is working — it disables password
login, locking you out if the key isn't in place.
bash linux/00_sshd.shChanges applied:
PubkeyAuthentication yesPasswordAuthentication noPermitRootLogin noAuthorizedKeysFile .ssh/authorized_keys
RSAAuthenticationis deprecated in OpenSSH 7.4+ and is no longer modified.
Adds the universe repo and installs a comprehensive set of apt packages.
Run this first on any Linux machine.
bash linux/01_basics.sh| Group | Tools |
|---|---|
| Core | git gh vim wget curl build-essential |
| Shell | zsh tmux fzf zoxide |
| Files | eza bat fd ripgrep ranger |
| Monitor | btop htop ncdu powertop hyperfine |
| Data | jq yq glow lnav csvlens ack tldr |
| Dev workflow | git-delta direnv watchexec python3 docker-compose |
| Network | httpie rsync dnsutils |
| AI / LLM | models |
| Runtime | Node.js LTS (via nvm) libfuse2 |
Notes:
batis installed asbatcaton Ubuntu — the script creates a~/.local/bin/batsymlink automatically.fdis thefd-findapt package — the binary isfdafter install.- nvm init is added to
~/.zshrcby02_dotfiles.shso it survives chezmoi applying dotfiles.
Installs chezmoi to ~/.local/bin/chezmoi and applies
the dotfiles repo (DOTFILES_REPO from .env). Also bootstraps
tpm (Tmux Plugin Manager) and appends
nvm init to ~/.zshrc if not already present.
bash linux/02_dotfiles.shAfter running, open tmux and press prefix+I to install tmux plugins.
Idempotent — safe to re-run. Skips any component already installed.
bash linux/03_shell.shInstalls:
- oh-my-zsh — with
RUNZSH=no KEEP_ZSHRC=yes(won't overwrite your.zshrc) - powerlevel10k — cloned into
~/.oh-my-zsh/custom/themes/ - zsh-autosuggestions — fish-style inline completions
- zsh-syntax-highlighting — command highlighting as you type
- Sets zsh as default shell via
usermod(falls back with instructions if sudo unavailable)
After running:
exec zsh # reload shell
p10k configure # optional — config already applied from dotfilesMake sure your .zshrc contains:
ZSH_THEME="powerlevel10k/powerlevel10k"
plugins=(git zsh-autosuggestions zsh-syntax-highlighting)Downloads the latest Neovim AppImage and installs it to ~/.local/bin/nvim.
libfuse2 (required for AppImage) is already included in linux/01_basics.sh.
bash linux/10_neovim.shInstalls three Docker companion tools. All versions resolved at runtime via the GitHub API — no hardcoded versions.
bash linux/11_docker_tools.sh| Tool | What it does |
|---|---|
| ctop | top-like interface for containers |
| dive | Explore image layers and wasted space |
| lazydocker | TUI for Docker management |
Installs restic via apt, then runs restic self-update
to ensure the latest version regardless of what's in the apt repo.
bash linux/20_restic.shDownloads the latest release from GitHub and installs to /usr/local/bin.
bash tools/10_lazygit.shDownloads the latest stable kubectl binary from the official Kubernetes CDN.
bash tools/10_kubectl.shRuns the official Helm installer script.
bash tools/10_helm.shInstalls k3d (k3s in Docker) via the official installer script.
bash tools/10_k3d.shInstalls Claude Code using the native installer.
bash tools/10_claude.shAfter installing, run claude to get started.
Installs Gemini CLI, OpenAI Codex CLI, GitHub Copilot CLI, and Pi. Requires nodejs + npm
and gh (both included in the Phase 1 basics scripts).
bash tools/10_ai_tools.sh| Tool | Command | Source |
|---|---|---|
| Gemini CLI | gemini |
Google — @google/gemini-cli |
| OpenAI Codex CLI | codex |
OpenAI — @openai/codex |
| GitHub Copilot CLI | gh copilot |
gh extension install github/gh-copilot |
| Pi coding agent | pi |
badlogic — @mariozechner/pi-coding-agent |
Installs Simon Willison's LLM stack and aider via uv tool install.
Bootstraps uv automatically if not present.
bash tools/10_llm_tools.sh| Tool | Command | What it does |
|---|---|---|
| llm | llm |
Run prompts against any model; log history |
| files-to-prompt | files-to-prompt |
Concat a codebase into a single prompt |
| ttok | ttok |
Count tokens before making API calls |
| strip-tags | strip-tags |
Strip HTML to clean text for LLM input |
| aider | aider |
AI pair programmer, git-native |
llmfitandtimgare installed via brew inmac/01_basics.sh.
Installs atuin — shell history with full-text search, statistics, and optional cross-machine sync.
bash tools/20_atuin.shThe script automatically:
- Adds
~/.atuin/bintoPATHin.zshrcand.bashrc - Adds
eval "$(atuin init zsh)"to.zshrc(guarded so it's safe if atuin isn't present)
After installing:
atuin import auto # migrate existing shell historyOptional sync across machines:
atuin register # create account
atuin login # on other machines
atuin syncInstalls uv by Astral — an extremely fast Python package and project manager. Handles Python version management, virtual envs, and package installation. Replaces pip/pyenv/conda for most workflows.
bash tools/20_uv.shQuick reference:
uv python install 3.12 # install a Python version
uv venv && source .venv/bin/activate
uv pip install <package> # fast pip replacement
uv run script.py # run with auto-managed depsInstalls Miniconda (default, recommended) or full Anaconda. Prefer tools/20_uv.sh
for most Python workflows — use conda only when you need the conda ecosystem.
bash tools/20_conda.sh # Miniconda (default)
bash tools/20_conda.sh miniconda # explicit
bash tools/20_conda.sh anaconda # full Anaconda suite (Anaconda3-2024.10-1)After Miniconda:
~/miniconda/bin/conda init zsh
exec zshInstalls kind (Kubernetes IN Docker). Version resolved at runtime from the GitHub API.
bash tools/20_kind.shInstalls the latest minikube for running a local Kubernetes cluster.
bash tools/20_minikube.shInstalls Coder for self-hosted cloud development environments using the official installer.
bash tools/20_coder.shAfter installing: coder server to start, then open http://localhost:3000.
Installs Teleport using the official installer. Defaults to v17; pass a version argument to override.
bash tools/20_teleport.sh # installs v17
bash tools/20_teleport.sh 16 # specific major versionDownloads and installs JetBrainsMono and Meslo Nerd Fonts to
~/.local/share/fonts, then rebuilds the font cache. Version resolved at
runtime from the GitHub API.
bash tools/20_fonts.shNote: If you use
linux/02_dotfiles.sh, the chezmoi dotfiles already manage MesloLGS NF fonts — you may only need JetBrainsMono.
Set your terminal font to JetBrainsMono Nerd Font or MesloLGS NF after running.
Runs YABS: disk, network, and CPU benchmarks. Useful for evaluating a new VPS.
bash tools/yabs.shProvision VMs on the homelab cluster from any machine. See proxmox/README.md for full documentation.
cp proxmox/.env.example proxmox/.env # first time: fill in credentials
./proxmox/provision.sh --dry-run proxmox/vms/ragflow.yaml
./proxmox/provision.sh proxmox/vms/ragflow.yaml| File | Purpose |
|---|---|
linux/60-vxlan.cfg |
VXLAN network configuration snippet |
linux/docker-grub.txt |
GRUB cmdline settings for Docker (cgroup, memory) |