From 6d22256a85df7228a356a802dbc513c8abeeb2b7 Mon Sep 17 00:00:00 2001 From: Linnnus Date: Sun, 1 Oct 2023 21:48:51 +0200 Subject: Export modules --- modules/cloudflare-proxy/default.nix | 39 --- modules/darwin/default.nix | 4 + modules/darwin/still-awake/default.nix | 50 ++++ modules/default.nix | 11 - modules/graphics/default.nix | 36 --- modules/linus.onl/default.nix | 98 ------- modules/nixos/cloudflare-proxy/default.nix | 39 +++ modules/nixos/default.nix | 10 + modules/nixos/duksebot/default.nix | 71 +++++ modules/nixos/on-demand-minecraft/default.nix | 359 ++++++++++++++++++++++++++ modules/notifications.linus.onl/default.nix | 42 --- 11 files changed, 533 insertions(+), 226 deletions(-) delete mode 100644 modules/cloudflare-proxy/default.nix create mode 100644 modules/darwin/default.nix create mode 100644 modules/darwin/still-awake/default.nix delete mode 100644 modules/default.nix delete mode 100644 modules/graphics/default.nix delete mode 100644 modules/linus.onl/default.nix create mode 100644 modules/nixos/cloudflare-proxy/default.nix create mode 100644 modules/nixos/default.nix create mode 100644 modules/nixos/duksebot/default.nix create mode 100644 modules/nixos/on-demand-minecraft/default.nix delete mode 100644 modules/notifications.linus.onl/default.nix (limited to 'modules') diff --git a/modules/cloudflare-proxy/default.nix b/modules/cloudflare-proxy/default.nix deleted file mode 100644 index 73d8893..0000000 --- a/modules/cloudflare-proxy/default.nix +++ /dev/null @@ -1,39 +0,0 @@ -# This module adds some extra configuration useful when running behid a Cloudflare Proxy. -# - -{ config, lib, pkgs, ... }: - -let - inherit (lib) mkEnableOption mkIf; - - cfg = config.my.modules.cloudflare-proxy; -in -{ - options.my.modules.cloudflare-proxy.enable = mkEnableOption "Cloudflare proxy IP extraction for NGINX"; - - config = mkIf cfg.enable { - # Teach NGINX how to extract the proxied IP from proxied requests. - # - # See: https://nixos.wiki/wiki/Nginx#Using_realIP_when_behind_CloudFlare_or_other_CDN - services.nginx.commonHttpConfig = - let - realIpsFromList = lib.strings.concatMapStringsSep "\n" (x: "set_real_ip_from ${x};"); - fileToList = x: lib.strings.splitString "\n" (builtins.readFile x); - cfipv4 = fileToList (pkgs.fetchurl { - url = "https://www.cloudflare.com/ips-v4"; - sha256 = "0ywy9sg7spafi3gm9q5wb59lbiq0swvf0q3iazl0maq1pj1nsb7h"; - }); - cfipv6 = fileToList (pkgs.fetchurl { - url = "https://www.cloudflare.com/ips-v6"; - sha256 = "1ad09hijignj6zlqvdjxv7rjj8567z357zfavv201b9vx3ikk7cy"; - }); - in - '' - ${realIpsFromList cfipv4} - ${realIpsFromList cfipv6} - real_ip_header CF-Connecting-IP; - ''; - - # TODO: Only allow incomming HTTP{,S} requests from non-Cloudflare IPs. - }; -} diff --git a/modules/darwin/default.nix b/modules/darwin/default.nix new file mode 100644 index 0000000..2419e48 --- /dev/null +++ b/modules/darwin/default.nix @@ -0,0 +1,4 @@ + +{ + still-awake = import ./still-awake; +} diff --git a/modules/darwin/still-awake/default.nix b/modules/darwin/still-awake/default.nix new file mode 100644 index 0000000..9221359 --- /dev/null +++ b/modules/darwin/still-awake/default.nix @@ -0,0 +1,50 @@ +{ pkgs, lib, config, ... }: + +let + inherit (lib) mkIf mkEnableOption; + + cfg = config.my.services.still-awake; +in +{ + options.my.services.still-awake.enable = mkEnableOption "still-awake launchd job"; + + config = mkIf cfg.enable { + launchd.agents."still-awake" = + let + # https://macperformanceguide.com/blog/2022/20221125_2044-launch_daemon-launchctl-posix-spawn-permission-denied.html + log-file = "/tmp/still-awake.log"; + in + { + enable = true; + config = { + ProgramArguments = [ "${pkgs.still-awake}/bin/still-awake" ]; + ProcessType = "Interactive"; + + # WARNING: These times must match the ones specified in ${source}! + StartCalendarInterval = [ + { Hour = 21; Minute = 30; } + { Hour = 22; } + { Hour = 22; Minute = 30; } + { Hour = 23; } + { Hour = 23; Minute = 30; } + { Hour = 23; } + { Hour = 23; Minute = 30; } + { Hour = 00; } + { Hour = 00; Minute = 30; } + { Hour = 01; } + { Hour = 01; Minute = 30; } + { Hour = 02; } + { Hour = 02; Minute = 30; } + { Hour = 03; } + { Hour = 03; Minute = 30; } + { Hour = 04; } + { Hour = 04; Minute = 30; } + { Hour = 05; } + ]; + + StandardOutPath = log-file; + StandardErrorPath = log-file; + }; + }; + }; +} diff --git a/modules/default.nix b/modules/default.nix deleted file mode 100644 index 3015d59..0000000 --- a/modules/default.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ ... }: - -{ - imports = - [ - ./linus.onl - ./notifications.linus.onl - ./cloudflare-proxy - ./graphics - ]; -} diff --git a/modules/graphics/default.nix b/modules/graphics/default.nix deleted file mode 100644 index e2b7a86..0000000 --- a/modules/graphics/default.nix +++ /dev/null @@ -1,36 +0,0 @@ -# This module configures a basic graphical environment. I use this sometimes for -# ahmed when muhammed is being repaired. - -{ config, lib, pkgs, ... }: - -let - inherit (lib) mkEnableOption mkIf; - - cfg = config.my.modules.graphics; -in -{ - options.my.modules.graphics.enable = mkEnableOption "basic graphical environment"; - - config = mkIf cfg.enable { - services.xserver.enable = true; - - # Match console keyboard layout but swap capslock and escape. - # TODO: Create a custom keymap with esc/capslock swap so console can use it. - services.xserver.layout = config.console.keyMap; - services.xserver.xkbOptions = "caps:swapescape"; - - # Enable touchpad support. - services.xserver.libinput.enable = true; - - services.xserver.windowManager.dwm.enable = true; - - # Enable sound. - sound.enable = true; - hardware.pulseaudio.enable = true; - - environment.systemPackages = with pkgs; [ - st # suckless terminal - dwm is pretty sucky without this - dmenu # application launcher - ]; - }; -} diff --git a/modules/linus.onl/default.nix b/modules/linus.onl/default.nix deleted file mode 100644 index 617865c..0000000 --- a/modules/linus.onl/default.nix +++ /dev/null @@ -1,98 +0,0 @@ -{ pkgs, lib, config, ... }: - -let - inherit (lib) mkEnableOption mkOption types mkIf optional; - - domain = "linus.onl"; - - cfg = config.my.modules."${domain}"; -in -{ - options.my.modules."${domain}" = { - enable = mkEnableOption "${domain} static site"; - - useACME = mkEnableOption "built-in HTTPS stuff"; - }; - - config = mkIf cfg.enable { - # Create a user to run the build script under. - users.users."${domain}-builder" = { - description = "builds ${domain}"; - group = "${domain}-builder"; - isSystemUser = true; - }; - users.groups."${domain}-builder" = { }; - - # Create the output directory. - system.activationScripts."${domain}-create-www" = lib.stringAfter [ "var" ] '' - mkdir -p /var/www/${domain} - chown ${domain}-builder /var/www/${domain} - chgrp ${domain}-builder /var/www/${domain} - chmod 0755 /var/www/${domain} - ''; - - # Create a systemd service which rebuild the site regularly. - # - # This can't be done using Nix because the site relies on the git build and - # there are some inherent difficulties with including .git/ in the - # inputSource for derivations. - # - # See: https://github.com/NixOS/nix/issues/6900 - # See: https://github.com/NixOS/nixpkgs/issues/8567 - # - # TODO: Integrate rebuilding with GitHub webhooks to rebuild on push. - systemd.services."${domain}-source" = { - description = "generate https://${domain} source"; - - serviceConfig = { - Type = "oneshot"; - User = "${domain}-builder"; - Group = "${domain}-builder"; - }; - startAt = "*-*-* *:00/5:00"; - - path = with pkgs; [ - git - rsync - coreutils-full - tcl-8_5 - gnumake - ]; - environment.TCLLIBPATH = "$TCLLIBPATH ${pkgs.tcl-cmark}/lib/tclcmark1.0"; - script = '' - set -ex - tmpdir="$(mktemp -d -t linus.onl-source.XXXXXXXXXXXX)" - cd "$tmpdir" - trap 'rm -rf $tmpdir' EXIT - # TODO: Only do minimal possible cloning - git clone https://github.com/linnnus/${domain} . - make _build - rsync --archive --delete _build/ /var/www/${domain} - ''; - - # TODO: Harden service - - # Network must be online for us to check. - after = [ "network-online.target" ]; - requires = [ "network-online.target" ]; - - # We must generate some files for NGINX to serve, so this should be run - # before NGINX. - before = [ "nginx.service" ]; - wantedBy = [ "nginx.service" ]; - }; - - # Register domain name with ddns. - services.cloudflare-dyndns.domains = [ domain ]; - - # Register virtual host. - services.nginx = { - virtualHosts."${domain}" = { - # NOTE: 'forceSSL' will cause an infite loop, if the cloudflare proxy does NOT connect over HTTPS. - enableACME = cfg.useACME; - forceSSL = cfg.useACME; - root = "/var/www/${domain}"; - }; - }; - }; -} diff --git a/modules/nixos/cloudflare-proxy/default.nix b/modules/nixos/cloudflare-proxy/default.nix new file mode 100644 index 0000000..73d8893 --- /dev/null +++ b/modules/nixos/cloudflare-proxy/default.nix @@ -0,0 +1,39 @@ +# This module adds some extra configuration useful when running behid a Cloudflare Proxy. +# + +{ config, lib, pkgs, ... }: + +let + inherit (lib) mkEnableOption mkIf; + + cfg = config.my.modules.cloudflare-proxy; +in +{ + options.my.modules.cloudflare-proxy.enable = mkEnableOption "Cloudflare proxy IP extraction for NGINX"; + + config = mkIf cfg.enable { + # Teach NGINX how to extract the proxied IP from proxied requests. + # + # See: https://nixos.wiki/wiki/Nginx#Using_realIP_when_behind_CloudFlare_or_other_CDN + services.nginx.commonHttpConfig = + let + realIpsFromList = lib.strings.concatMapStringsSep "\n" (x: "set_real_ip_from ${x};"); + fileToList = x: lib.strings.splitString "\n" (builtins.readFile x); + cfipv4 = fileToList (pkgs.fetchurl { + url = "https://www.cloudflare.com/ips-v4"; + sha256 = "0ywy9sg7spafi3gm9q5wb59lbiq0swvf0q3iazl0maq1pj1nsb7h"; + }); + cfipv6 = fileToList (pkgs.fetchurl { + url = "https://www.cloudflare.com/ips-v6"; + sha256 = "1ad09hijignj6zlqvdjxv7rjj8567z357zfavv201b9vx3ikk7cy"; + }); + in + '' + ${realIpsFromList cfipv4} + ${realIpsFromList cfipv6} + real_ip_header CF-Connecting-IP; + ''; + + # TODO: Only allow incomming HTTP{,S} requests from non-Cloudflare IPs. + }; +} diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix new file mode 100644 index 0000000..9ad08e5 --- /dev/null +++ b/modules/nixos/default.nix @@ -0,0 +1,10 @@ +{ + ## Reusable services. + + on-demand-minecraft = import ./on-demand-minecraft; + duksebot = import ./duksebot; + + ## Other miscellaneous configuration bits. These may be useful to other you. + + cloudflare-proxy = import ./cloudflare-proxy; +} diff --git a/modules/nixos/duksebot/default.nix b/modules/nixos/duksebot/default.nix new file mode 100644 index 0000000..c1dc5cf --- /dev/null +++ b/modules/nixos/duksebot/default.nix @@ -0,0 +1,71 @@ +# This module defines an on-demand minecraft server service which turns off the +# server when it's not being used. + +{ config, lib, pkgs, modulesPath, ... }: + +let + inherit (lib) mkIf mkOption mkEnableOption types; + + cfg = config.my.services.duksebot; +in +{ + options.my.services.duksebot = { + enable = mkEnableOption "duksebot daily reminder"; + + package = mkOption { + description = "What package to use"; + default = pkgs.duksebot; + type = types.package; + }; + }; + + config = mkIf cfg.enable { + # Create a user to run the server under. + users.users.duksebot = { + description = "Runs daily dukse reminder"; + group = "duksebot"; + isSystemUser = true; + home = "/srv/duksebot"; + createHome = true; + }; + users.groups.duksebot = { }; + + age.secrets.duksebot-env = { + file = ../../../secrets/duksebot.env.age; + owner = config.users.users.duksebot.name; + group = config.users.users.duksebot.group; + mode = "0440"; + }; + + # Create a service which simply runs script. This will be invoked by our timer. + systemd.services.duksebot = { + serviceConfig = { + # We only want to run this once every time the timer triggers it. + Type = "oneshot"; + # Run as the user we created above. + User = "duksebot"; + Group = "duksebot"; + WorkingDirectory = config.users.users.duksebot.home; + }; + script = '' + # Load the secret environment variables. + export $(grep -v '^#' ${config.age.secrets.duksebot-env.path} | xargs) + # Kick off. + exec "${cfg.package}"/bin/duksebot + ''; + }; + + # Create a timer to activate our oneshot service. + systemd.timers.duksebot = { + wantedBy = [ "timers.target" ]; + partOf = [ "duksebot.service" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; # FIXME: redundant? + timerConfig = { + # OnCalendar = "*-*-* 7:00:00"; + OnCalendar = "*:0/1"; + Unit = "duksebot.service"; + }; + }; + }; +} diff --git a/modules/nixos/on-demand-minecraft/default.nix b/modules/nixos/on-demand-minecraft/default.nix new file mode 100644 index 0000000..541a624 --- /dev/null +++ b/modules/nixos/on-demand-minecraft/default.nix @@ -0,0 +1,359 @@ +# This module defines an on-demand minecraft server service which turns off the +# server when it's not being used. + +{ config, lib, pkgs, modulesPath, ... }: + +let + inherit (lib) mkIf mkOption mkEnableOption types; + + cfg = config.my.services.on-demand-minecraft; +in +{ + options.my.services.on-demand-minecraft = { + enable = mkEnableOption "local minecraft server"; + + eula = mkOption { + description = '' + Whether you agree to [Mojangs EULA](https://account.mojang.com/documents/minecraft_eula). + This option must be set to `true` to run a Minecraft™️ server (??). + ''; + type = types.bool; + default = false; + }; + + frequency-check-players = mkOption { + description = '' + How often to check the number of players using the server. If + no players are using the server, it is shut down. + + This should be a valid value for systemd's `onCalendar` + property. + ''; + type = types.nonEmptyStr; + default = "*-*-* *:*:0/20"; + }; + + minimum-server-lifetime = mkOption { + description = '' + Minimum required time to pass from the server is started + before it is allowed to be killed. This should ensure the + server has time to start up before it is killed. + + The option is specified as a number of seconds. + ''; + type = types.ints.positive; + default = 300; + }; + + internal-port = mkOption { + description = '' + The internal port which the minecraft server will listen to. + This port does not need to be exposed to the network. + ''; + type = types.port; + default = cfg.external-port + 1; + }; + + external-port = mkOption { + description = '' + The external port of the socket which is forwarded to the + Minecraft server. This is the one users will connect to. You + will need to add it to `networking.firewall.allowedTCPPorts` + to open it in the firewall. + + You may also have to set up port forwarding if you want to + play with friends who are not on the same LAN. + ''; + type = types.port; + default = 25565; + }; + + rcon-password = mkOption { + description = '' + The RCON password used for remote control. + + Local systemd units use this password to execute commands + that fetch the current number of players. This number is used + to shut down the server, when there are no active players. + ''; + type = types.nonEmptyStr; + default = "260a368f55f4fb4fa"; # XXX: Is this a bad idea? + }; + + openFirewall = mkOption { + description = '' + Open holes in the firewall so clients on LAN can connect. You must + set up port forwarding if you want to play over WAN. + ''; + type = types.bool; + default = true; + }; + + package = mkOption { + description = "What Minecraft server to run."; + default = pkgs.minecraft-server; + type = types.package; + }; + + server-properties = mkOption { + description = '' + Minecraft server properties for the server.properties file. See + + for documentation on these values. Note that some options like + `enable-rcon` will be forced on because the're required for the + server to work. + ''; + type = with types; attrsOf (oneOf [ bool int str ]); + default = { }; + example = lib.literalExpression '' + { + difficulty = 3; + gamemode = 1; + motd = "My NixOS server!"; + } + ''; + }; + + jvm-options = mkOption { + description = "JVM options for the Minecraft server. List of command line arguments."; + type = types.listOf lib.types.str; + default = [ "-Xmx2048M" "-Xms2048M" ]; + }; + }; + + config = mkIf cfg.enable { + # Create a user to run the server under. + users.users.minecrafter = { + description = "On-demand minecraft server service user"; + home = "/srv/minecrafter"; + createHome = true; + group = "minecrafter"; + isSystemUser = true; + }; + users.groups.minecrafter = { }; + + # Create an internal socket and hook it up to minecraft-server process as + # stdin. That way we can send commands to it. + systemd.sockets.minecraft-server = { + bindsTo = [ "minecraft-server.service" ]; + socketConfig = { + ListenFIFO = "/run/minecraft-server.stdin"; + SocketMode = "0660"; + SocketUser = "minecrafter"; + SocketGroup = "minecrafter"; + RemoveOnStop = true; + FlushPending = true; + }; + }; + + # Create a service which runs the server. + systemd.services.minecraft-server = + let + server-properties = cfg.server-properties // { + server-port = cfg.internal-port; + enable-rcon = true; + "rcon.password" = cfg.rcon-password; + }; + cfg-to-str = v: + if builtins.isBool v + then (if v then "true" else "false") + else toString v; + server-properties-file = pkgs.writeText "server.properties" ('' + # server.properties managed by NixOS configuration. + '' + lib.concatStringsSep "\n" (lib.mapAttrsToList + (n: v: "${n}=${cfg-to-str v}") + server-properties)); + + # We don't allow eula=false anyways + eula-file = builtins.toFile "eula.txt" '' + # eula.txt managed by NixOS Configuration + eula=true + ''; + + # HACK: Each server is given its own subdirectory so + # incompatabilities between servers don't cause complaints. + start-server = pkgs.writeShellScript "minecraft-server-start" '' + # Switch to runtime directory. + export RUNTIME_DIR="${config.users.users.minecrafter.home}/${cfg.package.name}/" + ${pkgs.busybox}/bin/mkdir -p "$RUNTIME_DIR" + ${pkgs.busybox}/bin/chown minecrafter:minecrafter "$RUNTIME_DIR" + cd "$RUNTIME_DIR" + + # Set up/update environment for server + ln -sf ${eula-file} eula.txt + cp -f ${server-properties-file} server.properties + chmod u+w server.properties # Must be writable because server regenerates it. + + exec ${cfg.package}/bin/minecraft-server "$@" + ''; + + stop-server = pkgs.writeShellScript "minecraft-server-stop" '' + # Send the 'stop' command to the server. It listens for commands on stdin. + echo stop > ${config.systemd.sockets.minecraft-server.socketConfig.ListenFIFO} + # Wait for the PID of the minecraft server to disappear before + # returning, so systemd doesn't attempt to SIGKILL it. + while kill -0 "$1" 2> /dev/null; do + sleep 1s + done + ''; + in + { + description = "Actually runs the Minecraft server"; + requires = [ "minecraft-server.socket" ]; + after = [ "networking.target" "minecraft-server.socket" ]; + wantedBy = [ ]; # TEMP: Does this do anything? + + serviceConfig = { + ExecStart = "${start-server} ${lib.escapeShellArgs cfg.jvm-options}"; + ExecStop = "${stop-server} $MAINPID"; + Restart = "always"; + + User = "minecrafter"; + Group = "minecrafter"; + + StandardInput = "socket"; + StandardOutput = "journal"; + StandardError = "journal"; + + # Hardening + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + LockPersonality = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + UMask = "0077"; + }; + }; + + # This socket listens for connections on the public port and + # triggers `listen-minecraft.service` when a connection is made. + systemd.sockets.listen-minecraft = { + enable = true; + wantedBy = [ "sockets.target" ]; + requires = [ "network.target" ]; + listenStreams = [ (toString cfg.external-port) ]; + }; + + # This service is triggerd by a TCP connection on the public + # port. It starts hook-minecraft.service if it is not running + # already and waits for it to return (using `after`). Then it proxifies the TCP + # connection to the real (local) Minecraft port. + systemd.services.listen-minecraft = { + enable = true; + path = with pkgs; [ systemd ]; + requires = [ "hook-minecraft.service" "listen-minecraft.socket" ]; + after = [ "hook-minecraft.service" "listen-minecraft.socket" ]; + serviceConfig.ExecStart = '' + ${pkgs.systemd.out}/lib/systemd/systemd-socket-proxyd 127.0.0.1:${toString cfg.internal-port} + ''; + }; + + # This starts Minecraft if required and waits for it to be + # available over TCP to unlock the `listen-minecraft.service` + # proxy. + systemd.services.hook-minecraft = { + enable = true; + # Add tools used by scripts to path. + path = with pkgs; [ systemd libressl busybox ]; + serviceConfig = + let + # Start the Minecraft server and the timer regularly + # checking whether it should stop. + start-mc = pkgs.writeShellScriptBin "start-mc" '' + echo "Starting server and stop-timer..." + systemctl start minecraft-server.service + systemctl start stop-minecraft.timer + ''; + # Wait for the internal port to be accessible for max. + # 60 seconds before complaining. + wait-tcp = pkgs.writeShellScriptBin "wait-tcp" '' + echo "Waiting for server to start listening on port ${toString cfg.internal-port}..." + for i in `seq 60`; do + if nc -z 127.0.0.1 ${toString cfg.internal-port} >/dev/null; then + echo "Yay! ${toString cfg.internal-port} is not available. hook-minecraft is finished." + exit 0 + fi + sleep 1 + done + echo "${toString cfg.internal-port} did not become available in time." + exit 1 + ''; + in + { + # First we start the server, then we wait for it to become available. + ExecStart = "${start-mc}/bin/start-mc"; + ExecStartPost = "${wait-tcp}/bin/wait-tcp"; + }; + }; + + # This timer runs the service of the same name, that checks if + # the server needs to be stopped. + systemd.timers.stop-minecraft = { + enable = true; + timerConfig = { + OnCalendar = cfg.frequency-check-players; + #Unit = "stop-minecraft.service"; + }; + }; + + systemd.services.stop-minecraft = + let + # Script that returns true (exit code 1) if the server can be shut + # down. It uses RCON to get the player list. It does not continue if + # the server was started less than `minimum-server-lifetime` seconds + # ago. + no-player-connected = pkgs.writeShellScriptBin "no-player-connected" '' + servicestartsec="$(date -d "$(systemctl show --property=ActiveEnterTimestamp minecraft-server.service | cut -d= -f2)" +%s)" + serviceelapsedsec="$(( $(date +%s) - servicestartsec))" + + if [ $serviceelapsedsec -lt ${toString cfg.minimum-server-lifetime} ]; then + echo "Server is too young to be stopped (minimum lifetime is ${toString cfg.minimum-server-lifetime}s)" + exit 1 + fi + + PLAYERS="$(printf "list\n" | ${pkgs.rcon.out}/bin/rcon -m -H 127.0.0.1 -p 25575 -P ${cfg.rcon-password})" + if echo "$PLAYERS" | grep "are 0 of a"; then + exit 0 + else + exit 1 + fi + ''; + in + { + enable = true; + serviceConfig.Type = "oneshot"; + script = '' + if ${no-player-connected}/bin/no-player-connected; then + echo "Stopping minecraft server..." + systemctl stop minecraft-server.service + systemctl stop hook-minecraft.service + systemctl stop stop-minecraft.timer + fi + ''; + }; + + networking.firewall = mkIf cfg.openFirewall { + allowedUDPPorts = [ cfg.external-port ]; + allowedTCPPorts = [ cfg.external-port ]; + }; + + assertions = [{ + assertion = cfg.eula; + message = "You must agree to Mojangs EULA to run minecraft-server. Read https://account.mojang.com/documents/minecraft_eula and set `services.minecraft-server.eula` to `true` if you agree."; + }]; + }; +} diff --git a/modules/notifications.linus.onl/default.nix b/modules/notifications.linus.onl/default.nix deleted file mode 100644 index 443853f..0000000 --- a/modules/notifications.linus.onl/default.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ pkgs, lib, config, ... }: - -let - inherit (lib) mkEnableOption mkOption types mkIf optional; - - domain = "notifications.linus.onl"; - - # TODO: Make option internal-port. - internal-port = 13082; - - cfg = config.my.modules."notifications.linus.onl"; -in -{ - options.my.modules."notifications.linus.onl" = { - enable = mkEnableOption "notifications.linus.onl static site"; - - useACME = mkEnableOption "built-in HTTPS stuff"; - }; - - config = mkIf cfg.enable { - my.services.push-notification-api = { - enable = true; - # host = "notifications.linus.onl"; - host = "0.0.0.0"; - port = internal-port; - openFirewall = false; # We're using NGINX reverse proxy. - }; - - # Register domain name. - services.cloudflare-dyndns.domains = [ "notifications.linus.onl" ]; - - # Serve the generated page using NGINX. - services.nginx.virtualHosts."notifications.linus.onl" = { - enableACME = cfg.useACME; - forceSSL = cfg.useACME; - locations."/" = { - recommendedProxySettings = true; - proxyPass = "http://127.0.0.1:${toString internal-port}"; - }; - }; - }; -} -- cgit v1.2.3