diff --git a/config/hosts/matrix/nginx.nix b/config/hosts/matrix/nginx.nix index ab35ad3..f4ddec6 100644 --- a/config/hosts/matrix/nginx.nix +++ b/config/hosts/matrix/nginx.nix @@ -69,7 +69,7 @@ proxyPass = "http://localhost:8080"; }; "~ ^/api/admin" = { - proxyPass = "http://localhost:8082"; + proxyPass = "http://localhost:8083"; extraConfig = '' # Restrict access to admin API. allow 172.21.87.0/24; # management VPN diff --git a/config/hosts/web-public-2/nginx.nix b/config/hosts/web-public-2/nginx.nix index 608d6a7..066f3d2 100644 --- a/config/hosts/web-public-2/nginx.nix +++ b/config/hosts/web-public-2/nginx.nix @@ -19,6 +19,7 @@ anisync.grzb.de 127.0.0.1:8443; cloud.nekover.se 10.202.41.122:8443; element.nekover.se 127.0.0.1:8443; + element-admin.nekover.se 127.0.0.1:8443; fi.nekover.se 10.202.41.125:8443; gameserver.grzb.de 127.0.0.1:8443; git.grzb.de 127.0.0.1:8443; diff --git a/config/hosts/web-public-2/virtualHosts/default.nix b/config/hosts/web-public-2/virtualHosts/default.nix index 53294f7..445a087 100644 --- a/config/hosts/web-public-2/virtualHosts/default.nix +++ b/config/hosts/web-public-2/virtualHosts/default.nix @@ -4,6 +4,7 @@ ./acme-challenge.nix ./anisync.grzb.de.nix ./element.nekover.se.nix + ./element-admin.nekover.se.nix ./gameserver.grzb.de.nix ./git.grzb.de.nix ./mewtube.nekover.se.nix diff --git a/config/hosts/web-public-2/virtualHosts/element-admin.nekover.se.nix b/config/hosts/web-public-2/virtualHosts/element-admin.nekover.se.nix new file mode 100644 index 0000000..69c3a9a --- /dev/null +++ b/config/hosts/web-public-2/virtualHosts/element-admin.nekover.se.nix @@ -0,0 +1,95 @@ +{ config, pkgs, ... }: + +let + elementAdminVersion = "0.1.10"; + elementAdmin = pkgs.stdenv.mkDerivation (finalAttrs: { + pname = "element-admin"; + version = elementAdminVersion; + + src = pkgs.fetchzip { + url = "https://github.com/element-hq/element-admin/archive/refs/tags/v${elementAdminVersion}.zip"; + sha256 = "sha256-dh7tmzAaTfKB9FuOVhLHpOIsTZK1qMvNq16HeObHOqI="; + }; + + nativeBuildInputs = [ + pkgs.nodejs + pkgs.pnpm.configHook + ]; + + pnpmDeps = pkgs.pnpm.fetchDeps { + inherit (finalAttrs) pname version src; + fetcherVersion = 2; + hash = "sha256-S/MdfUv6q+PaAKWYHxVY80BcpL81dOfpPVhNxEPQVE4="; + }; + + buildPhase = '' + pnpm build + ''; + + installPhase = '' + cp -a dist $out + ''; + }); +in +{ + services.nginx.virtualHosts."element-admin.nekover.se" = { + forceSSL = true; + enableACME = true; + + listen = [{ + addr = "localhost"; + port = 8443; + ssl = true; + extraParameters = ["proxy_protocol"]; + }]; + + root = elementAdmin; + + locations."/assets" = { + extraConfig = '' + expires 1y; + add_header Cache-Control "public, max-age=31536000, immutable"; + # Security headers. + add_header X-Frame-Options "DENY" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data:; font-src 'self'; connect-src *; object-src 'none'; media-src 'self'; child-src 'none'; worker-src 'self'; manifest-src 'self';" always; + add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), payment=(), usb=(), magnetometer=(), accelerometer=(), gyroscope=()" always; + ''; + }; + + locations."/" = { + index = "/index.html"; + tryFiles = "$uri $uri/ /"; + extraConfig = '' + # Security headers. + add_header X-Frame-Options "DENY" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data:; font-src 'self'; connect-src *; object-src 'none'; media-src 'self'; child-src 'none'; worker-src 'self'; manifest-src 'self';" always; + add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), payment=(), usb=(), magnetometer=(), accelerometer=(), gyroscope=()" always; + ''; + }; + + extraConfig = '' + # Security headers. + add_header X-Frame-Options "DENY" always; + add_header X-XSS-Protection "1; mode=block" always; + add_header X-Content-Type-Options "nosniff" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' blob: data:; font-src 'self'; connect-src *; object-src 'none'; media-src 'self'; child-src 'none'; worker-src 'self'; manifest-src 'self';" always; + add_header Permissions-Policy "geolocation=(), camera=(), microphone=(), payment=(), usb=(), magnetometer=(), accelerometer=(), gyroscope=()" always; + + # Make use of the ngx_http_realip_module to set the $remote_addr and + # $remote_port to the client address and client port, when using proxy + # protocol. + # First set our proxy protocol proxy as trusted. + set_real_ip_from 127.0.0.1; + # Then tell the realip_module to get the addreses from the proxy protocol + # header. + real_ip_header proxy_protocol; + ''; + }; +}