at 18.09-beta 22 kB view raw
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}