This commit is contained in:
Julian Sutter 2026-02-15 16:57:07 -08:00
parent 532e01cbf1
commit 29eb6493be
3 changed files with 854 additions and 7 deletions

View file

@ -13,7 +13,8 @@ This repository manages NixOS configurations for multiple systems using flakes a
| `framework` | Desktop/Laptop | Framework AMD AI 300 series | User: jsutter, Uses nixos-hardware module |
| `aurora` | Desktop | Custom | Users: jsutter, isutter, aksutter |
| `labrizor` | Desktop | Custom | User: jsutter |
| `skip01` | Server (WIP) | Custom | Headless configuration |
| `skip01` | Server | Custom | Headless, Docker support |
| `warp` | Server | Custom | Minimal headless configuration |
### Core Technologies
@ -22,13 +23,15 @@ This repository manages NixOS configurations for multiple systems using flakes a
- **Home Manager**: Release 25.11
- **Plasma Manager**: KDE Plasma configuration management
- **Flakes**: For reproducible, declarative system definitions
- **App Flakes**: Standalone flakes for server applications (Immich, Octofriend, etc.)
## Project Structure
```
nixos/
├── appflakes/ # Local flake inputs
│ └── octofriend/ # Custom application flake
├── appflakes/ # Standalone flake inputs for server applications
│ ├── immich/ # Self-hosted photo/video backup (Docker Compose)
│ └── octofriend/ # CLI coding assistant
├── desktop/ # Desktop environment configurations
│ ├── plasma.nix # KDE Plasma + Plasma Manager
│ ├── dev.nix # Development tools and languages
@ -43,14 +46,17 @@ nixos/
│ └── stp-elc-udmshare.nix # Specific mount/share config
├── docs/ # Documentation
│ └── agents.md # This file
├── servers/ # Server configurations (future use)
├── servers/ # Server service modules
│ ├── common.nix # Common server settings (Docker enablement)
│ ├── forgejo.nix # Forgejo Git server module
│ └── hugo.nix # Hugo web server module (Docker compose)
├── systems/ # Hardware-specific configurations
│ ├── common.nix # Shared system settings (bootloader, nix config, etc.)
│ ├── common-headless.nix # Common settings for headless systems
│ ├── framework.nix # Framework laptop hardware config
│ ├── aurora.nix # Aurora desktop hardware config
│ ├── labrizor.nix # Labrizor desktop hardware config
│ └── skip01.nix # Skip01 server config
│ ├── skip01.nix # Skip01 server config
│ └── warp.nix # Warp server config
├── users/ # User configurations with Home Manager
│ ├── common-home.nix # Shared user packages and settings
│ ├── jsutter.nix # Primary user configuration
@ -59,6 +65,255 @@ nixos/
└── flake.nix # Top-level flake definition
```
### App Flakes Architecture
The `appflakes/` directory contains standalone flakes for server applications. These are self-contained, reusable flake definitions that can be used independently or integrated into NixOS configurations.
**Current App Flakes:**
- `immich/`: Self-hosted photo and video backup solution (Docker Compose deployment)
- `octofriend/`: CLI coding assistant packaged for Nix/NixOS
**App Flake Structure:**
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
# Additional inputs as needed
};
outputs = { self, nixpkgs, flake-utils, ... }:
{
# NixOS module (if applicable)
nixosModules.app-name = nixosModule;
# Package definition
packages = flake-utils.lib.eachDefaultSystem (system: { ... });
# App entry (if CLI tool)
apps.default = ...;
};
}
```
**Using App Flakes:**
1. **As a local input in main flake.nix:**
```nix
inputs = {
immich = { url = "path:./appflakes/immich"; };
};
outputs = { self, nixpkgs, immich, ... }: {
nixosConfigurations.server = nixpkgs.lib.nixosSystem {
modules = [
immich.nixosModules.immich-docker
./systems/server.nix
];
};
};
```
2. **Directly on a system:**
```bash
# Use app flake package on any system
nix run .#appflakes/octofriend
```
### Server Service Modules
The `servers/` directory contains NixOS modules for server-specific services. These differ from appflakes in that they are modules designed to be included in NixOS configurations rather than standalone flakes.
**Server Module Pattern:**
1. **Define options module-wide:**
```nix
{ config, pkgs, lib, ... }:
let
cfg = config.services.service-name;
in {
options.services.service-name = {
enable = mkEnableOption "Service description";
domain = mkOption {
type = types.str;
example = "service.example.com";
description = "Domain name for the service";
};
# Additional options...
};
}
```
2. **Configure service only if enabled:**
```nix
config = mkIf cfg.enable {
# Service dependencies (PostgreSQL, Nginx, etc.)
# Main service configuration
services.service-name = {
enable = true;
settings = { ... };
};
# Reverse proxy configuration (Nginx)
services.nginx.virtualHosts.${cfg.domain} = { ... };
# Firewall rules
networking.firewall.allowedTCPPorts = [ ... ];
# Backup systemd services
systemd.services.service-name-backup = { ... };
};
```
**Common Server Module Elements:**
- **Database backing:** PostgreSQL (`services.postgresql`)
- **Reverse proxy:** Nginx with SSL/TLS (`services.nginx`)
- **Firewall:** Open required ports (`networking.firewall`)
- **Backups:** Systemd timers for automated backups
- **Logging:** Centralized logging configuration
- **Monitoring:** Optional Prometheus/metrics endpoints
- **Security:** Hardening options, secret management
**Creating a New Server Module:**
1. Create `servers/<service-name>.nix`
2. Follow the standard module pattern with options
3. Use `mkIf cfg.enable` for conditional configuration
4. Include backup systemd service with timer
5. Add firewall rules if service is network-accessible
6. Document required secrets/password files
7. Test on a headless system first (`skip01` or `warp`)
**Server Module Organization:**
- `servers/common.nix`: Shared server infrastructure (Docker, etc.)
- `servers/forgejo.nix`: Forgejo Git server complete configuration
- `servers/hugo.nix`: Hugo static site server with Docker compose
- Additional server modules can be added as needed
**Headless System Configuration:**
Headless systems (`skip01`, `warp`) follow simplified patterns:
```nix
{
networking.hostName = "hostname";
# Minimal hardware configuration
boot.initrd.availableKernelModules = [ "nvme" "xhci_pci" "ahci" ];
boot.kernelModules = [ "kvm-intel" ];
# Enable container support
virtualisation.docker.enable = true;
# SSH for remote administration
services.openssh = {
enable = true;
settings.PasswordAuthentication = false;
};
# Disable desktop services
services.xserver.enable = false;
}
```
**Deploying Server Service Modules:**
1. Add server module to system configuration:
```nix
in {
nixosConfigurations.skip01 = nixpkgs.lib.nixosSystem {
modules = [
./systems/common.nix
./servers/forgejo.nix # Add server module
./systems/skip01.nix
{ services.forgejo.enable = true; }
];
};
}
```
2. Configure service options:
```nix
{
services.forgejo = {
domain = "git.example.com";
database.passwordFile = "/run/keys/forgejo-db";
};
}
```
3. Test on server system:
```bash
nixos-rebuild dry-run --flake .#skip01
sudo nixos-rebuild switch --flake .#skip01
```
**Secrets Management for Servers:**
Server services often require secrets (database passwords, API keys, OAuth secrets). Store these securely:
- Use `/run/keys/` for runtime secrets (systemd credentials)
- Use environment files with restricted permissions
- Never commit secrets to the repository
- Example: `passwordFile` options that point to secure paths
**Backup Strategy for Server Services:**
Server modules include automated backup services:
```nix
systemd.services.service-backup = {
description = "Service backup service";
serviceConfig = {
Type = "oneshot";
User = "service-user";
ExecStart = "${pkgs.service}/bin/service backup";
};
};
systemd.timers.service-backup = {
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "daily";
Persistent = true;
};
};
```
**Testing Server Modules:**
Always test server modules on headless systems before deploying to production:
```bash
# Check flake outputs
nix flake show
# Dry-run for server system
sudo nixos-rebuild dry-run --flake .#server-hostname
# Build without switching
sudo nixos-rebuild build --flake .#server-hostname
# Switch to new configuration
sudo nixos-rebuild switch --flake .#server-hostname
```
**Monitoring and Maintenance:**
- Check service status: `systemctl status service-name`
- View logs: `journalctl -u service-name`
- Monitor backup timers: `systemctl list-timers`
- Verify firewall rules: `nft list ruleset`
- Check Docker containers: `docker ps` (if using Docker-based services)
```
## Core Principles
### 1. Declarative Configuration
@ -233,6 +488,10 @@ Includes:
- Flatpak enabled
- USB plugdev group rules
### Server Common Settings (`servers/common.nix`)
Includes:
- Docker containerization enabled for server services
## File Naming Conventions
- Use lowercase with hyphens: `vpn-config.nix`, `development-tools.nix`
@ -263,6 +522,48 @@ Example:
}
```
Server module example:
```nix
{ config, pkgs, lib, ... }:
let
cfg = config.services.example-service;
in {
options.services.example-service = {
enable = mkEnableOption "Example service";
domain = mkOption {
type = types.str;
example = "service.example.com";
description = "Domain name for the service";
};
port = mkOption {
type = types.port;
default = 8080;
description = "Service port number";
};
};
config = mkIf cfg.enable {
systemd.services.example-service = {
description = "Example service";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.example}/bin/example --port ${toString cfg.port}";
Restart = "on-failure";
};
};
services.nginx.virtualHosts.${cfg.domain} = {
forceSSL = true;
enableACME = true;
locations."/".proxyPass = "http://localhost:${toString cfg.port}";
};
networking.firewall.allowedTCPPorts = [ 80 443 ];
};
}
```
## Common Workflows
### Adding a New Package
@ -317,6 +618,44 @@ new-system = mkSystem {
3. For user-specific changes: modify `<username>.nix`
4. Home Manager configuration goes in `home-manager.users.<username>`
### Creating a New Server Module
1. Create `servers/<service-name>.nix` following the module pattern
2. Define options using `mkOption` for all configurable parameters
3. Use `mkIf cfg.enable` to wrap all configuration
4. Include database, reverse proxy (Nginx), and firewall configuration
5. Add automated backup systemd service with timer
6. Document required secrets (passwordFile paths, API keys)
7. Test on headless system first
### Creating a New App Flake
1. Create `appflakes/<app-name>/` directory with `flake.nix`
2. Include `nixpkgs` and `flake-utils` as inputs
3. Define outputs with `packages` (and optionally `nixosModules`, `apps`)
4. Use `flake-utils.lib.eachDefaultSystem` for multi-system support
5. Add local input reference in main `flake.nix` if needed
6. Test build with `nix build .#appflakes/<app-name>`
### Adding a Server Service to a System
1. Choose target system (typically headless: `skip01` or `warp`)
2. Add server module to system's modules list in `flake.nix`:
```nix
nixosConfigurations.server = mkSystem {
modules = [
./systems/common.nix
./servers/common.nix
./servers/service-name.nix
./systems/server.nix
{ services.service-name.enable = true; }
];
};
```
3. Configure service-specific options in host config or separate file
4. Set up secret files (e.g., `/run/keys/service-db`)
5. Run dry-run and test before switching
## Testing and Validation
### Pre-commit Testing
@ -334,6 +673,10 @@ sudo nixos-rebuild dry-run --flake .#labrizor
# 3. Check flake outputs
nix flake show
# For server configurations, also test:
sudo nixos-rebuild dry-run --flake .#skip01
sudo nixos-rebuild dry-run --flake .#warp
```
### Applying Changes
@ -355,6 +698,7 @@ sudo nixos-rebuild boot --flake .#hostname
- Verify all services start correctly: `systemctl status`
- Check for package conflicts
- Validate hardware-specific configurations
- For server modules: verify Docker containers run, check systemd timers, validate firewall rules
### Updating Packages
@ -665,6 +1009,20 @@ Consider using `nix-serve` or Cachix for:
| Search packages | `nix search nixpkgs name` |
| Garbage collect | `sudo nix-collect-garbage -d` |
**Server-Specific Commands:**
| Action | Command |
|--------|---------|
| Check service status | `systemctl status service-name` |
| View service logs | `journalctl -u service-name` |
| List active timers | `systemctl list-timers` |
| Check Docker containers | `docker ps` |
| View Docker logs | `docker logs container-name` |
| Restart docker-compose stack | `docker-compose -f /etc/compose/service/docker-compose.yml restart` |
| Check firewall rules | `nft list ruleset` |
| Verify SSL certificates | `certbot certificates` |
| List backup directory | `ls -lh /var/backups/service-name` |
| Run manual backup | `systemctl start service-backup` |
### File Paths Reference
| Type | Location |
@ -674,6 +1032,12 @@ Consider using `nix-serve` or Cachix for:
| Common user settings | `users/common-home.nix` |
| User config | `users/<username>.nix` |
| Desktop apps | `desktop/<category>.nix` |
| Server common settings | `servers/common.nix` |
| Server service modules | `servers/<service-name>.nix` |
| App flakes | `appflakes/<app-name>/flake.nix` |
| Docker compose configs | `/etc/compose/<service>/docker-compose.yml` |
| Backup directories | `/var/backups/<service-name>/` |
| Runtime secrets | `/run/keys/<service-name>` |
| Flake definition | `flake.nix` |
## Maintenance & Changelog
@ -683,8 +1047,10 @@ This section tracks changes to the repository structure and when this document w
### Current Repository State
- **Last Updated**: February 2026
- **NixOS Version**: 25.11
- **Managed Systems**: 3 (framework, aurora, labrizor)
- **Managed Systems**: 5 (framework, aurora, labrizor, skip01, warp)
- **Users**: jsutter (primary), isutter, aksutter
- **App Flakes**: 2 (immich, octofriend)
- **Server Modules**: 3 (common, forgejo, hugo)
### Repository Change Log
@ -696,6 +1062,8 @@ This section tracks changes to the repository structure and when this document w
| 2026-02 - Cleanup | Removed commented packages across multiple files; fixed trailing whitespace | Code quality |
| 2026-02 - Cleanup | Removed .clinerules file; deleted gnome.nix (unused); common-headless.nix (duplicated) | File structure |
| 2026-02 - Improvement | Added result, *.swp, *~ to .gitignore | Maintenance |
| 2026-02 - Added | Added appflakes directory (immich, octofriend) and servers directory (forgejo, hugo) | Project structure, all server sections |
| 2026-02 - Documentation | Added comprehensive server module patterns, appflake architecture, server workflows, server-specific commands | Repository Overview, Workflows, Quick Reference |
### When to Update This Document
@ -706,24 +1074,40 @@ Update `agents.md` when any of the following occur:
- New user configuration added
- New or renamed desktop module
- Directory restructuring
- New app flake added to `appflakes/`
- New server module added to `servers/`
- **Configuration Changes**:
- New shared settings in `systems/common.nix`
- New shared user settings in `users/common-home.nix`
- New shared settings in `servers/common.nix`
- Changes to module pattern or function parameters
- New package categories or organizational changes
- Changes to server module standard pattern
- Updates to headless system configuration patterns
- **Technology Updates**:
- NixOS version changes
- Channel updates (stable/unstable)
- New major inputs added to flake
- Significant Nix configuration changes
- New app flake with different architecture
- Changes to Docker/compose deployment patterns
- **Procedure Changes**:
- New testing workflow
- Changed emergency procedures
- Updated installation steps
- New common commands
- New server deployment or backup procedures
- Changes to secrets management approach for servers
- **Server Changes**:
- New server service added to production
- Changes to backup strategy for server services
- Updates to monitoring or logging for servers
- New headless system deployed or configured
- Security hardening changes for server modules
### Update Template
@ -736,6 +1120,7 @@ When making changes, add an entry using this format:
### Version History for agents.md
- **v1.1** (2026-02): Added comprehensive server module patterns, appflake architecture, server workflows, and server-specific commands
- **v1.0** (2025-01): Initial creation with full repository documentation
## Getting Help

148
servers/README.md Normal file
View file

@ -0,0 +1,148 @@
# NixOS Server Configurations
This directory contains server-specific configuration files and modules for various services.
## Available Configurations
### common.nix
Common server configuration that includes Docker support.
**Features:**
- Docker container virtualization
- Base server utilities
**Usage:**
Include this module in your NixOS configuration for servers that need Docker support.
```nix
imports = [ ./nixos/servers/common.nix ];
```
### forgejo.nix
Comprehensive Forgejo Git server configuration module.
**Features:**
- Full Forgejo integration using NixOS native services
- PostgreSQL database with local setup
- TLS/SSL support via Let's Encrypt
- Nginx reverse proxy with WebSocket support
- Git LFS support
- Automated daily backups with retention
- OAuth2 authentication (GitHub)
- Email notifications (SMTP)
- Security hardening
**Configuration Example:**
```nix
{ config, pkgs, ... }: {
imports = [ ./nixos/servers/forgejo.nix ];
services.forgejo = {
enable = true;
domain = "git.example.com";
database.createLocally = true;
backup = {
enable = true;
interval = "daily";
retentionDays = 7;
};
};
}
```
### hugo.nix
Docker-based Hugo static site generator configuration.
**Features:**
- Hugo web server
- Remark42 comment system
- Watchtower for automatic updates
**Usage:**
This file uses a docker-compose style format. Deploy using Docker Compose or migrate to NixOS containers.
## Adding a New Server
To add a new server configuration:
1. Create a new `.nix` file in this directory
2. Follow the NixOS module pattern:
```nix
{ config, pkgs, lib, ... }: {
# Your configuration here
}
```
3. Import it in your system's `flake.nix` or configuration.nix
## Best Practices
- **Reusable Modules:** Design configurations to be reusable across multiple servers
- **Security:** Keep sensitive data (passwords, API keys) out of version control
- **Documentation:** Document complex configurations with inline comments
- **Modularization:** Split complex services into separate files
## Integration with Main Configuration
To use these server modules in your NixOS configuration, add them to your `flake.nix`:
```nix
{
description = "My NixOS configuration";
outputs = { self, nixpkgs, ... }: {
nixosConfigurations.my-server = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./nixos/servers/common.nix
./nixos/servers/forgejo.nix
# Other configurations
./systems/my-server.nix
];
};
};
}
```
## Maintenance
### Backups
Server configurations should be backed up regularly. The Forgejo module includes automated backups. For other services, implement appropriate backup strategies.
### Updates
Update server configurations with:
```bash
sudo nixos-rebuild switch
```
### Monitoring
Monitor server services:
```bash
sudo systemctl status <service-name>
sudo journalctl -u <service-name> -f
```
## Troubleshooting
### Common Issues
1. **Docker Not Starting:**
```bash
sudo systemctl status docker.service
sudo journalctl -u docker.service -f
```
2. **Port Conflicts:**
Check if services are conflicting on ports:
```bash
sudo netstat -tulpn
```
3. **Permission Issues:**
Verify file ownership and permissions for service directories
## Additional Resources
- [NixOS Documentation](https://nixos.org/manual/nixos/stable/)
- [NixOS Options Search](https://search.nixos.org/options)
- [Forgejo Documentation](https://forgejo.org/docs/latest/)
- [Docker NixOS Module](https://search.nixos.org/options?query=virtualisation.docker)

314
servers/forgejo.nix Normal file
View file

@ -0,0 +1,314 @@
{ config, pkgs, lib, ... }:
with lib;
let
cfg = config.services.forgejo;
in {
options.services.forgejo = {
enable = mkEnableOption "Forgejo Git server";
domain = mkOption {
type = types.str;
example = "git.example.com";
description = "The domain name for Forgejo";
};
stateDir = mkOption {
type = types.str;
default = "/var/lib/forgejo";
description = "Directory for Forgejo data";
};
database = {
createLocally = mkOption {
type = types.bool;
default = true;
description = "Whether to create a local PostgreSQL database";
};
passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/run/keys/forgejo-db";
description = "Path to file containing database password";
};
};
mailer = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable email notifications";
};
host = mkOption {
type = types.str;
example = "smtp.gmail.com";
description = "SMTP server hostname";
};
port = mkOption {
type = types.port;
default = 587;
description = "SMTP server port";
};
from = mkOption {
type = types.str;
example = "git@example.com";
description = "Email sender address";
};
userFile = mkOption {
type = types.path;
example = "/run/keys/forgejo-smtp-user";
description = "Path to file containing SMTP username";
};
passwordFile = mkOption {
type = types.path;
example = "/run/keys/forgejo-smtp-pass";
description = "Path to file containing SMTP password";
};
};
oauth2 = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable OAuth2 authentication";
};
github = {
enable = mkOption {
type = types.bool;
default = false;
description = "Enable GitHub OAuth2 provider";
};
clientId = mkOption {
type = types.str;
description = "GitHub OAuth client ID";
};
clientSecret = mkOption {
type = types.path;
description = "Path to GitHub OAuth client secret";
};
};
};
lfs = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable Git LFS support";
};
storage = mkOption {
type = types.str;
default = "/var/lib/forgejo/lfs";
description = "Path to LFS storage";
};
};
backup = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable automated backups";
};
interval = mkOption {
type = types.str;
default = "daily";
description = "Backup interval (systemd timer format)";
};
retentionDays = mkOption {
type = types.int;
default = 7;
description = "Number of backups to keep";
};
backupDir = mkOption {
type = types.str;
default = "/var/backups/forgejo";
description = "Directory to store backups";
};
};
};
config = mkIf cfg.enable {
# PostgreSQL database
services.postgresql = mkIf cfg.database.createLocally {
enable = true;
enableTCPIP = false;
ensureDatabases = [ "forgejo" ];
ensureUsers = [
{
name = "forgejo";
ensureDBOwnership = true;
}
];
};
# Forgejo service
services.forgejo = {
enable = true;
settings = {
server = {
HTTP_PORT = 3000;
DOMAIN = cfg.domain;
ROOT_URL = "https://${cfg.domain}/";
DISABLE_SSH = false;
SSH_PORT = 22;
LFS_START_SERVER = cfg.lfs.enable;
LFS_CONTENT_PATH = cfg.lfs.storage;
};
database = {
DB_TYPE = "postgres";
HOST = "/run/postgresql";
NAME = "forgejo";
USER = "forgejo";
PASSWD = mkIf (cfg.database.passwordFile != null) "#dbpass#";
};
service = {
DISABLE_REGISTRATION = false;
REQUIRE_SIGNIN_VIEW = false;
ENABLE_NOTIFY_MAIL = cfg.mailer.enable;
};
mailer = mkIf cfg.mailer.enable {
ENABLED = true;
FROM = cfg.mailer.from;
SMTP_ADDR = cfg.mailer.host;
SMTP_PORT = toString cfg.mailer.port;
USER = "#smtpuser#";
PASSWD = "#smtppass#";
PROTOCOL = "smtps";
};
session = {
COOKIE_SECURE = true;
COOKIE_SAMESITE = "strict";
};
security = {
INSTALL_LOCK = true;
PASSWORD_CHECK_PWN = true;
PASSWORD_COMPLEXITY = "lower,digit"
};
};
};
# Set database password from file
systemd.services.forgejo = {
serviceConfig = mkMerge [
(mkIf (cfg.database.passwordFile != null) {
EnvironmentFile = cfg.database.passwordFile;
})
(mkIf cfg.mailer.enable {
EnvironmentFile = [ cfg.mailer.userFile cfg.mailer.passwordFile ];
})
];
};
# Nginx reverse proxy
services.nginx = {
enable = true;
recommendedGzipSettings = true;
recommendedOptimisation = true;
recommendedProxySettings = true;
recommendedTlsSettings = true;
virtualHosts.${cfg.domain} = {
forceSSL = true;
enableACME = true;
locations."/".proxyPass = "http://localhost:3000";
# Proxy for WebSocket
locations."/" = {
proxyPass = "http://localhost:3000";
proxyWebsockets = true;
extraConfig = ''
proxy_buffering off;
proxy_read_timeout 86400;
'';
};
# Proxy for LFS
locations."/.git/info/lfs" = {
proxyPass = "http://localhost:3000";
extraConfig = ''
client_max_body_size 0;
'';
};
};
};
# Firewall
networking.firewall = {
allowedTCPPorts = [ 80 443 ];
allowedUDPPorts = [ 443 ];
};
# Backup service
systemd.services.forgejo-backup = mkIf cfg.backup.enable {
description = "Forgejo backup service";
serviceConfig = {
Type = "oneshot";
User = "forgejo";
Group = "forgejo";
WorkingDirectory = cfg.stateDir;
ExecStart = "${pkgs.forgejo}/bin/forgejo dump --type zip --file ${cfg.backup.backupDir}/forgejo-backup-%Y-%m-%d.zip";
};
};
systemd.timers.forgejo-backup = mkIf cfg.backup.enable {
description = "Forgejo backup timer";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = cfg.backup.interval;
Persistent = true;
};
};
# Backup cleanup
systemd.services.forgejo-backup-cleanup = mkIf cfg.backup.enable {
description = "Clean up old Forgejo backups";
serviceConfig = {
Type = "oneshot";
User = "root";
ExecStart = pkgs.writeShellScript "forgejo-backup-cleanup" ''
find ${cfg.backup.backupDir} -name "forgejo-backup-*.zip" -mtime +${toString cfg.backup.retentionDays} -delete
'';
};
};
systemd.timers.forgejo-backup-cleanup = mkIf cfg.backup.enable {
description = "Forgejo backup cleanup timer";
wantedBy = [ "timers.target" ];
timerConfig = {
OnCalendar = "weekly";
Persistent = true;
};
};
# Create backup directory
system.activationScripts.forgejo-backup-dir = ''
mkdir -p ${cfg.backup.backupDir}
chown forgejo:forgejo ${cfg.backup.backupDir}
chmod 750 ${cfg.backup.backupDir}
'';
# Add Forgejo to known services
environment.systemPackages = with pkgs; [
forgejo
];
};
}