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