Proxmox: Setting Up a New User Account with Dotfiles

This post follows on from Proxmox: Disable root@pam Login and Create a Sudo User. At that point you have a working dave account with sudo. The next step is making it feel like home: a few essential tools and your dotfiles pulled from GitHub.

The dotfiles repo used in this guide is morganp/dotfiles.

Two Strategies

Before diving in, it helps to understand the two ways config files are deployed. Most tools use GNU Stow, which creates symlinks from $HOME (or an XDG config dir) into the repo. A change to the repo file is immediately live everywhere that file is symlinked.

A small number of files -- shell configs and Vim -- use a source wrapper instead. ~/.zshrc is a real file that exists only on the local machine and contains a single source line pointing into the repo. This allows host-specific additions (work proxy settings, machine-specific aliases) to live below the source line without touching the shared repo file. It also prevents tools that append to .bashrc from dirtying the repo.

The split is:

File Strategy Reason
Most config (git, screen, ctags, ...) Stow symlink Identical across all hosts
~/.zshrc, ~/.bashrc Source wrapper Host-specific additions needed
~/.vimrc Source wrapper Different plugin sets per host

Install Basic Tools

SSH in as your new user and install the essentials in one pass:

sudo apt update && sudo apt install -y git stow

gh (the GitHub CLI) is not in the standard Debian/Ubuntu repos, so it needs the official GitHub apt source:

sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
    | sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] \
    https://cli.github.com/packages stable main" \
    | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null

sudo apt update && sudo apt install -y gh

Verify all three are present:

git --version
stow --version
gh --version

Authenticate with GitHub

Before cloning private repos, authenticate gh:

gh auth login

Select GitHub.com, then HTTPS, then Login with a web browser (or a personal access token if the host has no browser). The token is stored in ~/.config/gh/hosts.yml.

Confirm it worked:

gh auth status

Clone the Dotfiles Repository

gh repo clone morganp/dotfiles ~/dotfiles

Or with plain git over HTTPS if you skipped gh:

git clone https://github.com/morganp/dotfiles.git ~/dotfiles

Strategy 1: Apply with run_stow

The --dotfiles flag used throughout the script tells Stow to treat a file named dot-foo in the package as .foo in the target directory. This lets the repo store dotfiles without leading dots, making them visible in directory listings and avoiding accidental git ignores.

The repo ships a run_stow script that applies each package explicitly and creates any XDG config directories that may not exist yet:

cd ~/dotfiles/config
bash run_stow

Under the hood it does things like:

stow input --dotfiles -t ~/
stow screen --dotfiles -t ~/
stow ctags --dotfiles -t ~/

mkdir -p $HOME/.config/git
stow git -t $HOME/.config/git

If Stow finds a file already at the target (e.g. the default .inputrc written by the system), it will refuse to proceed and print a conflict warning. Remove or back up the conflicting file first:

mv ~/.inputrc ~/.inputrc.bak

Then re-run the script. Reload the shell once done:

exec bash

Strategy 2: Shell and Vim via Source Wrapper

The shared repo file holds config common to all hosts. Each machine's ~/.zshrc is a thin wrapper that sources the shared file first, then adds anything host-specific below:

# ~/.zshrc -- this file is NOT in the repo, it lives only on this host
source ~/dotfiles/config/shell/dot-zshrc

# host-specific additions below
export http_proxy=http://proxy.work.example.com:3128
alias backup="rsync -av /data /mnt/nas/backup"

For a work vs. home split, source a second context file or use a hostname conditional:

source ~/dotfiles/config/shell/dot-zshrc

if [[ $(hostname) == *"work"* ]]; then
    source ~/dotfiles/config/shell/dot-zshrc_work
fi

Create ~/.bashrc the same way:

# ~/.bashrc
source ~/dotfiles/config/shell/dot-bashrc

For Vim, dot-vimrc_clean is a minimal, plugin-free config well suited to servers. Create ~/.vimrc sourcing it:

" ~/.vimrc
so ~/dotfiles/config/vim/dot-vimrc_clean

The repo also contains dot-vimrc (full config with plugins) and dot-vimrc_spelling -- point ~/.vimrc at whichever suits the host. Because these wrapper files are not managed by Stow, they are not tracked by the dotfiles repo on this machine.

Verify

Check that the Stow symlinks landed:

ls -la ~/ | grep '\->'
ls -la ~/.config/git/ | grep '\->'

Check that the source wrappers are in place:

head -1 ~/.zshrc
head -1 ~/.vimrc

Both should show the source / so line pointing into ~/dotfiles/.

Any future change to a file in ~/dotfiles/ is immediately live. Commit and push from ~/dotfiles/ as normal to keep the repo in sync across hosts.

Summary

Strategy Files How
Stow symlink Most config (git, screen, ctags, ...) bash run_stow from ~/dotfiles/config
Source wrapper ~/.zshrc, ~/.bashrc, ~/.vimrc Real local file with a single source line
Tool Purpose
git Version control, cloning the dotfiles repo
stow Symlink manager for most config packages
gh GitHub CLI for authentication and repo operations

social