Automated and reproducible Debian installation, configuration, and system provisioning from bare metal using Preseed, POSIX shell scripts and Ansible
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-27 16:55:01 +02:00
README.md update readme with new sections ('What it does', 'Design Decisions', 'Scope') 2026-08-27 16:55:01 +02:00

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.