314 lines
7.8 KiB
Nix
314 lines
7.8 KiB
Nix
{ 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
|
|
];
|
|
};
|
|
}
|