Compare commits

...

2 commits

6 changed files with 43 additions and 371 deletions

View file

@ -66,23 +66,6 @@
recommendedProxySettings = true;
clientMaxBodySize = "10G";
domain = "tlater.net";
virtualHosts = let
proxyPassToPort = port: extra:
lib.recursiveUpdate {
forceSSL = true;
enableACME = true;
locations."/".proxyPass = "http://127.0.0.1:${toString port}";
extraConfig = ''
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
'';
}
extra;
domain = config.services.nginx.domain;
in {
"${domain}" = proxyPassToPort 3002 {serverAliases = ["www.${domain}"];};
"gitea.${domain}" = proxyPassToPort 3000 {};
};
};
security.acme = {

View file

@ -1,48 +1,31 @@
{config, ...}: {
users = {
extraUsers.gitea = {
uid = config.ids.uids.git;
isSystemUser = true;
description = "Gitea Service";
group = config.users.extraGroups.gitea.name;
};
extraGroups.gitea = {gid = config.ids.gids.git;};
{config, ...}: let
domain = "gitea.${config.services.nginx.domain}";
in {
services.gitea = {
inherit domain;
enable = true;
httpAddress = "127.0.0.1";
database.type = "postgres";
ssh.clonePort = 2222;
rootUrl = "https://gitea.tlater.net/";
cookieSecure = true;
appName = "Gitea: Git with a cup of tea";
disableRegistration = true;
};
virtualisation.pods.gitea = {
hostname = "gitea.tlater.net";
publish = ["3000:3000" "2221:2221"];
network = "slirp4netns";
# Set up SSL
services.nginx.virtualHosts."${domain}" = let
inherit (config.services.gitea) httpAddress httpPort;
in {
forceSSL = true;
enableACME = true;
extraConfig = ''
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
'';
containers = {
gitea = {
image = "gitea/gitea:latest";
volumes = ["gitea:/data:Z" "/etc/localtime:/etc/localtime:ro"];
dependsOn = ["postgres"];
environment = {
DB_TYPE = "postgres";
DB_HOST = "localhost:5432";
DB_NAME = "gitea";
DB_USER = "gitea";
USER_UID = toString config.users.extraUsers.gitea.uid;
USER_GID = toString config.users.extraGroups.gitea.gid;
RUN_MODE = "prod";
DOMAIN = "gitea.tlater.net";
SSH_PORT = "2221";
};
};
postgres = {
image = "postgres:alpine";
environment = {
POSTGRES_DB = "gitea";
POSTGRES_USER = "gitea";
};
volumes = ["gitea-postgres-14:/var/lib/postgresql/data"];
};
};
locations."/".proxyPass = "http://${httpAddress}:${toString httpPort}";
};
}

View file

@ -1,47 +1,20 @@
{
config,
pkgs,
...
}: {
users = {
extraUsers.webserver = {
uid = config.ids.uids.webserver;
group = config.users.extraGroups.webserver.name;
isSystemUser = true;
description = "tlater.net web server user";
};
extraGroups.webserver = {gid = config.ids.gids.webserver;};
};
virtualisation.oci-containers.containers.webserver = {
image = "tlaternet/webserver";
imageFile = pkgs.dockerTools.buildImage {
name = "tlaternet/webserver";
tag = "latest";
contents = pkgs.tlaternet-webserver.webserver;
config = let
uid = toString config.users.extraUsers.webserver.uid;
gid = toString config.users.extraGroups.webserver.gid;
{config, ...}: let
domain = config.services.nginx.domain;
in {
Cmd = ["tlaternet-webserver"];
Volumes = {"/srv/mail" = {};};
Env = [
"ROCKET_PORT=3002"
"ROCKET_TEMPLATE_DIR=${pkgs.tlaternet-templates.templates}/browser/"
];
ExposedPorts = {"3002" = {};};
User = "${uid}:${gid}";
};
};
services.tlaternet-webserver.enable = true;
ports = ["3002:3002"];
volumes = ["tlaternet-mail:/srv/mail"];
extraOptions = [
"--hostname=tlater.net"
# Rocket 0.4 doesn't support SIGTERM anyway, so SIGKILL is the cleanest exit possible.
"--stop-signal=SIGKILL"
];
# Set up SSL
services.nginx.virtualHosts."${domain}" = let
inherit (config.services.tlaternet-webserver.listen) addr port;
in {
serverAliases = ["www.${domain}"];
forceSSL = true;
enableACME = true;
extraConfig = ''
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
'';
locations."/".proxyPass = "http://${addr}:${toString port}";
};
}

View file

@ -15,21 +15,6 @@
"type": "github"
}
},
"flake-utils_2": {
"locked": {
"lastModified": 1659877975,
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"naersk": {
"inputs": {
"nixpkgs": [
@ -88,7 +73,6 @@
"nixos-hardware": "nixos-hardware",
"nixpkgs": "nixpkgs",
"sops-nix": "sops-nix",
"tlaternet-templates": "tlaternet-templates",
"tlaternet-webserver": "tlaternet-webserver"
}
},
@ -137,30 +121,9 @@
"type": "github"
}
},
"tlaternet-templates": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1633432574,
"narHash": "sha256-IjGaJAQuFIJ1Is9gtHXsryPOnTDE6tlA61PUKuS8dzw=",
"ref": "master",
"rev": "555a2949bdf643c74b535bd0c623d98f99d33628",
"revCount": 61,
"type": "git",
"url": "https://gitea.tlater.net/tlaternet/tlaternet-templates.git"
},
"original": {
"type": "git",
"url": "https://gitea.tlater.net/tlaternet/tlaternet-templates.git"
}
},
"tlaternet-webserver": {
"inputs": {
"flake-utils": "flake-utils_2",
"flake-utils": "flake-utils",
"naersk": "naersk",
"nixpkgs": [
"nixpkgs"

View file

@ -13,10 +13,6 @@
url = "git+https://gitea.tlater.net/tlaternet/tlaternet.git";
inputs.nixpkgs.follows = "nixpkgs";
};
tlaternet-templates = {
url = "git+https://gitea.tlater.net/tlaternet/tlaternet-templates.git";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
@ -25,16 +21,11 @@
nixos-hardware,
sops-nix,
tlaternet-webserver,
tlaternet-templates,
}: let
system = "x86_64-linux";
overlays = [
(final: prev: {
tlaternet-webserver =
tlaternet-webserver.legacyPackages.${prev.system}.packages;
tlaternet-templates =
tlaternet-templates.legacyPackages.${prev.system}.packages;
local = import ./pkgs {
pkgs = prev;
};
@ -59,6 +50,7 @@
(import ./configuration/linode.nix)
(import ./configuration/hardware-configuration.nix)
sops-nix.nixosModules.sops
tlaternet-webserver.nixosModules.default
];
};

View file

@ -1,222 +0,0 @@
{
lib,
config,
options,
...
}:
with lib; let
cfg = config.virtualisation.pods;
list-to-args = arg: list:
concatStringsSep " " (map (e: "--${arg}=${escapeShellArg e}") list);
possibly-unset-arg = arg: val: (optionalString (val != null) "--${arg}=${escapeShellArg val}");
mkPod = name: pod: rec {
path = [config.virtualisation.podman.package];
wants = ["network.target"];
after = ["network-online.target"];
wantedBy = ["multi-user.target" "default.target"];
environment.PODMAN_SYSTEMD_UNIT = "%n";
preStart = concatStringsSep " " [
"mkdir -p /run/podman/pods/ ;"
"podman pod create"
"--infra-conmon-pidfile=${escapeShellArg "/run/podman/pods/${name}.pid"}"
"--name=${escapeShellArg name}"
"--replace"
(list-to-args "add-host" pod.added-hosts)
(possibly-unset-arg "cgroup-parent" pod.cgroup-parent)
(list-to-args "dns" pod.dns)
(list-to-args "dns-opt" pod.dns-opt)
(list-to-args "dns-search" pod.dns-search)
(possibly-unset-arg "hostname" pod.hostname)
(possibly-unset-arg "infra" pod.infra)
(possibly-unset-arg "infra-command" pod.infra-command)
(possibly-unset-arg "infra-image" pod.infra-image)
(possibly-unset-arg "ip" pod.ip)
(possibly-unset-arg "mac-address" pod.mac-address)
(possibly-unset-arg "network" pod.network)
(possibly-unset-arg "network-alias" pod.network-alias)
(possibly-unset-arg "no-hosts" pod.no-hosts)
(list-to-args "publish" pod.publish)
(list-to-args "share" pod.share)
];
script = "podman pod start ${escapeShellArg name}";
preStop = "podman pod stop ${escapeShellArg name}";
# `podman generate systemd` generates a second stop after the
# first; not sure why but clearly it's recommended.
postStop = preStop;
serviceConfig = rec {
Type = "forking";
TimeoutStopSec = 70;
Restart = "on-failure";
PIDFile = "/run/podman/pods/${name}.pid";
};
};
in {
options.virtualisation.pods = mkOption {
type = with types;
attrsOf (submodule {
options = {
added-hosts = mkOption {
type = listOf str;
default = [];
description = "Additional hosts to add to /etc/hosts for each container.";
example = literalExample ''
[ "database:10.0.0.1" ]
'';
};
cgroup-parent = mkOption {
type = nullOr str;
default = null;
description = "The cgroups path under which the pod cgroup will be created.";
};
dns = mkOption {
type = listOf str;
default = [];
description = "The dns servers to set in /etc/resolv.conf.";
};
dns-opt = mkOption {
type = listOf str;
default = [];
description = "dns options to set in /etc/resolv.conf.";
};
dns-search = mkOption {
type = listOf str;
default = [];
description = "Search domains to set in /etc/resolv.conf.";
};
hostname = mkOption {
type = nullOr str;
default = null;
description = "The pod hostname.";
};
infra = mkOption {
type = nullOr bool;
default = null;
description = "Whether to create the infra container for the pod.";
};
infra-command = mkOption {
type = nullOr str;
default = null;
description = "The command to run in the infra container.";
};
infra-image = mkOption {
type = nullOr str;
default = null;
description = "The image to use for the infra container.";
};
ip = mkOption {
type = nullOr str;
default = null;
description = "A static IP address for the pod network.";
};
# TODO: set up label file stuff.
#
# labels = mkOption {};
mac-address = mkOption {
type = nullOr str;
default = null;
description = "A static mac address for the pod network.";
};
network = mkOption {
type = nullOr str;
default = null;
description = "Network configuration for the pod.";
};
network-alias = mkOption {
type = nullOr str;
default = null;
description = "DNS alias for the pod.";
};
no-hosts = mkOption {
type = nullOr bool;
default = null;
description = "Whether to disable /etc/hosts creation for the pod.";
};
publish = mkOption {
type = listOf str;
default = [];
description = "List of ports to publish from the pod.";
};
share = mkOption {
type = listOf str;
default = [];
description = "List of kernel namespaces to share.";
};
containers = options.virtualisation.oci-containers.containers;
};
});
default = {};
description = "Podman pods to run as systemd services.";
};
config = let
# Merge a list of attribute sets together
#
# TODO: See if there's a generic version for this somewhere in the
# pkgs lib?
mergeAttrs = attrList: foldr (a: b: a // b) {} attrList;
# Create services for all defined pods
pod-services = mapAttrs' (n: v: nameValuePair "pod-${n}" (mkPod n v)) cfg;
# Override the systemd-specific settings of containers defined in
# pods.
#
# I.e., make a systemd unit dependency on the pod service.
pod-container-services = mergeAttrs (mapAttrsToList (pname: pod:
mapAttrs' (cname: container:
nameValuePair "podman-${pname}-${cname}" rec {
after = ["pod-${pname}.service"];
requires = after;
})
pod.containers)
cfg);
# Override the oci-container settings for containers defined in pods.
#
# I.e., set the --pod=podname setting, and update the dependsOn so
# it points to containers in the same pod.
podifyContainer = container: podname:
container
// {
dependsOn =
map (dependency: "${podname}-${dependency}") container.dependsOn;
extraOptions = container.extraOptions ++ ["--pod=${podname}"];
};
in
lib.mkIf (cfg != {}) {
virtualisation.podman.enable = true;
virtualisation.oci-containers.backend = "podman";
systemd.services = pod-services // pod-container-services;
virtualisation.oci-containers.containers = mergeAttrs (mapAttrsToList
(pname: pod:
mapAttrs' (cname: container:
nameValuePair "${pname}-${cname}" (podifyContainer container pname))
pod.containers)
cfg);
};
}