From 23d92c4be377248883a39e489c71df3c67fbff64 Mon Sep 17 00:00:00 2001 From: akshat5302 Date: Fri, 12 Sep 2025 14:16:37 +0530 Subject: [PATCH] Add relativeUrlRoot configuration support for GitLab charts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Related to gitlab-org/charts/gitlab#6121. GitLab can now run under a subpath like /gitlab/ by setting the relativeUrlRoot parameter. This is useful when you want to: • Deploy GitLab behind a reverse proxy • Run multiple GitLab instances on the same domain • Access GitLab at a custom path like yourdomain.com/gitlab This can be done by adding relativeUrlRoot under global.appConfig in gitlab values file Changelog: added --- .../charts/sidekiq/templates/configmap.yaml | 3 + .../charts/sidekiq/templates/deployment.yaml | 4 + .../charts/webservice/templates/_ingress.tpl | 2 +- .../charts/webservice/templates/configmap.yml | 3 + .../webservice/templates/deployment.yaml | 10 ++- charts/gitlab/templates/_workhorse.tpl | 2 +- doc/charts/globals.md | 38 +++++++++ spec/configuration/gitlab-yml-erb_spec.rb | 78 +++++++++++++++++++ templates/_checkConfig.tpl | 1 + templates/_checkConfig_webservice.tpl | 13 ++++ templates/_helpers.tpl | 4 +- values.yaml | 1 + 12 files changed, 152 insertions(+), 7 deletions(-) diff --git a/charts/gitlab/charts/sidekiq/templates/configmap.yaml b/charts/gitlab/charts/sidekiq/templates/configmap.yaml index 8c2d67ad30..f66058e37f 100644 --- a/charts/gitlab/charts/sidekiq/templates/configmap.yaml +++ b/charts/gitlab/charts/sidekiq/templates/configmap.yaml @@ -29,6 +29,9 @@ data: gitlab: host: {{ template "gitlab.gitlab.hostname" . }} https: {{ hasPrefix "https://" (include "gitlab.gitlab.url" .) }} + {{- if .Values.global.appConfig.relativeUrlRoot }} + relative_url_root: {{ .Values.global.appConfig.relativeUrlRoot | quote }} + {{- end }} {{- with .Values.global.hosts.ssh }} ssh_host: {{ . | quote }} {{- end }} diff --git a/charts/gitlab/charts/sidekiq/templates/deployment.yaml b/charts/gitlab/charts/sidekiq/templates/deployment.yaml index 91dc3a4d0c..3418b74121 100644 --- a/charts/gitlab/charts/sidekiq/templates/deployment.yaml +++ b/charts/gitlab/charts/sidekiq/templates/deployment.yaml @@ -222,6 +222,10 @@ spec: - name: ENABLE_BOOTSNAP value: "1" {{- end }} + {{- if $.Values.global.appConfig.relativeUrlRoot }} + - name: RAILS_RELATIVE_URL_ROOT + value: {{ $.Values.global.appConfig.relativeUrlRoot | quote }} + {{- end }} {{- include "gitlab.tracing.env" $ | nindent 12 }} {{- include "sidekiq.podExtraEnv" (dict "local" . "context" $) | nindent 12 }} {{- include "gitlab.extraEnvFrom" (dict "root" $ "local" .) | nindent 12 }} diff --git a/charts/gitlab/charts/webservice/templates/_ingress.tpl b/charts/gitlab/charts/webservice/templates/_ingress.tpl index e95212fa93..b7880fa474 100644 --- a/charts/gitlab/charts/webservice/templates/_ingress.tpl +++ b/charts/gitlab/charts/webservice/templates/_ingress.tpl @@ -42,7 +42,7 @@ spec: - host: {{ .host }} http: paths: - - path: {{ .deployment.ingress.path }} + - path: {{ $global.appConfig.relativeUrlRoot }}{{ .deployment.ingress.path }} {{ if or (.root.Capabilities.APIVersions.Has "networking.k8s.io/v1/Ingress") (eq $global.ingress.apiVersion "networking.k8s.io/v1") -}} pathType: {{ default .deployment.ingress.pathType $global.ingress.pathType }} backend: diff --git a/charts/gitlab/charts/webservice/templates/configmap.yml b/charts/gitlab/charts/webservice/templates/configmap.yml index e9245dd087..fb269bd8e8 100644 --- a/charts/gitlab/charts/webservice/templates/configmap.yml +++ b/charts/gitlab/charts/webservice/templates/configmap.yml @@ -38,6 +38,9 @@ data: gitlab: host: {{ template "gitlab.gitlab.hostname" . }} https: {{ hasPrefix "https://" (include "gitlab.gitlab.url" .) }} + {{- if .Values.global.appConfig.relativeUrlRoot }} + relative_url_root: {{ .Values.global.appConfig.relativeUrlRoot | quote }} + {{- end }} {{- with .Values.global.hosts.ssh }} ssh_host: {{ . | quote }} {{- end }} diff --git a/charts/gitlab/charts/webservice/templates/deployment.yaml b/charts/gitlab/charts/webservice/templates/deployment.yaml index 5db51df8cf..1ca48e5275 100644 --- a/charts/gitlab/charts/webservice/templates/deployment.yaml +++ b/charts/gitlab/charts/webservice/templates/deployment.yaml @@ -255,6 +255,10 @@ spec: {{- end }} - name: WORKHORSE_ARCHIVE_CACHE_DISABLED value: "true" + {{- if $.Values.global.appConfig.relativeUrlRoot }} + - name: RAILS_RELATIVE_URL_ROOT + value: {{ $.Values.global.appConfig.relativeUrlRoot | quote }} + {{- end }} {{- include "webservice.extraEnv" (dict "global" $.Values.global "local" .) | nindent 12 }} {{- include "gitlab.extraEnvFrom" (dict "root" $ "local" .) | nindent 12 }} volumeMounts: @@ -312,7 +316,7 @@ spec: {{- end }} livenessProbe: httpGet: - path: /-/liveness + path: {{ $.Values.global.appConfig.relativeUrlRoot }}/-/liveness {{- if and (not $.Values.http.enabled) $.Values.tls.enabled }} scheme: HTTPS port: {{ $.Values.service.tls.internalPort }} @@ -326,7 +330,7 @@ spec: failureThreshold: {{ .deployment.livenessProbe.failureThreshold }} readinessProbe: httpGet: - path: /-/readiness + path: {{ $.Values.global.appConfig.relativeUrlRoot }}/-/readiness {{- if and (not $.Values.http.enabled) $.Values.tls.enabled }} scheme: HTTPS port: {{ $.Values.service.tls.internalPort }} @@ -364,7 +368,7 @@ spec: - name: TMPDIR value: "/tmp/gitlab" - name: GITLAB_WORKHORSE_AUTH_BACKEND - value: "http://localhost:{{ $.Values.service.internalPort }}" + value: "http://localhost:{{ $.Values.service.internalPort }}{{ $.Values.global.appConfig.relativeUrlRoot }}" - name: GITLAB_WORKHORSE_EXTRA_ARGS value: {{ .workhorse.extraArgs | quote }} - name: GITLAB_WORKHORSE_LISTEN_PORT diff --git a/charts/gitlab/templates/_workhorse.tpl b/charts/gitlab/templates/_workhorse.tpl index ba43643f33..ac7cce9764 100644 --- a/charts/gitlab/templates/_workhorse.tpl +++ b/charts/gitlab/templates/_workhorse.tpl @@ -4,7 +4,7 @@ Return the workhorse url */}} {{- define "gitlab.workhorse.url" -}} -{{ template "gitlab.workhorse.scheme" . }}://{{ template "gitlab.workhorse.host" . }}:{{ template "gitlab.workhorse.port" . }} +{{ template "gitlab.workhorse.scheme" . }}://{{ template "gitlab.workhorse.host" . }}:{{ template "gitlab.workhorse.port" . }}{{ .Values.global.appConfig.relativeUrlRoot }} {{- end -}} {{- define "gitlab.workhorse.scheme" -}} diff --git a/doc/charts/globals.md b/doc/charts/globals.md index 196a1b01f5..cd62cdc6d8 100644 --- a/doc/charts/globals.md +++ b/doc/charts/globals.md @@ -976,6 +976,7 @@ with the `global.appConfig` key. global: appConfig: # cdnHost: + relativeUrlRoot: "" contentSecurityPolicy: enabled: false report_only: true @@ -1124,12 +1125,19 @@ global: ### General application settings +{{< history >}} + +- `relativeUrlRoot` setting [introduced](https://gitlab.com/gitlab-org/charts/gitlab/-/issues/6121) in GitLab 18.4. + +{{< /history >}} + The `appConfig` settings that can be used to tweak the general properties of the Rails application are described below: | Name | Type | Default | Description | |:------------------------------------|:-------:|:--------|:------------| | `cdnHost` | String | (empty) | Sets a base URL for a CDN to serve static assets (for example, `https://mycdnsubdomain.fictional-cdn.com`). | +| `relativeUrlRoot` | String | (empty) | Sets a [relative URL root](#configure-a-relative-url-root) for GitLab (for example, `/gitlab`). When configured, GitLab will be accessible at the specified path instead of the root path. | | `contentSecurityPolicy` | Struct | | [See below](#content-security-policy). | | `enableUsagePing` | Boolean | `true` | A flag to disable the [usage ping support](https://docs.gitlab.com/administration/settings/usage_statistics/). | | `enableSeatLink` | Boolean | `true` | A flag to disable the [seat link support](https://docs.gitlab.com/subscriptions/#seat-link). | @@ -1180,6 +1188,36 @@ Improperly configuring the CSP rules could prevent GitLab from working properly. Before rolling out a policy, you may also want to change `report_only` to `true` to test the configuration. +#### Configure a relative URL root + +{{< details >}} + +- Status: Beta + +{{< /details >}} + +{{< alert type="warning" >}} + +Configuring a relative URL for GitLab has [known issues with Geo](https://gitlab.com/gitlab-org/gitlab/-/issues/456427) and +[testing limitations](https://gitlab.com/gitlab-org/gitlab/-/issues/439943). + +{{< /alert >}} + +Though you should install GitLab on its own domain or subdomain, you can install under a relative URL if required. For example, +`https://example.com/gitlab`. + +The ingresses of all webservice deployments will have this path prefixed. + +```yaml +global: + appConfig: + relativeUrlRoot: "/gitlab" + hosts: + domain: example.com + gitlab: + name: example.com +``` + #### `defaultProjectsFeatures` Flags to decide if new projects should be created with the respective features by diff --git a/spec/configuration/gitlab-yml-erb_spec.rb b/spec/configuration/gitlab-yml-erb_spec.rb index 63ef4915eb..68fc239bf9 100644 --- a/spec/configuration/gitlab-yml-erb_spec.rb +++ b/spec/configuration/gitlab-yml-erb_spec.rb @@ -697,4 +697,82 @@ describe 'gitlab.yml.erb configuration' do end end end + + context 'relativeUrlRoot configuration' do + let(:required_values) do + YAML.safe_load(%( + global: + appConfig: + relativeUrlRoot: #{value} + )).deep_merge!(default_values) + end + + context 'when configured' do + let(:value) { "/gitlab" } + + it 'populates relative_url_root in gitlab.yml.erb' do + t = HelmTemplate.new(required_values) + expect(t.exit_code).to eq(0) + + # Check webservice config + expect(t.dig( + 'ConfigMap/test-webservice', + 'data', + 'gitlab.yml.erb' + )).to include('relative_url_root: "/gitlab"') + + # Check sidekiq config + expect(t.dig( + 'ConfigMap/test-sidekiq', + 'data', + 'gitlab.yml.erb' + )).to include('relative_url_root: "/gitlab"') + end + + it 'includes relativeUrlRoot in registry auth endpoint' do + t = HelmTemplate.new(required_values) + expect(t.exit_code).to eq(0) + + expect(t.dig( + 'ConfigMap/test-registry', + 'data', + 'config.yml.tpl' + )).to include('realm: https://gitlab.example.com/gitlab/jwt/auth') + end + end + + context 'when not configured' do + let(:value) { nil } + + it 'does not populate relative_url_root in gitlab.yml.erb' do + t = HelmTemplate.new(required_values) + expect(t.exit_code).to eq(0) + + # Check webservice config + expect(t.dig( + 'ConfigMap/test-webservice', + 'data', + 'gitlab.yml.erb' + )).not_to include('relative_url_root') + + # Check sidekiq config + expect(t.dig( + 'ConfigMap/test-sidekiq', + 'data', + 'gitlab.yml.erb' + )).not_to include('relative_url_root') + end + + it 'does not include relativeUrlRoot in registry auth endpoint' do + t = HelmTemplate.new(required_values) + expect(t.exit_code).to eq(0) + + expect(t.dig( + 'ConfigMap/test-registry', + 'data', + 'config.yml.tpl' + )).to include('realm: https://gitlab.example.com/jwt/auth') + end + end + end end diff --git a/templates/_checkConfig.tpl b/templates/_checkConfig.tpl index e2f6fef147..a3903ea7af 100644 --- a/templates/_checkConfig.tpl +++ b/templates/_checkConfig.tpl @@ -94,6 +94,7 @@ Due to gotpl scoping, we can't make use of `range`, so we have to add action lin {{/* _checkConfig_webservice.tpl*/}} {{- $messages = append $messages (include "gitlab.checkConfig.appConfig.maxRequestDurationSeconds" .) -}} +{{- $messages = append $messages (include "gitlab.checkConfig.appConfig.relativeUrlRoot" .) -}} {{- $messages = append $messages (include "gitlab.checkConfig.webservice.gracePeriod" .) -}} {{- $messages = append $messages (include "gitlab.checkConfig.webservice.loadBalancer" .) -}} diff --git a/templates/_checkConfig_webservice.tpl b/templates/_checkConfig_webservice.tpl index 3cf280547e..63ab3f1846 100644 --- a/templates/_checkConfig_webservice.tpl +++ b/templates/_checkConfig_webservice.tpl @@ -48,3 +48,16 @@ webservice: {{- end -}} {{- end -}} {{/* END gitlab.checkConfig.webservice.loadBalancer */}} + +{{/* +Ensure relativeUrlRoot is properly formatted using regex pattern validation +*/}} +{{- define "gitlab.checkConfig.appConfig.relativeUrlRoot" -}} +{{- $relativeUrlRoot := $.Values.global.appConfig.relativeUrlRoot }} +{{- if and $relativeUrlRoot (not (regexMatch "^(/[a-zA-Z0-9]+)+$" $relativeUrlRoot)) }} +gitlab: relativeUrlRoot has unexpected pattern + The current value of global.appConfig.relativeUrlRoot ({{ $relativeUrlRoot }}) does not match the expected pattern. + Make sure to specify a subpath without any special characters. For example: /gitlab +{{- end }} +{{- end }} +{{/* END gitlab.checkConfig.appConfig.relativeUrlRoot */}} diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 5ae504163e..5c6203259b 100644 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -54,9 +54,9 @@ Calls into the `gitlab.gitlabHost` function for the hostname part of the url. */}} {{- define "gitlab.gitlab.url" -}} {{- if or .Values.global.hosts.https .Values.global.hosts.gitlab.https -}} -{{- printf "https://%s" (include "gitlab.gitlab.hostname" .) -}} +{{- printf "https://%s%s" (include "gitlab.gitlab.hostname" .) .Values.global.appConfig.relativeUrlRoot -}} {{- else -}} -{{- printf "http://%s" (include "gitlab.gitlab.hostname" .) -}} +{{- printf "http://%s%s" (include "gitlab.gitlab.hostname" .) .Values.global.appConfig.relativeUrlRoot -}} {{- end -}} {{- end -}} diff --git a/values.yaml b/values.yaml index b788a8906b..dd5b09649a 100644 --- a/values.yaml +++ b/values.yaml @@ -249,6 +249,7 @@ global: appConfig: ## https://docs.gitlab.com/charts/charts/globals#general-application-settings # cdnHost: + relativeUrlRoot: "" enableUsagePing: true enableSeatLink: true enableImpersonation: -- GitLab