diff --git a/modules/nixos/services/caddy.nix b/modules/nixos/services/caddy.nix index ab24506..702e20b 100644 --- a/modules/nixos/services/caddy.nix +++ b/modules/nixos/services/caddy.nix @@ -2,6 +2,11 @@ options = { caddy.enable = lib.mkEnableOption "Caddy reverse proxy."; + caddy.tlsPolicies = lib.mkOption { + type = lib.types.listOf lib.types.attrs; + description = "Caddy JSON TLS policies"; + default = [ ]; + }; caddy.routes = lib.mkOption { type = lib.types.listOf lib.types.attrs; description = "Caddy JSON routes for http servers"; @@ -26,6 +31,7 @@ errors.routes = config.caddy.blocks; # logs = { }; # Uncomment to collect access logs }; + apps.tls.automation.policies = config.caddy.tlsPolicies; logging.logs.main = { encoder = { format = "console"; }; writer = { diff --git a/modules/nixos/services/cloudflare.nix b/modules/nixos/services/cloudflare.nix index aac2582..0df2068 100644 --- a/modules/nixos/services/cloudflare.nix +++ b/modules/nixos/services/cloudflare.nix @@ -1,6 +1,6 @@ # This module is necessary for hosts that are serving through Cloudflare. -{ config, lib, ... }: +{ config, pkgs, lib, ... }: let @@ -49,6 +49,38 @@ in { }]; }]; + # Tell Caddy to use Cloudflare DNS for ACME challenge validation + services.caddy.package = (pkgs.callPackage ../../../overlays/caddy.nix { + plugins = [ "github.com/caddy-dns/cloudflare" ]; + # vendorSha256 = "sha256-K9HPZnr+hMcK5aEd1H4gEg6PXAaNrNWFvaHYm5m62JY="; + }); + caddy.tlsPolicies = [{ + issuers = [{ + module = "acme"; + challenges = { + dns = { + provider = { + name = "cloudflare"; + api_token = "{env.CF_API_TOKEN}"; + }; + resolvers = [ "1.1.1.1" ]; + }; + }; + }]; + }]; + systemd.services.caddy.serviceConfig.EnvironmentFile = + config.secrets.cloudflareApi.dest; + systemd.services.caddy.serviceConfig.AmbientCapabilities = + "CAP_NET_BIND_SERVICE"; + + # API key must have access to modify Cloudflare DNS records + secrets.cloudflareApi = { + source = ../../../private/cloudflare-api.age; + dest = "${config.secretsDirectory}/cloudflare-api"; + owner = "caddy"; + group = "caddy"; + }; + # Allows Nextcloud to trust Cloudflare IPs services.nextcloud.config.trustedProxies = cloudflareIpRanges; diff --git a/overlays/caddy.nix b/overlays/caddy.nix new file mode 100644 index 0000000..966d681 --- /dev/null +++ b/overlays/caddy.nix @@ -0,0 +1,56 @@ +{ lib, buildGo118Module, fetchFromGitHub, plugins ? [ ] }: +let + goImports = lib.flip lib.concatMapStrings plugins (pkg: " _ \"${pkg}\"\n"); + goGets = lib.flip lib.concatMapStrings plugins (pkg: "go get ${pkg}\n "); + main = '' + package main + import ( + caddycmd "github.com/caddyserver/caddy/v2/cmd" + _ "github.com/caddyserver/caddy/v2/modules/standard" + ${goImports} + ) + func main() { + caddycmd.Main() + } + ''; +in buildGo118Module rec { + pname = "caddy"; + version = "2.6.4"; + runVend = true; + + subPackages = [ "cmd/caddy" ]; + + src = fetchFromGitHub { + owner = "caddyserver"; + repo = "caddy"; + rev = "v${version}"; + sha256 = "sha256:3a3+nFHmGONvL/TyQRqgJtrSDIn0zdGy9YwhZP17mU0="; + }; + + vendorSha256 = "sha256:CrHqJcJ0knX+txQ5qvzW4JrU8vfi3FO3M/xtislIC1M="; + + overrideModAttrs = (_: { + preBuild = '' + echo '${main}' > cmd/caddy/main.go + ${goGets} + ''; + postInstall = "cp go.sum go.mod $out/ && ls $out/"; + }); + + postPatch = '' + echo '${main}' > cmd/caddy/main.go + cat cmd/caddy/main.go + ''; + + postConfigure = '' + cp vendor/go.sum ./ + cp vendor/go.mod ./ + ''; + + meta = with lib; { + homepage = "https://caddyserver.com"; + description = "Fast, cross-platform HTTP/2 web server with automatic HTTPS"; + license = licenses.asl20; + maintainers = with maintainers; [ Br1ght0ne techknowlogick ]; + }; +} diff --git a/overlays/calibre-web-cloudflare.patch b/overlays/calibre-web-cloudflare.patch index 3378dcd..b454caa 100644 --- a/overlays/calibre-web-cloudflare.patch +++ b/overlays/calibre-web-cloudflare.patch @@ -1,25 +1,25 @@ diff --git a/cps/__init__.py b/cps/__init__.py -index 1ba1f778..da0bc718 100644 +index 269e4aca..e2b828a9 100644 --- a/cps/__init__.py +++ b/cps/__init__.py -@@ -100,7 +100,6 @@ updater_thread = Updater() - def create_app(): +@@ -150,7 +150,6 @@ def create_app(): + lm.login_view = 'web.login' lm.anonymous_user = ub.Anonymous -- lm.session_protection = 'strong' +- lm.session_protection = 'strong' if config.config_session == 1 else "basic" - if csrf: - csrf.init_app(app) + db.CalibreDB.update_config(config) + db.CalibreDB.setup_db(config.config_calibre_dir, cli_param.settings_path) diff --git a/cps/admin.py b/cps/admin.py -index 09a553b4..5c646e46 100644 +index 20c58aac..99d2ad19 100644 --- a/cps/admin.py +++ b/cps/admin.py -@@ -104,8 +104,6 @@ def before_request(): - # make remember me function work - if current_user.is_authenticated: - confirm_login() +@@ -101,8 +101,6 @@ def admin_required(f): + + @admi.before_app_request + def before_request(): - if not ub.check_user_session(current_user.id, flask_session.get('_id')) and 'opds' not in request.path: - logout_user() g.constants = constants - g.user = current_user + g.google_site_verification = os.getenv('GOOGLE_SITE_VERIFICATION','') g.allow_registration = config.config_public_reg diff --git a/private/cloudflare-api.age b/private/cloudflare-api.age new file mode 100644 index 0000000..51f3080 --- /dev/null +++ b/private/cloudflare-api.age @@ -0,0 +1,13 @@ +-----BEGIN AGE ENCRYPTED FILE----- +YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IE1nSGFPdyByWGJS +SmJlSVhZcUx5Y3JhVXYxUVhUbmp2QjNXeUxYL1EwNThJelRoTVNvCjFsU0gyaWNJ +SEJpNVpYWm1TL24yeHNLaWNIdU9FdWw2d3p6UVVMSEYwT28KLT4gc3NoLWVkMjU1 +MTkgWXlTVU1RIEV4NU1sOENFK1NvUWlZL1NmUCtUM2RRQmd1c2pnb3p6V3Bsc3pC +UVdYV3cKYmFkR0EwNVpRbzJBb2Z4RmpXSGVyK3BkLzd6TTMvQWRRK3BtRXZDUjVZ +UQotPiBzc2gtZWQyNTUxOSBuanZYNUEgMG9rU0lzTU1iV1grOTNzZS85cldQZGE5 +Ym9nVkRvNC9OMUFBbStNT1BBOApucnl1Z0w1Y1RRU3grS0Z0TjNNRXcwVnVqeDFF +VGc3Mm93UFc0YXoweVBBCi0tLSBvTnpCc3hBVU81dkpBRzV2L3NWTlZaV2QxUVNZ +KzJwcUI2QUl2NEY0R1p3CmDvQwsKrtmTJliCxHv+LSoIV8jYpQJ7I2LJSH9uP89N ++7wbAwGjv/Uxk7gnMn5EqQuFKZeOl8LLhKEprmVqVZqlkgbpaaaWud/4xNKu9v5h +lWuY1sYd +-----END AGE ENCRYPTED FILE-----