diff --git a/.woodpecker.yml b/.woodpecker.yml new file mode 100644 index 0000000..f757ca1 --- /dev/null +++ b/.woodpecker.yml @@ -0,0 +1,14 @@ +pipeline: + build: + image: nixos/nix + environment: + NIX_CONFIG: "experimental-features = nix-command flakes" + commands: + - nix --log-format raw -L build .#docker.x86_64-linux + deploy: + image: nixos/nix + environment: + NIX_CONFIG: "experimental-features = nix-command flakes" + secrets: [ fly_api_token ] + commands: + - nix --log-format raw -L run .#deploy diff --git a/Caddyfile b/Caddyfile new file mode 100644 index 0000000..084e996 --- /dev/null +++ b/Caddyfile @@ -0,0 +1,56 @@ +{ + # fly.io handles HTTPS for us + auto_https off +} + +http://static-mat-services.fly.dev { + redir https://mat.services/ +} + +:8080 { + root * /var/www + encode gzip + file_server + + handle_errors { + @404 { + expression {http.error.status_code} == 404 + } + rewrite @404 /404.html + file_server + } + + header { + # disable FLoC tracking + Permissions-Policy interest-cohort=() + # enable HSTS + # currently ramping up max-age as per https://hstspreload.org/ + Strict-Transport-Security max-age=604800; includeSubDomains + # disable clients from sniffing the media type + X-Content-Type-Options nosniff + # clickjacking protection + X-Frame-Options DENY + # keep referrer data off of HTTP connections + Referrer-Policy no-referrer + # content security policy + # style-src 'unsafe-inline': syntax highlighting in codefences + # sandbox allow-popups: enable target="_blank" links to open in new tabs + Content-Security-Policy "default-src 'none'; + img-src 'self'; + style-src 'self' 'unsafe-inline'; + font-src 'self'; + form-action 'none'; + frame-ancestors 'none'; + base-uri 'none'; + upgrade-insecure-requests; + sandbox allow-same-origin allow-popups allow-popups-to-escape-sandbox" + } + + # caching + route { + header /style/* Cache-Control max-age=31536000, immutable + header /image/* Cache-Control max-age=31536000, immutable + header /font/* Cache-Control max-age=31536000, immutable + header Cache-Control max-age=180 + } +} diff --git a/flake.nix b/flake.nix index 6e3a3cf..fd129e1 100644 --- a/flake.nix +++ b/flake.nix @@ -21,22 +21,9 @@ systems = inputs.nixpkgs.lib.systems.flakeExposed; perSystem = { config, self', inputs', pkgs, system, ... }: let - optimize-images = pkgs.writeShellScriptBin "optimize-images" '' - shopt -s globstar nullglob - ${pkgs.scour}/bin/scour -i static/image/_favicon.svg -o static/image/favicon.svg - for image in content/**/_*.png static/image/**/_*.png; do - path=$(dirname $image) - file=$(basename $image) - newimage=$path/''${file:1} - echo "optimizing $image" - ${pkgs.pngquant}/bin/pngquant --quality 80-90 -f -o $newimage $image - oldsize=$(stat --format=%s $image) - newsize=$(stat --format=%s $newimage) - pct=$(${pkgs.bc}/bin/bc <<< "scale=1; $newsize * 100 / $oldsize") - echo "size went from "$(($oldsize / 1024))"KB to "$(($newsize / 1024))"KB ("$pct"% as large as original)" - done - ''; - inherit (pkgs.callPackage ./fonts.nix { }) copyFonts linkFonts; + inherit (pkgs) callPackage; + optimize-images = callPackage ./nix/optimize-images.nix { }; + inherit (callPackage ./nix/fonts.nix { }) copyFonts linkFonts; in { packages.default = with pkgs; stdenv.mkDerivation { @@ -52,7 +39,10 @@ optimize-images zola build ''; - installPhase = "cp -r public $out"; + installPhase = '' + cp -r public $out + cp Caddyfile $out + ''; }; devShells.default = with pkgs; mkShell { packages = [ flyctl optimize-images zola ]; @@ -61,19 +51,10 @@ ln -snf "${theme}" "themes/${themeName}" '' + linkFonts; }; - packages.docker = - let - site = self'.packages.default; - in - pkgs.dockerTools.buildLayeredImage { - name = site.pname; - tag = site.version; - contents = [ site pkgs.caddy ]; - - config = { - Cmd = [ "caddy" ]; - }; - }; + packages.docker = callPackage ./nix/docker.nix { site = self'.packages.default; }; + apps.deploy.program = + let deploy = callPackage ./nix/deploy.nix { dockerImg = self'.packages.docker; }; + in "${deploy}/bin/deploy"; }; }; } diff --git a/nix/deploy.nix b/nix/deploy.nix new file mode 100644 index 0000000..e8a040b --- /dev/null +++ b/nix/deploy.nix @@ -0,0 +1,9 @@ +{ lib, docker, flyctl, formats, writeShellScriptBin, dockerImg }: + +writeShellScriptBin "deploy" '' + set -euxo pipefail + export PATH="${lib.makeBinPath [(docker.override { clientOnly = true; }) flyctl]}:$PATH" + archive=${dockerImg} + image=$(docker load < $archive | awk '{ print $3; }') + flyctl deploy -i $image +'' diff --git a/nix/docker.nix b/nix/docker.nix new file mode 100644 index 0000000..f7d8fbc --- /dev/null +++ b/nix/docker.nix @@ -0,0 +1,11 @@ +{ dockerTools, caddy, site }: + +dockerTools.buildLayeredImage { + name = site.pname; + tag = site.version; + contents = [ site caddy ]; + + config = { + Cmd = [ "${caddy}/bin/caddy" "run" "-config" "${site}/Caddyfile" ]; + }; +} diff --git a/fonts.nix b/nix/fonts.nix similarity index 95% rename from fonts.nix rename to nix/fonts.nix index b856a17..fa737d6 100644 --- a/fonts.nix +++ b/nix/fonts.nix @@ -61,13 +61,6 @@ rec { font = fontDerivation fontSrc; }; fonts = map fetchFont fontSrcs; - copyFont = { font, name, ... }: '' - mkdir -p static/font/${name} - cp -r ${font}/* static/font/${pathName name} - ''; - linkFont = { font, name, ... }: '' - ln -snf "${font}" static/font/${pathName name} - ''; mkFontCss = { font, name, fileName, cssVar }: let path = pathName name; in '' @font-face { @@ -109,10 +102,18 @@ rec { ''; fontCss = lib.concatMapStrings mkFontCss fonts; fontCssFile = writeText "fonts.css" fontCss; + copyFont = { font, name, ... }: + let path = pathName name; in '' + mkdir -p static/font/${path} + cp -r ${font}/* static/font/${path} + ''; copyFonts = (lib.concatMapStrings copyFont fonts) + '' mkdir -p static/style cp ${fontCssFile} static/style/fonts.css ''; + linkFont = { font, name, ... }: '' + ln -snf "${font}" static/font/${pathName name} + ''; linkFonts = '' mkdir -p static/font '' + (lib.concatMapStrings linkFont fonts) + '' diff --git a/nix/optimize-images.nix b/nix/optimize-images.nix new file mode 100644 index 0000000..84bb309 --- /dev/null +++ b/nix/optimize-images.nix @@ -0,0 +1,17 @@ +{ bc, pngquant, scour, writeShellScriptBin }: + +writeShellScriptBin "optimize-images" '' + shopt -s globstar nullglob + ${scour}/bin/scour -i static/image/_favicon.svg -o static/image/favicon.svg + for image in content/**/_*.png static/image/**/_*.png; do + path=$(dirname $image) + file=$(basename $image) + newimage=$path/''${file:1} + echo "optimizing $image" + ${pngquant}/bin/pngquant --quality 80-90 -f -o $newimage $image + oldsize=$(stat --format=%s $image) + newsize=$(stat --format=%s $newimage) + pct=$(${bc}/bin/bc <<< "scale=1; $newsize * 100 / $oldsize") + echo "size went from "$(($oldsize / 1024))"KB to "$(($newsize / 1024))"KB ("$pct"% as large as original)" + done +''