Skip to content

Repository files navigation

server4home

A template for building custom bootc operating system images based on the lessons from Universal Blue and Bluefin. It is designed to be used manually, but is optimized to be bootstraped by GitHub Copilot. After set up you'll have your own custom Linux.

K3s/Rancher flavor docs: see docs/k3s-rancher-vms.md for the build → deploy → operate guide (with diagrams).

This template uses the multi-stage build architecture from , combining resources from multiple OCI containers for modularity and maintainability. See the Architecture section below for details.

Unlike previous templates, you are not modifying Bluefin and making changes.: You are assembling your own Bluefin in the same exact way that Bluefin, Aurora, and Bluefin LTS are built. This is way more flexible and better for everyone since the image-agnostic and desktop things we love about Bluefin lives in @projectbluefin/common.

Instead, you create your own OS repository based on this template, allowing full customization while leveraging Bluefin's robust build system and shared components.

Be the one who moves, not the one who is moved.

Guided Copilot Mode

This repository can be used as a template in two ways:

Option 1: Use GitHub's Template Feature (Recommended for Customization)

  1. Click the green "Use this as a template" button on GitHub and create a new repository
  2. Select your owner, pick a repo name for your OS, and a description
  3. In the "Jumpstart your project with Copilot (optional)" field, add:
Use @projectbluefin/server4home as a template, name the OS the repository name. Ensure the entire operating system is bootstrapped. Ensure all github actions are enabled and running. Ensure the README has the github setup instructions for cosign and the other steps required to finish the task.

GitHub Copilot will automatically:

  • Bootstrap your repository
  • Configure all GitHub Actions workflows
  • Update the README with your project name
  • Prepare everything for your first build

Option 2: Use Directly as a Template

Clone this repository and customize it manually by following the "Quick Start" section below.

What's Different

This is a custom bootc image template based on Universal Blue's architecture. By default, it includes:

System Foundation

  • Base Image: Fedora Silverblue (GNOME desktop included)
  • Container Runtime: Podman pre-configured and optimized
  • Package Manager: DNF5 for system-level packages, Homebrew for CLI tools

Pre-Configured Tools

  • Desktop Environment: GNOME (can be replaced with KDE, COSMIC, etc.)
  • Development Ready: Git, podman, and build tools included
  • System Utilities: Standard Unix tools and utilities

Customization Points

  • Add system packages via build/10-build.sh (build-time)
  • Add CLI tools via custom/brew/ Brewfiles (runtime)
  • Add GUI apps via custom/flatpaks/ (post-first-boot)
  • Add user shortcuts via custom/ujust/ commands (runtime)

What Makes This Different From Bluefin

You're not modifying Bluefin — you're assembling your own bootc image using the same architecture Bluefin uses. This is:

  • More Flexible: Customize everything without forking
  • Better Maintained: Use shared components from @projectbluefin/common
  • Easy to Update: Renovate automatically keeps base images current
  • Production Ready: Full build system, CI/CD, signing, and SBOM support

What's Included

Build System

  • Automated builds via GitHub Actions on every commit
  • Awesome self hosted Renovate setup that keeps all your images and actions up to date.
  • Automatic cleanup of old images (90+ days) to keep it tidy
  • Pull request workflow - test changes before merging to main
    • PRs build and validate before merge
    • main branch builds :stable images
  • Validates your files on pull requests so you never break a build:
    • Brewfile, Justfile, ShellCheck, Renovate config, and it'll even check to make sure the flatpak you add exists on FlatHub
  • Production Grade Features
    • Container signing and SBOM Generation
    • See checklist below to enable these as they take some manual configuration

Homebrew Integration

  • Pre-configured Brewfiles for easy package installation and customization
  • Includes curated collections: development tools, fonts, CLI utilities. Go nuts.
  • Users install packages at runtime with brew bundle, aliased to premade ujust commands
  • See custom/brew/README.md for details

Flatpak Support

  • Ship your favorite flatpaks
  • Automatically installed on first boot after user setup
  • See custom/flatpaks/README.md for details

ujust Commands

  • User-friendly command shortcuts via ujust
  • Pre-configured examples for app installation and system maintenance for you to customize
  • See custom/ujust/README.md for details

Build Scripts

  • Modular numbered scripts (10-, 20-, 30-) run in order
  • Example scripts included for third-party repositories and desktop replacement
  • Helper functions for safe COPR usage
  • See build/README.md for details

Quick Start

1. Create Your Repository

Click "Use this template" to create a new repository from this template.

2. Rename the Project

Important: Change server4home to your repository name in these 6 files:

  1. Containerfile (line 4): # Name: your-repo-name
  2. Justfile (line 1): export image_name := env("IMAGE_NAME", "your-repo-name")
  3. README.md (line 1): # your-repo-name
  4. artifacthub-repo.yml (line 5): repositoryID: your-repo-name
  5. custom/ujust/README.md (~line 175): localhost/your-repo-name:stable
  6. .github/workflows/clean.yml (line 23): packages: your-repo-name

3. Enable GitHub Actions

  • Go to the "Actions" tab in your repository
  • Click "I understand my workflows, go ahead and enable them"

Your first build will start automatically!

Note: Image signing is disabled by default. Your images will build successfully without any signing keys. Once you're ready for production, see "Optional: Enable Image Signing" below.

4. Customize Your Image

Choose your base image in Containerfile (currently set to uCore HCI):

FROM ghcr.io/ublue-os/ucore-hci:latest

Other available base images:

  • ghcr.io/ublue-os/ucore-server:latest - uCore Server variant
  • ghcr.io/ublue-os/silverblue-main:latest - Fedora-based with GNOME
  • ghcr.io/ublue-os/bluefin:stable - Fedora-based dev image
  • quay.io/centos-bootc/centos-bootc:stream10 - CentOS bootc
  • quay.io/gnome_infrastructure/gnome-build-meta:gnomeos-nightly - GNOME OS

uCore Documentation: https://github.com/ublue-os/ucore

Add your packages in build/10-build.sh:

dnf5 install -y package-name

Customize your apps:

  • Add Brewfiles in custom/brew/ (guide)
  • Add Flatpaks in custom/flatpaks/ (guide)
  • Add ujust commands in custom/ujust/ (guide)

5. Development Workflow

All changes should be made via pull requests:

  1. Open a pull request on GitHub with the change you want.
  2. The PR will automatically trigger:
    • Build validation
    • Brewfile, Flatpak, Justfile, and shellcheck validation
    • Test image build
  3. Once checks pass, merge the PR
  4. Merging triggers publication of a :stable image

6. Deploy Your Image

Switch to your image:

sudo bootc switch ghcr.io/your-username/your-repo-name:stable
sudo systemctl reboot

GitHub Setup Complete Checklist

After creating your repository, ensure these steps are completed:

  • Enable GitHub Actions - Go to Actions tab, click "I understand my workflows, go ahead and enable them"
  • Verify Initial Build - Watch the first build complete (check Actions tab)
  • Check Build Output - View logs to ensure no errors
  • Verify Package Registry - Go to repository → Packages section, confirm server4home image appears
  • Make Test Commit - Push a small change to verify PR workflow works
  • Configure Renovate (optional) - Renovate automatically updates base image tags
    • Already configured in .github/renovate.json5
    • Check for Renovate PR if enabled by repository admin
  • Plan Image Signing (for production) - See "Optional: Enable Image Signing" section below
  • Update Documentation - Customize README.md with your OS details

Git Configuration (First Time Only)

If you haven't configured git locally yet:

git config user.email "your-email@example.com"
git config user.name "Your Name"

For GitHub-based email (if using noreply):

git config user.email "your-gh-username+your-id@users.noreply.github.com"

Build Triggers

Your image automatically builds on:

  • Push to main - Triggers :stable build
  • Pull requests - Test build (not pushed to registry)
  • Daily - Scheduled build at 10:05 UTC (see .github/workflows/build.yml)
  • Manual - Click "Run workflow" in Actions tab

Optional: Enable Image Signing

Image signing is disabled by default to let you start building immediately. However, signing is strongly recommended for production use.

Why Sign Images?

  • Verify image authenticity and integrity
  • Prevent tampering and supply chain attacks
  • Required for some enterprise/security-focused deployments
  • Industry best practice for production images

Setup Instructions

  1. Generate signing keys:
cosign generate-key-pair

This creates two files:

  • cosign.key (private key) - Keep this secret
  • cosign.pub (public key) - Commit this to your repository
  1. Add the private key to GitHub Secrets:

    • Copy the entire contents of cosign.key
    • Go to your repository on GitHub
    • Navigate to Settings → Secrets and variables → Actions (GitHub docs)
    • Click "New repository secret"
    • Name: SIGNING_SECRET
    • Value: Paste the entire contents of cosign.key
    • Click "Add secret"
  2. Replace the contents of cosign.pub with your public key:

    • Open cosign.pub in your repository
    • Replace the placeholder with your actual public key
    • Commit and push the change
  3. Enable signing in the workflow:

    • Edit .github/workflows/build.yml
    • Find the "OPTIONAL: Image Signing with Cosign" section.
    • Uncomment the steps to install Cosign and sign the image (remove the # from the beginning of each line in that section).
    • Commit and push the change
  4. Your next build will produce signed images!

Important: Never commit cosign.key to the repository. It's already in .gitignore.

Love Your Image? Let's Go to Production

Ready to take your custom OS to production? Enable these features for enhanced security, reliability, and performance:

Production Checklist

  • Enable Image Signing (Recommended)

    • Provides cryptographic verification of your images
    • Prevents tampering and ensures authenticity
    • See "Optional: Enable Image Signing" section above for setup instructions
    • Status: Disabled by default to allow immediate testing
  • Enable SBOM Attestation (Recommended)

    • Generates Software Bill of Materials for supply chain security
    • Provides transparency about what's in your image
    • Requires image signing to be enabled first
    • To enable:
      1. First complete image signing setup above
      2. Edit .github/workflows/build.yml
      3. Find the "OPTIONAL: SBOM Attestation" section around line 232
      4. Uncomment the "Add SBOM Attestation" step
      5. Commit and push
    • Status: Disabled by default (requires signing first)
  • Enable Image Rechunking (Recommended)

    • Optimizes bootc image layers for better update performance
    • Reduces update sizes by 5-10x
    • Improves download resumability with evenly sized layers
    • To enable:
      1. Edit .github/workflows/build.yml
      2. Find the "Build Image" step
      3. Add a rechunk step after the build (see example below)
    • Status: Not enabled by default (optional optimization)

Adding Image Rechunking

After building your bootc image, add a rechunk step before pushing to the registry. Here's an example based on the workflow used by zirconium-dev/zirconium:

- name: Build image
  id: build
  run: sudo podman build -t "${IMAGE_NAME}:${DEFAULT_TAG}" -f ./Containerfile .

- name: Rechunk Image
  run: |
    sudo podman run --rm --privileged \
      -v /var/lib/containers:/var/lib/containers \
      --entrypoint /usr/libexec/bootc-base-imagectl \
      "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" \
      rechunk --max-layers 96 \
      "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" \
      "localhost/${IMAGE_NAME}:${DEFAULT_TAG}"

- name: Push to Registry
  run: sudo podman push "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" "${IMAGE_REGISTRY}/${IMAGE_NAME}:${DEFAULT_TAG}"

Alternative approach using a temporary tag for clarity:

- name: Rechunk Image
  run: |
    sudo podman run --rm --privileged \
      -v /var/lib/containers:/var/lib/containers \
      --entrypoint /usr/libexec/bootc-base-imagectl \
      "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" \
      rechunk --max-layers 67 \
      "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" \
      "localhost/${IMAGE_NAME}:${DEFAULT_TAG}-rechunked"
    
    # Tag the rechunked image with the original tag
    sudo podman tag "localhost/${IMAGE_NAME}:${DEFAULT_TAG}-rechunked" "localhost/${IMAGE_NAME}:${DEFAULT_TAG}"
    sudo podman rmi "localhost/${IMAGE_NAME}:${DEFAULT_TAG}-rechunked"

Parameters:

  • --max-layers: Maximum number of layers for the rechunked image (typically 67 for optimal balance)
  • The first image reference is the source (input)
  • The second image reference is the destination (output)
    • When using the same reference for both, the image is rechunked in-place
    • You can also use different tags (e.g., -rechunked suffix) and then retag if preferred

References:

After Enabling Production Features

Your workflow will:

  • Sign all images with your key
  • Generate and attach SBOMs
  • Provide full supply chain transparency

Users can verify your images with:

cosign verify --key cosign.pub ghcr.io/your-username/your-repo-name:stable

Detailed Guides

Architecture

This template follows the multi-stage build architecture from @projectbluefin/distroless, as documented in the Bluefin Contributing Guide.

Multi-Stage Build Pattern

Stage 1: Context (ctx) - Combines resources from multiple sources:

  • Local build scripts (/build)
  • Local custom files (/custom)
  • @projectbluefin/common - Desktop configuration shared with Aurora
  • @projectbluefin/branding - Branding assets
  • @ublue-os/artwork - Artwork shared with Aurora and Bazzite
  • @ublue-os/brew - Homebrew integration

Stage 2: Base Image - Default options:

  • ghcr.io/ublue-os/silverblue-main:latest (Fedora-based, default)
  • quay.io/centos-bootc/centos-bootc:stream10 (CentOS-based alternative)

Benefits of This Architecture

  • Modularity: Compose your image from reusable OCI containers
  • Maintainability: Update shared components independently
  • Reproducibility: Renovate automatically updates OCI tags to SHA digests
  • Consistency: Share components across Bluefin, Aurora, and custom images

OCI Container Resources

The template imports files from these OCI containers at build time:

COPY --from=ghcr.io/ublue-os/base-main:latest /system_files /oci/base
COPY --from=ghcr.io/projectbluefin/common:latest /system_files /oci/common
COPY --from=ghcr.io/ublue-os/brew:latest /system_files /oci/brew

Your build scripts can access these files at:

  • /ctx/oci/base/ - Base system configuration
  • /ctx/oci/common/ - Shared desktop configuration
  • /ctx/oci/branding/ - Branding assets
  • /ctx/oci/artwork/ - Artwork files
  • /ctx/oci/brew/ - Homebrew integration files

Note: Renovate automatically updates :latest tags to SHA digests for reproducible builds.

Local Testing

Test your changes before pushing:

just build              # Build container image
just build-qcow2        # Build VM disk image
just run-vm-qcow2       # Test in browser-based VM

Community

Learn More

Security

This template provides security features for production use:

  • Optional SBOM generation (Software Bill of Materials) for supply chain transparency
  • Optional image signing with cosign for cryptographic verification
  • Automated security updates via Renovate
  • Build provenance tracking

These security features are disabled by default to allow immediate testing. When you're ready for production, see the "Love Your Image? Let's Go to Production" section above to enable them.

About

server4home is custom immutable server for my homelab

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages