# 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+

### Enable Flakes (Recommended)

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

```bash
# 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

```bash
# 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

```bash
# 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`):

```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:
```bash
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:

```nix
{
  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:
```bash
# /var/lib/gitea-mirror/secrets.env
BETTER_AUTH_SECRET=your-32-character-minimum-secret-key-here
ENCRYPTION_SECRET=your-encryption-secret-here
```

2. Reference it in your configuration:
```nix
{
  services.gitea-mirror = {
    enable = true;
    environmentFile = "/var/lib/gitea-mirror/secrets.env";
  };
}
```

### Full Configuration Options

```nix
{
  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)

```bash
# 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:

```bash
# === 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:

```bash
# 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:

```nix
{ 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:

```nix
# 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:
```bash
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
```bash
# 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
```bash
# 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)
```bash
sudo chown -R gitea-mirror:gitea-mirror /var/lib/gitea-mirror
sudo chmod 700 /var/lib/gitea-mirror
```

### Port Already in Use
```bash
# Change port
export PORT=8080
gitea-mirror

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

### View Startup Logs
```bash
# Standalone (verbose output on console)
gitea-mirror

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

## Updating

### Standalone Installation
```bash
# 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
```bash
# 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:**
   ```bash
   docker-compose -f docker-compose.alt.yml down
   ```

2. **Copy data directory:**
   ```bash
   # 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):**
   ```bash
   # 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:**
   ```bash
   gitea-mirror
   ```

## CI/CD Integration

Example GitHub Actions workflow (see `.github/workflows/nix-build.yml`):

```yaml
name: Nix Build

on: [push, pull_request]

permissions:
  contents: read

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
    - uses: actions/checkout@v4
    - uses: DeterminateSystems/nix-installer-action@main
    - uses: DeterminateSystems/magic-nix-cache-action@main
    - run: nix flake check
    - run: nix build --print-build-logs
```

This uses:
- **Determinate Nix Installer** - Fast, reliable Nix installation with flakes enabled by default
- **Magic Nix Cache** - Free caching using GitHub Actions cache (no account needed)

## Resources

- [Nix Manual](https://nixos.org/manual/nix/stable/)
- [NixOS Options Search](https://search.nixos.org/options)
- [Nix Pills Tutorial](https://nixos.org/guides/nix-pills/)
- [Project Documentation](../README.md)
- [Docker Deployment](../docker-compose.alt.yml) - Equivalent minimal config
