mirror of https://gitlab.crans.org/nounous/nixos
322 lines
10 KiB
Nix
322 lines
10 KiB
Nix
{
|
||
lib,
|
||
config,
|
||
...
|
||
}:
|
||
|
||
let
|
||
cfg = config.crans.reverseProxy;
|
||
|
||
mainTld = "org";
|
||
otherTld = [
|
||
"fr"
|
||
"eu"
|
||
];
|
||
|
||
inherit (lib)
|
||
literalExpression
|
||
mkEnableOption
|
||
mkIf
|
||
mkOption
|
||
types
|
||
;
|
||
in
|
||
|
||
{
|
||
options.crans.reverseProxy = {
|
||
enable = mkEnableOption "Configuration du reverseproxy.";
|
||
|
||
virtualHosts = mkOption {
|
||
type = types.attrsOf (
|
||
types.submodule {
|
||
options = {
|
||
serverAliases = mkOption {
|
||
type = types.listOf types.str;
|
||
default = [ ];
|
||
example = [
|
||
"everything"
|
||
"voyager"
|
||
];
|
||
description = ''
|
||
Déclaration des alias.
|
||
'';
|
||
};
|
||
|
||
proxyPass = mkOption {
|
||
type = types.nullOr types.str;
|
||
default = null;
|
||
description = ''
|
||
Indique la destination à proxy.
|
||
'';
|
||
example = "172.16.10.128:8000";
|
||
};
|
||
|
||
serveLocalFiles = mkOption {
|
||
type = types.nullOr types.path;
|
||
default = null;
|
||
description = ''
|
||
Chemin vers un dossier à exposer statiquement.
|
||
'';
|
||
example = "/var/local/adopter-un-manchot";
|
||
};
|
||
|
||
globalRedirect = mkOption {
|
||
type = types.nullOr types.str;
|
||
default = null;
|
||
description = ''
|
||
Si définie, toutes les requêtes sont redirigées (via 301) sur cet hôte.
|
||
'';
|
||
example = "perso.crans.org/club";
|
||
};
|
||
|
||
anubisConfig = mkOption {
|
||
type = types.nullOr types.str;
|
||
default = null;
|
||
description = ''
|
||
Chemin du fichier de configuration
|
||
'';
|
||
example = "/var/www/anubis.conf";
|
||
};
|
||
|
||
anubisOpenGraph = mkOption {
|
||
type = types.bool;
|
||
default = true;
|
||
description = ''
|
||
Activer openGraph pour l'indexation et l'embedding
|
||
'';
|
||
};
|
||
|
||
httpOnly = mkOption {
|
||
type = types.bool;
|
||
default = false;
|
||
description = ''
|
||
Interdit les connexions en https
|
||
'';
|
||
example = "true";
|
||
};
|
||
|
||
proxyWebsockets = mkOption {
|
||
type = types.bool;
|
||
default = false;
|
||
description = ''
|
||
Activer les websockets
|
||
'';
|
||
example = "true";
|
||
};
|
||
};
|
||
}
|
||
);
|
||
|
||
default = { };
|
||
|
||
example = literalExpression ''
|
||
{
|
||
"framadate" = {
|
||
host = "176.16.10.128:8000";
|
||
serverAliases = [
|
||
"everything"
|
||
"voyager"
|
||
]
|
||
};
|
||
};
|
||
'';
|
||
description = "Déclaration des machines.";
|
||
};
|
||
};
|
||
|
||
config = {
|
||
systemd.services = lib.mapAttrs (vhostName: vhostConfig: {
|
||
wantedBy = [ "multi-user.target" ];
|
||
}) cfg.virtualHosts;
|
||
|
||
# On fait un certificat commun pour tous les hosts
|
||
security.acme.certs."all.crans.all" = mkIf cfg.enable {
|
||
domain = "*.crans.${mainTld}";
|
||
dnsProvider = "rfc2136";
|
||
# Contient le serveur à contacter avec le protocole
|
||
# et le mot de passe
|
||
environmentFile = config.age.secrets.acme-env.path;
|
||
extraDomainNames =
|
||
lib.concatMap (tld: [
|
||
"*.crans.${tld}"
|
||
"crans.${tld}"
|
||
]) otherTld
|
||
++ [
|
||
"crans.${mainTld}"
|
||
];
|
||
group = config.services.nginx.group;
|
||
};
|
||
|
||
# Création des dossiers de logs
|
||
system.activationScripts = {
|
||
nginx-logs = {
|
||
text =
|
||
lib.concatMapStrings (f: "mkdir -p /var/log/nginx/${f}/\n") (
|
||
[ "anubis" ] ++ (lib.map (hn: "host/${hn}") (builtins.attrNames cfg.virtualHosts))
|
||
)
|
||
+ "chown -R ${config.services.nginx.user}:${config.services.nginx.group} /var/log/nginx/\n";
|
||
};
|
||
};
|
||
|
||
services = mkIf cfg.enable {
|
||
anubis = {
|
||
defaultOptions.group = "nginx";
|
||
instances = lib.mapAttrs (
|
||
vhostName: vhostConfig:
|
||
mkIf (vhostConfig.anubisConfig != null) {
|
||
enable = true;
|
||
settings = {
|
||
BIND = "/run/anubis/anubis-${vhostName}/socket.sock";
|
||
BIND_NETWORK = "unix";
|
||
METRICS_BIND = "/run/anubis/anubis-${vhostName}/anubis-${vhostName}-metrics.sock";
|
||
TARGET = "unix:///run/nginx/nginx-${vhostName}.sock";
|
||
COOKIE_DOMAIN = "crans.${mainTld}";
|
||
REDIRECT_DOMAINS = "${vhostName}.crans.${mainTld}";
|
||
SOCKET_MODE = "0660";
|
||
# OpenGraph config
|
||
OG_PASSTHROUGH = vhostConfig.anubisOpenGraph;
|
||
OG_EXPIRY_TIME = "24h";
|
||
OG_CACHE_CONSIDER_HOST = true;
|
||
# Policy config
|
||
POLICY_FNAME = vhostConfig.anubisConfig;
|
||
};
|
||
}
|
||
) cfg.virtualHosts;
|
||
};
|
||
|
||
logrotate.settings =
|
||
let
|
||
# https://github.com/NixOS/nixpkgs/blob/nixos-26.05/nixos/modules/services/web-servers/nginx/default.nix
|
||
base = {
|
||
su = "${config.services.nginx.user} ${config.services.nginx.group}";
|
||
postrotate = "[ ! -f /var/run/nginx/nginx.pid ] || kill -USR1 `cat /var/run/nginx/nginx.pid`";
|
||
frequency = "daily";
|
||
ifempty = true;
|
||
compress = true;
|
||
delaycompress = true;
|
||
dateyesterday = true;
|
||
};
|
||
in
|
||
{
|
||
nginx-anubis = base // {
|
||
files = [ "/var/log/nginx/anubis/*.log" ];
|
||
rotate = 7; # une semaine de log pour débugguer
|
||
};
|
||
nginx-hosts = base // {
|
||
files = [ "/var/log/nginx/host/*/*.log" ];
|
||
rotate = 173; # 6 mois de logs
|
||
dateext = true;
|
||
dateformat = "%Y-%m-%d";
|
||
};
|
||
};
|
||
|
||
nginx =
|
||
let
|
||
configVhost =
|
||
vhostName: vhostConfig:
|
||
let
|
||
sslConf = {
|
||
forceSSL = !vhostConfig.httpOnly;
|
||
rejectSSL = vhostConfig.httpOnly;
|
||
useACMEHost = mkIf (!vhostConfig.httpOnly) "all.crans.all";
|
||
acmeRoot = null;
|
||
};
|
||
|
||
# Conf pour l’hôte en entrée
|
||
entryExtraConf = {
|
||
extraConfig = ''
|
||
set_real_ip_from 172.16.0.0/16;
|
||
set_real_ip_from fd00::/56;
|
||
real_ip_header X-Real-Ip;
|
||
'';
|
||
}
|
||
// sslConf;
|
||
# Conf supplémentaire pour le proxy principal
|
||
vhostExtraConf =
|
||
if vhostConfig.anubisConfig != null then
|
||
# Il reçoit les requêtes d’Anubis
|
||
{
|
||
listen = [
|
||
{ addr = "unix:/run/nginx/nginx-${vhostName}.sock"; }
|
||
];
|
||
extraConfig = ''
|
||
set_real_ip_from unix:;
|
||
real_ip_header X-Real-IP;
|
||
'';
|
||
}
|
||
else
|
||
# Il est en entrée
|
||
entryExtraConf;
|
||
|
||
logHostConf = ''
|
||
access_log /var/log/nginx/host/${vhostName}/access.log;
|
||
error_log /var/log/nginx/host/${vhostName}/error.log;
|
||
'';
|
||
|
||
# Les alias : vhostName × otherTld U serverAliases × allTld
|
||
mkHostName = als: tld: if als == "." then "crans.${tld}" else "${als}.crans.${tld}";
|
||
aliases =
|
||
lib.foldr
|
||
(
|
||
tld: acc:
|
||
acc
|
||
++ (lib.foldr (alias: acc: acc ++ [ (mkHostName alias tld) ]) [
|
||
(mkHostName vhostName tld)
|
||
] vhostConfig.serverAliases)
|
||
)
|
||
(lib.foldr (alias: acc: acc ++ [ (mkHostName alias mainTld) ]) [ ] vhostConfig.serverAliases)
|
||
otherTld;
|
||
in
|
||
{
|
||
# Configuration du service à proxy.
|
||
"${vhostName}" = vhostExtraConf // {
|
||
serverName = mkHostName vhostName mainTld;
|
||
locations."/" = mkIf (vhostConfig.proxyPass != null) {
|
||
proxyPass = "http://${vhostConfig.proxyPass}";
|
||
proxyWebsockets = vhostConfig.proxyWebsockets;
|
||
};
|
||
root = vhostConfig.serveLocalFiles;
|
||
globalRedirect = vhostConfig.globalRedirect;
|
||
extraConfig = vhostExtraConf.extraConfig + logHostConf;
|
||
};
|
||
|
||
# Entrée d’Anubis
|
||
"${vhostName}-anubis" = mkIf (vhostConfig.anubisConfig != null) (
|
||
entryExtraConf
|
||
// rec {
|
||
serverName = mkHostName vhostName mainTld;
|
||
locations."/" = {
|
||
proxyPass = "http://unix:/run/anubis/anubis-${vhostName}/socket.sock";
|
||
proxyWebsockets = vhostConfig.proxyWebsockets;
|
||
};
|
||
locations."/.within.website/x/cmd/anubis/api/honeypot/" = locations."/" // {
|
||
extraConfig = ''
|
||
add_header 'X-Robots-Tag' 'noindex,nofollow' always;
|
||
'';
|
||
};
|
||
extraConfig = entryExtraConf.extraConfig + ''
|
||
access_log /var/log/nginx/anubis/access.log;
|
||
error_log /var/log/nginx/anubis/error.log;
|
||
'';
|
||
}
|
||
);
|
||
}
|
||
# Les alias
|
||
// lib.mergeAttrsList (
|
||
lib.map (alias: {
|
||
"${vhostName}-alias-${alias}" = sslConf // {
|
||
serverName = alias;
|
||
globalRedirect = lib.defaultTo "${vhostName}.crans.${mainTld}" vhostConfig.globalRedirect;
|
||
extraConfig = logHostConf;
|
||
};
|
||
}) aliases
|
||
);
|
||
in
|
||
{
|
||
enable = true;
|
||
virtualHosts = lib.concatMapAttrs configVhost cfg.virtualHosts;
|
||
};
|
||
};
|
||
};
|
||
}
|