forgejo good, nginx coming along
This commit is contained in:
parent
29eb6493be
commit
8fdbb33939
40 changed files with 153 additions and 493 deletions
0
servers/README.md
Normal file → Executable file
0
servers/README.md
Normal file → Executable file
0
servers/common.nix
Normal file → Executable file
0
servers/common.nix
Normal file → Executable file
368
servers/forgejo.nix
Normal file → Executable file
368
servers/forgejo.nix
Normal file → Executable file
|
|
@ -1,314 +1,92 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{ lib, pkgs, config, ... }:
|
||||
let
|
||||
cfg = config.services.forgejo;
|
||||
in {
|
||||
options.services.forgejo = {
|
||||
enable = mkEnableOption "Forgejo Git server";
|
||||
srv = cfg.settings.server;
|
||||
|
||||
domain = mkOption {
|
||||
type = types.str;
|
||||
example = "git.example.com";
|
||||
description = "The domain name for Forgejo";
|
||||
};
|
||||
fqdn = "git.symbiotrip.com";
|
||||
|
||||
stateDir = mkOption {
|
||||
type = types.str;
|
||||
default = "/var/lib/forgejo";
|
||||
description = "Directory for Forgejo data";
|
||||
};
|
||||
smtpPassword = "Monaco55";
|
||||
runnerToken = "PUT_RUNNER_REGISTRATION_TOKEN_HERE";
|
||||
adminPassword = "2wiggyWah!";
|
||||
|
||||
database = {
|
||||
createLocally = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Whether to create a local PostgreSQL database";
|
||||
adminUser = "jsutter";
|
||||
adminEmail = "jsutter@symbiotrip.com";
|
||||
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
security.acme.certs.${fqdn}.group = config.services.nginx.group;
|
||||
services.nginx.virtualHosts.${fqdn} = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
useACMEHost = fqdn;
|
||||
acmeRoot = null;
|
||||
extraConfig = ''
|
||||
client_max_body_size 512M;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
'';
|
||||
locations."/".proxyPass = "http://localhost:${toString srv.HTTP_PORT}";
|
||||
};
|
||||
|
||||
services.forgejo = {
|
||||
enable = true;
|
||||
database.type = "postgres";
|
||||
lfs.enable = true;
|
||||
|
||||
settings = {
|
||||
server = {
|
||||
DOMAIN = fqdn;
|
||||
ROOT_URL = "https://${fqdn}/";
|
||||
HTTP_PORT = 3000;
|
||||
};
|
||||
|
||||
passwordFile = mkOption {
|
||||
type = types.nullOr types.path;
|
||||
default = null;
|
||||
example = "/run/keys/forgejo-db";
|
||||
description = "Path to file containing database password";
|
||||
};
|
||||
};
|
||||
service.DISABLE_REGISTRATION = true;
|
||||
|
||||
mailer = {
|
||||
enable = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable email notifications";
|
||||
actions = {
|
||||
ENABLED = true;
|
||||
DEFAULT_ACTIONS_URL = "github";
|
||||
};
|
||||
|
||||
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";
|
||||
mailer = {
|
||||
ENABLED = true;
|
||||
SMTP_ADDR = "mail.example.com";
|
||||
FROM = "noreply@${fqdn}";
|
||||
USER = "noreply@${fqdn}";
|
||||
PASSWD = smtpPassword;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
# PostgreSQL database
|
||||
services.postgresql = mkIf cfg.database.createLocally {
|
||||
# Create/ensure admin user
|
||||
systemd.services.forgejo.preStart = let
|
||||
adminCmd = "${lib.getExe cfg.package} admin user";
|
||||
in ''
|
||||
${adminCmd} create \
|
||||
--admin \
|
||||
--username ${adminUser} \
|
||||
--email "${adminEmail}" \
|
||||
--password "${adminPassword}" \
|
||||
--must-change-password=false || true
|
||||
'';
|
||||
|
||||
# Actions runner (runs jobs in Docker containers per labels)
|
||||
virtualisation.docker.enable = true;
|
||||
|
||||
services.gitea-actions-runner = {
|
||||
package = pkgs.forgejo-runner;
|
||||
instances.default = {
|
||||
enable = true;
|
||||
enableTCPIP = false;
|
||||
ensureDatabases = [ "forgejo" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "forgejo";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
name = "warp";
|
||||
url = "https://${fqdn}";
|
||||
token = runnerToken;
|
||||
labels = [
|
||||
"node-22:docker://node:22-bookworm"
|
||||
"nixos-latest:docker://nixos/nix"
|
||||
# "native:host"
|
||||
];
|
||||
};
|
||||
|
||||
# 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
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
0
servers/hugo.nix
Normal file → Executable file
0
servers/hugo.nix
Normal file → Executable file
29
servers/nginx.nix
Normal file
29
servers/nginx.nix
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
# WARNING: this ends up world-readable in the Nix store if you inline it.
|
||||
cloudflareEnv = pkgs.writeText "cloudflare-acme.env" ''
|
||||
umnyPSYOr9U3m404_IBMl4PTOzg29nz_XzNEGw2v
|
||||
'';
|
||||
in
|
||||
{
|
||||
networking.firewall.allowedTCPPorts = [ 80 443 ];
|
||||
|
||||
services.nginx = {
|
||||
enable = true;
|
||||
recommendedGzipSettings = true;
|
||||
recommendedOptimisation = true;
|
||||
recommendedProxySettings = true;
|
||||
recommendedTlsSettings = true;
|
||||
};
|
||||
|
||||
security.acme = {
|
||||
acceptTerms = true;
|
||||
|
||||
# These defaults are inherited by security.acme.certs.* unless overridden. :contentReference[oaicite:0]{index=0}
|
||||
defaults = {
|
||||
email = "admin@symbiotrip.com";
|
||||
dnsProvider = "cloudflare"; # :contentReference[oaicite:1]{index=1}
|
||||
environmentFile = cloudflareEnv; # :contentReference[oaicite:2]{index=2}
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue