1{
2 config,
3 lib,
4 inputs,
5 ...
6}:
7{
8 services.nginx = {
9 enable = true;
10 recommendedTlsSettings = true;
11 recommendedOptimisation = true;
12 recommendedGzipSettings = true;
13 recommendedProxySettings = true;
14 # /nginx_status
15 statusPage = true;
16 };
17
18 networking.firewall.public."http".allowedTCPPorts = [ 80 ];
19 networking.firewall.public."https".allowedTCPPorts = [ 443 ];
20
21 # output json logs so we can consume them more easily
22 services.nginx.appendHttpConfig = ''
23 log_format json_logs escape=json '{'
24 '"_msg":"request completed",'
25 '"time":"$time_local",'
26 '"req.remoteAddr":"$remote_addr",'
27 '"req.method":"$request_method",'
28 '"req.url":"$uri",'
29 '"req.httpVersion":"$server_protocol",'
30 '"res.statusCode":$status,'
31 '"res.bodySize":$body_bytes_sent,'
32 '"req.headers.id":"$request_id",'
33 '"req.headers.referer":"$http_referer",'
34 '"req.headers.user-agent":"$http_user_agent",'
35 '"requestTime":$request_time'
36 '}';
37 access_log /var/log/nginx/access.log json_logs;
38 '';
39
40 users.users.nginx.extraGroups = [ "acme" ];
41
42 age.secrets.cfDnsEditToken.file = ../../../secrets/cloudflareDnsEdit.age;
43 security.acme = {
44 acceptTerms = true;
45 defaults = {
46 group = "nginx";
47 email = (import "${inputs.self}/personal.nix").emails.primary;
48 dnsProvider = "cloudflare";
49 credentialFiles = {
50 CF_DNS_API_TOKEN_FILE = config.age.secrets.cfDnsEditToken.path;
51 };
52 };
53 certs."poor.dog" = { };
54 certs."ptr.pet" = { };
55 certs."gaze.systems" = { };
56 };
57 services.nginx.virtualHosts."gaze.systems" = {
58 quic = true;
59 kTLS = true;
60 useACMEHost = "gaze.systems";
61 forceSSL = true;
62 };
63 services.nginx.virtualHosts."poor.dog" = {
64 quic = true;
65 kTLS = true;
66 useACMEHost = "poor.dog";
67 forceSSL = true;
68 };
69 services.nginx.virtualHosts."ptr.pet" = {
70 quic = true;
71 kTLS = true;
72 useACMEHost = "ptr.pet";
73 forceSSL = true;
74 };
75
76 # services.fluent-bit.settings = {
77 # parsers = [
78 # {
79 # name = "nginx_json";
80 # format = "json";
81 # time_key = "time";
82 # time_format = "%d/%b/%Y:%H:%M:%S %z";
83 # }
84 # ];
85 # pipeline = {
86 # inputs = [
87 # {
88 # name = "nginx_metrics";
89 # tag = "metrics.nginx";
90 # status_url = "/nginx_status";
91 # nginx_plus = false;
92 # }
93 # {
94 # name = "tail";
95 # tag = "logs.nginx";
96 # path = "/var/log/nginx/*.log";
97 # db = "/var/lib/fluent-bit/nginx-access.db";
98 # "db.locking" = true;
99 # buffer_chunk_size = "4m";
100 # buffer_max_size = "32m";
101 # parser = "nginx_json";
102 # }
103 # ];
104 # filters = [
105 # {
106 # name = "modify";
107 # match = "logs.nginx";
108 # Add = [ "name nginx" ];
109 # }
110 # ];
111 # };
112 # };
113
114 # # need so fluent-bit can access nginx
115 # systemd.services.fluent-bit.serviceConfig.SupplementaryGroups = lib.mkForce "systemd-journal nginx";
116
117 # services.vmalert.instances."".rules.groups = [
118 # {
119 # name = "nginx-logs";
120 # type = "vlogs";
121 # interval = "1m";
122 # rules = [
123 # {
124 # record = "nginx_request_count";
125 # expr = "name:nginx | stats (res.statusCode) count() as total_requests";
126 # }
127 # {
128 # record = "nginx_request_latency";
129 # # filter out subscribeRepos requests because they are long polling http L
130 # expr = "name:nginx | filter req.url:!/xrpc/com.atproto.sync.subscribeRepos | stats avg(requestTime) avg, quantile(0.5, requestTime) p50, quantile(0.9, requestTime) p90, quantile(0.99, requestTime) p99";
131 # }
132 # ];
133 # }
134 # ];
135}