Files
gitea-mirror/docs/NIX_DEPLOYMENT.md
Arunavo Ray 109958342d updated docs
2025-10-31 09:17:28 +05:30

12 KiB

Nix Deployment Guide

This guide covers deploying Gitea Mirror using Nix flakes. The Nix deployment follows the same minimal configuration philosophy as docker-compose.alt.yml - secrets are auto-generated, and everything else can be configured via the web UI.

Prerequisites

  • Nix 2.4+ installed
  • For NixOS module: NixOS 23.05+

To enable flakes permanently and avoid typing flags, add to /etc/nix/nix.conf or ~/.config/nix/nix.conf:

experimental-features = nix-command flakes

Note: If you don't enable flakes globally, add --extra-experimental-features 'nix-command flakes' to all nix commands shown below.

Quick Start (Zero Configuration!)

Run Immediately - No Setup Required

# Run directly from the flake (local)
nix run --extra-experimental-features 'nix-command flakes' .#gitea-mirror

# Or from GitHub (once published)
nix run --extra-experimental-features 'nix-command flakes' github:RayLabsHQ/gitea-mirror

# If you have flakes enabled globally, simply:
nix run .#gitea-mirror

That's it! On first run:

  • Secrets (BETTER_AUTH_SECRET and ENCRYPTION_SECRET) are auto-generated
  • Database is automatically created and initialized
  • Startup recovery and repair scripts run automatically
  • Access the web UI at http://localhost:4321

Everything else (GitHub credentials, Gitea settings, mirror options) is configured through the web interface after signup.

Development Environment

# Enter development shell with all dependencies
nix develop --extra-experimental-features 'nix-command flakes'

# Or use direnv for automatic environment loading (handles flags automatically)
echo "use flake" > .envrc
direnv allow

Build and Install

# Build the package
nix build --extra-experimental-features 'nix-command flakes'

# Run the built package
./result/bin/gitea-mirror

# Install to your profile
nix profile install --extra-experimental-features 'nix-command flakes' .#gitea-mirror

What Happens on First Run?

Following the same pattern as the Docker deployment, the Nix package automatically:

  1. Creates data directory: ~/.local/share/gitea-mirror (or $DATA_DIR)
  2. Generates secrets (stored securely in data directory):
    • BETTER_AUTH_SECRET - Session authentication (32-char hex)
    • ENCRYPTION_SECRET - Token encryption (48-char base64)
  3. Initializes database: SQLite database with Drizzle migrations
  4. Runs startup scripts:
    • Environment configuration loader
    • Crash recovery for interrupted jobs
    • Repository status repair
  5. Starts the application with graceful shutdown handling

NixOS Module - Minimal Deployment

Simplest Possible Configuration

Add to your NixOS configuration (/etc/nixos/configuration.nix):

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    gitea-mirror.url = "github:RayLabsHQ/gitea-mirror";
  };

  outputs = { nixpkgs, gitea-mirror, ... }: {
    nixosConfigurations.your-hostname = nixpkgs.lib.nixosSystem {
      system = "x86_64-linux";
      modules = [
        gitea-mirror.nixosModules.default
        {
          # That's it! Just enable the service
          services.gitea-mirror.enable = true;
        }
      ];
    };
  };
}

Apply with:

sudo nixos-rebuild switch

Access at http://localhost:4321, sign up (first user is admin), and configure everything via the web UI.

Production Configuration

For production with custom domain and firewall:

{
  services.gitea-mirror = {
    enable = true;
    host = "0.0.0.0";
    port = 4321;
    betterAuthUrl = "https://mirror.example.com";
    betterAuthTrustedOrigins = "https://mirror.example.com";
    openFirewall = true;
  };

  # Optional: Use with nginx reverse proxy
  services.nginx = {
    enable = true;
    virtualHosts."mirror.example.com" = {
      locations."/" = {
        proxyPass = "http://127.0.0.1:4321";
        proxyWebsockets = true;
      };
      enableACME = true;
      forceSSL = true;
    };
  };
}

Advanced: Manual Secret Management

If you prefer to manage secrets manually (e.g., with sops-nix or agenix):

  1. Create a secrets file:
# /var/lib/gitea-mirror/secrets.env
BETTER_AUTH_SECRET=your-32-character-minimum-secret-key-here
ENCRYPTION_SECRET=your-encryption-secret-here
  1. Reference it in your configuration:
{
  services.gitea-mirror = {
    enable = true;
    environmentFile = "/var/lib/gitea-mirror/secrets.env";
  };
}

Full Configuration Options

{
  services.gitea-mirror = {
    enable = true;
    package = gitea-mirror.packages.x86_64-linux.default;  # Override package
    dataDir = "/var/lib/gitea-mirror";
    user = "gitea-mirror";
    group = "gitea-mirror";
    host = "0.0.0.0";
    port = 4321;
    betterAuthUrl = "https://mirror.example.com";
    betterAuthTrustedOrigins = "https://mirror.example.com";

    # Concurrency controls (match docker-compose.alt.yml)
    mirrorIssueConcurrency = 3;  # Set to 1 for perfect chronological order
    mirrorPullRequestConcurrency = 5;  # Set to 1 for perfect chronological order

    environmentFile = null;  # Optional secrets file
    openFirewall = true;
  };
}

Service Management (NixOS)

# Start the service
sudo systemctl start gitea-mirror

# Stop the service
sudo systemctl stop gitea-mirror

# Restart the service
sudo systemctl restart gitea-mirror

# Check status
sudo systemctl status gitea-mirror

# View logs
sudo journalctl -u gitea-mirror -f

# Health check
curl http://localhost:4321/api/health

Environment Variables

All variables from docker-compose.alt.yml are supported:

# === AUTO-GENERATED (Don't set unless you want specific values) ===
BETTER_AUTH_SECRET          # Auto-generated, stored in data dir
ENCRYPTION_SECRET           # Auto-generated, stored in data dir

# === CORE SETTINGS (Have good defaults) ===
DATA_DIR="$HOME/.local/share/gitea-mirror"
DATABASE_URL="file:$DATA_DIR/gitea-mirror.db"
HOST="0.0.0.0"
PORT="4321"
NODE_ENV="production"

# === BETTER AUTH (Override for custom domains) ===
BETTER_AUTH_URL="http://localhost:4321"
BETTER_AUTH_TRUSTED_ORIGINS="http://localhost:4321"
PUBLIC_BETTER_AUTH_URL="http://localhost:4321"

# === CONCURRENCY CONTROLS ===
MIRROR_ISSUE_CONCURRENCY=3           # Default: 3 (set to 1 for perfect order)
MIRROR_PULL_REQUEST_CONCURRENCY=5    # Default: 5 (set to 1 for perfect order)

# === CONFIGURE VIA WEB UI (Not needed at startup) ===
# GitHub credentials, Gitea settings, mirror options, scheduling, etc.
# All configured after signup through the web interface

Database Management

The Nix package includes a database management helper:

# Initialize database (done automatically on first run)
gitea-mirror-db init

# Check database health
gitea-mirror-db check

# Fix database issues
gitea-mirror-db fix

# Reset users
gitea-mirror-db reset-users

Home Manager Integration

For single-user deployments:

{ config, pkgs, ... }:
let
  gitea-mirror = (import (fetchTarball "https://github.com/RayLabsHQ/gitea-mirror/archive/main.tar.gz")).packages.${pkgs.system}.default;
in {
  home.packages = [ gitea-mirror ];

  # Optional: Run as user service
  systemd.user.services.gitea-mirror = {
    Unit = {
      Description = "Gitea Mirror Service";
      After = [ "network.target" ];
    };

    Service = {
      Type = "simple";
      ExecStart = "${gitea-mirror}/bin/gitea-mirror";
      Restart = "always";
      Environment = [
        "DATA_DIR=%h/.local/share/gitea-mirror"
        "HOST=127.0.0.1"
        "PORT=4321"
      ];
    };

    Install = {
      WantedBy = [ "default.target" ];
    };
  };
}

Docker Image from Nix (Optional)

You can also use Nix to create a Docker image:

# Add to flake.nix packages section
dockerImage = pkgs.dockerTools.buildLayeredImage {
  name = "gitea-mirror";
  tag = "latest";
  contents = [ self.packages.${system}.default pkgs.cacert pkgs.openssl ];
  config = {
    Cmd = [ "${self.packages.${system}.default}/bin/gitea-mirror" ];
    ExposedPorts = { "4321/tcp" = {}; };
    Env = [
      "DATA_DIR=/data"
      "DATABASE_URL=file:/data/gitea-mirror.db"
    ];
    Volumes = { "/data" = {}; };
  };
};

Build and load:

nix build --extra-experimental-features 'nix-command flakes' .#dockerImage
docker load < result
docker run -p 4321:4321 -v gitea-mirror-data:/data gitea-mirror:latest

Comparison: Docker vs Nix

Both deployment methods follow the same philosophy:

Feature Docker Compose Nix
Configuration Minimal (only BETTER_AUTH_SECRET) Zero config (auto-generated)
Secret Generation Auto-generated & persisted Auto-generated & persisted
Database Init Automatic on first run Automatic on first run
Startup Scripts Runs recovery/repair/env-config Runs recovery/repair/env-config
Graceful Shutdown Signal handling in entrypoint Signal handling in wrapper
Health Check Docker healthcheck systemd timer (optional)
Updates docker pull nix flake update && nixos-rebuild

Troubleshooting

Check Auto-Generated Secrets

# For standalone
cat ~/.local/share/gitea-mirror/.better_auth_secret
cat ~/.local/share/gitea-mirror/.encryption_secret

# For NixOS service
sudo cat /var/lib/gitea-mirror/.better_auth_secret
sudo cat /var/lib/gitea-mirror/.encryption_secret

Database Issues

# Check if database exists
ls -la ~/.local/share/gitea-mirror/gitea-mirror.db

# Reinitialize (deletes all data!)
rm ~/.local/share/gitea-mirror/gitea-mirror.db
gitea-mirror-db init

Permission Issues (NixOS)

sudo chown -R gitea-mirror:gitea-mirror /var/lib/gitea-mirror
sudo chmod 700 /var/lib/gitea-mirror

Port Already in Use

# Change port
export PORT=8080
gitea-mirror

# Or in NixOS config
services.gitea-mirror.port = 8080;

View Startup Logs

# Standalone (verbose output on console)
gitea-mirror

# NixOS service
sudo journalctl -u gitea-mirror -f --since "5 minutes ago"

Updating

Standalone Installation

# Update flake lock
nix flake update --extra-experimental-features 'nix-command flakes'

# Rebuild
nix build --extra-experimental-features 'nix-command flakes'

# Or update profile
nix profile upgrade --extra-experimental-features 'nix-command flakes' gitea-mirror

NixOS

# Update input
sudo nix flake lock --update-input gitea-mirror --extra-experimental-features 'nix-command flakes'

# Rebuild system
sudo nixos-rebuild switch --flake .#your-hostname

Migration from Docker

To migrate from Docker to Nix while keeping your data:

  1. Stop Docker container:

    docker-compose -f docker-compose.alt.yml down
    
  2. Copy data directory:

    # For standalone
    cp -r ./data ~/.local/share/gitea-mirror
    
    # For NixOS
    sudo cp -r ./data /var/lib/gitea-mirror
    sudo chown -R gitea-mirror:gitea-mirror /var/lib/gitea-mirror
    
  3. Copy secrets (if you want to keep them):

    # Extract from Docker volume
    docker run --rm -v gitea-mirror_data:/data alpine \
      cat /data/.better_auth_secret > better_auth_secret
    docker run --rm -v gitea-mirror_data:/data alpine \
      cat /data/.encryption_secret > encryption_secret
    
    # Copy to new location
    cp better_auth_secret ~/.local/share/gitea-mirror/.better_auth_secret
    cp encryption_secret ~/.local/share/gitea-mirror/.encryption_secret
    chmod 600 ~/.local/share/gitea-mirror/.*_secret
    
  4. Start Nix version:

    gitea-mirror
    

CI/CD Integration

Example GitHub Actions workflow:

name: Build with Nix

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: cachix/install-nix-action@v24
      with:
        extra_nix_config: |
          experimental-features = nix-command flakes
    - uses: cachix/cachix-action@v12
      with:
        name: gitea-mirror
        authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
    - run: nix build
    - run: nix flake check
    # Note: GitHub Actions runner usually has flakes enabled by install-nix-action

Resources