A CoreOS homelab configuration using Butane to generate Ignition files for automated server provisioning and container orchestration.
- Automated Provisioning: Complete CoreOS server setup with Ignition
- Container Services: Media server stack (Plex, Radarr, Sonarr, etc.)
- Security First: Credential templating with 1Password integration
- CI/CD Pipeline: Automated validation and security scanning
- Backup System: Scheduled backups with SystemD timers
- Network Isolation: Custom Podman networks with security boundaries
- Shell Environment: Custom ZSH profile with Starship prompt
- 1Password CLI installed and authenticated
- Butane for config transpilation
- Make for build automation
- Configure credentials: Update
default.envwith your 1Password item references - Generate configs: Run
make generateto process templates with your credentials - Build ignition: Run
make buildto create the CoreOS ignition file - Serve locally: Run
make serveto host the ignition file athttp://YOUR_IP:8080/latest
Boot target server from CoreOS Live ISO to access coreos-installer.
- Serve ignition: Run
make serveon your build machine - Install CoreOS: From the Live ISO environment, run:
sudo coreos-installer install /dev/sda --ignition-url http://YOUR_BUILD_MACHINE_IP:8080/latest
- Copy to USB: Copy
build/latest(the ignition JSON file) to a USB drive - Install CoreOS: From the Live ISO environment, run:
sudo coreos-installer install /dev/sda --ignition-file /path/to/usb/latest
# Generate container services
make new service NAME=jellyfin IMAGE=jellyfin/jellyfin:latest PORTS=8096:8096
# Generate scheduled tasks
make new timer NAME=backup DESCRIPTION="Daily backup" SCHEDULE="*-*-* 02:00:00"
# Generate oneshot system tasks
make new task NAME=deps SCRIPT=init-deps.sh REMAIN_ACTIVE=yes
# Interactive mode (prompts for all values)
make new service # or timer, task-
Generate the service:
make new service NAME=jellyfin IMAGE=jellyfin/jellyfin:latest PORTS=8096:8096
-
Review the generated template:
cat services/container-jellyfin.service.template
-
Enable the service by adding to
systemd.yaml.template:# Add this section to systemd.yaml.template - name: container-jellyfin.service enabled: true # Auto-start on boot
-
Build and test:
make generate # Process templates with credentials make build # Create ignition file and validate make serve # Serve for deployment at http://YOUR_IP:8080/latest
service: Container applications (web apps, media servers, databases)timer: Scheduled tasks with SystemD timer syntaxtask: One-time setup scripts (dependencies, initialization)
# Media server with external access
make new service NAME=plex IMAGE=plexinc/pms-docker PORTS=32400:32400
# Internal service (no external ports)
make new service NAME=radarr IMAGE=linuxserver/radarr
# Daily backup task
make new timer NAME=backup SCHEDULE="*-*-* 04:00:00"
# System initialization task
make new task NAME=setup-storage SCRIPT=init-storage.sh REMAIN_ACTIVE=yes# Run all validation checks
make lint
# Clean build artifacts
make clean# Run all linting and validation checks
make lint
# Or run individual checks
make lint-yaml # YAML syntax and style
make lint-shell # Shell script analysis
make validate-butane # Butane config validation
make validate-systemd # SystemD service validation| Command | Description |
|---|---|
make build |
Primary build: validates and generates ignition file |
make generate |
Generates templates (credentials, users.yaml) using 1Password CLI |
make clean |
Cleanup build artifacts and temporary files |
make serve |
Builds and serves ignition file locally on port 8080 |
make new [service,timer,task] |
Generate new resource templates |
make lint |
Run all local linting and validation checks |
make lint-yaml |
Lint YAML files with yamllint |
make lint-shell |
Lint shell scripts with shellcheck |
make validate-butane |
Validate Butane configuration files |
make validate-systemd |
Validate SystemD service files |
make validate-templates |
Validate that referenced services have template files |
make help |
Show available targets with descriptions |
├── .github/workflows/ # CI/CD pipeline
├── profile/ # Shell configuration
├── scripts/ # System scripts
├── security/ # Credential templates
├── services/ # SystemD service definitions
├── templates/ # Resource generation templates
├── default.env # Centralized token configuration
├── storage.yaml.template # File/directory provisioning
├── systemd.yaml.template # Service management
├── users.yaml.template # User account template
└── Makefile # Build automation
- Centralized Credentials: All tokens managed in
default.envwith 1Password references - Template Processing: Dynamic credential injection during build
- Automated Scanning: Checkov security analysis in CI pipeline
- No Secrets in Git: Credentials resolved at build time, never committed
The CI pipeline automatically validates:
- YAML Linting: Syntax and formatting validation
- Shell Scripts: ShellCheck analysis for POSIX compliance
- Butane Configs: Ignition generation validation
- Security Scan: Secret detection and vulnerability analysis
- SystemD Services: Service file validation
Generated service won't start after deployment:
# Check if service is enabled in systemd.yaml.template
grep "container-myapp.service" systemd.yaml.template
# If missing, add it:
- name: container-myapp.service
enabled: trueBuild fails with "template not found":
# Ensure the template exists
ls services/container-myapp.service.template
# Regenerate if needed
make new service NAME=myapp IMAGE=nginxPort conflicts or networking issues:
# Check for port conflicts in other services
grep "8080:8080" services/*.template
# Verify network configuration
grep "network" services/container-*.template1Password authentication errors:
# Verify 1Password CLI is authenticated
op account list
# Test credential access
op read "op://Private/PLEX_CLAIM/credential"
# Check default.env format
grep "^[A-Z]" default.envTemplate validation errors:
# Run individual validation steps
make lint-yaml
make validate-butane
make validate-systemd
make validate-templates # Check for missing service templates
# Check specific service syntax
systemd-analyze verify services/container-app.service.templateMissing template files:
# If build fails with missing template references:
make validate-templates # Shows which templates are missing and how to create them- YAML files: 2-space indentation, no tabs
- Shell scripts: POSIX-compliant, use
#!/bin/shshebang - File permissions: Explicit mode settings (0755 for executables, 0644 for configs)
- Security: Credentials via templates, never commit secrets
- Template tokens: Use
{{TOKEN_NAME}}format for all placeholders - SystemD services: Follow naming pattern
container-{app}.serviceortask-{name}.service - File paths: Use absolute paths in configurations (
/var/services/,/etc/systemd/system/)
