krops-multi-deploy/DEPLOYMENT-GUIDE.md
padreug ca5b78b561 Add build-local.nix for machine-specific web-app builds and update deployment instructions
Introduced a new example-build-local.nix file to facilitate machine-specific web-app builds, enhancing the deployment process. Updated the .gitignore to include build-local.nix, ensuring user-specific configurations remain untracked. Revised the DEPLOYMENT-GUIDE.md to reflect the addition of build-local.nix and provide clearer instructions for setting up configuration files, improving the onboarding experience for new users.
2025-10-12 08:34:58 +02:00

10 KiB

Web-App Deployment Guide

Overview

This setup builds the web-app locally with machine-specific configuration, then deploys the built artifacts to each target machine. Each machine gets its own customized build with:

  • Machine-specific .env files
  • Machine-specific images in the public folder

Initial Setup

When you first clone this repository, you need to set up your local configuration:

1. Create your configuration files

# Copy the example templates
cp example-krops.nix krops.nix
cp example-build-local.nix build-local.nix

2. Create your first machine configuration

# Copy the example machine template
cp -r config/machines/example-machine config/machines/my-machine

# Edit the configuration
# - Change the domain in configuration.nix
# - Add your hardware-configuration.nix (from nixos-generate-config)

3. Create machine-specific web-app assets (if deploying web-app)

mkdir -p machine-specific/my-machine/env
mkdir -p machine-specific/my-machine/images

# Add your .env file and images
# See machine-specific/example-machine/ for reference

4. Update krops.nix and build-local.nix

In krops.nix:

  • Replace example-machine with your machine name
  • Update the SSH target (root@your-host)
  • Add to the inherit list and all script

In build-local.nix:

  • Replace example-machine with your machine name
  • Add to the all build script

5. Build and deploy!

# Build web-app locally (if using web-app)
nix-build ./build-local.nix -A my-machine && ./result/bin/build-my-machine

# Deploy to target machine
nix-build ./krops.nix -A my-machine && ./result

Note: Your krops.nix, build-local.nix, and machine configs in config/machines/* are gitignored. You can safely pull updates without overwriting your local configuration.

Structure

.
├── config/                           # NixOS configuration files
│   ├── shared.nix                    # Shared config for all machines
│   ├── nginx.nix                     # Nginx configuration
│   ├── lnbits.nix                    # LNBits configuration
│   ├── pict-rs.nix                   # Pict-rs configuration
│   └── machines/                     # Machine-specific configs (gitignored)
│       ├── example-machine/          # Template (committed to git)
│       │   ├── configuration.nix     # Main config entry point
│       │   ├── boot.nix             # Bootloader settings
│       │   └── example-service.nix  # Service examples
│       ├── machine1/                 # Your machines (gitignored)
│       └── machine2/                 # Your machines (gitignored)
├── web-app/                          # Shared web-app source (symlink)
├── machine-specific/                 # Machine-specific web-app assets (symlink)
├── lnbits/                          # LNBits source (symlink)
├── secrets/                         # Encrypted secrets
│   ├── example-machine/
│   │   └── README.md                # Secrets usage guide
│   ├── machine1/                    # Machine-specific secrets
│   │   └── *.age                    # Encrypted with age
│   └── machine2/
├── build/                           # Generated locally (gitignored)
├── build-local.nix                  # Local build scripts
└── krops.nix                        # Deployment configuration

How It Works

1. Build Locally

First, build the web-app for each machine on your local machine:

# Build for a specific machine
nix-build ./build-local.nix -A machine1 && ./result/bin/build-machine1

# Or build for all machines
nix-build ./build-local.nix -A all && ./result/bin/build-all

This:

  1. Copies web-app source to ./build/{machine}/
  2. Copies machine-specific .env file
  3. Copies machine-specific images to public/
  4. Runs npm run build
  5. Creates ./build/{machine}/dist/ with the built app

2. Deploy Built Artifacts

After building, deploy to target machines:

# Deploy to specific machine
nix-build ./krops.nix -A machine1 && ./result

# Deploy to all machines
nix-build ./krops.nix -A all && ./result

The built files from ./build/{machine}/dist/ are copied to /var/src/web-app-dist/ on each target machine.

Complete Workflow

# 1. Build locally for all machines
nix-build ./build-local.nix -A all && ./result/bin/build-all

# 2. Deploy to all machines
nix-build ./krops.nix -A all && ./result

Customization

Add a new machine

  1. Copy the example template:

    cp -r config/machines/example-machine config/machines/my-new-machine
    
  2. Edit the configuration:

    • Open config/machines/my-new-machine/configuration.nix
    • Change domain = "example.com" to your domain
    • Add your hardware-configuration.nix (from nixos-generate-config)
  3. Create machine-specific web-app assets (if using web-app):

    mkdir -p machine-specific/my-new-machine/env
    mkdir -p machine-specific/my-new-machine/images
    # Add .env file and images
    
  4. Add to krops.nix and build-local.nix:

    • Add my-new-machine configuration to both files
  5. Build and deploy:

    nix-build ./build-local.nix -A my-new-machine && ./result/bin/build-my-new-machine
    nix-build ./krops.nix -A my-new-machine && ./result
    

Update environment variables

Edit .env in machine-specific/{machine-name}/env/.env, then rebuild locally

Update images

Replace files in machine-specific/{machine-name}/images/, then rebuild locally

Update web-app code

Edit files in web-app/, then rebuild locally

After any changes: rebuild locally, then redeploy.

Adding Machine-Specific Services

Sometimes you need services that only run on certain machines (e.g., WireGuard on machine1 but not machine2).

Using the Example Template

A complete example machine configuration is provided in config/example-machine/:

config/example-machine/
  ├── configuration.nix      # Template with domain parameter
  ├── boot.nix              # Bootloader configuration examples
  └── example-service.nix   # WireGuard and other service examples

To use the template:

  1. Copy the example-machine directory to your new machine name:
    cp -r config/example-machine config/my-new-machine
    
  2. Edit configuration.nix to set your domain
  3. Copy your hardware-configuration.nix from nixos-generate-config
  4. Customize boot.nix for your bootloader (UEFI or BIOS)
  5. Modify or remove example-service.nix as needed
  6. Add the machine to build-local.nix and krops.nix

Example: Machine1 has WireGuard

Structure:

config/
  ├── shared.nix                    # Shared config for all machines
  ├── machine1/
  │   ├── configuration.nix         # Imports shared.nix + machine-specific modules
  │   ├── wireguard.nix            # Machine1-specific service
  │   ├── hardware-configuration.nix
  │   └── boot.nix
  └── machine2/
      ├── configuration.nix         # Only imports shared.nix
      ├── hardware-configuration.nix
      └── boot.nix

Steps to Add a Machine-Specific Service

  1. Create a service configuration file in the machine's directory:

    # Example: config/machine1/wireguard.nix
    { config, lib, pkgs, ... }:
    {
      networking.wireguard.interfaces = {
        wg0 = {
          privateKeyFile = "/etc/wireguard/privatekey";
          ips = [ "10.0.0.2/24" ];
          peers = [ ... ];
        };
      };
    }
    
  2. Import it in the machine's configuration.nix:

    # config/machine1/configuration.nix
    { config, pkgs, ... }:
    {
      imports = [
        (import /var/src/config-shared {
          inherit config pkgs;
          domain = "4lpaca.io";
        })
        ./hardware-configuration.nix
        ./boot.nix
        ./wireguard.nix        # ← Add your service here
      ];
    }
    
  3. Deploy - the service will only be deployed to that specific machine:

    nix-build ./krops.nix -A machine1 && ./result
    

Common Machine-Specific Services

  • WireGuard VPN - Only on machines that need VPN access
  • Backup services - Different backup targets per machine
  • Development tools - Extra packages for staging vs production
  • Custom hardware drivers - GPU drivers, specific hardware support

The key is that each machine's configuration.nix can import different modules while still sharing common configuration through shared.nix.

Deploying LNBits Extensions

You can deploy custom LNBits extensions to /var/lib/lnbits/extensions on your target machines.

Setup

1. Create extensions directory:

mkdir -p lnbits-extensions

2. Add your custom extensions:

# Example: Clone a custom extension
git clone https://github.com/your-org/custom-extension lnbits-extensions/custom-extension

3. Enable in krops.nix: Uncomment the lnbits-extensions line:

lnbits-extensions.file = toString ./lnbits-extensions;

4. Enable in config/lnbits.nix:

Choose one of two options:

Option 1: Replace extensions directory (use if you manage ALL extensions via deployment)

systemd.tmpfiles.rules = [
  "L+ /var/lib/lnbits/extensions - - - - /var/src/lnbits-extensions"
];

⚠️ Warning: This will DELETE any extensions installed via the LNBits UI!

Option 2: Merge deployed extensions (safer - keeps UI-installed extensions)

systemd.services.lnbits-copy-extensions = {
  description = "Copy deployed LNBits extensions";
  before = [ "lnbits.service" ];
  wantedBy = [ "lnbits.service" ];
  serviceConfig = {
    Type = "oneshot";
    ExecStart = "${pkgs.rsync}/bin/rsync -av /var/src/lnbits-extensions/ /var/lib/lnbits/extensions/";
  };
};

5. Deploy:

nix-build ./krops.nix -A machine1 && ./result

How It Works

Option 1 (Symlink):

  • Your ./lnbits-extensions directory is deployed to /var/src/lnbits-extensions
  • A symlink replaces /var/lib/lnbits/extensions/var/src/lnbits-extensions
  • Any existing extensions directory is deleted
  • All extensions must be managed via deployment

Option 2 (Copy/Merge):

  • Your ./lnbits-extensions directory is deployed to /var/src/lnbits-extensions
  • Deployed extensions are copied into /var/lib/lnbits/extensions/
  • Existing UI-installed extensions are preserved
  • You can mix deployed extensions with UI-installed ones