1{ config, lib, pkgs, ... }:
2
3with lib;
4let
5
6 cfg = config.services.code-server;
7 defaultUser = "code-server";
8 defaultGroup = defaultUser;
9
10in {
11 ###### interface
12 options = {
13 services.code-server = {
14 enable = mkEnableOption (lib.mdDoc "code-server");
15
16 package = mkOption {
17 default = pkgs.code-server;
18 defaultText = lib.literalExpression "pkgs.code-server";
19 description = lib.mdDoc "Which code-server derivation to use.";
20 type = types.package;
21 };
22
23 extraPackages = mkOption {
24 default = [ ];
25 description = lib.mdDoc "Packages that are available in the PATH of code-server.";
26 example = "[ pkgs.go ]";
27 type = types.listOf types.package;
28 };
29
30 extraEnvironment = mkOption {
31 type = types.attrsOf types.str;
32 description =
33 lib.mdDoc "Additional environment variables to passed to code-server.";
34 default = { };
35 example = { PKG_CONFIG_PATH = "/run/current-system/sw/lib/pkgconfig"; };
36 };
37
38 extraArguments = mkOption {
39 default = [ "--disable-telemetry" ];
40 description = lib.mdDoc "Additional arguments that passed to code-server";
41 example = ''[ "--verbose" ]'';
42 type = types.listOf types.str;
43 };
44
45 host = mkOption {
46 default = "127.0.0.1";
47 description = lib.mdDoc "The host-ip to bind to.";
48 type = types.str;
49 };
50
51 port = mkOption {
52 default = 4444;
53 description = lib.mdDoc "The port where code-server runs.";
54 type = types.port;
55 };
56
57 auth = mkOption {
58 default = "password";
59 description = lib.mdDoc "The type of authentication to use.";
60 type = types.enum [ "none" "password" ];
61 };
62
63 hashedPassword = mkOption {
64 default = "";
65 description =
66 lib.mdDoc "Create the password with: `echo -n 'thisismypassword' | npx argon2-cli -e`.";
67 type = types.str;
68 };
69
70 user = mkOption {
71 default = defaultUser;
72 example = "yourUser";
73 description = lib.mdDoc ''
74 The user to run code-server as.
75 By default, a user named `${defaultUser}` will be created.
76 '';
77 type = types.str;
78 };
79
80 group = mkOption {
81 default = defaultGroup;
82 example = "yourGroup";
83 description = lib.mdDoc ''
84 The group to run code-server under.
85 By default, a group named `${defaultGroup}` will be created.
86 '';
87 type = types.str;
88 };
89
90 extraGroups = mkOption {
91 default = [ ];
92 description =
93 lib.mdDoc "An array of additional groups for the `${defaultUser}` user.";
94 example = [ "docker" ];
95 type = types.listOf types.str;
96 };
97
98 };
99 };
100
101 ###### implementation
102 config = mkIf cfg.enable {
103 systemd.services.code-server = {
104 description = "VSCode server";
105 wantedBy = [ "multi-user.target" ];
106 after = [ "network-online.target" ];
107 path = cfg.extraPackages;
108 environment = {
109 HASHED_PASSWORD = cfg.hashedPassword;
110 } // cfg.extraEnvironment;
111 serviceConfig = {
112 ExecStart = "${cfg.package}/bin/code-server --bind-addr ${cfg.host}:${toString cfg.port} --auth ${cfg.auth} " + lib.escapeShellArgs cfg.extraArguments;
113 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
114 RuntimeDirectory = cfg.user;
115 User = cfg.user;
116 Group = cfg.group;
117 Restart = "on-failure";
118 };
119
120 };
121
122 users.users."${cfg.user}" = mkMerge [
123 (mkIf (cfg.user == defaultUser) {
124 isNormalUser = true;
125 description = "code-server user";
126 inherit (cfg) group;
127 })
128 {
129 packages = cfg.extraPackages;
130 inherit (cfg) extraGroups;
131 }
132 ];
133
134 users.groups."${defaultGroup}" = mkIf (cfg.group == defaultGroup) { };
135
136 };
137
138 meta.maintainers = with maintainers; [ stackshadow ];
139}