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, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
let
|
||||||
|
domain = "example.com";
|
||||||
|
in
|
||||||
{
|
{
|
||||||
# Import shared configuration and machine-specific modules
|
|
||||||
imports = [
|
imports = [
|
||||||
# Import shared.nix with your domain parameter
|
{ _module.args = { inherit domain; }; }
|
||||||
# Replace "example.com" with your actual domain
|
|
||||||
(import /var/src/config-shared {
|
(import /var/src/config-shared {
|
||||||
inherit config pkgs;
|
inherit config pkgs domain;
|
||||||
domain = "example.com";
|
|
||||||
})
|
})
|
||||||
|
|
||||||
# Import hardware-specific configuration
|
# Import hardware-specific configuration
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ config, lib, pkgs, ... }:
|
{ config, lib, pkgs, domain, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
# Example: WireGuard VPN Service
|
# Example: WireGuard VPN Service
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,10 @@
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
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
|
/var/src/config-nginx
|
||||||
{ _module.args = { inherit domain; }; } # passes <mydomain.com> for nginx virtualHosts
|
|
||||||
/var/src/config-pict-rs
|
/var/src/config-pict-rs
|
||||||
/var/src/config-lnbits
|
/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