Skip to content
rustytensorPublic

About

Unified interactive Bash toolkit for Linux server provisioning

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

64 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Warning

This project is under active development and is not yet fully functional. Features described in this README may be incomplete, unstable, or broken. Do not use in production.

Crucible
Unified interactive Bash toolkit for Linux server provisioning

Version License Shell ShellCheck Tests


Crucible automates the full lifecycle of a Linux server β€” from bare-metal OS installation through web application deployment and post-install hardening β€” across four enterprise Linux distributions. It drives every step through an interactive TUI (whiptail/dialog with plain-text fallback) and persists session state to JSON, so interrupted workflows resume exactly where they left off.


Feature Highlights

Install Provision Deploy Harden Docker
What Bare-metal OS PHP, web servers, databases 10 app types SSH, firewall, fail2ban Dev environments
How Disk partitioning, LUKS2, LVM, BTRFS subvolumes, debootstrap/dnf PHP-FPM, nginx, OpenLiteSpeed, MariaDB, PostgreSQL Idempotent 10-step pipeline with per-app state Key auth, nftables/firewalld, jails, logrotate Compose generation, distro mirroring, per-app dev
Where Bare metal Bare metal, VPS Bare metal, VPS Bare metal, VPS Any Docker host

Supported Distributions

Distribution Family Codename
Ubuntu 24.04 LTS Debian Noble Numbat
Debian 13 Debian Trixie
Rocky Linux 10 RHEL Green Obsidian
AlmaLinux 10 RHEL Purple Lion

All cross-distro differences (package names, service paths, config locations) are resolved through lib/detect.sh β€” no module ever checks the distro directly.


Quick Start

git clone https://github.com/fluxgear/crucible.git
cd crucible
sudo ./crucible

This launches the interactive TUI. For CLI usage, see CLI Reference.


How It Works

Crucible uses a phase-gated workflow β€” each major phase must complete (or be explicitly skipped) before the next unlocks:

Phase-gated workflow: Phase 1 (OS Install) β†’ Phase 2 (Provisioning) β†’ Phase 3 (Web Apps), Phase 2 β†’ Phase 4 (Hardening)

State persistence β€” All progress is stored in a JSON state file (/var/lib/crucible/state.json as root, ~/.crucible/state.json otherwise) via atomic writes (mktemp + jq + mv). If a session is interrupted, re-running crucible picks up from the last completed step.

Phase badges β€” The main menu shows live progress for each phase:

  • [ ] pending Β Β  [~] in progress Β Β  [βœ“] complete Β Β  [-] skipped

Interactive TUI

The main menu adapts based on environment and phase progress:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               Crucible v0.13.2                       β”‚
β”‚                                                      β”‚
β”‚  Select a phase:                                     β”‚
β”‚                                                      β”‚
β”‚    [ ] OS Installation                               β”‚
β”‚    [ ] Server Provisioning                           β”‚
β”‚        Web Applications                              β”‚
β”‚    [ ] Hardening                                     β”‚
β”‚        Docker Environments                           β”‚
β”‚        Update Crucible                               β”‚
β”‚        Quit                                          β”‚
β”‚                                                      β”‚
β”‚           < OK >          < Cancel >                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Three TUI backends are supported, auto-detected in order: whiptail (default on Debian/Ubuntu), dialog (common on RHEL), and plain-text (universal fallback requiring no dependencies).


Phase 1: OS Installation

Automates bare-metal disk setup and OS bootstrapping. Skipped automatically on WSL2 and Docker.

Feature Details
Boot modes EFI (GPT + ESP) and Legacy BIOS (GPT + BIOS boot partition) β€” auto-detected
Encryption LUKS2 with configurable iteration time, double-entry password verification
Filesystems BTRFS, BTRFS-on-LVM, XFS, LVM+XFS
BTRFS subvolumes @ (root), @home, @snapshots
Bootstrap debootstrap for Debian-family, dnf --installroot for RHEL-family
Device awareness NVMe and loop device partition naming handled automatically

The installation wizard walks through disk selection, filesystem choice, optional LUKS encryption, partitioning, and bootstrap β€” with a confirmation summary before any destructive operation.


Phase 2: Server Provisioning

Provisions the server stack through a sub-menu:

Component Options
PHP Installs PHP-FPM with per-app pool configuration, OPcache, APCu
Web server nginx or OpenLiteSpeed β€” vhost templates with security rules per app type
Database MariaDB (with tuning template) or PostgreSQL β€” user/database provisioning

Each component tracks its own completion state. The provisioning sub-menu shows which components have been configured.


Phase 3: Web Applications

Deploys web applications through an idempotent 10-step pipeline. Each step is individually tracked β€” if any step fails, re-running resumes from exactly where it stopped.

Supported App Types

PHP Apps Python Apps
WordPress Django
Drupal Flask
XenForo FastAPI
Invision Power Board Generic WSGI/ASGI
StackLuma
Generic PHP

Provisioning Pipeline

 1. Create system user          6. Create web server vhost
 2. Create database             7. Set filesystem ACLs
 3. Create database user        8. Generate self-signed SSL certificate
 4. Configure app type          9. Set up cron jobs (app-specific)
 5. Create FPM pool / venv     10. Write credentials file
  • PHP apps get a dedicated FPM pool with per-app socket, OPcache, and session paths
  • Python apps get a virtualenv, systemd service unit (gunicorn or uvicorn), and reverse-proxy vhost
  • OpenLiteSpeed is supported for PHP apps only β€” Python apps require nginx
  • SSL is generated by default (self-signed) and can be disabled per app
  • Each app gets its own system user, home directory (from skel-app/), and isolated log paths

Phase 4: Hardening

Post-provisioning security hardening through four modules:

Module Capabilities
SSH Key-only auth, disable root login, custom port, allowed-users list, protocol hardening
Firewall nftables (Debian) / firewalld (RHEL) β€” opens SSH port from state, HTTP/HTTPS, custom ports
fail2ban nginx-auth jail, bad-bots filter, WordPress login protection (auto-detected from state)
Logrotate Per-app log rotation for nginx, PHP-FPM, and application logs

All systemctl calls are gated on environment detection β€” hardening modules are skipped in Docker containers where systemd is unavailable.


Phase 5: Docker Dev Environments

Create disposable development environments that mirror your production distro. Two modes:

Mode A β€” Distro Mirror Mode B β€” Per-App Dev
Purpose Full server replica Single-app development
Volumes Named: apps + db Bind-mount: host webroot; Named: db
Services nginx PHP: php-fpm + mysqld + nginx; Python: postgresql + nginx
Use case Run crucible provisioning inside a container Edit code on host, run services in container

Docker environments are managed through the TUI or CLI:

# Mode A β€” mirror an Ubuntu server
crucible docker up myserver a ubuntu2404

# Mode B β€” WordPress dev environment with host webroot
crucible docker up myapp b debian13 apptype=wordpress webroot=/path/to/site ports=9080:80

# Manage containers
crucible docker list
crucible docker exec myserver
crucible docker down myserver

CLI Reference

Command Description
crucible Launch the interactive TUI
crucible docker up <name> <mode> <distro> [opts] Create and start a Docker environment
crucible docker down <name> Stop and remove a Docker environment
crucible docker list List all managed Docker environments (syncs live status)
crucible docker exec <name> [cmd] Execute a command in a running container (default: bash)
crucible update Update crucible to the latest version
crucible --version Print version
crucible --help Print usage information

Docker up Options

Options are passed as KEY=VALUE pairs after the positional arguments:

Option Default Description
ports 8080:80,8443:443 Port mappings (comma-separated host:container)
webroot β€” Host directory to bind-mount (required for Mode B)
apptype β€” App type for Mode B service selection

Self-Update

Crucible detects its installation method and updates accordingly:

  • Git clone β€” git pull --ff-only origin develop with automatic stash of local changes
  • Release tarball β€” Downloads the latest GitHub release, verifies SHA-256 checksum (if provided), and replaces files in-place

In both cases, the state file is never touched β€” your provisioning progress is preserved across updates.


Architecture Overview

Component Tree

crucible                          ← entrypoint (arg parsing, dispatch)
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ detect.sh                 ← distro/environment detection (leaf dependency)
β”‚   β”œβ”€β”€ state.sh                  ← JSON state persistence via jq
β”‚   β”œβ”€β”€ tui.sh                    ← TUI abstraction (whiptail/dialog/plaintext)
β”‚   β”œβ”€β”€ install/
β”‚   β”‚   β”œβ”€β”€ os-install.sh         ← disk setup, partitioning, filesystem creation
β”‚   β”‚   └── bootstrap.sh          ← debootstrap/dnf chroot bootstrapping
β”‚   β”œβ”€β”€ provision/
β”‚   β”‚   β”œβ”€β”€ php.sh                ← PHP-FPM installation and pool management
β”‚   β”‚   β”œβ”€β”€ nginx.sh              ← nginx installation and vhost management
β”‚   β”‚   β”œβ”€β”€ ols.sh                ← OpenLiteSpeed installation and vhost management
β”‚   β”‚   β”œβ”€β”€ mariadb.sh            ← MariaDB installation, tuning, user/db management
β”‚   β”‚   β”œβ”€β”€ postgresql.sh         ← PostgreSQL installation, user/db management
β”‚   β”‚   β”œβ”€β”€ webapp.sh             ← 10-step app provisioning orchestrator
β”‚   β”‚   β”œβ”€β”€ apptypes.sh           ← app type dispatcher (sources all 10 modules)
β”‚   β”‚   └── apptypes/             ← per-app-type configuration
β”‚   β”‚       β”œβ”€β”€ wordpress.sh      β”œβ”€β”€ django.sh
β”‚   β”‚       β”œβ”€β”€ drupal.sh         β”œβ”€β”€ flask.sh
β”‚   β”‚       β”œβ”€β”€ xenforo.sh        β”œβ”€β”€ fastapi.sh
β”‚   β”‚       β”œβ”€β”€ ipb.sh            β”œβ”€β”€ generic_wsgi.sh
β”‚   β”‚       β”œβ”€β”€ stackluma.sh      └── generic_php.sh
β”‚   β”œβ”€β”€ harden/
β”‚   β”‚   β”œβ”€β”€ ssh.sh                ← SSH hardening
β”‚   β”‚   β”œβ”€β”€ firewall.sh           ← nftables/firewalld management
β”‚   β”‚   β”œβ”€β”€ fail2ban.sh           ← jail and filter management
β”‚   β”‚   └── logrotate.sh          ← per-app log rotation
β”‚   └── docker/
β”‚       β”œβ”€β”€ compose.sh            ← docker-compose.yml generation
β”‚       └── env.sh                ← container lifecycle management
β”œβ”€β”€ templates/                    ← 15 config templates (FPM, vhosts, systemd, etc.)
β”œβ”€β”€ skel-app/                     ← skeleton home directory for app users
└── tests/                        ← 203 BATS tests + 4-distro matrix runner

Dependency Chain

detect.sh ← state.sh ← tui.sh ← everything else
   (leaf)

detect.sh is the leaf dependency β€” every module depends on it, and it depends on nothing. All cross-distro path lookups, package names, and service names are resolved through detect.sh functions. No other module ever inspects CRUCIBLE_DISTRO_FAMILY directly.

State Architecture

State is a single JSON document managed by lib/state.sh:

{
  "version": "0.13.2",
  "phases": {
    "os_install": { "status": "complete" },
    "provisioning": {
      "status": "complete",
      "components": { "php": true, "webserver": "nginx", "database": "mariadb" }
    },
    "apps": [
      { "name": "example.com", "type": "wordpress", "status": "complete", "completed_steps": [...] }
    ],
    "hardening": {
      "status": "complete",
      "components": { "ssh": true, "firewall": true, "fail2ban": true, "logrotate": true }
    },
    "docker": { "containers": [...] }
  }
}

All writes are atomic: write to a temp file via jq, then mv to the final path. The in-memory _CRUCIBLE_STATE global avoids repeated disk reads.


Requirements

  • Bash 5.0+
  • jq (for state management)
  • Root access (for provisioning and hardening operations)
  • whiptail or dialog (optional β€” plain-text fallback works without either)
  • curl (for self-update via release tarball)
  • Docker + Docker Compose (for Docker dev environments only)

Environment Support

Environment Install Provision Apps Harden Docker
Bare metal Yes Yes Yes Yes Yes
VPS β€” Yes Yes Yes Yes
WSL2 β€” Requires systemd Requires systemd Requires systemd Yes
Docker β€” β€” β€” β€” β€”

Crucible auto-detects the runtime environment and adjusts available phases accordingly. OS installation is only available on bare metal. Provisioning and hardening require systemd.


Testing

Running Tests

# Run all host-compatible tests (skips container-only tests)
bats tests/

# Run a specific test suite
bats tests/test_detect.bats
bats tests/test_webapp.bats

# Run the 4-distro matrix (requires Docker)
bash tests/matrix.sh

Test Suites

Suite Tests Scope
test_detect.bats 66 Distro detection, path lookups, environment detection
test_webapp.bats 31 App provisioning pipeline, user creation, state tracking
test_state.bats 26 JSON state persistence, atomic writes, schema validation
test_crossdistro.bats 20 Container-only: cross-distro path resolution
test_mariadb.bats 20 Database/user provisioning, tuning template
test_php.bats 17 PHP-FPM installation, pool creation
test_matrix.bats 11 Matrix runner infrastructure
test_postgresql.bats 8 Database/user provisioning
test_tui.bats 4 Backend detection, dialog fallback
Total 203

Matrix Runner

The matrix runner (tests/matrix.sh) builds lightweight containers for all four supported distros and executes the cross-distro test suite inside each:

bash tests/matrix.sh              # run all distros
bash tests/matrix.sh ubuntu       # run a single distro
bash tests/matrix.sh --cleanup    # remove matrix images

Contributing

  1. Follow the coding standards in docs/conventions.md
  2. All cross-distro differences go through lib/detect.sh β€” never check CRUCIBLE_DISTRO_FAMILY in other modules
  3. Every .sh file needs: shebang, set -euo pipefail, file header, source guard
  4. Functions are prefixed by module name: nginx_create_vhost(), state_save()
  5. Run shellcheck and bats tests/ before submitting changes

License

MIT β€” see LICENSE

Author

Marc Mironescu β€” fluxgear.io

About

Unified interactive Bash toolkit for Linux server provisioning

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages