https://github.com/raminr77/zero-day
One command to transform a fresh machine into your complete development environment.
https://github.com/raminr77/zero-day
bootstrap dotfiles initial zero-dey
Last synced: 4 days ago
JSON representation
One command to transform a fresh machine into your complete development environment.
- Host: GitHub
- URL: https://github.com/raminr77/zero-day
- Owner: raminr77
- License: mit
- Created: 2026-06-25T11:53:46.000Z (8 days ago)
- Default Branch: main
- Last Pushed: 2026-06-25T12:39:38.000Z (8 days ago)
- Last Synced: 2026-06-25T13:21:49.596Z (8 days ago)
- Topics: bootstrap, dotfiles, initial, zero-dey
- Language: Shell
- Homepage:
- Size: 58.6 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# zero-day · one-command machine setup
[](https://github.com/raminr77/zero-day/actions/workflows/ci.yml)
[](LICENSE)
Provision a fresh **Ubuntu/Debian server** or **macOS laptop** from nothing with
a single command: system update, all your tools, your shell, and your config files.
```bash
curl -fsSL https://raw.githubusercontent.com/raminr77/zero-day/main/install.sh | bash
```
> [`install.sh`](install.sh)). The bootstrap installs `git`, clones this repo to
> `~/.zero-day`, then runs [`setup.sh`](setup.sh).
The script is **idempotent** — safe to run again any time to top up a machine.
---
## What it does
| Module | What it installs / configures |
| ------------- | ------------------------------------------------------------------------------------------------ |
| `00-update` | `apt update && upgrade` / Homebrew install + `brew upgrade` |
| `10-base` | git, curl, wget, htop + modern CLI: bat, eza, fd, ripgrep, fzf, zoxide, jq, yq, tldr, btop, ncdu |
| `20-zsh` | zsh, oh-my-zsh, **Powerlevel10k**, and all your plugins |
| `30-node` | Node.js (LTS), npm, pnpm + yarn (via corepack) |
| `40-docker` | Docker Engine + Compose (Linux) / Docker Desktop (macOS) |
| `50-extra` | tmux, neovim, lazygit, lazydocker, direnv, mise |
| `60-dotfiles` | symlinks `config/*` into `$HOME` (backs up existing files) |
| `70-git` | git identity + sensible defaults |
| `75-ssh` | **(Linux)** optionally authorise an SSH public key |
| `80-security` | **(Linux)** ufw firewall, fail2ban, unattended-upgrades |
OS is detected automatically; macOS skips the Linux-only modules.
---
## Configuration files (kept in the repo)
Your real dotfiles live under [`config/`](config/) and are **symlinked** onto the
machine, so the repo is the single source of truth:
```txt
config/zsh/.zshrc config/git/.gitconfig
config/zsh/.p10k.zsh config/tmux/.tmux.conf
config/nvim/init.lua
```
Edit them in the repo, commit, and re-run `setup.sh` (or just `git pull` —
they're symlinks). Existing files are backed up to `*.bak.`.
---
## Options
```bash
./setup.sh --yes # assume yes (non-interactive)
./setup.sh --only 20,30 # run only zsh + node modules
./setup.sh --skip 40,80 # skip docker + security
./setup.sh --dry-run # show what would run
```
### Interactive by default — `.env` is optional
You don't need any config file. When run, `setup.sh` **asks for whatever it
needs** along the way (git name/email, whether to add an SSH key, etc.), and
prompts work even under `curl | bash` because they read from your terminal.
If you'd rather run **fully unattended** (no prompts), drop the values into a
git-ignored `.env` (see [`.env.example`](.env.example)) or pass them inline:
```bash
curl -fsSL https://raw.githubusercontent.com/raminr77/zero-day/main/install.sh \
| GIT_NAME="Ramin" GIT_EMAIL="you@example.com" bash
```
---
## SSH key on a new server
`75-ssh` asks whether to add an SSH public key. Paste the **public** key from
your laptop (`cat ~/.ssh/id_ed25519.pub`) and it's appended to
`~/.ssh/authorized_keys` with correct permissions (deduplicated). Or set
`SSH_PUBLIC_KEY` in `.env` to do it without a prompt.
---
## A note on version managers
You use both the `pyenv` zsh plugin and `mise`. **mise** is the primary version
manager here (Node, Python, etc. via `mise use -g node@lts`); the `pyenv` plugin
stays enabled in `.zshrc` and activates only if `pyenv` is present. Pick whichever
you prefer per language — they don't conflict.
`fast-syntax-highlighting` is enabled in `.zshrc` (not `zsh-syntax-highlighting`)
since the two conflict; both are cloned so you can switch by editing the plugin list.
---
## Development
```bash
make lint # shellcheck all scripts
make test # run the bats suite
make dry-run # preview without changes
```
### Testing safely in a container
```bash
docker run -it --rm ubuntu:24.04 bash -c '
apt-get update && apt-get install -y curl &&
curl -fsSL https://raw.githubusercontent.com/raminr77/zero-day/main/install.sh | bash'
```
---
## Layout
```txt
install.sh bootstrap entrypoint (curl | bash)
setup.sh orchestrator: sources libs, runs modules in order
lib/ui.sh pretty CLI: colours, banner, spinner, prompts
lib/common.sh OS detection, package helpers, linking, SSH keys
modules/ one file per step (NN-name.sh)
config/ your dotfiles (symlink sources)
tests/ bats unit tests for the pure helpers
.github/ CI workflow (shellcheck + bats + integration)
```
---
## License
[MIT](LICENSE) © Ramin Rezaei