simple-web-app.nix (3285B)
1 { 2 config, 3 lib, 4 pkgs, 5 ... 6 }: 7 8 with lib; 9 10 let 11 cfg = config.services.simple-web-app; 12 in 13 { 14 options = { 15 services.simple-web-app = { 16 enable = mkEnableOption "Simple Web App"; 17 18 package = mkOption { 19 defaultText = lib.literalMD "`packages.default` from the simple-web-app flake"; 20 }; 21 22 addr = mkOption { 23 type = types.str; 24 default = "0.0.0.0:8000"; 25 description = "Address to bind the server to."; 26 }; 27 28 dbPath = mkOption { 29 type = types.str; 30 default = "/var/lib/simple-web-app/data/app.db"; 31 description = "Path to the SQLite database file."; 32 }; 33 34 }; 35 }; 36 37 config = mkIf cfg.enable { 38 systemd.services.simple-web-app = { 39 wantedBy = [ "multi-user.target" ]; 40 description = "Run simple web app."; 41 after = [ "network.target" ]; 42 serviceConfig = { 43 Type = "simple"; 44 ExecStart = "${cfg.package}/bin/simple-web-app"; 45 DynamicUser = true; 46 StateDirectory = "simple-web-app"; 47 StateDirectoryMode = "0755"; 48 }; 49 environment = { 50 ADDR = cfg.addr; 51 DEBUG = "false"; 52 DB_PATH = cfg.dbPath; 53 SMTP_ADDR = "localhost:25"; 54 SMTP_FROM = "noreply@silasbrack.com"; 55 SITE_URL = "https://simple.fnarglebeast.com"; 56 }; 57 }; 58 59 services.nginx.virtualHosts."simple.fnarglebeast.com" = { 60 forceSSL = true; 61 enableACME = true; 62 locations."/" = { 63 proxyPass = "http://127.0.0.1:8000"; 64 recommendedProxySettings = true; 65 }; 66 }; 67 68 69 # Serve logs — firewall restricts to VPN (wg0) only 70 networking.firewall.interfaces."wg0".allowedTCPPorts = [ 9090 ]; 71 services.nginx.virtualHosts."simple-web-app-logs" = { 72 listen = [{ addr = "0.0.0.0"; port = 9090; }]; 73 locations."/" = { 74 root = "/mnt/volume-hel1-1/logs"; 75 extraConfig = "autoindex on;"; 76 }; 77 }; 78 79 # Archive logs to volume 80 systemd.services.log-collection = { 81 script = let 82 logDir = "/mnt/volume-hel1-1/logs"; 83 in '' 84 PREVIOUS_HOUR=$(${pkgs.coreutils}/bin/date -d '1 hour ago 5 minutes ago' +%Y-%m-%dT%H:00:00) 85 CURRENT_HOUR=$(${pkgs.coreutils}/bin/date -d '5 minutes ago' +%Y-%m-%dT%H:00:00) 86 DATEPATH=$(date -d "$PREVIOUS_HOUR" +%Y/%m/%d/%H) 87 88 # App logs (journald) 89 mkdir -p ${logDir}/app/$(dirname $DATEPATH) 90 journalctl -u simple-web-app \ 91 --since=$PREVIOUS_HOUR \ 92 --until=$CURRENT_HOUR \ 93 -o json | \ 94 ${pkgs.gzip}/bin/gzip \ 95 > ${logDir}/app/$DATEPATH.json.gz 96 97 # Nginx access logs (raw lines, not JSON) 98 mkdir -p ${logDir}/nginx/$(dirname $DATEPATH) 99 ${pkgs.gawk}/bin/awk -v start="$(date -d "$PREVIOUS_HOUR" '+%d/%b/%Y:%H')" \ 100 '$0 ~ "\\[" start' /var/log/nginx/access.log | \ 101 ${pkgs.gzip}/bin/gzip \ 102 > ${logDir}/nginx/$DATEPATH.log.gz 103 ''; 104 serviceConfig = { 105 Type = "oneshot"; 106 User = "root"; 107 }; 108 }; 109 systemd.timers = { 110 log-collection = { 111 wantedBy = [ "timers.target" ]; 112 timerConfig = { 113 OnCalendar = "hourly"; 114 Persistent = true; 115 Unit = "log-collection.service"; 116 }; 117 }; 118 }; 119 }; 120 }