1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 inherit (lib)
10 mkEnableOption
11 mkPackageOption
12 mkIf
13 mkOption
14 types
15 literalExpression
16 ;
17
18 cfg = config.services.meme-bingo-web;
19in
20{
21 options = {
22 services.meme-bingo-web = {
23 enable = mkEnableOption ''
24 a web app for the meme bingo, rendered entirely on the web server and made interactive with forms.
25
26 Note: The application's author suppose to run meme-bingo-web behind a reverse proxy for SSL and HTTP/3
27 '';
28
29 package = mkPackageOption pkgs "meme-bingo-web" { };
30
31 baseUrl = mkOption {
32 description = ''
33 URL to be used for the HTML \<base\> element on all HTML routes.
34 '';
35 type = types.str;
36 default = "http://localhost:41678/";
37 example = "https://bingo.example.com/";
38 };
39 address = mkOption {
40 description = ''
41 The address the webserver will bind to.
42 '';
43 type = types.str;
44 default = "localhost";
45 example = "::";
46 };
47 port = mkOption {
48 description = ''
49 Port to be used for the web server.
50 '';
51 type = types.port;
52 default = 41678;
53 example = 21035;
54 };
55 openFirewall = mkEnableOption ''
56 Opens the specified port in the firewall.
57 '';
58 };
59 };
60
61 config = mkIf cfg.enable {
62 networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ];
63
64 systemd.services.meme-bingo-web = {
65 description = "A web app for playing meme bingos";
66 wantedBy = [ "multi-user.target" ];
67
68 environment = {
69 MEME_BINGO_BASE = cfg.baseUrl;
70 MEME_BINGO_ADDRESS = cfg.address;
71 MEME_BINGO_PORT = toString cfg.port;
72 };
73 path = [ cfg.package ];
74
75 serviceConfig = {
76 User = "meme-bingo-web";
77 Group = "meme-bingo-web";
78
79 DynamicUser = true;
80
81 ExecStart = "${cfg.package}/bin/meme-bingo-web";
82
83 Restart = "always";
84 RestartSec = 1;
85
86 # Hardening
87 CapabilityBoundingSet = [ "" ];
88 DeviceAllow = [ "/dev/random" ];
89 InaccessiblePaths = [
90 "/dev/shm"
91 "/sys"
92 "/run/dbus"
93 "/run/user"
94 "/run/nscd"
95 ];
96 LockPersonality = true;
97 PrivateDevices = true;
98 PrivateUsers = true;
99 ProcSubset = "pid";
100 ProtectSystem = "strict";
101 ProtectClock = true;
102 ProtectControlGroups = true;
103 ProtectHome = true;
104 ProtectHostname = true;
105 ProtectKernelLogs = true;
106 ProtectKernelModules = true;
107 ProtectKernelTunables = true;
108 ProtectProc = "invisible";
109 RestrictAddressFamilies = [
110 "AF_INET"
111 "AF_INET6"
112 ];
113 RestrictFilesystems = [
114 "@basic-api"
115 "~sysfs"
116 ];
117 RestrictNamespaces = true;
118 RestrictRealtime = true;
119 SystemCallArchitectures = "native";
120 SystemCallFilter = [
121 "@system-service"
122 "~@privileged"
123 "~@resources"
124 ];
125 UMask = "0077";
126 RestrictSUIDSGID = true;
127 RemoveIPC = true;
128 NoNewPrivileges = true;
129 MemoryDenyWriteExecute = true;
130 ExecPaths = [ "/nix/store" ];
131 NoExecPaths = [ "/" ];
132 };
133 };
134 };
135}