1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 cfg = config.services.code-server;
10 defaultUser = "code-server";
11 defaultGroup = defaultUser;
12in
13{
14 options = {
15 services.code-server = {
16 enable = lib.mkEnableOption "code-server";
17
18 package = lib.mkPackageOption pkgs "code-server" {
19 example = ''
20 pkgs.vscode-with-extensions.override {
21 vscode = pkgs.code-server;
22 vscodeExtensions = with pkgs.vscode-extensions; [
23 bbenoist.nix
24 dracula-theme.theme-dracula
25 ];
26 }
27 '';
28 };
29
30 extraPackages = lib.mkOption {
31 default = [ ];
32 description = ''
33 Additional packages to add to the code-server {env}`PATH`.
34 '';
35 example = lib.literalExpression "[ pkgs.go ]";
36 type = lib.types.listOf lib.types.package;
37 };
38
39 extraEnvironment = lib.mkOption {
40 type = lib.types.attrsOf lib.types.str;
41 description = ''
42 Additional environment variables to pass to code-server.
43 '';
44 default = { };
45 example = {
46 PKG_CONFIG_PATH = "/run/current-system/sw/lib/pkgconfig";
47 };
48 };
49
50 extraArguments = lib.mkOption {
51 default = [ ];
52 description = ''
53 Additional arguments to pass to code-server.
54 '';
55 example = lib.literalExpression ''[ "--log=info" ]'';
56 type = lib.types.listOf lib.types.str;
57 };
58
59 host = lib.mkOption {
60 default = "localhost";
61 description = ''
62 The host name or IP address the server should listen to.
63 '';
64 type = lib.types.str;
65 };
66
67 port = lib.mkOption {
68 default = 4444;
69 description = ''
70 The port the server should listen to.
71 '';
72 type = lib.types.port;
73 };
74
75 auth = lib.mkOption {
76 default = "password";
77 description = ''
78 The type of authentication to use.
79 '';
80 type = lib.types.enum [
81 "none"
82 "password"
83 ];
84 };
85
86 hashedPassword = lib.mkOption {
87 default = "";
88 description = ''
89 Create the password with: {command}`echo -n 'thisismypassword' | nix run nixpkgs#libargon2 -- "$(head -c 20 /dev/random | base64)" -e`
90 '';
91 type = lib.types.str;
92 };
93
94 user = lib.mkOption {
95 default = defaultUser;
96 example = "yourUser";
97 description = ''
98 The user to run code-server as.
99 By default, a user named `${defaultUser}` will be created.
100 '';
101 type = lib.types.str;
102 };
103
104 group = lib.mkOption {
105 default = defaultGroup;
106 example = "yourGroup";
107 description = ''
108 The group to run code-server under.
109 By default, a group named `${defaultGroup}` will be created.
110 '';
111 type = lib.types.str;
112 };
113
114 extraGroups = lib.mkOption {
115 default = [ ];
116 description = ''
117 An array of additional groups for the `${defaultUser}` user.
118 '';
119 example = [ "docker" ];
120 type = lib.types.listOf lib.types.str;
121 };
122
123 socket = lib.mkOption {
124 default = null;
125 example = "/run/code-server/socket";
126 description = ''
127 Path to a socket (bind-addr will be ignored).
128 '';
129 type = lib.types.nullOr lib.types.str;
130 };
131
132 socketMode = lib.mkOption {
133 default = null;
134 description = ''
135 File mode of the socket.
136 '';
137 type = lib.types.nullOr lib.types.str;
138 };
139
140 userDataDir = lib.mkOption {
141 default = null;
142 description = ''
143 Path to the user data directory.
144 '';
145 type = lib.types.nullOr lib.types.str;
146 };
147
148 extensionsDir = lib.mkOption {
149 default = null;
150 description = ''
151 Path to the extensions directory.
152 '';
153 type = lib.types.nullOr lib.types.str;
154 };
155
156 proxyDomain = lib.mkOption {
157 default = null;
158 example = "code-server.lan";
159 description = ''
160 Domain used for proxying ports.
161 '';
162 type = lib.types.nullOr lib.types.str;
163 };
164
165 disableTelemetry = lib.mkOption {
166 default = false;
167 example = true;
168 description = ''
169 Disable telemetry.
170 '';
171 type = lib.types.bool;
172 };
173
174 disableUpdateCheck = lib.mkOption {
175 default = false;
176 example = true;
177 description = ''
178 Disable update check.
179 Without this flag, code-server checks every 6 hours against the latest github release and
180 then notifies you once every week that a new release is available.
181 '';
182 type = lib.types.bool;
183 };
184
185 disableFileDownloads = lib.mkOption {
186 default = false;
187 example = true;
188 description = ''
189 Disable file downloads from Code.
190 '';
191 type = lib.types.bool;
192 };
193
194 disableWorkspaceTrust = lib.mkOption {
195 default = false;
196 example = true;
197 description = ''
198 Disable Workspace Trust feature.
199 '';
200 type = lib.types.bool;
201 };
202
203 disableGettingStartedOverride = lib.mkOption {
204 default = false;
205 example = true;
206 description = ''
207 Disable the coder/coder override in the Help: Getting Started page.
208 '';
209 type = lib.types.bool;
210 };
211
212 };
213 };
214
215 config = lib.mkIf cfg.enable {
216 systemd.services.code-server = {
217 description = "Code server";
218 wantedBy = [ "multi-user.target" ];
219 wants = [ "network-online.target" ];
220 after = [ "network-online.target" ];
221 path = cfg.extraPackages;
222 environment = {
223 HASHED_PASSWORD = cfg.hashedPassword;
224 }
225 // cfg.extraEnvironment;
226 serviceConfig = {
227 ExecStart = ''
228 ${lib.getExe cfg.package} \
229 --auth=${cfg.auth} \
230 --bind-addr=${cfg.host}:${toString cfg.port} \
231 ''
232 + lib.optionalString (cfg.socket != null) ''
233 --socket=${cfg.socket} \
234 ''
235 + lib.optionalString (cfg.userDataDir != null) ''
236 --user-data-dir=${cfg.userDataDir} \
237 ''
238 + lib.optionalString (cfg.extensionsDir != null) ''
239 --extensions-dir=${cfg.extensionsDir} \
240 ''
241 + lib.optionalString (cfg.disableTelemetry == true) ''
242 --disable-telemetry \
243 ''
244 + lib.optionalString (cfg.disableUpdateCheck == true) ''
245 --disable-update-check \
246 ''
247 + lib.optionalString (cfg.disableFileDownloads == true) ''
248 --disable-file-downloads \
249 ''
250 + lib.optionalString (cfg.disableWorkspaceTrust == true) ''
251 --disable-workspace-trust \
252 ''
253 + lib.optionalString (cfg.disableGettingStartedOverride == true) ''
254 --disable-getting-started-override \
255 ''
256 + lib.escapeShellArgs cfg.extraArguments;
257 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
258 RuntimeDirectory = cfg.user;
259 User = cfg.user;
260 Group = cfg.group;
261 Restart = "on-failure";
262 };
263 };
264
265 users.users."${cfg.user}" = lib.mkMerge [
266 (lib.mkIf (cfg.user == defaultUser) {
267 isNormalUser = true;
268 description = "code-server user";
269 inherit (cfg) group;
270 })
271 {
272 packages = cfg.extraPackages;
273 inherit (cfg) extraGroups;
274 }
275 ];
276
277 users.groups."${defaultGroup}" = lib.mkIf (cfg.group == defaultGroup) { };
278 };
279
280 meta.maintainers = [ lib.maintainers.stackshadow ];
281}