all repos — nixfiles @ aedea00a8b6ccbbeea0ea0215af0652ff7ccbd28

System and user configuration, managed by nix and home-manager

system/roles/webserver/reverse-proxy.nix (view raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
{
  config,
  pkgs,
  ...
}:
{
  imports = [
    ../../settings/services/caddy.nix
  ];
  age.secrets = {
    # TS_AUTHKEY for caddy-tailscale plugin
    caddy.file = ../../../secrets/caddy.age;
  };

  security.acme.defaults = {
    email = "security@${config.networking.domain}";
    validMinDays = 32;
  };

  services.tailscale.permitCertUid = config.services.caddy.user;
  services.caddy = {
    environmentFile = config.age.secrets.caddy.path;
    package = pkgs.caddy.withPlugins {
      plugins = [
        "github.com/caddyserver/cache-handler@v0.16.0"
        "github.com/tailscale/caddy-tailscale@v0.0.0-20260106222316-bb080c4414ac"
        "github.com/caddy-dns/rfc2136@v1.0.0"
        "pkg.jsn.cam/caddy-defender@v0.10.1"
        "github.com/mholt/caddy-ratelimit@v0.1.1-0.20260521172720-16aecbbcb8ca"
      ];
      hash = "sha256-qaHc2jmyFJ/MwazQpcdLe/fmEB13X1MtvfVBUR/MymA=";
    };
    globalConfig = ''
      cache
      tailscale {
        tags tag:app
      }
      acme_dns rfc2136 {
        key_name caddy
        key_alg hmac-sha512
        key "{env.DDNS_TSIG_KEY}"
        server pdns.alin.ovh:53
      }
    '';
    extraConfig = ''
      (rate_limit) {
        rate_limit {
          log_key
          zone global_static {
            match {
              query query=*
            }
            key static
            events 180
            window 1m
          }
          zone net_short {
            match {
              query query=*
            }
            key {remote_host}
            ipv4_prefix 24
            ipv6_prefix 56
            events 10
            window 5s
          }
        }
      }
      (defender) {
        defender ratelimit {
          ranges all
        }
        defender tarpit {
          tarpit_config {
            timeout 30s
            bytes_per_second 500
            response_code 200
          }
        }
      }
      (goaccess) {
        handle_path /stats/* {
          root /srv/http/access/{args[0]}
          file_server
          log_skip
        }
      }
    '';
  };

  users.groups.caddy.members = [ "alin" ];
  users.groups.webservice = {
    members = [ "caddy" ];
  };
  systemd.tmpfiles.rules = [
    # setgid bit (2)
    # sticky bit (4)
    "d /run/web/ 6770 caddy webservice -"
  ];
  systemd.services.caddy.serviceConfig = {
    ReadWritePaths = [ "/run/web" ];
  };

  boot.kernel.sysctl =
    let
      buffer_size = 16 * 1024 * 1024;
      server_count = 2;
      max_clients = 100;
      page_size = 4096;
      # This server might have 100 clients simultaneously, so:
      #   max(tcp_wmem) * 2 * 100 / 4096
      mem = toString (buffer_size * server_count * max_clients / page_size);
    in
    {
      # Provide adequate buffer memory.
      # rmem_max and wmem_max are TCP max buffer size
      # settable with setsockopt(), in bytes
      # tcp_rmem and tcp_wmem are per socket in bytes.
      # tcp_mem is for all TCP streams, in 4096-byte pages.
      # The following are suggested on IBM's
      # High Performance Computing page
      "net.core.rmem_max" = buffer_size;
      "net.core.wmem_max" = buffer_size;
      "net.core.rmem_default" = buffer_size;
      "net.core.wmem_default" = buffer_size;
      "net.ipv4.tcp_rmem" = "4096 87380 ${toString buffer_size}";
      "net.ipv4.tcp_wmem" = "4096 87380 ${toString buffer_size}";
      "net.ipv4.tcp_mem" = "${mem} ${mem} ${mem}";

      "net.ipv4.tcp_sack" = 0;
      "net.ipv4.tcp_dsack" = 0;

      "net.ipv4.tcp_slow_start_after_idle" = 0;
    };

}