Refactor shared configuration and update LNBits service for improved domain handling
Updated shared.nix to enhance domain parameter propagation and modified configuration.nix to utilize the inherited domain for machine-specific setups. Adjusted example-service.nix to accept the domain as an argument, improving modularity. Additionally, added a new documentation file explaining the LNBits flake deployment process, detailing architecture, key components, and deployment instructions for better onboarding and understanding of the system.
This commit is contained in:
parent
ca5b78b561
commit
30a1ae28f7
4 changed files with 273 additions and 8 deletions
|
|
@ -1,13 +1,12 @@
|
|||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
domain = "example.com";
|
||||
in
|
||||
{
|
||||
# Import shared configuration and machine-specific modules
|
||||
imports = [
|
||||
# Import shared.nix with your domain parameter
|
||||
# Replace "example.com" with your actual domain
|
||||
{ _module.args = { inherit domain; }; }
|
||||
(import /var/src/config-shared {
|
||||
inherit config pkgs;
|
||||
domain = "example.com";
|
||||
inherit config pkgs domain;
|
||||
})
|
||||
|
||||
# Import hardware-specific configuration
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
{ config, lib, pkgs, domain, ... }:
|
||||
|
||||
{
|
||||
# Example: WireGuard VPN Service
|
||||
|
|
|
|||
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
{
|
||||
imports = [
|
||||
# Note: 'domain' is made available via _module.args in the machine's configuration.nix
|
||||
# It's passed to this module and propagated to all imports automatically
|
||||
|
||||
/var/src/config-nginx
|
||||
{ _module.args = { inherit domain; }; } # passes <mydomain.com> for nginx virtualHosts
|
||||
/var/src/config-pict-rs
|
||||
/var/src/config-lnbits
|
||||
];
|
||||
|
|
|
|||
264
docs/lnbits-flake-explanation.md
Normal file
264
docs/lnbits-flake-explanation.md
Normal file
|
|
@ -0,0 +1,264 @@
|
|||
# How the LNBits Flake Works
|
||||
|
||||
## Overview
|
||||
|
||||
This document explains how the LNBits flake deployment works, particularly how it achieves the equivalent of running `uv run lnbits` on the deployed NixOS machine.
|
||||
|
||||
## Architecture
|
||||
|
||||
The LNBits flake uses `uv2nix` to convert `uv`'s lock file into a reproducible Nix build, creating a Python virtual environment that can be deployed as a NixOS service.
|
||||
|
||||
## Key Components
|
||||
|
||||
### 1. uv2nix: Converting uv.lock to Nix
|
||||
|
||||
The flake uses `uv2nix` to read the `uv.lock` file and create a reproducible Nix build:
|
||||
|
||||
```nix
|
||||
# Read uv.lock and pyproject.toml
|
||||
workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; };
|
||||
|
||||
# Create overlay preferring wheels (faster than building from source)
|
||||
uvLockedOverlay = workspace.mkPyprojectOverlay { sourcePreference = "wheel"; };
|
||||
```
|
||||
|
||||
This converts the uv-managed dependencies into Nix packages.
|
||||
|
||||
### 2. Building a Python Virtual Environment
|
||||
|
||||
Instead of `uv` creating a venv at runtime, Nix creates one during the build:
|
||||
|
||||
```nix
|
||||
# Build venv with all dependencies from uv.lock
|
||||
runtimeVenv = pythonSet.mkVirtualEnv "${projectName}-env" workspace.deps.default;
|
||||
```
|
||||
|
||||
This creates an immutable virtual environment in `/nix/store/...-lnbits-env` with all Python packages installed from the locked dependencies.
|
||||
|
||||
### 3. The Wrapper Script (Equivalent to `uv run`)
|
||||
|
||||
The flake creates a wrapper that mimics `uv run lnbits`:
|
||||
|
||||
```nix
|
||||
lnbitsApp = pkgs.writeShellApplication {
|
||||
name = "lnbits";
|
||||
text = ''
|
||||
export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
|
||||
export REQUESTS_CA_BUNDLE=$SSL_CERT_FILE
|
||||
export PYTHONPATH="$PWD:${PYTHONPATH:-}"
|
||||
exec ${runtimeVenv}/bin/lnbits "$@"
|
||||
'';
|
||||
};
|
||||
```
|
||||
|
||||
This wrapper:
|
||||
- Sets up SSL certificates for HTTPS requests
|
||||
- Adds the current directory to `PYTHONPATH` (so it can find local source files)
|
||||
- Executes the `lnbits` binary from the built venv
|
||||
|
||||
### 4. The NixOS Service Module
|
||||
|
||||
The service module (`lnbits-service.nix`) configures systemd to run LNBits:
|
||||
|
||||
```nix
|
||||
# The actual command that runs
|
||||
ExecStart = "${lib.getExe cfg.package} --port ${toString cfg.port} --host ${cfg.host}";
|
||||
|
||||
# Environment variables
|
||||
environment = {
|
||||
LNBITS_DATA_FOLDER = "${cfg.stateDir}"; # /var/lib/lnbits
|
||||
LNBITS_EXTENSIONS_PATH = "${cfg.stateDir}/extensions";
|
||||
LNBITS_PATH = "${cfg.package.src}"; # Points to source
|
||||
}
|
||||
```
|
||||
|
||||
Key points:
|
||||
- `cfg.package` = the venv from the flake (`runtimeVenv`)
|
||||
- `lib.getExe cfg.package` = extracts the executable path: `/nix/store/xxx-lnbits-env/bin/lnbits`
|
||||
- `cfg.package.src` = points back to the LNBits source directory for templates/static files
|
||||
|
||||
### 5. Flake Outputs
|
||||
|
||||
The flake exposes the venv as a package:
|
||||
|
||||
```nix
|
||||
packages.default = runtimeVenv;
|
||||
packages.${projectName} = runtimeVenv; # packages.lnbits = runtimeVenv
|
||||
```
|
||||
|
||||
## How Your Deployment Uses It
|
||||
|
||||
In your `config/lnbits.nix`:
|
||||
|
||||
```nix
|
||||
package = (builtins.getFlake "path:/var/src/lnbits-src").packages.${pkgs.system}.lnbits;
|
||||
```
|
||||
|
||||
This breaks down as:
|
||||
|
||||
1. `builtins.getFlake "path:/var/src/lnbits-src"` - Loads the flake from the deployed source
|
||||
2. `.packages` - Accesses the packages output from the flake
|
||||
3. `.${pkgs.system}` - Selects the right system architecture (e.g., `x86_64-linux`)
|
||||
4. `.lnbits` - Gets the `lnbits` package (which equals `runtimeVenv`)
|
||||
|
||||
## Understanding Flake References
|
||||
|
||||
The **flake reference format** is crucial to understanding how this works:
|
||||
|
||||
### Local Path Reference
|
||||
|
||||
```nix
|
||||
builtins.getFlake "path:/var/src/lnbits-src"
|
||||
```
|
||||
|
||||
- Uses files from the local filesystem at `/var/src/lnbits-src`
|
||||
- The `.src` attribute points to `/var/src/lnbits-src`
|
||||
- Files are mutable - you can edit them
|
||||
- Requires deploying the full source tree via krops
|
||||
|
||||
### GitHub Reference
|
||||
|
||||
```nix
|
||||
builtins.getFlake "github:lnbits/lnbits/main"
|
||||
```
|
||||
|
||||
- Nix fetches the repository from GitHub
|
||||
- Stores it in `/nix/store/xxx-source/` (read-only)
|
||||
- The `.src` attribute points to `/nix/store/xxx-source`
|
||||
- Files are immutable
|
||||
- No need to deploy source separately
|
||||
|
||||
### Comparison
|
||||
|
||||
| Aspect | `path:/var/src/lnbits-src` | `github:lnbits/lnbits` |
|
||||
|--------|---------------------------|------------------------|
|
||||
| **Source location** | `/var/src/lnbits-src` | `/nix/store/xxx-source` |
|
||||
| **Mutable?** | Yes - can edit files | No - read-only |
|
||||
| **Deployment** | Deploy via krops | Built-in to Nix |
|
||||
| **Updates** | Redeploy source | Change flake ref |
|
||||
| **Local changes** | Supported | Not possible |
|
||||
|
||||
## Why Deploy the Full Source?
|
||||
|
||||
The entire `lnbits` folder must be copied to `/var/src/lnbits-src` because:
|
||||
|
||||
### 1. Build Time Requirements
|
||||
|
||||
The flake needs these files to build the venv:
|
||||
- `flake.nix` - Defines how to build the venv
|
||||
- `uv.lock` - Contains locked dependency versions
|
||||
- `pyproject.toml` - Defines project metadata
|
||||
|
||||
### 2. Runtime Requirements
|
||||
|
||||
LNBits needs the source tree at runtime for:
|
||||
- Python modules in `lnbits/`
|
||||
- HTML templates
|
||||
- Static files (CSS, JavaScript, images)
|
||||
- Extension loading system
|
||||
|
||||
## Directory Structure
|
||||
|
||||
### On the Deployed Machine
|
||||
|
||||
```
|
||||
/var/src/lnbits-src/ ← Full source deployed by krops
|
||||
├── flake.nix ← Used to build venv
|
||||
├── uv.lock ← Used to build venv
|
||||
├── pyproject.toml ← Used to build venv
|
||||
└── lnbits/ ← Used at runtime
|
||||
├── templates/
|
||||
├── static/
|
||||
└── ...
|
||||
|
||||
/nix/store/xxx-lnbits-env/ ← Built venv (Python packages only)
|
||||
├── bin/lnbits ← Executable
|
||||
└── lib/python3.12/... ← Dependencies
|
||||
```
|
||||
|
||||
### At Runtime
|
||||
|
||||
The systemd service:
|
||||
- Runs: `/nix/store/xxx-lnbits-env/bin/lnbits`
|
||||
- With: `LNBITS_PATH=/var/src/lnbits-src` (to find templates/static/etc)
|
||||
- With: `WorkingDirectory=/var/src/lnbits-src`
|
||||
|
||||
## Comparison: `uv run` vs Nix Flake
|
||||
|
||||
### Traditional `uv run lnbits`
|
||||
|
||||
```bash
|
||||
cd /path/to/lnbits
|
||||
uv run lnbits --port 5000 --host 0.0.0.0
|
||||
```
|
||||
|
||||
This:
|
||||
1. Reads `uv.lock`
|
||||
2. Creates/updates a venv in `.venv/`
|
||||
3. Installs dependencies if needed
|
||||
4. Runs `lnbits` from the venv
|
||||
5. Uses current directory for source files
|
||||
|
||||
### Nix Flake Approach
|
||||
|
||||
```nix
|
||||
package = (builtins.getFlake "path:/var/src/lnbits-src").packages.${pkgs.system}.lnbits;
|
||||
```
|
||||
|
||||
This:
|
||||
1. ✅ Reads `uv.lock` via `uv2nix`
|
||||
2. ✅ Creates a venv in `/nix/store` (immutable)
|
||||
3. ✅ All dependencies are locked and reproducible
|
||||
4. ✅ Runs `/nix/store/xxx-lnbits-env/bin/lnbits`
|
||||
5. ✅ Sets `LNBITS_PATH` to source directory for templates/static/extensions
|
||||
6. ✅ Runs as a systemd service with proper user/permissions
|
||||
7. ✅ No runtime dependency on `uv` itself
|
||||
|
||||
### Key Differences
|
||||
|
||||
| Aspect | `uv run` | Nix Flake |
|
||||
|--------|----------|-----------|
|
||||
| **Venv location** | `.venv/` in source | `/nix/store/xxx-env` |
|
||||
| **Mutability** | Mutable | Immutable |
|
||||
| **Reproducibility** | Lock file only | Full Nix derivation |
|
||||
| **Service management** | Manual | systemd integration |
|
||||
| **Dependency on uv** | Required at runtime | Only at build time |
|
||||
|
||||
## The `.src` Attribute Mystery
|
||||
|
||||
A common question: where is `cfg.package.src` defined?
|
||||
|
||||
### Answer: It's Automatic
|
||||
|
||||
The `.src` attribute is **not explicitly defined** - it's automatically set by Nix when loading a flake:
|
||||
|
||||
```nix
|
||||
# When you do this:
|
||||
builtins.getFlake "path:/var/src/lnbits-src"
|
||||
|
||||
# Nix automatically:
|
||||
# 1. Reads the flake at /var/src/lnbits-src
|
||||
# 2. Evaluates it and builds outputs
|
||||
# 3. Adds .src = /var/src/lnbits-src to the package
|
||||
```
|
||||
|
||||
This is a built-in Nix flake feature - packages inherit the source location from where the flake was loaded.
|
||||
|
||||
## Summary
|
||||
|
||||
The LNBits flake deployment:
|
||||
|
||||
1. **Converts uv dependencies to Nix** using `uv2nix`
|
||||
2. **Builds an immutable venv** in `/nix/store`
|
||||
3. **Deploys full source** to `/var/src/lnbits-src` via krops
|
||||
4. **Loads the flake** from the deployed source using `path:/var/src/lnbits-src`
|
||||
5. **Runs as a systemd service** with proper environment variables pointing to the source
|
||||
|
||||
This provides:
|
||||
- ✅ **Reproducibility** - exact same dependencies every time
|
||||
- ✅ **Declarative configuration** - everything in `configuration.nix`
|
||||
- ✅ **Source mutability** - can edit files in `/var/src/lnbits-src`
|
||||
- ✅ **No uv dependency** - service doesn't need `uv` at runtime
|
||||
- ✅ **Proper service management** - systemd integration with user permissions
|
||||
|
||||
The key insight is that **`path:` vs `github:` in the flake reference** determines whether you use local deployed files or Nix fetches from a remote repository.
|
||||
Loading…
Add table
Add a link
Reference in a new issue