gitleaks, web stack (mariadb-server, imagemagick, unversioned php-* modules), ubuntu-desktop-minimal before the RDP setup, and a lspci-gated install_nvidia_driver() that runs ubuntu-drivers install. README + TODO updated.
11 KiB
config
Personal dotfiles — vim + bash configuration and a one-shot installer.
Quick start
Install everything (clone + setup) with one command:
curl -fsSL https://git.bchanot.fr/bchanot/config/raw/branch/master/remote-install.sh | bash
(Runs a remote script through bash — see the Install section for what it does and the manual alternative.)
What's inside
| Path | Purpose |
|---|---|
install.sh |
Installs apt packages + Docker + code-server + RDP (gnome-remote-desktop), backs up old config, deploys vim + bashrc (OS-detected), installs CLI scripts, pipx tools, a low-disk login warning and the cloudpex NAS mount helper; ends by offering two system changes (/tmp on disk, SSH memory guard). |
cloudpex/ |
On-demand SMB mount of a NAS share (cloudpex command + its installer). Site values (host, share, SMB user, mount point, SMB version) are prompted at install and stored in /etc/cloudpex.conf, never in the script. French README inside. |
etc/tmpfiles.d/tmp.conf |
Cleanup rules for a disk-backed /tmp (wiped at boot, 10-day purge). Deployed by the /tmp on disk offer. |
etc/systemd/ssh.service.d/override.conf |
ssh.service drop-in: sshd exempt from the OOM killer + memory reclaim protection. Deployed by the SSH memory guard offer. |
etc/default/earlyoom |
earlyoom arguments: spare sshd/systemd, kill node/java first. Deployed by the SSH memory guard offer. |
etc/fail2ban/jail.d/local.conf |
fail2ban sshd jail: journal backend, all-ports ban, 5 tries / 10 min / 1 h, private LAN never banned. Deployed on every Linux install. |
etc/apt/apt.conf.d/20auto-upgrades |
Enables unattended security upgrades (what dpkg-reconfigure writes). Deployed on every Linux install. |
etc/ssh/sshd_config.d/20-hardening.conf |
sshd limits that cannot lock you out: PermitRootLogin no, MaxAuthTries 3, LoginGraceTime 20. Deployed on every Linux install after sshd -t. |
vim/vimrc |
Vim config: pathogen, molokai, syntastic (C with -Wall -Werror -Wextra), NERDTree, 42-style canonical class generators (:ClassH, :ClassC). |
vim/autoload/ |
pathogen.vim plugin loader (committed). |
vim/colors/ |
molokai.vim colorscheme (committed). |
bash/bashrc-linux |
bashrc for desktop Linux (git-aware prompt + command timer). |
bash/bashrc-osx |
bashrc for macOS. |
bin/dt |
dtach session manager for claude-in-dtach sessions. |
bin/dtach-router |
Dashboard to resume dtach sessions, shown at the start of every interactive shell (wired into ~/.bashrc by the installer). |
bin/claude-provider |
Switch Claude Code between Anthropic and OpenRouter. |
etc/profile.d/disk-usage-warning.sh |
Login-time warning (bold red) when / or /home cross 85% usage. Deployed to /etc/profile.d/ on Linux. |
Install
One-liner (clone + install)
curl -fsSL https://git.bchanot.fr/bchanot/config/raw/branch/master/remote-install.sh | bash
remote-install.sh ensures git is present, clones the repo to ~/config (or pulls if already there), then runs install.sh. Override with env vars: REPO_URL=... CLONE_DIR=... BRANCH=... curl ... | bash.
Piping a remote script into
bashruns unreviewed code over the network. Readremote-install.shfirst, or use the manual clone below.
Manual
git clone https://git.bchanot.fr/bchanot/config.git && cd config
./install.sh
No argument — the OS is auto-detected.
What it does:
- On Debian/Ubuntu, installs a set of CLI/dev packages via
apt-get(see below). Skipped automatically whereapt-getis absent (macOS). - Sets up Docker's official apt repo (Ubuntu) and installs the engine + compose plugin — skipped if
dockeris already present. - Moves any existing
~/.vim,~/.vimrc,~/.bashrc,~/.Sublivimto~/Oldconfig. - Clones the
syntasticandnerdtreevim plugins into~/.vim/bundle/. - Copies the tracked vim files into
~/.vimand symlinks~/.vimrc. - Picks the bashrc by OS: macOS →
bashrc-osx(falls back tobashrc-linuxif missing), everything else →bashrc-linux. Copies it to~/.bashrc. - Installs Python CLIs via
pipx(PyMuPDF→pymupdf,Markdown→markdown_py) — skipped ifpipxis absent. - Copies the
bin/scripts (dt,dtach-router,claude-provider) into~/.local/bin. The dtach session-resume menu ships in the deployedbashrc-linux, so every interactive shell offers it — including VS Code Remote-SSH terminals, which are non-login and never read~/.profile. The installer also strips any older dtach block left in~/.profileso a plain SSH login doesn't prompt twice. - On Linux, installs
etc/profile.d/disk-usage-warning.shto/etc/profile.d/(needssudo) so each login warns when/or/homecross 85% usage. - On Linux, installs code-server (VS Code in the browser) via its vendor script — skipped if already present — and enables the
code-server@$USERsystemd service. - On Linux, installs
ubuntu-desktop-minimal(GDM + GNOME Shell, ~1.5 GB): the RDP remote login below hands out a GNOME session, which a bare server install does not have. Then sets up RDP remote login viagnome-remote-desktop(Wayland-native): installs the daemon +openssl, generates a self-signed TLS cert once, and prompts interactively for shared "gate" credentials (skipped when no terminal is attached, or already set). Disablesxrdpif present; opens UFW port3389only when UFW is already active. Finally, whenlspcisees an NVIDIA GPU, runsubuntu-drivers installto put on the driver the distro recommends for the card (no version pinned; loads at the next reboot). Skipped on machines without an NVIDIA GPU. - On Linux, installs the
cloudpexNAS mount helper to/usr/local/binviacloudpex/install.sh, which prompts for the NAS host, share name, SMB user, mount point and SMB version and writes them to/etc/cloudpex.conf(root,0600; an existing config is shown and kept unless you sayn; skipped when no terminal is attached). Nothing is mounted, no password stored, seecloudpex/README.md. - On Linux, installs the security baseline, always, no prompt: fail2ban (+
nftables) withetc/fail2ban/jail.d/local.conf(sshd jail reading the journal, bans the offending IP on every port so the SSH port does not matter, 5 failures in 10 min → 1 h ban, loopback and private LAN ranges never banned); unattended-upgrades enabled throughetc/apt/apt.conf.d/20auto-upgrades; and the sshd drop-inetc/ssh/sshd_config.d/20-hardening.conf(PermitRootLogin no,MaxAuthTries 3,LoginGraceTime 20), checked withsshd -tand removed again if sshd rejects it, thenreload ssh. Authentication methods, port and user lists are left as they are. - On Linux, at the very end, offers (
[y/N], skipped when no terminal is attached) to move/tmpto disk: Ubuntu mounts/tmpas a RAM-backed tmpfs capped at 50% of RAM, which agent runs fill, halving the RAM and breaking every shell with "No space left on device". Accepting maskstmp.mountand installsetc/tmpfiles.d/tmp.conf(wipe at boot, 10-day purge). Effective at the next reboot. - On Linux, at the very end, offers to keep SSH reachable under memory pressure: installs the
ssh.servicedrop-in (OOMScoreAdjust=-1000,MemoryMin=256M) andearlyoomwithetc/default/earlyoom(kills the largest process,node/javafirst and neversshd, once free RAM and swap both drop under 10%). Restartingsshkeeps open sessions. Note:MemoryMinprotects the sshd daemon only; login sessions live inuser.slice, so no setting can reserve RAM for a future shell. earlyoom acting in time is the real protection.
Packages installed (apt)
- Build / VCS / C dev:
vim git git-lfs git-filter-repo gitleaks gcc make pkg-config dkms valgrind shellcheck gh - Net / security / transport:
curl gnupg ca-certificates apt-transport-https net-tools openssh-server cifs-utils lftp ftp - Shell tooling:
unzip tree tmux fzf dtach - Runtimes:
nodejs python3-pip pipx php-cli - Web stack (local WordPress/LAMP):
mariadb-server imagemagick php-mysql php-gd php-imagick php-mbstring php-xml php-intl php-curl(unversionedphp-*metapackages, so they follow the distro's PHP) - Media / doc CLI:
ffmpeg weasyprint poppler-utils qpdf webp libavif-bin - Docker:
docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin(via Docker's repo) - Desktop / GPU:
ubuntu-desktop-minimal(always, Linux) + the distro-recommended NVIDIA driver viaubuntu-drivers install(only when an NVIDIA GPU is detected) - Remote access:
gnome-remote-desktop openssl(apt) +code-server(via its vendor install script, not apt) — RDP remote login + browser VS Code - pipx:
PyMuPDF(pymupdf),Markdown(markdown_py) - Security baseline (Linux, always):
fail2ban nftables unattended-upgrades - Optional (end-of-install offer, Linux):
earlyoom
The script is re-runnable: each run re-backs up to ~/Oldconfig (overwriting the previous backup), re-clones plugins, skips Docker if already installed, and re-deploys the bin/ scripts.
Notes: the package list is Debian/Ubuntu-specific, and the Docker repo step assumes Ubuntu. On macOS the whole
apt-getblock is skipped — installvim/git/toolchain via Homebrew yourself.
CLI scripts (bin/)
Deployed to ~/.local/bin (the deployed bashrc adds this dir to PATH):
dt— manage claude-in-dtach sessions (dt ls|at|kill). Needsdtach+fzf.dtach-router— session dashboard shown at shell startup. It ships in the deployed bashrc and is sourced (not executed) in every interactive shell, so it also fires in VS Code Remote-SSH terminals (non-login shells that skip~/.profile). Silent no-op when no session exists. Create a session withcc [name], re-open the menu anytime withd(both aliases from the bashrc). Needsdt,dtach,fzf.claude-provider— switch Claude Code between Anthropic and OpenRouter. OpenRouter mode reads the key from$OPENROUTER_API_KEY(never hardcoded). Export it from a private, untracked file, e.g.~/.bashrc.local:export OPENROUTER_API_KEY="<your-openrouter-key>"
Requirements
bash,git- Debian/Ubuntu
apt-getfor the package step (optional elsewhere) - A
bashlogin shell (zsh users: switch to bash for these prompts to apply)
License
GPL-3.0-or-later — see LICENSE.
Copyright (C) 2026 Bastien Chanot.