diff --git a/flake.lock b/flake.lock index 6381e029..71ca5f5d 100644 --- a/flake.lock +++ b/flake.lock @@ -126,11 +126,11 @@ }, "secrets": { "locked": { - "lastModified": 1624476463, - "narHash": "sha256-RRDJT8rHY9gIT+LQaH7DDzgONbOXcEbL5kZhaxGVac0=", + "lastModified": 1633479869, + "narHash": "sha256-HhpstvGfR0TyCCFVOGZVRAay+6dJ6d8EMMTx952xKQ0=", "ref": "master", - "rev": "c263340bc845380a60678cea9609c14ad0fcf2ce", - "revCount": 100, + "rev": "eecfed3c6287b9a3f5f0c9469a3f6975048b891a", + "revCount": 101, "type": "git", "url": "ssh://gitea@gitea.c3d2.de/c3d2-admins/secrets.git" }, @@ -215,11 +215,11 @@ "zentralwerk-network-key": "zentralwerk-network-key" }, "locked": { - "lastModified": 1633196885, - "narHash": "sha256-+G0Zya8eLQpENx0EFZVQshNrMAgPBNrrR/30wKg9d4Q=", + "lastModified": 1633478755, + "narHash": "sha256-BeTHIpOgsonVnfrzSihrgHytwzqZuRVqYVL/MrFWArg=", "ref": "master", - "rev": "6ad5b94603bdcf4b9309fa044ea5094c2f8a4f4a", - "revCount": 1190, + "rev": "f23649855c3ac9c2cd3e77600488960709ea7414", + "revCount": 1194, "type": "git", "url": "https://gitea.c3d2.de/zentralwerk/network.git" }, diff --git a/flake.nix b/flake.nix index 8f53c1ff..5a7c205f 100644 --- a/flake.nix +++ b/flake.nix @@ -371,6 +371,20 @@ system = "x86_64-linux"; }; + c3d2-web = nixosSystem' { + modules = [ + ./lib/lxc-container.nix + ./hosts/containers/c3d2-web + ({ ... }: { + nixpkgs.overlays = [ secrets.overlays.c3d2-web ]; + }) + ]; + extraArgs = { + inherit nixpkgs; + }; + system = "x86_64-linux"; + }; + }; nixosModule = import ./lib; diff --git a/hosts/containers/c3d2-web/default.nix b/hosts/containers/c3d2-web/default.nix new file mode 100644 index 00000000..0711c27e --- /dev/null +++ b/hosts/containers/c3d2-web/default.nix @@ -0,0 +1,163 @@ +{ hostRegistry, nixpkgs, config, pkgs, ... }: +let + webroot = "/var/www"; + deployCommand = "${pkgs.systemd}/bin/systemctl start deploy-c3d2-web.service"; +in +{ + boot.tmpOnTmpfs = true; + # Network setup + networking.hostName = "c3d2-web"; + networking.useNetworkd = true; + networking.interfaces.eth0.ipv4.addresses = [{ + address = hostRegistry.hosts.${config.networking.hostName}.ip4; + prefixLength = 26; + }]; + networking.defaultGateway = "172.20.73.1"; + networking.firewall.allowedTCPPorts = [ 80 443 ]; + + # Web server + services.nginx = { + enable = true; + virtualHosts = { + "www.c3d2.de" = { + default = true; + serverAliases = [ + "c3d2.de" + "c3dd.de" "www.c3dd.de" + "cccdd.de" "www.cccdd.de" + "dresden.ccc.de" "www.dresden.ccc.de" + "datenspuren.de" "www.datenspuren.de" + ]; + # enableACME = true; + # forceSSL = true; + root = "${webroot}/c3d2"; + locations = { + # webhook + "/hooks/".proxyPass = "http://localhost:9000/hooks/"; + # SpaceAPI + "/status.png".proxyPass = "http://[${hostRegistry.hosts.spaceapi.ip6}]:3000/status.png"; + "/spaceapi.json".proxyPass = "http://[${hostRegistry.hosts.spaceapi.ip6}]:3000/spaceapi.json"; + # Jabber + # TODO: does this work? + "/http-bind".proxyPass = "http://jabber.c3d2.de:5280/http-bind"; + # TODO: websockets too? + }; + }; + + "c3d2-web.serv.zentralwerk.org" = { + enableACME = true; + forceSSL = true; + root = webroot; + locations."/hooks/".proxyPass = "http://localhost:9000/hooks/"; + }; + }; + }; + + # Build user + users.groups.c3d2-web = {}; + users.users.c3d2-web = { + isSystemUser = true; + group = "c3d2-web"; + home = "/var/lib/c3d2-web"; + }; + + systemd.tmpfiles.rules = [ + "d ${webroot}/c3d2 0755 c3d2-web ${config.users.users.c3d2-web.group} -" + "d ${webroot}/log 0755 c3d2-web ${config.users.users.c3d2-web.group} -" + "d ${config.users.users.c3d2-web.home} 0700 c3d2-web ${config.users.users.c3d2-web.group} -" + ]; + + # Build script + systemd.services.deploy-c3d2-web = { + wantedBy = [ "multi-user.target" ]; + path = with pkgs; [ git nix curl ]; + script = '' + # Build at least once + touch ${config.users.users.c3d2-web.home}/deploy-pending + + TEMP=$(mktemp -d) + cd $TEMP + + git clone --depth=1 https://gitea.c3d2.de/c3d2/c3d2-web.git + cd c3d2-web + + # Loop in case the webhook was called while we were building + while [ -e ${config.users.users.c3d2-web.home}/deploy-pending ]; do + rm ${config.users.users.c3d2-web.home}/deploy-pending + git pull + REV=$(git rev-parse HEAD) + + set +e + curl -X POST \ + "https://gitea.c3d2.de/api/v1/repos/c3d2/c3d2-web/statuses/$REV?token=${pkgs.c3d2-web.giteaToken}" \ + -H "accept: application/json" \ + -H "Content-Type: application/json" \ + -d "{ \"context\": \"c3d2-web\", \"description\": \"building...\", \"state\": \"pending\", \"target_url\": \"https://c3d2-web.serv.zentralwerk.org/log/build-$REV.txt\"}" + + nix-shell shell.nix \ + -I nixpkgs=${nixpkgs} \ + --run "make -j$(nproc) export DESTDIR=${webroot}/c3d2" \ + 2>&1 \ + >${webroot}/log/build-$REV.txt + + if [ $? = 0 ]; then + STATUS="{ \"context\": \"c3d2-web\", \"description\": \"deployed\", \"state\": \"success\", \"target_url\": \"https://c3d2-web.serv.zentralwerk.org/log/build-$REV.txt\"}" + else + STATUS="{ \"context\": \"c3d2-web\", \"description\": \"build failure\", \"state\": \"failure\", \"target_url\": \"https://c3d2-web.serv.zentralwerk.org/log/build-$REV.txt\"}" + fi + curl -X POST \ + "https://gitea.c3d2.de/api/v1/repos/c3d2/c3d2-web/statuses/$REV?token=${pkgs.c3d2-web.giteaToken}" \ + -H "accept: application/json" \ + -H "Content-Type: application/json" \ + -d "$STATUS" + + set -e + done + ''; + serviceConfig = { + User = "c3d2-web"; + Group = config.users.users.c3d2-web.group; + PrivateTmp = true; + ProtectSystem = "full"; + ReadWritePaths = webroot; + }; + }; + + systemd.timers.deploy-c3d2-web = { + partOf = [ "deploy-c3d2-web.service" ]; + wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = "hourly"; + }; + + security.sudo.extraRules = [ { + users = [ "c3d2-web" ]; + commands = [ { + command = deployCommand; + options = [ "NOPASSWD" ]; + } ]; + } ]; + + systemd.services.webhook = + let + hooksJson = pkgs.writeText "hooks.json" (builtins.toJSON [ { + id = "deploy-c3d2-web"; + execute-command = pkgs.writeShellScript "deploy-c3d2-web" '' + # Request (re-)deployment + touch ${config.users.users.c3d2-web.home}/deploy-pending + + # Start deploy-c3d2-web.service if not already running + exec /run/wrappers/bin/sudo ${deployCommand} + ''; + } ]); + in { + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + ExecStart = "${pkgs.webhook}/bin/webhook -hooks ${hooksJson} -verbose -ip 127.0.0.1"; + User = "c3d2-web"; + Group = config.users.users.c3d2-web.group; + PrivateTmp = true; + ProtectSystem = "full"; + }; + }; + # TODO: letsencrypt /.well-known before DNS switch +} diff --git a/secrets b/secrets index 0efb7df8..eecfed3c 160000 --- a/secrets +++ b/secrets @@ -1 +1 @@ -Subproject commit 0efb7df81d358c033a72fcc0c65016ff86f54858 +Subproject commit eecfed3c6287b9a3f5f0c9469a3f6975048b891a