{ config, lib, pkgs, ... }: with lib; let nginxSsoAuth = pkgs.writeText "nginx-sso_auth.inc" '' # Protect this location using the auth_request auth_request /sso-auth; # Redirect the user to the login page when they are not logged in error_page 401 = @error401; location /sso-auth { # Do not allow requests from outside internal; # Access /auth endpoint to query login state proxy_pass http://127.0.0.1:${toString(config.services.nginx.sso.configuration.listen.port)}/auth; # Do not forward the request body (nginx-sso does not care about it) proxy_pass_request_body off; proxy_set_header Content-Length ""; # Set custom information for ACL matching: Each one is available as # a field for matching: X-Host = x-host, ... proxy_set_header X-Origin-URI $request_uri; proxy_set_header X-Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } # If the user is lead to /logout redirect them to the logout endpoint # of ngninx-sso which then will redirect the user to / on the current host location /sso-logout { return 302 https://login.nyanlout.re/logout?go=$scheme://$http_host/; } # Define where to send the user to login and specify how to get back location @error401 { return 302 https://login.nyanlout.re/login?go=$scheme://$http_host$request_uri; } ''; nginxSimpleReverse = rport: { enableACME = true; forceSSL = true; locations."/" = { proxyPass = "http://127.0.0.1:${toString(rport)}/"; }; }; nginxAuthReverse = rport: { enableACME = true; forceSSL = true; extraConfig = '' include ${nginxSsoAuth}; ''; locations."/" = { proxyPass = "http://127.0.0.1:${toString(rport)}/"; extraConfig = '' auth_request_set $cookie $upstream_http_set_cookie; add_header Set-Cookie $cookie; ''; }; }; in { security.acme = { email = "paul@nyanlout.re"; acceptTerms = true; }; services = { nginx = { enable = true; package = pkgs.nginx.override { modules = with pkgs.nginxModules; [ rtmp ]; }; recommendedGzipSettings = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; commonHttpConfig = '' map $scheme $hsts_header { https "max-age=31536000; includeSubdomains; preload"; } add_header Strict-Transport-Security $hsts_header; add_header Referrer-Policy origin-when-cross-origin; error_page 500 502 503 504 https://nyanlout.re/errorpages/50x.html; ''; sso = { enable = true; environmentFile = "/mnt/secrets/nginx-sso.env"; configuration = { listen = { addr = "127.0.0.1"; port = 8082; }; login = { title = "LoutreOS login"; default_method = "simple"; hide_mfa_field = true; names.simple = "Username / Password"; }; cookie = { domain = ".nyanlout.re"; secure = true; }; audit_log = { targets = [ "fd://stdout" ]; events = [ "access_denied" "login_success" "login_failure" "logout" ]; }; providers.simple = { enable_basic_auth = true; users = { paul = "$2y$10$RMqeJF/hUasXZ5/SLKAu4uKKp6ac6qXCaRu4OY/fIN6ZYucDXzqYm"; }; groups = { admins = [ "paul" ]; }; }; acl = { rule_sets = [ { rules = [ { field = "x-host"; regexp = ".*"; } ]; allow = [ "@admins" ]; } ]; }; }; }; virtualHosts = { "nyanlout.re" = { default = true; enableACME = true; forceSSL = true; locations = { "/" = { alias = "/var/www/site-perso/"; }; "/errorpages/" = { alias = "/var/www/errorpages/"; }; "/.well-known/openpgpkey/" = { alias = "/var/lib/gnupg/wks/nyanlout.re"; extraConfig = '' add_header Access-Control-Allow-Origin * always; ''; }; }; }; "riot.nyanlout.re" = { enableACME = true; forceSSL = true; locations = { "/" = { root = pkgs.riot-web; }; }; }; "factorio.nyanlout.re" = { enableACME = true; forceSSL = true; locations = { "/" = { root = "/var/www/factorio"; }; }; }; "minecraft.nyanlout.re" = { enableACME = true; forceSSL = true; locations = { "/" = { root = "/var/www/minecraft-overviewer"; }; }; }; "musique-meyenheim.fr" = { enableACME = true; forceSSL = true; locations = { "/" = { proxyPass = "http://unix:/run/site-musique.sock"; }; "/static/" = { alias = "/var/www/site-musique/staticfiles/"; }; "/media/" = { alias = "/var/www/site-musique/media/"; }; }; }; "maxspiegel.fr" = { enableACME = true; forceSSL = true; locations."/" = { root = "/run/python-ci/nyanloutre/site-max"; }; }; "stream.nyanlout.re" = { enableACME = true; forceSSL = true; root = "/var/www/hls/"; locations."/" = { extraConfig = '' add_header Cache-Control no-cache; add_header Access-Control-Allow-Origin *; ''; }; }; "login.nyanlout.re" = { enableACME = true; forceSSL = true; locations."/" = { proxyPass = "http://127.0.0.1:${toString(config.services.nginx.sso.configuration.listen.port)}/"; }; }; "grafana.nyanlout.re" = nginxAuthReverse config.services.grafana.port; "transmission.nyanlout.re" = nginxAuthReverse config.services.transmission.port; "radarr.nyanlout.re" = nginxAuthReverse 7878; "sonarr.nyanlout.re" = nginxAuthReverse 8989; "syncthing.nyanlout.re" = nginxAuthReverse 8384; "jackett.nyanlout.re" = nginxAuthReverse 9117; "pgmanage.nyanlout.re" = nginxAuthReverse config.services.pgmanage.port; "matrix.nyanlout.re" = nginxSimpleReverse 8008; "airsonic.nyanlout.re" = nginxSimpleReverse 4040; "emby.nyanlout.re" = nginxSimpleReverse 8096; "ci.nyanlout.re" = nginxSimpleReverse 52350; "gitea.nyanlout.re" = nginxSimpleReverse config.services.gitea.httpPort; }; appendConfig = '' rtmp { server { listen 1935; application live { live on; exec_push ${pkgs.ffmpeg}/bin/ffmpeg -i rtmp://localhost/$app/$name -async 1 -vsync -1 -c:v libx264 -c:a aac -b:v 768k -b:a 96k -vf "scale=720:trunc(ow/a/2)*2" -tune zerolatency -preset ultrafast -crf 28 -f flv rtmp://localhost/show/$name_mid -c:v libx264 -c:a aac -b:v 1024k -b:a 128k -vf "scale=960:trunc(ow/a/2)*2" -tune zerolatency -preset ultrafast -crf 28 -f flv rtmp://localhost/show/$name_high -c copy -f flv rtmp://localhost/show/$name_src 2>>${config.services.nginx.virtualHosts."stream.nyanlout.re".root}/ffmpeg-$name.log; } application show { live on; hls on; hls_path ${config.services.nginx.virtualHosts."stream.nyanlout.re".root}; hls_fragment 3s; hls_playlist_length 60s; hls_variant _mid BANDWIDTH=448000; # Medium bitrate, SD resolution hls_variant _high BANDWIDTH=1152000; # High bitrate, higher-than-SD resolution hls_variant _src BANDWIDTH=4096000; # Source bitrate, source resolution } } } ''; }; postgresql.enable = true; pgmanage = { enable = true; port = 10006; connections = { localhost = "hostaddr=127.0.0.1 port=5432 dbname=postgres"; }; }; gitea = { enable = true; cookieSecure = true; httpPort = 3001; rootUrl = "https://gitea.nyanlout.re/"; database = { type = "postgres"; port = 5432; passwordFile = "/var/lib/gitea/custom/conf/database_password"; }; log.level = "Warn"; extraConfig = '' [ui] DEFAULT_THEME = arc-green [service] DISABLE_REGISTRATION = true ''; }; python-ci.enable = true; }; systemd.services.site-musique = let djangoEnv =(pkgs.python3.withPackages (ps: with ps; [ gunicorn django_2_2 pillow setuptools ])); in { description = "Site Django de la musique de Meyenheim"; after = [ "network.target" ]; requires = [ "site-musique.socket" ]; preStart = '' ${djangoEnv}/bin/python manage.py migrate; ${djangoEnv}/bin/python manage.py collectstatic --no-input; ''; environment = { DJANGO_SETTINGS_MODULE = "site_musique.settings.prod"; NGINX_DIRECTORY = "/var/www/site-musique"; }; serviceConfig = { DynamicUser = true; Group = "nginx"; StateDirectory = "site-musique"; WorkingDirectory = "/var/www/site-musique/"; ReadWritePaths = [ "/var/www/site-musique/staticfiles" "/var/www/site-musique/media" ]; EnvironmentFile = "/mnt/secrets/site-musique.env"; ExecStart = ''${djangoEnv}/bin/gunicorn \ --access-logfile - \ --bind unix:/run/site-musique.sock \ site_musique.wsgi:application ''; PrivateTmp = true; }; }; systemd.sockets.site-musique = { description = "Site Musique socket"; wantedBy = [ "sockets.target" ]; listenStreams = [ "/run/site-musique.sock" ]; }; }