dotfiles/modules/nixos/services/caddy.nix

99 lines
3.1 KiB
Nix
Raw Permalink Normal View History

2024-01-10 04:11:11 +00:00
# Caddy is a reverse proxy, like Nginx or Traefik. This creates an ingress
# point from my local network or the public (via Cloudflare). Instead of a
# Caddyfile, I'm using the more expressive JSON config file format. This means
# I can source routes from other areas in my config and build the JSON file
# using the result of the expression.
# Caddy helpfully provides automatic ACME cert generation and management, but
# it requires a form of validation. We are using a custom build of Caddy
# (compiled with an overlay) to insert a plugin for managing DNS validation
# with Cloudflare's DNS API.
2022-10-13 23:40:30 +00:00
{ config, pkgs, lib, ... }: {
2022-10-02 15:24:25 +00:00
options = {
2023-07-18 03:52:37 +00:00
caddy = {
tlsPolicies = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
description = "Caddy JSON TLS policies";
default = [ ];
};
routes = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
description = "Caddy JSON routes for http servers";
default = [ ];
};
blocks = lib.mkOption {
type = lib.types.listOf lib.types.attrs;
description = "Caddy JSON error blocks for http servers";
default = [ ];
};
cidrAllowlist = lib.mkOption {
type = lib.types.listOf lib.types.str;
description = "CIDR blocks to allow for requests";
default = [ ];
2023-07-18 03:52:37 +00:00
};
2022-10-15 19:00:37 +00:00
};
2022-10-02 15:24:25 +00:00
};
2023-07-18 03:52:37 +00:00
config = lib.mkIf config.services.caddy.enable {
# Force Caddy to 403 if not coming from allowlisted source
caddy.cidrAllowlist = [ "127.0.0.1/32" ];
2023-07-18 03:52:37 +00:00
caddy.routes = [{
match = [{ not = [{ remote_ip.ranges = config.caddy.cidrAllowlist; }]; }];
handle = [{
handler = "static_response";
status_code = "403";
}];
}];
services.caddy = {
adapter = "''"; # Required to enable JSON
configFile = pkgs.writeText "Caddyfile" (builtins.toJSON {
apps.http.servers.main = {
listen = [ ":443" ];
2024-01-10 04:11:11 +00:00
# These routes are pulled from the rest of this repo
2023-07-18 03:52:37 +00:00
routes = config.caddy.routes;
errors.routes = config.caddy.blocks;
2024-01-10 04:11:11 +00:00
logs = { }; # Uncommenting collects access logs
2023-07-18 03:52:37 +00:00
};
apps.http.servers.metrics = { }; # Enables Prometheus metrics
apps.tls.automation.policies = config.caddy.tlsPolicies;
2024-01-10 04:11:11 +00:00
# Setup logging to file
2023-07-18 03:52:37 +00:00
logging.logs.main = {
encoder = { format = "console"; };
writer = {
output = "file";
filename = "${config.services.caddy.logDir}/caddy.log";
roll = true;
2023-08-04 05:13:43 +00:00
roll_size_mb = 1;
};
2023-07-18 03:52:37 +00:00
level = "INFO";
};
2024-01-10 04:11:11 +00:00
2023-07-18 03:52:37 +00:00
});
2022-10-02 15:24:25 +00:00
2023-07-18 03:52:37 +00:00
};
2022-10-02 15:24:25 +00:00
2024-01-10 04:11:11 +00:00
# Allows Caddy to serve lower ports (443, 80)
systemd.services.caddy.serviceConfig.AmbientCapabilities =
"CAP_NET_BIND_SERVICE";
# Required for web traffic to reach this machine
2023-07-18 03:52:37 +00:00
networking.firewall.allowedTCPPorts = [ 80 443 ];
2024-01-10 04:11:11 +00:00
# HTTP/3 QUIC uses UDP (not sure if being used)
2023-07-18 03:52:37 +00:00
networking.firewall.allowedUDPPorts = [ 443 ];
2022-10-03 12:19:29 +00:00
2024-01-10 04:11:11 +00:00
# Caddy exposes Prometheus metrics with the admin API
# https://caddyserver.com/docs/api
2023-07-18 03:52:37 +00:00
prometheus.scrapeTargets = [ "127.0.0.1:2019" ];
2023-07-16 20:13:41 +00:00
2023-07-18 03:52:37 +00:00
};
2022-10-02 15:24:25 +00:00
}