1{ config, lib, pkgs, ... }:
2
3# TODO: support non-postgresql
4
5with lib;
6
7let
8 cfg = config.services.gitlab;
9
10 ruby = cfg.packages.gitlab.ruby;
11
12 gitlabSocket = "${cfg.statePath}/tmp/sockets/gitlab.socket";
13 gitalySocket = "${cfg.statePath}/tmp/sockets/gitaly.socket";
14 pathUrlQuote = url: replaceStrings ["/"] ["%2F"] url;
15 pgSuperUser = config.services.postgresql.superUser;
16
17 databaseYml = ''
18 production:
19 adapter: postgresql
20 database: ${cfg.databaseName}
21 host: ${cfg.databaseHost}
22 password: ${cfg.databasePassword}
23 username: ${cfg.databaseUsername}
24 encoding: utf8
25 '';
26
27 gitalyToml = pkgs.writeText "gitaly.toml" ''
28 socket_path = "${lib.escape ["\""] gitalySocket}"
29 bin_dir = "${cfg.packages.gitaly}/bin"
30 prometheus_listen_addr = "localhost:9236"
31
32 [git]
33 bin_path = "${pkgs.git}/bin/git"
34
35 [gitaly-ruby]
36 dir = "${cfg.packages.gitaly.ruby}"
37
38 [gitlab-shell]
39 dir = "${cfg.packages.gitlab-shell}"
40
41 ${concatStringsSep "\n" (attrValues (mapAttrs (k: v: ''
42 [[storage]]
43 name = "${lib.escape ["\""] k}"
44 path = "${lib.escape ["\""] v.path}"
45 '') gitlabConfig.production.repositories.storages))}
46 '';
47
48 gitlabShellYml = ''
49 user: ${cfg.user}
50 gitlab_url: "http+unix://${pathUrlQuote gitlabSocket}"
51 http_settings:
52 self_signed_cert: false
53 repos_path: "${cfg.statePath}/repositories"
54 secret_file: "${cfg.statePath}/config/gitlab_shell_secret"
55 log_file: "${cfg.statePath}/log/gitlab-shell.log"
56 redis:
57 bin: ${pkgs.redis}/bin/redis-cli
58 host: 127.0.0.1
59 port: 6379
60 database: 0
61 namespace: resque:gitlab
62 '';
63
64 redisYml = ''
65 production:
66 url: redis://localhost:6379/
67 '';
68
69 secretsYml = ''
70 production:
71 secret_key_base: ${cfg.secrets.secret}
72 otp_key_base: ${cfg.secrets.otp}
73 db_key_base: ${cfg.secrets.db}
74 openid_connect_signing_key: ${builtins.toJSON cfg.secrets.jws}
75 '';
76
77 gitlabConfig = {
78 # These are the default settings from config/gitlab.example.yml
79 production = flip recursiveUpdate cfg.extraConfig {
80 gitlab = {
81 host = cfg.host;
82 port = cfg.port;
83 https = cfg.https;
84 user = cfg.user;
85 email_enabled = true;
86 email_display_name = "GitLab";
87 email_reply_to = "noreply@localhost";
88 default_theme = 2;
89 default_projects_features = {
90 issues = true;
91 merge_requests = true;
92 wiki = true;
93 snippets = true;
94 builds = true;
95 container_registry = true;
96 };
97 };
98 repositories.storages.default.path = "${cfg.statePath}/repositories";
99 repositories.storages.default.gitaly_address = "unix:${gitalySocket}";
100 artifacts.enabled = true;
101 lfs.enabled = true;
102 gravatar.enabled = true;
103 cron_jobs = { };
104 gitlab_ci.builds_path = "${cfg.statePath}/builds";
105 ldap.enabled = false;
106 omniauth.enabled = false;
107 shared.path = "${cfg.statePath}/shared";
108 gitaly.client_path = "${cfg.packages.gitaly}/bin";
109 backup.path = "${cfg.backupPath}";
110 gitlab_shell = {
111 path = "${cfg.packages.gitlab-shell}";
112 hooks_path = "${cfg.statePath}/shell/hooks";
113 secret_file = "${cfg.statePath}/config/gitlab_shell_secret";
114 upload_pack = true;
115 receive_pack = true;
116 };
117 workhorse = {
118 secret_file = "${cfg.statePath}/.gitlab_workhorse_secret";
119 };
120 git = {
121 bin_path = "git";
122 };
123 monitoring = {
124 ip_whitelist = [ "127.0.0.0/8" "::1/128" ];
125 sidekiq_exporter = {
126 enable = true;
127 address = "localhost";
128 port = 3807;
129 };
130 };
131 extra = {};
132 uploads.storage_path = cfg.statePath;
133 };
134 };
135
136 gitlabEnv = {
137 HOME = "${cfg.statePath}/home";
138 UNICORN_PATH = "${cfg.statePath}/";
139 GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/";
140 GITLAB_STATE_PATH = "${cfg.statePath}";
141 GITLAB_UPLOADS_PATH = "${cfg.statePath}/uploads";
142 SCHEMA = "${cfg.statePath}/db/schema.rb";
143 GITLAB_LOG_PATH = "${cfg.statePath}/log";
144 GITLAB_SHELL_PATH = "${cfg.packages.gitlab-shell}";
145 GITLAB_SHELL_CONFIG_PATH = "${cfg.statePath}/shell/config.yml";
146 GITLAB_SHELL_SECRET_PATH = "${cfg.statePath}/config/gitlab_shell_secret";
147 GITLAB_SHELL_HOOKS_PATH = "${cfg.statePath}/shell/hooks";
148 GITLAB_REDIS_CONFIG_FILE = pkgs.writeText "gitlab-redis.yml" redisYml;
149 prometheus_multiproc_dir = "/run/gitlab";
150 RAILS_ENV = "production";
151 };
152
153 unicornConfig = builtins.readFile ./defaultUnicornConfig.rb;
154
155 gitlab-rake = pkgs.stdenv.mkDerivation rec {
156 name = "gitlab-rake";
157 buildInputs = [ pkgs.makeWrapper ];
158 dontBuild = true;
159 unpackPhase = ":";
160 installPhase = ''
161 mkdir -p $out/bin
162 makeWrapper ${cfg.packages.gitlab.rubyEnv}/bin/rake $out/bin/gitlab-rake \
163 ${concatStrings (mapAttrsToList (name: value: "--set ${name} '${value}' ") gitlabEnv)} \
164 --set GITLAB_CONFIG_PATH '${cfg.statePath}/config' \
165 --set PATH '${lib.makeBinPath [ pkgs.nodejs pkgs.gzip pkgs.git pkgs.gnutar config.services.postgresql.package ]}:$PATH' \
166 --set RAKEOPT '-f ${cfg.packages.gitlab}/share/gitlab/Rakefile' \
167 --run 'cd ${cfg.packages.gitlab}/share/gitlab'
168 '';
169 };
170
171 smtpSettings = pkgs.writeText "gitlab-smtp-settings.rb" ''
172 if Rails.env.production?
173 Rails.application.config.action_mailer.delivery_method = :smtp
174
175 ActionMailer::Base.delivery_method = :smtp
176 ActionMailer::Base.smtp_settings = {
177 address: "${cfg.smtp.address}",
178 port: ${toString cfg.smtp.port},
179 ${optionalString (cfg.smtp.username != null) ''user_name: "${cfg.smtp.username}",''}
180 ${optionalString (cfg.smtp.password != null) ''password: "${cfg.smtp.password}",''}
181 domain: "${cfg.smtp.domain}",
182 ${optionalString (cfg.smtp.authentication != null) "authentication: :${cfg.smtp.authentication},"}
183 enable_starttls_auto: ${toString cfg.smtp.enableStartTLSAuto},
184 openssl_verify_mode: '${cfg.smtp.opensslVerifyMode}'
185 }
186 end
187 '';
188
189in {
190
191 options = {
192 services.gitlab = {
193 enable = mkOption {
194 type = types.bool;
195 default = false;
196 description = ''
197 Enable the gitlab service.
198 '';
199 };
200
201 packages.gitlab = mkOption {
202 type = types.package;
203 default = pkgs.gitlab;
204 defaultText = "pkgs.gitlab";
205 description = "Reference to the gitlab package";
206 };
207
208 packages.gitlab-shell = mkOption {
209 type = types.package;
210 default = pkgs.gitlab-shell;
211 defaultText = "pkgs.gitlab-shell";
212 description = "Reference to the gitlab-shell package";
213 };
214
215 packages.gitlab-workhorse = mkOption {
216 type = types.package;
217 default = pkgs.gitlab-workhorse;
218 defaultText = "pkgs.gitlab-workhorse";
219 description = "Reference to the gitlab-workhorse package";
220 };
221
222 packages.gitaly = mkOption {
223 type = types.package;
224 default = pkgs.gitaly;
225 defaultText = "pkgs.gitaly";
226 description = "Reference to the gitaly package";
227 };
228
229 statePath = mkOption {
230 type = types.str;
231 default = "/var/gitlab/state";
232 description = "Gitlab state directory, logs are stored here.";
233 };
234
235 backupPath = mkOption {
236 type = types.str;
237 default = cfg.statePath + "/backup";
238 description = "Gitlab path for backups.";
239 };
240
241 databaseHost = mkOption {
242 type = types.str;
243 default = "127.0.0.1";
244 description = "Gitlab database hostname.";
245 };
246
247 databasePassword = mkOption {
248 type = types.str;
249 description = "Gitlab database user password.";
250 };
251
252 databaseName = mkOption {
253 type = types.str;
254 default = "gitlab";
255 description = "Gitlab database name.";
256 };
257
258 databaseUsername = mkOption {
259 type = types.str;
260 default = "gitlab";
261 description = "Gitlab database user.";
262 };
263
264 host = mkOption {
265 type = types.str;
266 default = config.networking.hostName;
267 description = "Gitlab host name. Used e.g. for copy-paste URLs.";
268 };
269
270 port = mkOption {
271 type = types.int;
272 default = 8080;
273 description = ''
274 Gitlab server port for copy-paste URLs, e.g. 80 or 443 if you're
275 service over https.
276 '';
277 };
278
279 https = mkOption {
280 type = types.bool;
281 default = false;
282 description = "Whether gitlab prints URLs with https as scheme.";
283 };
284
285 user = mkOption {
286 type = types.str;
287 default = "gitlab";
288 description = "User to run gitlab and all related services.";
289 };
290
291 group = mkOption {
292 type = types.str;
293 default = "gitlab";
294 description = "Group to run gitlab and all related services.";
295 };
296
297 initialRootEmail = mkOption {
298 type = types.str;
299 default = "admin@local.host";
300 description = ''
301 Initial email address of the root account if this is a new install.
302 '';
303 };
304
305 initialRootPassword = mkOption {
306 type = types.str;
307 default = "UseNixOS!";
308 description = ''
309 Initial password of the root account if this is a new install.
310 '';
311 };
312
313 smtp = {
314 enable = mkOption {
315 type = types.bool;
316 default = false;
317 description = "Enable gitlab mail delivery over SMTP.";
318 };
319
320 address = mkOption {
321 type = types.str;
322 default = "localhost";
323 description = "Address of the SMTP server for Gitlab.";
324 };
325
326 port = mkOption {
327 type = types.int;
328 default = 465;
329 description = "Port of the SMTP server for Gitlab.";
330 };
331
332 username = mkOption {
333 type = types.nullOr types.str;
334 default = null;
335 description = "Username of the SMTP server for Gitlab.";
336 };
337
338 password = mkOption {
339 type = types.nullOr types.str;
340 default = null;
341 description = "Password of the SMTP server for Gitlab.";
342 };
343
344 domain = mkOption {
345 type = types.str;
346 default = "localhost";
347 description = "HELO domain to use for outgoing mail.";
348 };
349
350 authentication = mkOption {
351 type = types.nullOr types.str;
352 default = null;
353 description = "Authentitcation type to use, see http://api.rubyonrails.org/classes/ActionMailer/Base.html";
354 };
355
356 enableStartTLSAuto = mkOption {
357 type = types.bool;
358 default = true;
359 description = "Whether to try to use StartTLS.";
360 };
361
362 opensslVerifyMode = mkOption {
363 type = types.str;
364 default = "peer";
365 description = "How OpenSSL checks the certificate, see http://api.rubyonrails.org/classes/ActionMailer/Base.html";
366 };
367 };
368
369 secrets.secret = mkOption {
370 type = types.str;
371 description = ''
372 The secret is used to encrypt variables in the DB. If
373 you change or lose this key you will be unable to access variables
374 stored in database.
375
376 Make sure the secret is at least 30 characters and all random,
377 no regular words or you'll be exposed to dictionary attacks.
378 '';
379 };
380
381 secrets.db = mkOption {
382 type = types.str;
383 description = ''
384 The secret is used to encrypt variables in the DB. If
385 you change or lose this key you will be unable to access variables
386 stored in database.
387
388 Make sure the secret is at least 30 characters and all random,
389 no regular words or you'll be exposed to dictionary attacks.
390 '';
391 };
392
393 secrets.otp = mkOption {
394 type = types.str;
395 description = ''
396 The secret is used to encrypt secrets for OTP tokens. If
397 you change or lose this key, users which have 2FA enabled for login
398 won't be able to login anymore.
399
400 Make sure the secret is at least 30 characters and all random,
401 no regular words or you'll be exposed to dictionary attacks.
402 '';
403 };
404
405 secrets.jws = mkOption {
406 type = types.str;
407 description = ''
408 The secret is used to encrypt session keys. If you change or lose
409 this key, users will be disconnected.
410
411 Make sure the secret is an RSA private key in PEM format. You can
412 generate one with
413
414 openssl genrsa 2048
415 '';
416 };
417
418 extraConfig = mkOption {
419 type = types.attrs;
420 default = {};
421 example = {
422 gitlab = {
423 default_projects_features = {
424 builds = false;
425 };
426 };
427 };
428 description = ''
429 Extra options to be merged into config/gitlab.yml as nix
430 attribute set.
431 '';
432 };
433 };
434 };
435
436 config = mkIf cfg.enable {
437
438 environment.systemPackages = [ pkgs.git gitlab-rake cfg.packages.gitlab-shell ];
439
440 # Redis is required for the sidekiq queue runner.
441 services.redis.enable = mkDefault true;
442 # We use postgres as the main data store.
443 services.postgresql.enable = mkDefault true;
444 # Use postfix to send out mails.
445 services.postfix.enable = mkDefault true;
446
447 users.users = [
448 { name = cfg.user;
449 group = cfg.group;
450 home = "${cfg.statePath}/home";
451 shell = "${pkgs.bash}/bin/bash";
452 uid = config.ids.uids.gitlab;
453 }
454 ];
455
456 users.groups = [
457 { name = cfg.group;
458 gid = config.ids.gids.gitlab;
459 }
460 ];
461
462 systemd.services.gitlab-sidekiq = {
463 after = [ "network.target" "redis.service" ];
464 wantedBy = [ "multi-user.target" ];
465 partOf = [ "gitlab.service" ];
466 environment = gitlabEnv;
467 path = with pkgs; [
468 config.services.postgresql.package
469 gitAndTools.git
470 ruby
471 openssh
472 nodejs
473 gnupg
474 ];
475 serviceConfig = {
476 Type = "simple";
477 User = cfg.user;
478 Group = cfg.group;
479 TimeoutSec = "infinity";
480 Restart = "on-failure";
481 WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
482 ExecStart="${cfg.packages.gitlab.rubyEnv}/bin/sidekiq -C \"${cfg.packages.gitlab}/share/gitlab/config/sidekiq_queues.yml\" -e production -P ${cfg.statePath}/tmp/sidekiq.pid";
483 };
484 };
485
486 systemd.services.gitaly = {
487 after = [ "network.target" "gitlab.service" ];
488 wantedBy = [ "multi-user.target" ];
489 environment.HOME = gitlabEnv.HOME;
490 environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH;
491 path = with pkgs; [ gitAndTools.git cfg.packages.gitaly.rubyEnv cfg.packages.gitaly.rubyEnv.wrappedRuby ];
492 serviceConfig = {
493 Type = "simple";
494 User = cfg.user;
495 Group = cfg.group;
496 TimeoutSec = "infinity";
497 Restart = "on-failure";
498 WorkingDirectory = gitlabEnv.HOME;
499 ExecStart = "${cfg.packages.gitaly}/bin/gitaly ${gitalyToml}";
500 };
501 };
502
503 systemd.services.gitlab-workhorse = {
504 after = [ "network.target" "gitlab.service" ];
505 wantedBy = [ "multi-user.target" ];
506 environment.HOME = gitlabEnv.HOME;
507 environment.GITLAB_SHELL_CONFIG_PATH = gitlabEnv.GITLAB_SHELL_CONFIG_PATH;
508 path = with pkgs; [
509 gitAndTools.git
510 gnutar
511 gzip
512 openssh
513 gitlab-workhorse
514 ];
515 preStart = ''
516 mkdir -p /run/gitlab
517 chown ${cfg.user}:${cfg.group} /run/gitlab
518 '';
519 serviceConfig = {
520 PermissionsStartOnly = true; # preStart must be run as root
521 Type = "simple";
522 User = cfg.user;
523 Group = cfg.group;
524 TimeoutSec = "infinity";
525 Restart = "on-failure";
526 WorkingDirectory = gitlabEnv.HOME;
527 ExecStart =
528 "${cfg.packages.gitlab-workhorse}/bin/gitlab-workhorse "
529 + "-listenUmask 0 "
530 + "-listenNetwork unix "
531 + "-listenAddr /run/gitlab/gitlab-workhorse.socket "
532 + "-authSocket ${gitlabSocket} "
533 + "-documentRoot ${cfg.packages.gitlab}/share/gitlab/public "
534 + "-secretPath ${cfg.statePath}/.gitlab_workhorse_secret";
535 };
536 };
537
538 systemd.services.gitlab = {
539 after = [ "network.target" "postgresql.service" "redis.service" ];
540 requires = [ "gitlab-sidekiq.service" ];
541 wantedBy = [ "multi-user.target" ];
542 environment = gitlabEnv;
543 path = with pkgs; [
544 config.services.postgresql.package
545 gitAndTools.git
546 openssh
547 nodejs
548 procps
549 gnupg
550 ];
551 preStart = ''
552 mkdir -p ${cfg.backupPath}
553 mkdir -p ${cfg.statePath}/builds
554 mkdir -p ${cfg.statePath}/repositories
555 mkdir -p ${gitlabConfig.production.shared.path}/artifacts
556 mkdir -p ${gitlabConfig.production.shared.path}/lfs-objects
557 mkdir -p ${gitlabConfig.production.shared.path}/pages
558 mkdir -p ${cfg.statePath}/log
559 mkdir -p ${cfg.statePath}/tmp/pids
560 mkdir -p ${cfg.statePath}/tmp/sockets
561 mkdir -p ${cfg.statePath}/shell
562 mkdir -p ${cfg.statePath}/db
563 mkdir -p ${cfg.statePath}/uploads
564
565 rm -rf ${cfg.statePath}/config ${cfg.statePath}/shell/hooks
566 mkdir -p ${cfg.statePath}/config
567
568 ${pkgs.openssl}/bin/openssl rand -hex 32 > ${cfg.statePath}/config/gitlab_shell_secret
569
570 mkdir -p /run/gitlab
571 mkdir -p ${cfg.statePath}/log
572 ln -sf ${cfg.statePath}/log /run/gitlab/log
573 ln -sf ${cfg.statePath}/tmp /run/gitlab/tmp
574 ln -sf ${cfg.statePath}/uploads /run/gitlab/uploads
575 ln -sf $GITLAB_SHELL_CONFIG_PATH /run/gitlab/shell-config.yml
576 chown -R ${cfg.user}:${cfg.group} /run/gitlab
577
578 # Prepare home directory
579 mkdir -p ${gitlabEnv.HOME}/.ssh
580 touch ${gitlabEnv.HOME}/.ssh/authorized_keys
581 chown -R ${cfg.user}:${cfg.group} ${gitlabEnv.HOME}/
582
583 cp -rf ${cfg.packages.gitlab}/share/gitlab/db/* ${cfg.statePath}/db
584 cp -rf ${cfg.packages.gitlab}/share/gitlab/config.dist/* ${cfg.statePath}/config
585 ${optionalString cfg.smtp.enable ''
586 ln -sf ${smtpSettings} ${cfg.statePath}/config/initializers/smtp_settings.rb
587 ''}
588 ln -sf ${cfg.statePath}/config /run/gitlab/config
589 if [ -e ${cfg.statePath}/lib ]; then
590 rm ${cfg.statePath}/lib
591 fi
592 ln -sf ${pkgs.gitlab}/share/gitlab/lib ${cfg.statePath}/lib
593 cp ${cfg.packages.gitlab}/share/gitlab/VERSION ${cfg.statePath}/VERSION
594
595 # JSON is a subset of YAML
596 ln -fs ${pkgs.writeText "gitlab.yml" (builtins.toJSON gitlabConfig)} ${cfg.statePath}/config/gitlab.yml
597 ln -fs ${pkgs.writeText "database.yml" databaseYml} ${cfg.statePath}/config/database.yml
598 ln -fs ${pkgs.writeText "secrets.yml" secretsYml} ${cfg.statePath}/config/secrets.yml
599 ln -fs ${pkgs.writeText "unicorn.rb" unicornConfig} ${cfg.statePath}/config/unicorn.rb
600
601 chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}/
602 chmod -R ug+rwX,o-rwx+X ${cfg.statePath}/
603
604 # Install the shell required to push repositories
605 ln -fs ${pkgs.writeText "config.yml" gitlabShellYml} "$GITLAB_SHELL_CONFIG_PATH"
606 ln -fs ${cfg.packages.gitlab-shell}/hooks "$GITLAB_SHELL_HOOKS_PATH"
607 ${cfg.packages.gitlab-shell}/bin/install
608
609 if [ "${cfg.databaseHost}" = "127.0.0.1" ]; then
610 if ! test -e "${cfg.statePath}/db-created"; then
611 ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql postgres -c "CREATE ROLE ${cfg.databaseUsername} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '${cfg.databasePassword}'"
612 ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} ${config.services.postgresql.package}/bin/createdb --owner ${cfg.databaseUsername} ${cfg.databaseName}
613 touch "${cfg.statePath}/db-created"
614 fi
615
616 # enable required pg_trgm extension for gitlab
617 ${pkgs.sudo}/bin/sudo -u ${pgSuperUser} psql ${cfg.databaseName} -c "CREATE EXTENSION IF NOT EXISTS pg_trgm"
618 fi
619
620 # Always do the db migrations just to be sure the database is up-to-date
621 ${gitlab-rake}/bin/gitlab-rake db:migrate RAILS_ENV=production
622
623 # The gitlab:setup task is horribly broken somehow, the db:migrate
624 # task above and the db:seed_fu below will do the same for setting
625 # up the initial database
626 if ! test -e "${cfg.statePath}/db-seeded"; then
627 ${gitlab-rake}/bin/gitlab-rake db:seed_fu RAILS_ENV=production \
628 GITLAB_ROOT_PASSWORD='${cfg.initialRootPassword}' GITLAB_ROOT_EMAIL='${cfg.initialRootEmail}'
629 touch "${cfg.statePath}/db-seeded"
630 fi
631
632 # The gitlab:shell:create_hooks task seems broken for fixing links
633 # so we instead delete all the hooks and create them anew
634 rm -f ${cfg.statePath}/repositories/**/*.git/hooks
635 ${gitlab-rake}/bin/gitlab-rake gitlab:shell:create_hooks RAILS_ENV=production
636
637 # Change permissions in the last step because some of the
638 # intermediary scripts like to create directories as root.
639 chown -R ${cfg.user}:${cfg.group} ${cfg.statePath}
640 chmod -R ug+rwX,o-rwx+X ${cfg.statePath}
641 chmod -R u+rwX,go-rwx+X ${gitlabEnv.HOME}
642 chmod -R ug+rwX,o-rwx ${cfg.statePath}/repositories
643 chmod -R ug-s ${cfg.statePath}/repositories
644 find ${cfg.statePath}/repositories -type d -print0 | xargs -0 chmod g+s
645 '';
646
647 serviceConfig = {
648 PermissionsStartOnly = true; # preStart must be run as root
649 Type = "simple";
650 User = cfg.user;
651 Group = cfg.group;
652 TimeoutSec = "infinity";
653 Restart = "on-failure";
654 WorkingDirectory = "${cfg.packages.gitlab}/share/gitlab";
655 ExecStart = "${cfg.packages.gitlab.rubyEnv}/bin/unicorn -c ${cfg.statePath}/config/unicorn.rb -E production";
656 };
657
658 };
659
660 };
661
662 meta.doc = ./gitlab.xml;
663
664}