nixos/sourcehut: remove forgotten unused files

This commit is contained in:
Julien Moutinho 2022-05-06 21:55:26 +02:00 committed by tomberek
parent 876f3a8bf0
commit 43b5dcd60c
10 changed files with 0 additions and 1697 deletions

View file

@ -1,236 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
scfg = cfg.builds;
rcfg = config.services.redis;
iniKey = "builds.sr.ht";
drv = pkgs.sourcehut.buildsrht;
in
{
options.services.sourcehut.builds = {
user = mkOption {
type = types.str;
default = "buildsrht";
description = ''
User for builds.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5002;
description = ''
Port on which the "builds" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "builds.sr.ht";
description = ''
PostgreSQL database name for builds.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/buildsrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/buildsrht"'';
description = ''
State path for builds.sr.ht.
'';
};
enableWorker = mkOption {
type = types.bool;
default = false;
description = ''
Run workers for builds.sr.ht.
'';
};
images = mkOption {
type = types.attrsOf (types.attrsOf (types.attrsOf types.package));
default = { };
example = lib.literalExpression ''(let
# Pinning unstable to allow usage with flakes and limit rebuilds.
pkgs_unstable = builtins.fetchGit {
url = "https://github.com/NixOS/nixpkgs";
rev = "ff96a0fa5635770390b184ae74debea75c3fd534";
ref = "nixos-unstable";
};
image_from_nixpkgs = pkgs_unstable: (import ("''${pkgs.sourcehut.buildsrht}/lib/images/nixos/image.nix") {
pkgs = (import pkgs_unstable {});
});
in
{
nixos.unstable.x86_64 = image_from_nixpkgs pkgs_unstable;
}
)'';
description = ''
Images for builds.sr.ht. Each package should be distro.release.arch and point to a /nix/store/package/root.img.qcow2.
'';
};
};
config = with scfg; let
image_dirs = lib.lists.flatten (
lib.attrsets.mapAttrsToList
(distro: revs:
lib.attrsets.mapAttrsToList
(rev: archs:
lib.attrsets.mapAttrsToList
(arch: image:
pkgs.runCommand "buildsrht-images" { } ''
mkdir -p $out/${distro}/${rev}/${arch}
ln -s ${image}/*.qcow2 $out/${distro}/${rev}/${arch}/root.img.qcow2
'')
archs)
revs)
scfg.images);
image_dir_pre = pkgs.symlinkJoin {
name = "builds.sr.ht-worker-images-pre";
paths = image_dirs ++ [
"${pkgs.sourcehut.buildsrht}/lib/images"
];
};
image_dir = pkgs.runCommand "builds.sr.ht-worker-images" { } ''
mkdir -p $out/images
cp -Lr ${image_dir_pre}/* $out/images
'';
in
lib.mkIf (cfg.enable && elem "builds" cfg.services) {
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
extraGroups = lib.optionals cfg.builds.enableWorker [ "docker" ];
description = "builds.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services.postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
systemd = {
tmpfiles.rules = [
"d ${statePath} 0755 ${user} ${user} -"
] ++ (lib.optionals cfg.builds.enableWorker
[ "d ${statePath}/logs 0775 ${user} ${user} - -" ]
);
services = {
buildsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey
{
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "builds.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
# Hack to bypass this hack: https://git.sr.ht/~sircmpwn/core.sr.ht/tree/master/item/srht-update-profiles#L6
} // { preStart = " "; };
buildsrht-worker = {
enable = scfg.enableWorker;
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
partOf = [ "buildsrht.service" ];
description = "builds.sr.ht worker service";
path = [ pkgs.openssh pkgs.docker ];
preStart = let qemuPackage = pkgs.qemu_kvm;
in ''
if [[ "$(docker images -q qemu:latest 2> /dev/null)" == "" || "$(cat ${statePath}/docker-image-qemu 2> /dev/null || true)" != "${qemuPackage.version}" ]]; then
# Create and import qemu:latest image for docker
${
pkgs.dockerTools.streamLayeredImage {
name = "qemu";
tag = "latest";
contents = [ qemuPackage ];
}
} | docker load
# Mark down current package version
printf "%s" "${qemuPackage.version}" > ${statePath}/docker-image-qemu
fi
'';
serviceConfig = {
Type = "simple";
User = user;
Group = "nginx";
Restart = "always";
};
serviceConfig.ExecStart = "${pkgs.sourcehut.buildsrht}/bin/builds.sr.ht-worker";
};
};
};
services.sourcehut.settings = {
# URL builds.sr.ht is being served at (protocol://domain)
"builds.sr.ht".origin = mkDefault "http://builds.${cfg.originBase}";
# Address and port to bind the debug server to
"builds.sr.ht".debug-host = mkDefault "0.0.0.0";
"builds.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"builds.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"builds.sr.ht".migrate-on-upgrade = mkDefault "yes";
# builds.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"builds.sr.ht".oauth-client-id = mkDefault null;
"builds.sr.ht".oauth-client-secret = mkDefault null;
# The redis connection used for the celery worker
"builds.sr.ht".redis = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/3";
# The shell used for ssh
"builds.sr.ht".shell = mkDefault "runner-shell";
# Register the builds.sr.ht dispatcher
"git.sr.ht::dispatch".${builtins.unsafeDiscardStringContext "${pkgs.sourcehut.buildsrht}/bin/buildsrht-keys"} = mkDefault "${user}:${user}";
# Location for build logs, images, and control command
} // lib.attrsets.optionalAttrs scfg.enableWorker {
# Default worker stores logs that are accessible via this address:port
"builds.sr.ht::worker".name = mkDefault "127.0.0.1:5020";
"builds.sr.ht::worker".buildlogs = mkDefault "${scfg.statePath}/logs";
"builds.sr.ht::worker".images = mkDefault "${image_dir}/images";
"builds.sr.ht::worker".controlcmd = mkDefault "${image_dir}/images/control";
"builds.sr.ht::worker".timeout = mkDefault "3m";
};
services.nginx.virtualHosts."logs.${cfg.originBase}" =
if scfg.enableWorker then {
listen = with builtins; let address = split ":" cfg.settings."builds.sr.ht::worker".name;
in [{ addr = elemAt address 0; port = lib.toInt (elemAt address 2); }];
locations."/logs".root = "${scfg.statePath}";
} else { };
services.nginx.virtualHosts."builds.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.buildsrht}/${pkgs.sourcehut.python.sitePackages}/buildsrht";
};
};
}

View file

@ -1,127 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
cfgIni = cfg.settings;
scfg = cfg.dispatch;
iniKey = "dispatch.sr.ht";
drv = pkgs.sourcehut.dispatchsrht;
in
{
options.services.sourcehut.dispatch = {
user = mkOption {
type = types.str;
default = "dispatchsrht";
description = ''
User for dispatch.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5005;
description = ''
Port on which the "dispatch" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "dispatch.sr.ht";
description = ''
PostgreSQL database name for dispatch.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/dispatchsrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/dispatchsrht"'';
description = ''
State path for dispatch.sr.ht.
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "dispatch" cfg.services) {
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
description = "dispatch.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services.postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
systemd = {
tmpfiles.rules = [
"d ${statePath} 0750 ${user} ${user} -"
];
services.dispatchsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "dispatch.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
};
services.sourcehut.settings = {
# URL dispatch.sr.ht is being served at (protocol://domain)
"dispatch.sr.ht".origin = mkDefault "http://dispatch.${cfg.originBase}";
# Address and port to bind the debug server to
"dispatch.sr.ht".debug-host = mkDefault "0.0.0.0";
"dispatch.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"dispatch.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"dispatch.sr.ht".migrate-on-upgrade = mkDefault "yes";
# dispatch.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"dispatch.sr.ht".oauth-client-id = mkDefault null;
"dispatch.sr.ht".oauth-client-secret = mkDefault null;
# Github Integration
"dispatch.sr.ht::github".oauth-client-id = mkDefault null;
"dispatch.sr.ht::github".oauth-client-secret = mkDefault null;
# Gitlab Integration
"dispatch.sr.ht::gitlab".enabled = mkDefault null;
"dispatch.sr.ht::gitlab".canonical-upstream = mkDefault "gitlab.com";
"dispatch.sr.ht::gitlab".repo-cache = mkDefault "./repo-cache";
# "dispatch.sr.ht::gitlab"."gitlab.com" = mkDefault "GitLab:application id:secret";
};
services.nginx.virtualHosts."dispatch.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.dispatchsrht}/${pkgs.sourcehut.python.sitePackages}/dispatchsrht";
};
};
}

View file

@ -1,217 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
scfg = cfg.git;
iniKey = "git.sr.ht";
rcfg = config.services.redis;
drv = pkgs.sourcehut.gitsrht;
in
{
options.services.sourcehut.git = {
user = mkOption {
type = types.str;
visible = false;
internal = true;
readOnly = true;
default = "git";
description = ''
User for git.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5001;
description = ''
Port on which the "git" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "git.sr.ht";
description = ''
PostgreSQL database name for git.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/gitsrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/gitsrht"'';
description = ''
State path for git.sr.ht.
'';
};
package = mkOption {
type = types.package;
default = pkgs.git;
defaultText = literalExpression "pkgs.git";
example = literalExpression "pkgs.gitFull";
description = ''
Git package for git.sr.ht. This can help silence collisions.
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "git" cfg.services) {
# sshd refuses to run with `Unsafe AuthorizedKeysCommand ... bad ownership or modes for directory /nix/store`
environment.etc."ssh/gitsrht-dispatch" = {
mode = "0755";
text = ''
#! ${pkgs.stdenv.shell}
${cfg.python}/bin/gitsrht-dispatch "$@"
'';
};
# Needs this in the $PATH when sshing into the server
environment.systemPackages = [ cfg.git.package ];
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
# https://stackoverflow.com/questions/22314298/git-push-results-in-fatal-protocol-error-bad-line-length-character-this
# Probably could use gitsrht-shell if output is restricted to just parameters...
shell = pkgs.bash;
description = "git.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services = {
cron.systemCronJobs = [ "*/20 * * * * ${cfg.python}/bin/gitsrht-periodic" ];
fcgiwrap.enable = true;
openssh.authorizedKeysCommand = ''/etc/ssh/gitsrht-dispatch "%u" "%h" "%t" "%k"'';
openssh.authorizedKeysCommandUser = "root";
openssh.extraConfig = ''
PermitUserEnvironment SRHT_*
'';
postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
};
systemd = {
tmpfiles.rules = [
# /var/log is owned by root
"f /var/log/git-srht-shell 0644 ${user} ${user} -"
"d ${statePath} 0750 ${user} ${user} -"
"d ${cfg.settings."${iniKey}".repos} 2755 ${user} ${user} -"
];
services = {
gitsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "redis.service" "postgresql.service" "network.target" ];
requires = [ "redis.service" "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
# Needs internally to create repos at the very least
path = [ pkgs.git ];
description = "git.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
gitsrht-webhooks = {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "git.sr.ht webhooks service";
serviceConfig = {
Type = "simple";
User = user;
Restart = "always";
};
serviceConfig.ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
};
};
};
services.sourcehut.settings = {
# URL git.sr.ht is being served at (protocol://domain)
"git.sr.ht".origin = mkDefault "http://git.${cfg.originBase}";
# Address and port to bind the debug server to
"git.sr.ht".debug-host = mkDefault "0.0.0.0";
"git.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"git.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"git.sr.ht".migrate-on-upgrade = mkDefault "yes";
# The redis connection used for the webhooks worker
"git.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/1";
# A post-update script which is installed in every git repo.
"git.sr.ht".post-update-script = mkDefault "${pkgs.sourcehut.gitsrht}/bin/gitsrht-update-hook";
# git.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"git.sr.ht".oauth-client-id = mkDefault null;
"git.sr.ht".oauth-client-secret = mkDefault null;
# Path to git repositories on disk
"git.sr.ht".repos = mkDefault "/var/lib/git";
"git.sr.ht".outgoing-domain = mkDefault "http://git.${cfg.originBase}";
# The authorized keys hook uses this to dispatch to various handlers
# The format is a program to exec into as the key, and the user to match as the
# value. When someone tries to log in as this user, this program is executed
# and is expected to omit an AuthorizedKeys file.
#
# Discard of the string context is in order to allow derivation-derived strings.
# This is safe if the relevant package is installed which will be the case if the setting is utilized.
"git.sr.ht::dispatch".${builtins.unsafeDiscardStringContext "${pkgs.sourcehut.gitsrht}/bin/gitsrht-keys"} = mkDefault "${user}:${user}";
};
services.nginx.virtualHosts."git.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.gitsrht}/${pkgs.sourcehut.python.sitePackages}/gitsrht";
extraConfig = ''
location = /authorize {
proxy_pass http://${cfg.address}:${toString port};
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
}
location ~ ^/([^/]+)/([^/]+)/(HEAD|info/refs|objects/info/.*|git-upload-pack).*$ {
auth_request /authorize;
root /var/lib/git;
fastcgi_pass unix:/run/fcgiwrap.sock;
fastcgi_param SCRIPT_FILENAME ${pkgs.git}/bin/git-http-backend;
fastcgi_param PATH_INFO $uri;
fastcgi_param GIT_PROJECT_ROOT $document_root;
fastcgi_read_timeout 500s;
include ${config.services.nginx.package}/conf/fastcgi_params;
gzip off;
}
'';
};
};
}

View file

@ -1,175 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
scfg = cfg.hg;
iniKey = "hg.sr.ht";
rcfg = config.services.redis;
drv = pkgs.sourcehut.hgsrht;
in
{
options.services.sourcehut.hg = {
user = mkOption {
type = types.str;
internal = true;
readOnly = true;
default = "hg";
description = ''
User for hg.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5010;
description = ''
Port on which the "hg" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "hg.sr.ht";
description = ''
PostgreSQL database name for hg.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/hgsrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/hgsrht"'';
description = ''
State path for hg.sr.ht.
'';
};
cloneBundles = mkOption {
type = types.bool;
default = false;
description = ''
Generate clonebundles (which require more disk space but dramatically speed up cloning large repositories).
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "hg" cfg.services) {
# In case it ever comes into being
environment.etc."ssh/hgsrht-dispatch" = {
mode = "0755";
text = ''
#! ${pkgs.stdenv.shell}
${cfg.python}/bin/gitsrht-dispatch $@
'';
};
environment.systemPackages = [ pkgs.mercurial ];
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
# Assuming hg.sr.ht needs this too
shell = pkgs.bash;
description = "hg.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services = {
cron.systemCronJobs = [ "*/20 * * * * ${cfg.python}/bin/hgsrht-periodic" ]
++ optional cloneBundles "0 * * * * ${cfg.python}/bin/hgsrht-clonebundles";
openssh.authorizedKeysCommand = ''/etc/ssh/hgsrht-dispatch "%u" "%h" "%t" "%k"'';
openssh.authorizedKeysCommandUser = "root";
openssh.extraConfig = ''
PermitUserEnvironment SRHT_*
'';
postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
};
systemd = {
tmpfiles.rules = [
# /var/log is owned by root
"f /var/log/hg-srht-shell 0644 ${user} ${user} -"
"d ${statePath} 0750 ${user} ${user} -"
"d ${cfg.settings."${iniKey}".repos} 2755 ${user} ${user} -"
];
services.hgsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "redis.service" "postgresql.service" "network.target" ];
requires = [ "redis.service" "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
path = [ pkgs.mercurial ];
description = "hg.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
};
services.sourcehut.settings = {
# URL hg.sr.ht is being served at (protocol://domain)
"hg.sr.ht".origin = mkDefault "http://hg.${cfg.originBase}";
# Address and port to bind the debug server to
"hg.sr.ht".debug-host = mkDefault "0.0.0.0";
"hg.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"hg.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# The redis connection used for the webhooks worker
"hg.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/1";
# A post-update script which is installed in every mercurial repo.
"hg.sr.ht".changegroup-script = mkDefault "${cfg.python}/bin/hgsrht-hook-changegroup";
# hg.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"hg.sr.ht".oauth-client-id = mkDefault null;
"hg.sr.ht".oauth-client-secret = mkDefault null;
# Path to mercurial repositories on disk
"hg.sr.ht".repos = mkDefault "/var/lib/hg";
# Path to the srht mercurial extension
# (defaults to where the hgsrht code is)
# "hg.sr.ht".srhtext = mkDefault null;
# .hg/store size (in MB) past which the nightly job generates clone bundles.
# "hg.sr.ht".clone_bundle_threshold = mkDefault 50;
# Path to hg-ssh (if not in $PATH)
# "hg.sr.ht".hg_ssh = mkDefault /path/to/hg-ssh;
# The authorized keys hook uses this to dispatch to various handlers
# The format is a program to exec into as the key, and the user to match as the
# value. When someone tries to log in as this user, this program is executed
# and is expected to omit an AuthorizedKeys file.
#
# Uncomment the relevant lines to enable the various sr.ht dispatchers.
"hg.sr.ht::dispatch"."/run/current-system/sw/bin/hgsrht-keys" = mkDefault "${user}:${user}";
};
# TODO: requires testing and addition of hg-specific requirements
services.nginx.virtualHosts."hg.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.hgsrht}/${pkgs.sourcehut.python.sitePackages}/hgsrht";
};
};
}

View file

@ -1,120 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
cfgIni = cfg.settings;
scfg = cfg.hub;
iniKey = "hub.sr.ht";
drv = pkgs.sourcehut.hubsrht;
in
{
options.services.sourcehut.hub = {
user = mkOption {
type = types.str;
default = "hubsrht";
description = ''
User for hub.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5014;
description = ''
Port on which the "hub" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "hub.sr.ht";
description = ''
PostgreSQL database name for hub.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/hubsrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/hubsrht"'';
description = ''
State path for hub.sr.ht.
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "hub" cfg.services) {
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
description = "hub.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services.postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
systemd = {
tmpfiles.rules = [
"d ${statePath} 0750 ${user} ${user} -"
];
services.hubsrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "hub.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
};
services.sourcehut.settings = {
# URL hub.sr.ht is being served at (protocol://domain)
"hub.sr.ht".origin = mkDefault "http://hub.${cfg.originBase}";
# Address and port to bind the debug server to
"hub.sr.ht".debug-host = mkDefault "0.0.0.0";
"hub.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"hub.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"hub.sr.ht".migrate-on-upgrade = mkDefault "yes";
# hub.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"hub.sr.ht".oauth-client-id = mkDefault null;
"hub.sr.ht".oauth-client-secret = mkDefault null;
};
services.nginx.virtualHosts."${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.hubsrht}/${pkgs.sourcehut.python.sitePackages}/hubsrht";
};
services.nginx.virtualHosts."hub.${cfg.originBase}" = {
globalRedirect = "${cfg.originBase}";
forceSSL = true;
};
};
}

View file

@ -1,187 +0,0 @@
# Email setup is fairly involved, useful references:
# https://drewdevault.com/2018/08/05/Local-mail-server.html
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
cfgIni = cfg.settings;
scfg = cfg.lists;
iniKey = "lists.sr.ht";
rcfg = config.services.redis;
drv = pkgs.sourcehut.listssrht;
in
{
options.services.sourcehut.lists = {
user = mkOption {
type = types.str;
default = "listssrht";
description = ''
User for lists.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5006;
description = ''
Port on which the "lists" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "lists.sr.ht";
description = ''
PostgreSQL database name for lists.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/listssrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/listssrht"'';
description = ''
State path for lists.sr.ht.
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "lists" cfg.services) {
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
extraGroups = [ "postfix" ];
description = "lists.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services.postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
systemd = {
tmpfiles.rules = [
"d ${statePath} 0750 ${user} ${user} -"
];
services = {
listssrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "lists.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
listssrht-process = {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "lists.sr.ht process service";
serviceConfig = {
Type = "simple";
User = user;
Restart = "always";
ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.process worker --loglevel=info";
};
};
listssrht-lmtp = {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "lists.sr.ht process service";
serviceConfig = {
Type = "simple";
User = user;
Restart = "always";
ExecStart = "${cfg.python}/bin/listssrht-lmtp";
};
};
listssrht-webhooks = {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "lists.sr.ht webhooks service";
serviceConfig = {
Type = "simple";
User = user;
Restart = "always";
ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
};
};
};
};
services.sourcehut.settings = {
# URL lists.sr.ht is being served at (protocol://domain)
"lists.sr.ht".origin = mkDefault "http://lists.${cfg.originBase}";
# Address and port to bind the debug server to
"lists.sr.ht".debug-host = mkDefault "0.0.0.0";
"lists.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"lists.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"lists.sr.ht".migrate-on-upgrade = mkDefault "yes";
# lists.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"lists.sr.ht".oauth-client-id = mkDefault null;
"lists.sr.ht".oauth-client-secret = mkDefault null;
# Outgoing email for notifications generated by users
"lists.sr.ht".notify-from = mkDefault "CHANGEME@example.org";
# The redis connection used for the webhooks worker
"lists.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/2";
# The redis connection used for the celery worker
"lists.sr.ht".redis = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/4";
# Network-key
"lists.sr.ht".network-key = mkDefault null;
# Allow creation
"lists.sr.ht".allow-new-lists = mkDefault "no";
# Posting Domain
"lists.sr.ht".posting-domain = mkDefault "lists.${cfg.originBase}";
# Path for the lmtp daemon's unix socket. Direct incoming mail to this socket.
# Alternatively, specify IP:PORT and an SMTP server will be run instead.
"lists.sr.ht::worker".sock = mkDefault "/tmp/lists.sr.ht-lmtp.sock";
# The lmtp daemon will make the unix socket group-read/write for users in this
# group.
"lists.sr.ht::worker".sock-group = mkDefault "postfix";
"lists.sr.ht::worker".reject-url = mkDefault "https://man.sr.ht/lists.sr.ht/etiquette.md";
"lists.sr.ht::worker".reject-mimetypes = mkDefault "text/html";
};
services.nginx.virtualHosts."lists.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.listssrht}/${pkgs.sourcehut.python.sitePackages}/listssrht";
};
};
}

View file

@ -1,124 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
cfgIni = cfg.settings;
scfg = cfg.man;
iniKey = "man.sr.ht";
drv = pkgs.sourcehut.mansrht;
in
{
options.services.sourcehut.man = {
user = mkOption {
type = types.str;
default = "mansrht";
description = ''
User for man.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5004;
description = ''
Port on which the "man" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "man.sr.ht";
description = ''
PostgreSQL database name for man.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/mansrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/mansrht"'';
description = ''
State path for man.sr.ht.
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "man" cfg.services) {
assertions =
[
{
assertion = hasAttrByPath [ "git.sr.ht" "oauth-client-id" ] cfgIni;
message = "man.sr.ht needs access to git.sr.ht.";
}
];
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
description = "man.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services.postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
systemd = {
tmpfiles.rules = [
"d ${statePath} 0750 ${user} ${user} -"
];
services.mansrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "man.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
};
services.sourcehut.settings = {
# URL man.sr.ht is being served at (protocol://domain)
"man.sr.ht".origin = mkDefault "http://man.${cfg.originBase}";
# Address and port to bind the debug server to
"man.sr.ht".debug-host = mkDefault "0.0.0.0";
"man.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"man.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"man.sr.ht".migrate-on-upgrade = mkDefault "yes";
# man.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"man.sr.ht".oauth-client-id = mkDefault null;
"man.sr.ht".oauth-client-secret = mkDefault null;
};
services.nginx.virtualHosts."man.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.mansrht}/${pkgs.sourcehut.python.sitePackages}/mansrht";
};
};
}

View file

@ -1,213 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
cfgIni = cfg.settings;
scfg = cfg.meta;
iniKey = "meta.sr.ht";
rcfg = config.services.redis;
drv = pkgs.sourcehut.metasrht;
in
{
options.services.sourcehut.meta = {
user = mkOption {
type = types.str;
default = "metasrht";
description = ''
User for meta.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5000;
description = ''
Port on which the "meta" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "meta.sr.ht";
description = ''
PostgreSQL database name for meta.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/metasrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/metasrht"'';
description = ''
State path for meta.sr.ht.
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "meta" cfg.services) {
assertions =
[
{
assertion = with cfgIni."meta.sr.ht::billing"; enabled == "yes" -> (stripe-public-key != null && stripe-secret-key != null);
message = "If meta.sr.ht::billing is enabled, the keys should be defined.";
}
];
users = {
users = {
${user} = {
isSystemUser = true;
group = user;
description = "meta.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services.cron.systemCronJobs = [ "0 0 * * * ${cfg.python}/bin/metasrht-daily" ];
services.postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
systemd = {
tmpfiles.rules = [
"d ${statePath} 0750 ${user} ${user} -"
];
services = {
metasrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "meta.sr.ht website service";
preStart = ''
# Configure client(s) as "preauthorized"
${concatMapStringsSep "\n\n"
(attr: ''
if ! test -e "${statePath}/${attr}.oauth" || [ "$(cat ${statePath}/${attr}.oauth)" != "${cfgIni."${attr}".oauth-client-id}" ]; then
# Configure ${attr}'s OAuth client as "preauthorized"
psql ${database} \
-c "UPDATE oauthclient SET preauthorized = true WHERE client_id = '${cfgIni."${attr}".oauth-client-id}'"
printf "%s" "${cfgIni."${attr}".oauth-client-id}" > "${statePath}/${attr}.oauth"
fi
'')
(builtins.attrNames (filterAttrs
(k: v: !(hasInfix "::" k) && builtins.hasAttr "oauth-client-id" v && v.oauth-client-id != null)
cfg.settings))}
'';
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
metasrht-api = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "meta.sr.ht api service";
preStart = ''
# Configure client(s) as "preauthorized"
${concatMapStringsSep "\n\n"
(attr: ''
if ! test -e "${statePath}/${attr}.oauth" || [ "$(cat ${statePath}/${attr}.oauth)" != "${cfgIni."${attr}".oauth-client-id}" ]; then
# Configure ${attr}'s OAuth client as "preauthorized"
psql ${database} \
-c "UPDATE oauthclient SET preauthorized = true WHERE client_id = '${cfgIni."${attr}".oauth-client-id}'"
printf "%s" "${cfgIni."${attr}".oauth-client-id}" > "${statePath}/${attr}.oauth"
fi
'')
(builtins.attrNames (filterAttrs
(k: v: !(hasInfix "::" k) && builtins.hasAttr "oauth-client-id" v && v.oauth-client-id != null)
cfg.settings))}
'';
serviceConfig.ExecStart = "${pkgs.sourcehut.metasrht}/bin/metasrht-api -b :${toString (port + 100)}";
};
metasrht-webhooks = {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "meta.sr.ht webhooks service";
serviceConfig = {
Type = "simple";
User = user;
Restart = "always";
ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
};
};
};
};
services.sourcehut.settings = {
# URL meta.sr.ht is being served at (protocol://domain)
"meta.sr.ht".origin = mkDefault "https://meta.${cfg.originBase}";
# Address and port to bind the debug server to
"meta.sr.ht".debug-host = mkDefault "0.0.0.0";
"meta.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"meta.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"meta.sr.ht".migrate-on-upgrade = mkDefault "yes";
# If "yes", the user will be sent the stock sourcehut welcome emails after
# signup (requires cron to be configured properly). These are specific to the
# sr.ht instance so you probably want to patch these before enabling this.
"meta.sr.ht".welcome-emails = mkDefault "no";
# The redis connection used for the webhooks worker
"meta.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/6";
# If "no", public registration will not be permitted.
"meta.sr.ht::settings".registration = mkDefault "no";
# Where to redirect new users upon registration
"meta.sr.ht::settings".onboarding-redirect = mkDefault "https://meta.${cfg.originBase}";
# How many invites each user is issued upon registration (only applicable if
# open registration is disabled)
"meta.sr.ht::settings".user-invites = mkDefault 5;
# Origin URL for API, 100 more than web
"meta.sr.ht".api-origin = mkDefault "http://localhost:5100";
# You can add aliases for the client IDs of commonly used OAuth clients here.
#
# Example:
"meta.sr.ht::aliases" = mkDefault { };
# "meta.sr.ht::aliases"."git.sr.ht" = 12345;
# "yes" to enable the billing system
"meta.sr.ht::billing".enabled = mkDefault "no";
# Get your keys at https://dashboard.stripe.com/account/apikeys
"meta.sr.ht::billing".stripe-public-key = mkDefault null;
"meta.sr.ht::billing".stripe-secret-key = mkDefault null;
};
services.nginx.virtualHosts."meta.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.metasrht}/${pkgs.sourcehut.python.sitePackages}/metasrht";
};
};
}

View file

@ -1,135 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
cfgIni = cfg.settings;
scfg = cfg.paste;
iniKey = "paste.sr.ht";
rcfg = config.services.redis;
drv = pkgs.sourcehut.pastesrht;
in
{
options.services.sourcehut.paste = {
user = mkOption {
type = types.str;
default = "pastesrht";
description = ''
User for paste.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5011;
description = ''
Port on which the "paste" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "paste.sr.ht";
description = ''
PostgreSQL database name for paste.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/pastesrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/pastesrht"'';
description = ''
State path for pastesrht.sr.ht.
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "paste" cfg.services) {
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
description = "paste.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services.postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
systemd = {
tmpfiles.rules = [
"d ${statePath} 0750 ${user} ${user} -"
];
services = {
pastesrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "paste.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
pastesrht-webhooks = {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "paste.sr.ht webhooks service";
serviceConfig = {
Type = "simple";
User = user;
Restart = "always";
ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
};
};
};
};
services.sourcehut.settings = {
# URL paste.sr.ht is being served at (protocol://domain)
"paste.sr.ht".origin = mkDefault "http://paste.${cfg.originBase}";
# Address and port to bind the debug server to
"paste.sr.ht".debug-host = mkDefault "0.0.0.0";
"paste.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"paste.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"paste.sr.ht".migrate-on-upgrade = mkDefault "yes";
# paste.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"paste.sr.ht".oauth-client-id = mkDefault null;
"paste.sr.ht".oauth-client-secret = mkDefault null;
"paste.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/5";
};
services.nginx.virtualHosts."paste.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.pastesrht}/${pkgs.sourcehut.python.sitePackages}/pastesrht";
};
};
}

View file

@ -1,163 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.sourcehut;
opt = options.services.sourcehut;
cfgIni = cfg.settings;
scfg = cfg.todo;
iniKey = "todo.sr.ht";
rcfg = config.services.redis;
drv = pkgs.sourcehut.todosrht;
in
{
options.services.sourcehut.todo = {
user = mkOption {
type = types.str;
default = "todosrht";
description = ''
User for todo.sr.ht.
'';
};
port = mkOption {
type = types.port;
default = 5003;
description = ''
Port on which the "todo" module should listen.
'';
};
database = mkOption {
type = types.str;
default = "todo.sr.ht";
description = ''
PostgreSQL database name for todo.sr.ht.
'';
};
statePath = mkOption {
type = types.path;
default = "${cfg.statePath}/todosrht";
defaultText = literalExpression ''"''${config.${opt.statePath}}/todosrht"'';
description = ''
State path for todo.sr.ht.
'';
};
};
config = with scfg; lib.mkIf (cfg.enable && elem "todo" cfg.services) {
users = {
users = {
"${user}" = {
isSystemUser = true;
group = user;
extraGroups = [ "postfix" ];
description = "todo.sr.ht user";
};
};
groups = {
"${user}" = { };
};
};
services.postgresql = {
authentication = ''
local ${database} ${user} trust
'';
ensureDatabases = [ database ];
ensureUsers = [
{
name = user;
ensurePermissions = { "DATABASE \"${database}\"" = "ALL PRIVILEGES"; };
}
];
};
systemd = {
tmpfiles.rules = [
"d ${statePath} 0750 ${user} ${user} -"
];
services = {
todosrht = import ./service.nix { inherit config pkgs lib; } scfg drv iniKey {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "todo.sr.ht website service";
serviceConfig.ExecStart = "${cfg.python}/bin/gunicorn ${drv.pname}.app:app -b ${cfg.address}:${toString port}";
};
todosrht-lmtp = {
after = [ "postgresql.service" "network.target" ];
bindsTo = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "todo.sr.ht process service";
serviceConfig = {
Type = "simple";
User = user;
Restart = "always";
ExecStart = "${cfg.python}/bin/todosrht-lmtp";
};
};
todosrht-webhooks = {
after = [ "postgresql.service" "network.target" ];
requires = [ "postgresql.service" ];
wantedBy = [ "multi-user.target" ];
description = "todo.sr.ht webhooks service";
serviceConfig = {
Type = "simple";
User = user;
Restart = "always";
ExecStart = "${cfg.python}/bin/celery -A ${drv.pname}.webhooks worker --loglevel=info";
};
};
};
};
services.sourcehut.settings = {
# URL todo.sr.ht is being served at (protocol://domain)
"todo.sr.ht".origin = mkDefault "http://todo.${cfg.originBase}";
# Address and port to bind the debug server to
"todo.sr.ht".debug-host = mkDefault "0.0.0.0";
"todo.sr.ht".debug-port = mkDefault port;
# Configures the SQLAlchemy connection string for the database.
"todo.sr.ht".connection-string = mkDefault "postgresql:///${database}?user=${user}&host=/var/run/postgresql";
# Set to "yes" to automatically run migrations on package upgrade.
"todo.sr.ht".migrate-on-upgrade = mkDefault "yes";
# todo.sr.ht's OAuth client ID and secret for meta.sr.ht
# Register your client at meta.example.org/oauth
"todo.sr.ht".oauth-client-id = mkDefault null;
"todo.sr.ht".oauth-client-secret = mkDefault null;
# Outgoing email for notifications generated by users
"todo.sr.ht".notify-from = mkDefault "CHANGEME@example.org";
# The redis connection used for the webhooks worker
"todo.sr.ht".webhooks = mkDefault "redis://${rcfg.bind}:${toString rcfg.port}/1";
# Network-key
"todo.sr.ht".network-key = mkDefault null;
# Path for the lmtp daemon's unix socket. Direct incoming mail to this socket.
# Alternatively, specify IP:PORT and an SMTP server will be run instead.
"todo.sr.ht::mail".sock = mkDefault "/tmp/todo.sr.ht-lmtp.sock";
# The lmtp daemon will make the unix socket group-read/write for users in this
# group.
"todo.sr.ht::mail".sock-group = mkDefault "postfix";
"todo.sr.ht::mail".posting-domain = mkDefault "todo.${cfg.originBase}";
};
services.nginx.virtualHosts."todo.${cfg.originBase}" = {
forceSSL = true;
locations."/".proxyPass = "http://${cfg.address}:${toString port}";
locations."/query".proxyPass = "http://${cfg.address}:${toString (port + 100)}";
locations."/static".root = "${pkgs.sourcehut.todosrht}/${pkgs.sourcehut.python.sitePackages}/todosrht";
};
};
}