IndexPackages

server-shell-setup

One-command bootstrap for a modern dev environment: fish, nvim, nushell, bun, node, helix, starship, docker, and more.

Documentation

🤖 Agent skillnpx skills@latest add https://github.com/OpenSourceAGI/dev-tools-starter-agent --skill server-shell-setup (what it covers)

The Devil Is In The Defaults

If you hold a unix shell up to your ear, can you hear the C?

One-command setup for a modern dev environment: fish, nvim, nushell, bun, node, helix, starship, docker, and more. Includes fish aliases for service_manager, killport, search, and others.

Supported systems: Arch, Ubuntu/Debian, Android (Termux), macOS, Fedora, Alpine

Contents

Install

On a fresh server, you may first need to set passwords:

sudo passwd        # set root password
sudo passwd $USER  # set user password

Interactive menu — pick what to install:

wget -qO- tinyurl.com/shellsetup | bash
curl -sSL https://tinyurl.com/shellsetup | bash

Install everything unattended:

wget -qO- tinyurl.com/shellsetup | bash -s -- all

Install specific components only:

wget -qO- tinyurl.com/shellsetup | bash -s -- starship,docker,node

The -s -- is what forwards arguments through the pipe to bash. Dropping it silently gives you the interactive menu instead.

Install Modes

InvocationBehavior
| bashInteractive numbered menu, re-prompts until a valid selection is given
| bash -s -- allEverything, unattended
| bash -s -- fish,node,dockerOnly the named components, unattended
| bash -s -- sudoPasswordless sudo only (CLI-only, not in the menu)

Valid CLI component names: fish, nushell, nvim, helix, node, bun, pacstall, docker, starship, systeminfo, code, sudo. An unrecognized name exits with an error and lists the valid ones.

Two things to know about all:

  • The interactive menu's "Install Everything" includes code (code-server); the CLI all argument does not. Pass code explicitly if you want it unattended.
  • Neither form of all includes sudo — passwordless sudo is always opt-in.

Base dependencies (git, wget, curl, fzf, ripgrep, python3, python3-pip, unzip, util-linux) are installed on every run regardless of which components you select, because the fish functions depend on fzf and ripgrep.

When the run finishes, the script execs into fish if fish is on the PATH — so your terminal drops straight into the new shell.

Components

NameDescriptionInstalled viaVerify with
fishModern shell with auto-suggestions, syntax highlighting, and plugins (oh-my-fish, fzf, z, pisces). Set as your default login shell.distro package + oh-my-fishfish --version
nushellData-oriented shell that handles structured data nativelynpm i -g nushell (pkg on Termux)nu --version
nvimNeovim with NvChad config pre-installeddistro package + git clonenvim --version
helixModal terminal editor written in Rust, no config neededdistro packagehx --version
nodeNode.js via Volta version manager (no sudo issues); also installs pnpm, yarn, git0, vite, turboget.volta.shnode -v, volta -v
bunFast JavaScript runtime, bundler, and package managerbun.sh/installbun --version
dockerDocker with rootless mode enabledget.docker.com + rootless setuptooldocker version
starshipCross-shell prompt configured for bash, fish, and nushellstarship.rs/install.shstarship --version
systeminfoPrints system stats (user, host, disk, RAM, CPU, uptime, IP, location, open ports) on loginnpx about-system@latest in shell configsopen a new shell
pacstallAUR-like package manager for Ubuntu/Debianpacstall.dev/q/installpacstall -V
codecode-server — VSCode in the browsercode-server.dev/install.shcode-server --version
sudoEnable passwordless sudo for current userwrites /etc/sudoers.d/$USERsudo -n true

pacstall is Ubuntu/Debian only — on any other distro the script prints an error for that component and continues with the rest.

Fish Aliases

These are written as fish functions into ~/.config/fish/functions/ when the fish component is installed. Each is a real file you can edit or delete.

AliasExpands toNotes
in <pkg>sudo apt install <pkg>Hardcoded to apt — edit in.fish on non-Debian systems
e <file>nvim <file>
del <path>sudo rm -rf <path>No confirmation prompt
setupRe-run this install scriptFetches the latest installer and runs the menu
killportInteractive fzf menu to kill a process by portLists listening TCP ports via lsof, then kill -9. Falls back to a numbered menu without fzf
search <query>Search file names and file contents (via ripgrep)Prints filename matches, then content matches with 3 words of context on each side
service_managerInteractive fzf menu to start/stop/restart/view systemd servicesLists both system and --user units; actions: journal, start, stop, restart, status, edit, enable, disable

Command Reference

Everything below ships with a default all install. This is the day-to-day cheat sheet — the commands you actually reach for on Linux.

fish — the shell

Fish is not POSIX-compatible. Scripts written for bash won't run unmodified; use bash script.sh for those.

CommandWhat it does
fish_configOpen the web-based config UI (themes, prompt, functions)
fish_config theme choose <name>Switch color theme from the terminal
funced <name>Edit a function interactively
funcsave <name>Persist a function to ~/.config/fish/functions/
functionsList all defined functions
functions <name>Print a function's source
abbr -a gc git commitAdd an abbreviation that expands as you type
set -x VAR valueExport an environment variable for this session
set -U VAR valueSet a universal variable (persists across sessions)
set -e VARErase a variable
fish_add_path ~/.local/binAppend to $PATH permanently and idempotently
history search <term>Search shell history
history delete --contains <term>Remove matching entries from history
bindList current key bindings
type -q cmdTest whether a command exists (used by the bundled functions)
exec fishReload the shell in place after editing config

Key bindings worth knowing:

KeysAction
/ Ctrl+FAccept the autosuggestion
Alt+→Accept one word of the autosuggestion
/ History search filtered by what you've typed
Alt+↑ / Alt+↓Search history for the token under the cursor
Ctrl+Rfzf history search (from the fzf omf plugin)
Ctrl+Tfzf file finder (from the fzf omf plugin)
Alt+Cfzf cd into a subdirectory (from the fzf omf plugin)
Alt+EEdit the current command line in $EDITOR
Alt+SPrepend sudo to the current or previous command
Ctrl+C / Ctrl+DCancel line / exit shell

Fish plugins this script installs:

PluginWhat it adds
oh-my-fish (omf)Plugin/theme manager: omf install <pkg>, omf update, omf list, omf remove <pkg>, omf theme <name>
fzfFuzzy bindings: Ctrl+T find file, Ctrl+R history, Alt+C cd into a subdirectory, Alt+O open in $EDITOR (legacy bindings stay enabled by default)
zFrecency directory jumping: z proj cd's to the project dir you use most
piscesAuto-closes brackets and quotes as you type

nushell — structured data shell

Nushell pipes tables, not text. Every command emits structured data you can filter with the same verbs.

CommandWhat it does
nuStart nushell
ls | where size > 1mbFilter the directory listing as a table
ls | sort-by modified | last 10Ten most recently modified files
ps | where cpu > 10Processes above 10% CPU
sys hostStructured host info (uptime, kernel, hostname)
open file.jsonParse JSON/YAML/TOML/CSV/XLSX into a table automatically
open data.csv | get column_nameExtract one column
open x.json | to yamlConvert between formats
$env.PATHInspect environment as a list
$env.PATH | split row (char esep)PATH as a proper list
help commandsBrowse all builtins
config nuEdit the nushell config in $EDITOR
^lsEscape to the external binary instead of the builtin

The script writes ~/.config/nushell/config.nu with the startup banner disabled and $env.EDITOR set to nvim.

nvim — Neovim with NvChad

The script clones the NvChad starter to ~/.config/nvim and runs a headless Lazy! sync to install plugins. An existing config is moved to ~/.config/nvim.bak first.

Keys / commandWhat it does
SpaceLeader key
Space + thTheme picker (NvChad)
Space + ffFind files (Telescope)
Space + fwLive grep across the project
Space + fbBrowse open buffers
Space + foRecently opened files
Ctrl+nToggle the file tree (nvim-tree)
Space + eFocus the file tree
Tab / Shift+TabNext / previous buffer
Space + xClose current buffer
Space + chNvChad cheatsheet — all mappings in one screen
Space + /Toggle comment on line or selection
Ctrl+h/j/k/lMove between splits
:LazyPlugin manager UI (install, update, profile)
:MasonInstall LSP servers, formatters, linters
:LspInfoWhich language servers are attached
:checkhealthDiagnose a broken install
:w / :q / :wq / :q!Write / quit / write+quit / force quit

helix — modal editor, batteries included

Helix is selection-first: you select, then act (the reverse of vim). No config or plugins needed for LSP.

Keys / commandWhat it does
hx <file>Open a file
hx --healthCheck which language servers are detected
Space + fOpen file picker
Space + /Global search across the workspace
Space + bBuffer picker
Space + kShow hover documentation
Space + rRename symbol (LSP)
Space + aCode actions
gd / grGo to definition / find references
gg / geTop / end of file
xSelect the current line (repeat to extend)
d / c / y / pDelete / change / yank / paste the selection
mi( / ma(Select inside / around parentheses
Ctrl+w then v/sVertical / horizontal split
:w / :q / :wqWrite / quit / write+quit
:tutorBuilt-in interactive tutorial
:config-openEdit ~/.config/helix/config.toml

node, volta, and the package managers

Volta installs Node per-user under ~/.volta, so global installs never need sudo and each project can pin its own toolchain version.

CommandWhat it does
volta install nodeInstall the latest Node and make it default
volta install node@20Install and default to a specific major
volta install pnpm yarnManage package managers through Volta too
volta pin node@20Pin this project's Node version in package.json
volta listShow installed and pinned tools
volta which nodeResolve which binary actually runs here
node -v / node script.jsVersion / run a script
node --watch script.jsRe-run on file change
npx <pkg>Run a package without installing it
npm i -g <pkg>Install a CLI globally (no sudo, thanks to Volta)
npm ciClean, lockfile-exact install (use in CI)
npm outdated / npm audit fixFind and patch stale or vulnerable deps
npm run <script>Run a package.json script

Also installed globally by the node component:

ToolCommon commands
pnpmpnpm i, pnpm add <pkg>, pnpm dlx <pkg>, pnpm up -i, pnpm store prune
yarnyarn, yarn add <pkg>, yarn dlx <pkg>, yarn why <pkg>
git0git0 <repo-url> — clone a repo, install deps, and open it in one step
vitevite (dev server), vite build, vite preview
turboturbo run build, turbo run dev --filter=<pkg>, turbo prune <pkg> (--scope= in Turbo 1.x)

bun — runtime and package manager

CommandWhat it does
bun run <file.ts>Run TypeScript/JSX directly, no build step
bun installInstall dependencies (drop-in for npm i, much faster)
bun add <pkg> / bun add -d <pkg>Add a runtime / dev dependency
bun remove <pkg>Remove a dependency
bun x <pkg>Run a package without installing (like npx)
bun run --watch <file>Re-run on change
bun testBuilt-in Jest-compatible test runner
bun build <entry> --outdir distBundle for production
bun build <entry> --compileProduce a single-file executable
bun initScaffold a new project
bun upgradeUpdate bun itself
bun pm ls / bun pm cache rmInspect / clear the package cache

docker — rootless containers

The script installs Docker and then runs dockerd-rootless-setuptool.sh install, so the daemon runs as your user. Containers cannot bind ports below 1024 in rootless mode without extra capability configuration.

CommandWhat it does
docker ps / docker ps -aRunning / all containers
docker run -it --rm <img> <cmd>Run a throwaway interactive container
docker run -d -p 8080:80 <img>Run detached with a port mapping
docker exec -it <ctr> bashShell into a running container
docker logs -f <ctr>Follow container logs
docker stop <ctr> / docker rm <ctr>Stop / remove a container
docker images / docker rmi <img>List / remove images
docker build -t <name> .Build from the Dockerfile here
docker statsLive CPU/memory per container
docker inspect <ctr>Full JSON config of a container
docker cp <ctr>:/path ./hereCopy files out of a container
docker system dfHow much disk images/containers/volumes use
docker system prune -af --volumesReclaim all unused space (destructive)
docker compose up -d / downStart / stop a compose stack
docker compose logs -f <svc>Follow one service's logs
systemctl --user status dockerRootless daemon status (note --user)
systemctl --user restart dockerRestart the rootless daemon

starship — the prompt

Configured for bash, fish, and nushell in one pass. The script writes ~/.config/starship.toml setting the prompt character to ƒ.

CommandWhat it does
starship configOpen ~/.config/starship.toml in $EDITOR
starship preset nerd-font-symbols -o ~/.config/starship.tomlApply a built-in preset
starship preset --listList available presets
starship explainExplain what each segment of your prompt is showing
starship timingsFind which modules are making the prompt slow
starship module <name>Render a single module for debugging
starship init fish | sourceManually load in the current fish session

fzf — fuzzy finder

Installed as a base dependency; killport and service_manager both build on it.

CommandWhat it does
fzfFuzzy-pick from stdin (or the file list)
<cmd> | fzfFilter any command's output interactively
fzf --preview 'cat {}'Show a preview pane for the highlighted line
fzf -mMulti-select with Tab
vim (fzf)Open the picked file (fish command substitution)
kill -9 (ps -ef | fzf | awk '{print $2}')Pick a process and kill it

Inside fzf: type to filter, Ctrl+J/Ctrl+K to move, Tab to multi-select, Enter to accept, Esc to cancel.

Also a base dependency, and what the search function uses under the hood.

CommandWhat it does
rg <pattern>Recursive search, respecting .gitignore
rg -i <pattern>Case-insensitive
rg -w <pattern>Whole-word matches only
rg -l <pattern>List matching filenames only
rg -c <pattern>Count matches per file
rg -C 3 <pattern>Show 3 lines of context around each hit
rg -t py <pattern>Restrict to one file type
rg -g '*.ts' <pattern>Restrict by glob
rg -uu <pattern>Search hidden and gitignored files too
rg --files | rg <name>Search filenames instead of contents
rg --files-without-match <pattern>Find files that don't match

systemd — services and logs

What service_manager wraps. Drop sudo and add --user for user-scoped units.

CommandWhat it does
systemctl status <unit>Current state, recent log lines
sudo systemctl start|stop|restart <unit>Control a unit now
sudo systemctl enable --now <unit>Start it and start it on every boot
sudo systemctl disable --now <unit>Stop it and don't start on boot
systemctl list-units --type=serviceLoaded services
systemctl list-unit-files --type=serviceAll installed unit files and their enablement
systemctl --failedEverything currently broken
sudo systemctl edit --full <unit>Edit a unit file safely
sudo systemctl daemon-reloadReload after editing unit files by hand
journalctl -u <unit> -fFollow one service's logs
journalctl -u <unit> --since "1 hour ago"Time-filtered logs
journalctl -p err -bErrors from this boot
journalctl --disk-usageHow much disk the journal is using
sudo journalctl --vacuum-time=3dTrim the journal to the last 3 days

pacstall — AUR for Ubuntu/Debian

CommandWhat it does
pacstall -I <pkg>Install a package from the pacstall repos (like apt install)
pacstall -S <term>Search available packages (like apt search)
pacstall -R <pkg>Remove a package
pacstall -UUpdate pacstall's recipe scripts
pacstall -UpUpgrade installed pacstall packages
pacstall -LList installed pacstall packages
pacstall -A <repo>Add a package repository
pacstall -hFull flag reference

code-server — VS Code in the browser

CommandWhat it does
code-serverStart on 127.0.0.1:8080
code-server --bind-addr 0.0.0.0:8080Expose on the network (put it behind TLS/a proxy)
sudo systemctl enable --now code-server@$USERRun it as a service on boot
cat ~/.config/code-server/config.yamlRead the generated password and bind address
code-server --install-extension <id>Install an extension by marketplace ID
code-server --list-extensionsList installed extensions

Package managers by distro

The installer picks the right one automatically; these are for when you're doing it by hand afterward.

DistroInstallUpdate allSearchRemove
Ubuntu/Debiansudo apt install <pkg>sudo apt update && sudo apt upgradeapt search <term>sudo apt remove <pkg>
Fedorasudo dnf install <pkg>sudo dnf upgradednf search <term>sudo dnf remove <pkg>
Archsudo pacman -S <pkg>sudo pacman -Syupacman -Ss <term>sudo pacman -Rns <pkg>
Arch (AUR)yay -S <pkg>yay -Syuyay -Ss <term>yay -Rns <pkg>
Alpinesudo apk add <pkg>sudo apk update && sudo apk upgradeapk search <term>sudo apk del <pkg>
macOSbrew install <pkg>brew update && brew upgradebrew search <term>brew uninstall <pkg>
Termuxpkg install <pkg>pkg upgradepkg search <term>pkg uninstall <pkg>

On Arch, the script bootstraps yay first (initializing pacman keys and building yay-bin from the AUR) if it isn't already present.

Termux extras

On Android the script switches the Termux mirror to a faster one, installs the base tools, and sets up a full Ubuntu userland via proot.

CommandWhat it does
proot-distro listShow installable and installed distros
proot-distro install ubuntuInstall the Ubuntu rootfs
proot-distro login ubuntuEnter the Ubuntu environment
proot-distro login ubuntu -- <cmd>Run one command inside it
proot-distro remove ubuntuDelete the rootfs
termux-setup-storageGrant access to shared Android storage

The script creates an ubuntu user inside the proot distro with passwordless sudo. A startxfce4_ubuntu.sh script is downloaded for optional XFCE desktop use but is left uncalled — run it yourself if you want a GUI.

Files This Script Touches

Useful for auditing before you run it, or for undoing parts afterward.

PathWritten byContents
~/.config/fish/config.fishfish, starship, systeminfo, dockerPrompt init, greeting, about-system call, PATH additions
~/.config/fish/functions/*.fishfishin, e, del, setup, search, killport, service_manager
~/.config/nushell/config.nunushell, starship, systeminfoBanner off, EDITOR=nvim, starship autoload, about-system call
~/.config/nvimnvimNvChad starter clone (existing config moved to ~/.config/nvim.bak)
~/.config/starship.tomlstarshipOverwritten with the ƒ prompt character config
~/.bashrcnode, starship, systeminfo, dockerVolta PATH, starship init, about-system call, /usr/bin on PATH
~/.volta/nodeVolta toolchain and shims
~/.hushloginsysteminfoSuppresses the default login banner
/etc/motd, /etc/update-motd.dsysteminfoDeleted so the custom greeting is the only banner
/etc/sudoers.d/$USERsudoNOPASSWD:ALL for your user
Login shell (chsh)fishChanged to fish for $USER

Note that systeminfo deletes the system MOTD files and starship overwrites ~/.config/starship.toml wholesale — back those up first if they matter to you.

Companion Scripts

Two extra scripts live alongside the installer and are run directly, not through the component menu.

get-node.sh — reinstall the JS toolchain

A standalone, POSIX-sh script that wipes and reinstalls Volta, Node, Yarn, and Bun, then prints one summary line with all four versions. Use it when a toolchain install got into a bad state.

sh get-node.sh

It removes ~/.volta and ~/.bun if they already exist, so anything pinned through Volta will need reinstalling afterward. It exits with a clear error if curl is missing or any install step fails.

clean-server-disk.sh — aggressive disk cleanup

Frees space on a full server and reports how much it recovered. Must be run as root, and it is destructive — read it before running it.

sudo bash clean-server-disk.sh
StageWhat it removes
Package managerapt/yum/dnf caches, autoremovable packages, /var/lib/apt/lists
Dockerdocker system prune -af --volumes, build cache, ~/.docker/buildx
LogsTruncates /var/log/*.log; deletes rotated logs; vacuums journal to 3 days / 100 MB
Caches~/.cache and cache/ contents under /home and /root, thumbnails, font and man caches
Temp/tmp, /var/tmp, *.tmp files, crash reports and core dumps (and disables core dumps)
KernelsPurges old kernel packages, keeping the running one
App cachespip, npm, yarn, snap, unused flatpak runtimes
User dirs~/Downloads files untouched for 30+ days, bash history

It finishes by syncing and dropping the kernel page cache. The Docker prune deletes all unused volumes — stop and check anything holding data you care about first.

misc-setup/

FilePurpose
setup-windows.ps1PowerShell equivalent for Windows — installs Neovim, Starship, nushell, Git, VS Code, nvm, bun, and more via winget; defines a setup alias. Save it as $PSHOME\Profile.ps1.
chrome-extensions.mdCurated list of developer and general-purpose Chrome extensions

Troubleshooting

SymptomFix
Installer aborts immediately on a fresh serverSet passwords first (sudo passwd, sudo passwd $USER); many images ship with none, which makes sudo fail confusingly
Piped install shows the menu instead of running unattendedYou dropped -s -- — it's bash -s -- all, not bash all
Shell is still bash after loginchsh may have failed silently; run chsh -s $(which fish) and open a new session
Invalid component: <name>Check the name against the valid list above; the script exits rather than guessing
pacstall reports an errorIt's Ubuntu/Debian only — expected on other distros, the rest of the run continues
docker commands fail after installRootless docker runs as a user service: systemctl --user status docker, and open a new shell to pick up the PATH change
Node installed but node not foundOpen a new shell, or run fish_add_path ~/.volta/bin — Volta's shims live in ~/.volta/bin
Neovim opens with errors on first launchPlugin sync runs in the background; wait for it, or run nvim --headless "+Lazy! sync" +qa again
Login greeting is missingsysteminfo shells out to npx about-system@latest, which needs Node and network access on each login

Example: System Info on Login

👤 deck 🏠 steamdeck 📁 90% 💾 2/14GB 🔝 6% cursor ⏱️  1d 7h 18m 🌎 174.194.193.230
📍 San Jose 🔗 http://230.sub-174-194-193.myvzw.com 👮 Verizon Business ⚡ SteamOS
📈 AMD Custom APU 0405 💻 Jupiter 🔧 6.11.11-valve12-1-neptune 🐚 fish 🚀 npm pip docker nvim bun
🔌 57343stea 46583stea 27060stea 📦 docker-node

Reference Docs


PRs Welcome

Please star this repo for updates! 🌟


Source: packages/server-shell-setup/README.md

Last updated on

On this page