grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / web-apps / coder.nix
blob5450adbe118da4534a404be45de99845d2b12727
1 { config, lib, options, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.coder;
7   name = "coder";
8 in {
9   options = {
10     services.coder = {
11       enable = mkEnableOption "Coder service";
13       user = mkOption {
14         type = types.str;
15         default = "coder";
16         description = ''
17           User under which the coder service runs.
19           ::: {.note}
20           If left as the default value this user will automatically be created
21           on system activation, otherwise it needs to be configured manually.
22           :::
23         '';
24       };
26       group = mkOption {
27         type = types.str;
28         default = "coder";
29         description = ''
30           Group under which the coder service runs.
32           ::: {.note}
33           If left as the default value this group will automatically be created
34           on system activation, otherwise it needs to be configured manually.
35           :::
36         '';
37       };
39       package = mkPackageOption pkgs "coder" { };
41       homeDir = mkOption {
42         type = types.str;
43         description = ''
44           Home directory for coder user.
45         '';
46         default = "/var/lib/coder";
47       };
49       listenAddress = mkOption {
50         type = types.str;
51         description = ''
52           Listen address.
53         '';
54         default = "127.0.0.1:3000";
55       };
57       accessUrl = mkOption {
58         type = types.nullOr types.str;
59         description = ''
60           Access URL should be a external IP address or domain with DNS records pointing to Coder.
61         '';
62         default = null;
63         example = "https://coder.example.com";
64       };
66       wildcardAccessUrl = mkOption {
67         type = types.nullOr types.str;
68         description = ''
69           If you are providing TLS certificates directly to the Coder server, you must use a single certificate for the root and wildcard domains.
70         '';
71         default = null;
72         example = "*.coder.example.com";
73       };
75       environment = {
76         extra = mkOption {
77           type = types.attrs;
78           description = "Extra environment variables to pass run Coder's server with. See Coder documentation.";
79           default = {};
80           example = {
81             CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS = true;
82             CODER_OAUTH2_GITHUB_ALLOWED_ORGS = "your-org";
83           };
84         };
85         file = mkOption {
86           type = types.nullOr types.path;
87           description = "Systemd environment file to add to Coder.";
88           default = null;
89         };
90       };
92       database = {
93         createLocally = mkOption {
94           type = types.bool;
95           default = true;
96           description = ''
97             Create the database and database user locally.
98           '';
99         };
101         host = mkOption {
102           type = types.str;
103           default = "/run/postgresql";
104           description = ''
105             Hostname hosting the database.
106           '';
107         };
109         database = mkOption {
110           type = types.str;
111           default = "coder";
112           description = ''
113             Name of database.
114           '';
115         };
117         username = mkOption {
118           type = types.str;
119           default = "coder";
120           description = ''
121             Username for accessing the database.
122           '';
123         };
125         password = mkOption {
126           type = types.nullOr types.str;
127           default = null;
128           description = ''
129             Password for accessing the database.
130           '';
131         };
133         sslmode = mkOption {
134           type = types.nullOr types.str;
135           default = "disable";
136           description = ''
137             Password for accessing the database.
138           '';
139         };
140       };
142       tlsCert = mkOption {
143         type = types.nullOr types.path;
144         description = ''
145           The path to the TLS certificate.
146         '';
147         default = null;
148       };
150       tlsKey = mkOption {
151         type = types.nullOr types.path;
152         description = ''
153           The path to the TLS key.
154         '';
155         default = null;
156       };
157     };
158   };
160   config = mkIf cfg.enable {
161     assertions = [
162       { assertion = cfg.database.createLocally -> cfg.database.username == name && cfg.database.database == cfg.database.username;
163         message = "services.coder.database.username must be set to ${name} if services.coder.database.createLocally is set true";
164       }
165     ];
167     systemd.services.coder = {
168       description = "Coder - Self-hosted developer workspaces on your infra";
169       after = [ "network.target" ];
170       wantedBy = [ "multi-user.target" ];
172       environment = cfg.environment.extra // {
173         CODER_ACCESS_URL = cfg.accessUrl;
174         CODER_WILDCARD_ACCESS_URL = cfg.wildcardAccessUrl;
175         CODER_PG_CONNECTION_URL = "user=${cfg.database.username} ${optionalString (cfg.database.password != null) "password=${cfg.database.password}"} database=${cfg.database.database} host=${cfg.database.host} ${optionalString (cfg.database.sslmode != null) "sslmode=${cfg.database.sslmode}"}";
176         CODER_ADDRESS = cfg.listenAddress;
177         CODER_TLS_ENABLE = optionalString (cfg.tlsCert != null) "1";
178         CODER_TLS_CERT_FILE = cfg.tlsCert;
179         CODER_TLS_KEY_FILE = cfg.tlsKey;
180       };
182       serviceConfig = {
183         ProtectSystem = "full";
184         PrivateTmp = "yes";
185         PrivateDevices = "yes";
186         SecureBits = "keep-caps";
187         AmbientCapabilities = "CAP_IPC_LOCK CAP_NET_BIND_SERVICE";
188         CacheDirectory = "coder";
189         CapabilityBoundingSet = "CAP_SYSLOG CAP_IPC_LOCK CAP_NET_BIND_SERVICE";
190         KillSignal = "SIGINT";
191         KillMode = "mixed";
192         NoNewPrivileges = "yes";
193         Restart = "on-failure";
194         ExecStart = "${cfg.package}/bin/coder server";
195         User = cfg.user;
196         Group = cfg.group;
197         EnvironmentFile = lib.mkIf (cfg.environment.file != null) cfg.environment.file;
198       };
199     };
201     services.postgresql = lib.mkIf cfg.database.createLocally {
202       enable = true;
203       ensureDatabases = [
204         cfg.database.database
205       ];
206       ensureUsers = [{
207         name = cfg.user;
208         ensureDBOwnership = true;
209         }
210       ];
211     };
213     users.groups = optionalAttrs (cfg.group == name) {
214       "${cfg.group}" = {};
215     };
216     users.users = optionalAttrs (cfg.user == name) {
217       ${name} = {
218         description = "Coder service user";
219         group = cfg.group;
220         home = cfg.homeDir;
221         createHome = true;
222         isSystemUser = true;
223       };
224     };
225   };
226   meta.maintainers = pkgs.coder.meta.maintainers;