| Filename | Latest commit message | Latest commit date |
|---|---|---|
| README.md | ||
Bootstrap
Automated Debian installation and system provisioning for a reproducible personal Linux environment.
The project combines Debian preseed, POSIX shell scripts and Ansible to automate the path from installation media to a fully configured workstation.
This repository serves as a documentation mirror, while the implementation is maintained in a private repository.
What it does
- Builds a customized Debian netinst ISO with unattended installation and preseed configuration.
- Bootstraps the installed system through modular Ansible tasks.
- Installs and configures system packages, third-party repositories and user applications.
- Configures rootless Docker, systemd user services/timers, filesystem mounts, GRUB, networking and other system components.
- Provisions systems both with and without full-disk encryption.
Architecture
%%{init: {
'theme': 'neutral',
'themeVariables': { 'fontSize': '12px' },
'flowchart': {
'padding': 9,
'nodeSpacing': 11,
'rankSpacing': 25,
'subGraphTitleMargin': { 'top': 8, 'bottom': 11 }
}
}}%%
flowchart TB
subgraph Phase1["<b>Phase 1: Unattended Debian install</b>"]
direction LR
P1["Make preseeded Debian ISO"] --> P2["Burn to USB & boot"] --> P3["Unattended install"]
end
subgraph Phase2["<b>Phase 2: Prepare Bootstrap USB</b>"]
direction LR
Q1["Export encrypted GPG keys"] --> Q2["Prepare Ansible Vault"] --> Q3["Copy bootstrap repo to USB"]
end
subgraph Phase3["<b>Phase 3: System Bootstrapping</b>"]
direction TB
R1["Import GPG keys"] --> R2["Decrypt Ansible Vault"]
subgraph Ansible["Executed by Ansible"]
direction LR
A1["Install packages"] --> A2["Configure repos"] --> A3["Configure system"]
end
R2 --> Ansible
end
P3 --> Phase3
Q3 --> Phase3
Design Decisions
Ansible over shell for system configuration
The original implementation was shell-based. Configuration was migrated to Ansible to provide clearer task boundaries, idempotency and easier maintenance.
Encrypted secrets
Secrets are kept outside version control and injected during bootstrap using Ansible Vault and encrypted GPG exports.
Rootless Docker
Docker is configured in rootless mode to avoid requiring a privileged Docker daemon for normal container workloads.
Ephemeral Git credentials
Private repositories (secrets, notes, dotfiles, homelab) are accessed using temporary Git credentials during bootstrap rather than persisting credentials in Git configuration.
Security
- Secrets are encrypted at rest.
- Private GPG keys are exported in encrypted form.
- Ansible secrets are protected with Ansible Vault.
- Secrets are decrypted only during the bootstrap process.
- Git credentials are not persistently stored on the target system.
Repository Structure
.
├── 1_make-preseed-iso.sh # Create a preseeded Debian installation ISO
├── 2_prepare-usb.sh # Prepare the bootstrap USB
├── 3_bootstrap.sh # Start system provisioning
├── ansible/ # Ansible configuration and provisioning tasks
├── archive/ # Previous shell-based provisioning implementation
├── assets/ # Assets used during system configuration
├── debian-installer/ # Debian preseed configuration and post-install scripts
├── private-keys/ # Encrypted GPG key exports (contents ignored by Git)
└── scripts/ # Supporting scripts
Requirements
- A Linux system is required to prepare the bootstrap USB.
- Two USBs are required.
- Supported USB filesystems are ext4, btrfs and FAT32.
Setup
The current workflow requires two USB devices: one for Debian installation and one for system bootstrapping.
1. Install Debian
Download a Debian netinst ISO, which is then customized with a preseed configuration and written to a USB device.
Create debian-installer/secrets.cfg from the example and set the user password:
cp debian-installer/secrets.cfg.example debian-installer/secrets.cfg
# create encrypted password and insert into `secrets.cfg`
sed -i "s|^\(d-i passwd/user-password-crypted password \).*|\1$(openssl passwd -6)|" debian-installer/secrets.cfg
Create the preseed ISO (sh is needed if using a FAT32 device):
sh 1_make-preseed-iso.sh path/to/debian-netinst.iso debian-installer/preseed-debian-amd64-netinst.iso
Write the ISO to a USB device:
sudo umount /dev/disk/by-id/usb-My-Flash-Drive
sudo cp debian-installer/preseed-debian-amd64-netinst.iso /dev/disk/by-id/usb-My-Flash-Drive
2. Prepare the bootstrap USB
Prepare the USB device on a Linux system with the required GPG keys. The same device can then be used to bootstrap multiple target systems.
Run the following from the USB:
# Clone the repository
git clone https://github.com/aleksa-radojicic/bootstrap.git path/to/usb/bootstrap
cd path/to/usb/bootstrap
# Create subkeyids.txt with the GPG subkeys to import on the target device
# (see subkeyids.txt.example)
gpg --list-secret-keys --with-subkey-fingerprint
vim subkeyids.txt
# Create the Ansible Vault from the example (passphrase is 'test', change it)
cp ansible/secrets.yml.example ansible/secrets.yml
ansible-vault edit ansible/secrets.yml
# Prepare the USB
sh 2_prepare-usb.sh
3. Bootstrap the system
After Debian has been installed, insert the bootstrap USB and run:
sh 3_bootstrap.sh
The script prompts for the passphrases required to unlock the encrypted GPG private keys and Ansible Vault, as well as the sudo password.
For systems using full-disk encryption:
sh 3_bootstrap.sh --fde
Useful commands
Securely delete an encrypted private-key export:
shred -u private-keys/MYSUBKEY.asc.gpg
Scope
This project is primarily a personal Debian workstation provisioning system, rather than a general-purpose fleet management framework. Some configuration is intentionally opinionated and tied to the target environment.
Future Work
- Put the Debian installation and bootstrap steps onto a single USB drive.
- Build a preconfigured Debian disk image with the required software and system configuration already applied, enabling significantly faster deployment to new machines.