This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / 2configs / timeful.nix
3.8 kB 118 lines
1{ 2 config, 3 lib, 4 pkgs, 5 self, 6 ... 7}: 8let 9 domain = "when.lassul.us"; 10 port = 3002; 11 timeful = self.packages.${pkgs.system}.timeful; 12in 13{ 14 # timeful (formerly schej): crab.fit/when2meet-style availability polls. 15 # Creating a poll and painting availability work without an account; 16 # signing in (GitHub OAuth, see pkgs/timeful/self-host.patch) keeps a 17 # dashboard of your polls. 18 services.mongodb = { 19 enable = true; 20 # prebuilt binary; the default `mongodb` builds from source for hours 21 package = pkgs.mongodb-ce; 22 }; 23 24 clan.core.vars.generators.timeful = { 25 files.env = { }; 26 runtimeInputs = [ pkgs.openssl ]; 27 # ENCRYPTION_KEY is fed raw to aes.NewCipher, so it must be exactly 28 # 16/24/32 bytes (upstream's `openssl rand -base64 32` hint is 44 bytes). 29 script = '' 30 { 31 echo "SESSION_SECRET=$(openssl rand -hex 32)" 32 echo "ENCRYPTION_KEY=$(openssl rand -hex 16)" 33 } > $out/env 34 ''; 35 }; 36 37 # GitHub OAuth app (https://github.com/settings/developers), callback URL 38 # https://when.lassul.us/api/auth/github/callback 39 clan.core.vars.generators.timeful-github = { 40 files.env = { }; 41 prompts.client_id = { 42 description = "GitHub OAuth app client ID for ${domain}"; 43 persist = true; 44 }; 45 prompts.client_secret = { 46 description = "GitHub OAuth app client secret for ${domain}"; 47 type = "hidden"; 48 persist = true; 49 }; 50 script = '' 51 printf 'GITHUB_CLIENT_ID=%s\nGITHUB_CLIENT_SECRET=%s\n' \ 52 "$(cat "$prompts"/client_id)" "$(cat "$prompts"/client_secret)" > "$out/env" 53 ''; 54 }; 55 56 systemd.services.timeful = { 57 description = "timeful availability polls"; 58 wantedBy = [ "multi-user.target" ]; 59 requires = [ "mongodb.service" ]; 60 after = [ 61 "network.target" 62 "mongodb.service" 63 ]; 64 environment = { 65 LISTEN_ADDR = "127.0.0.1:${toString port}"; 66 MONGODB_URI = "mongodb://127.0.0.1:27017"; 67 CORS_ORIGINS = "https://${domain}"; 68 # no listmonk mailing list; skip its HTTP calls on sign-up 69 LISTMONK_ENABLED = "false"; 70 }; 71 serviceConfig = { 72 ExecStart = "${lib.getExe timeful} -release"; 73 # The server unconditionally appends everything it prints to 74 # ./logs.log, which would grow forever; the journal already has it. 75 ExecStartPre = "${pkgs.coreutils}/bin/ln -sfn /dev/null logs.log"; 76 EnvironmentFile = [ 77 config.clan.core.vars.generators.timeful.files.env.path 78 config.clan.core.vars.generators.timeful-github.files.env.path 79 ]; 80 DynamicUser = true; 81 StateDirectory = "timeful"; 82 WorkingDirectory = "/var/lib/timeful"; 83 Restart = "on-failure"; 84 CapabilityBoundingSet = ""; 85 NoNewPrivileges = true; 86 PrivateDevices = true; 87 ProtectHome = true; 88 ProtectKernelTunables = true; 89 ProtectKernelModules = true; 90 ProtectControlGroups = true; 91 RestrictAddressFamilies = [ 92 "AF_INET" 93 "AF_INET6" 94 "AF_UNIX" 95 ]; 96 RestrictNamespaces = true; 97 LockPersonality = true; 98 SystemCallArchitectures = "native"; 99 }; 100 }; 101 102 services.nginx.virtualHosts.${domain} = { 103 enableACME = true; 104 forceSSL = true; 105 locations."/" = { 106 proxyPass = "http://127.0.0.1:${toString port}"; 107 # gin trusts every proxy and takes the leftmost X-Forwarded-For entry 108 # for its per-IP rate limiter, so overwrite instead of appending 109 # (recommendedProxySettings appends a client-controlled value). 110 extraConfig = '' 111 proxy_set_header Host $host; 112 proxy_set_header X-Real-IP $remote_addr; 113 proxy_set_header X-Forwarded-For $remote_addr; 114 proxy_set_header X-Forwarded-Proto $scheme; 115 ''; 116 }; 117 }; 118}