Skip to content

Commit 11ba7cf

Browse files
Naman Jagdish Galaibaum
authored andcommitted
Add namespace_in_path parameter in GitLab.rb for GitLab Pages
Related to: https://gitlab.com/gitlab-org/gitlab/-/issues/17584 Adds the 'namespace_in_path' parameter in gitlab.rb for GitLab Pages. This parameter is used to rewrite Pages URLs, allowing users to access Pages using the namespace in the path instead of the host. This modification will enable GitLab Pages to work without requiring a DNS wildcard. More context: https://gitlab.com/gitlab-org/gitlab/-/issues/211677#note_1646965167 Changelog: added
1 parent 9586e15 commit 11ba7cf

File tree

12 files changed

+212
-76
lines changed

12 files changed

+212
-76
lines changed

files/gitlab-config-template/gitlab.rb.template

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2007,6 +2007,9 @@ external_url 'GENERATED_EXTERNAL_URL'
20072007
# 'SSL_CERT_DIR' => "#{node['package']['install-dir']}/embedded/ssl/certs/"
20082008
# }
20092009

2010+
# Experimental - Enable namespace in path
2011+
# gitlab_pages['namespace_in_path'] = false
2012+
20102013
################################################################################
20112014
## GitLab Pages NGINX
20122015
################################################################################

files/gitlab-cookbooks/gitlab-pages/attributes/default.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
default['gitlab_pages']['redirects_max_path_segments'] = nil
8383
default['gitlab_pages']['redirects_max_rule_count'] = nil
8484
default['gitlab_pages']['register_as_oauth_app'] = true
85+
# Experimental - Enable namespace in path
86+
default['gitlab_pages']['namespace_in_path'] = false
8587

8688
# Temporarily retain support for `node['gitlab-pages'][*]` usage in
8789
# `/etc/gitlab/gitlab.rb`

files/gitlab-cookbooks/gitlab-pages/libraries/gitlab_pages.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def parse_variables
2929
parse_gitlab_pages_daemon
3030
parse_secrets
3131
parse_automatic_oauth_registration
32+
parse_namespace_in_path
3233
end
3334

3435
def parse_pages_external_url
@@ -134,5 +135,20 @@ def parse_automatic_oauth_registration
134135

135136
LoggingHelper.warning("Writing secrets to `gitlab-secrets.json` file is disabled. Hence, not automatically registering GitLab Pages as an Oauth App. So, GitLab SSO will not be available as a login option.")
136137
end
138+
139+
def parse_namespace_in_path
140+
# If GitLab Pages isn't enabled or namespace_in_path is isn't enabled, do nothing.
141+
return unless Gitlab['gitlab_pages']['enable'] && Gitlab['gitlab_pages']['namespace_in_path']
142+
143+
Gitlab['pages_nginx']['namespace_in_path'] = Gitlab['gitlab_pages']['namespace_in_path']
144+
url_scheme = Gitlab['gitlab_rails']['pages_https'] ? 'https' : 'http'
145+
146+
Gitlab['pages_nginx']['proxy_redirect'] = {
147+
"~^#{url_scheme}://(projects\\.#{Gitlab['pages_nginx']['fqdn_regex']})/(.*)$" => "#{url_scheme}://$1/$2",
148+
"~^#{url_scheme}://(.*)\\.(#{Gitlab['pages_nginx']['fqdn_regex']})/(.*)$" => "#{url_scheme}://$2/$1/$3",
149+
"~^//(.*)\\.(#{Gitlab['pages_nginx']['fqdn_regex']})/(.*)$" => "/$1/$3",
150+
"~^/(.*)$" => "/$namespace/$1",
151+
}
152+
end
137153
end
138154
end

files/gitlab-cookbooks/gitlab-pages/templates/default/gitlab-pages-config.erb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,6 @@ redirects-max-rule-count=<%= @redirects_max_rule_count %>
191191
<%- if @headers -%>
192192
header=<%= @headers.join(';;') %>
193193
<%-end -%>
194+
<%- if @namespace_in_path -%>
195+
namespace-in-path=<%= @namespace_in_path %>
196+
<%-end -%>

files/gitlab-cookbooks/gitlab/recipes/gitlab-rails.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@
377377
pages_object_store_enabled: node['gitlab']['gitlab_rails']['pages_object_store_enabled'],
378378
pages_object_store_remote_directory: node['gitlab']['gitlab_rails']['pages_object_store_remote_directory'],
379379
pages_object_store_connection: node['gitlab']['gitlab_rails']['pages_object_store_connection'],
380+
pages_namespace_in_path: node['gitlab_pages']['namespace_in_path'],
380381
mattermost_host: mattermost_host,
381382
mattermost_enabled: node['mattermost']['enable'] || !mattermost_host.nil?,
382383
sidekiq: node['gitlab']['sidekiq'],

files/gitlab-cookbooks/gitlab/templates/default/gitlab.yml.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ production: &base
436436
local_store:
437437
enabled: <%= @pages_local_store_enabled %>
438438
path: <%= @pages_local_store_path %>
439+
namespace_in_path: <%= @pages_namespace_in_path %>
439440

440441
## Gravatar
441442
## For Libravatar see: https://docs.gitlab.com/ee/customization/libravatar.html
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Prevent NGINX from caching pages in response to the pages `Cache-Control`
2+
# header.
3+
#
4+
# Browsers already respect this directive and Pages can handle the request
5+
# volume without help from NGINX.
6+
#
7+
# If this changes in the future, ensure `proxy_cache_key` is set to a value
8+
# like `$scheme$host$request_uri`, as the default value does not take the
9+
# Pages hostname into account, leading to incorrect responses being served.
10+
#
11+
# See https://gitlab.com/gitlab-org/gitlab-pages/issues/73
12+
proxy_cache off;
13+
14+
<% if @proxy_custom_buffer_size -%>
15+
proxy_buffers 8 <%= @proxy_custom_buffer_size %>;
16+
proxy_buffer_size <%= @proxy_custom_buffer_size %>;
17+
<% end -%>
18+
19+
proxy_http_version 1.1;
20+
proxy_pass http://<%= @pages_listen_proxy %>;
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
server_tokens off; ## Don't show the nginx version number, a security best practice
2+
3+
## Disable symlink traversal
4+
disable_symlinks on;
5+
6+
<% if @https %>
7+
## Strong SSL Security
8+
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
9+
ssl_certificate <%= @ssl_certificate %>;
10+
ssl_certificate_key <%= @ssl_certificate_key %>;
11+
<% if @ssl_client_certificate %>
12+
ssl_client_certificate <%= @ssl_client_certificate%>;
13+
<% end %>
14+
<% if @ssl_verify_client %>
15+
ssl_verify_client <%= @ssl_verify_client%>;
16+
ssl_verify_depth <%= @ssl_verify_depth%>;
17+
<% end %>
18+
19+
# GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
20+
ssl_ciphers '<%= @ssl_ciphers %>';
21+
ssl_protocols <%= @ssl_protocols %>;
22+
ssl_prefer_server_ciphers <%= @ssl_prefer_server_ciphers %>;
23+
ssl_session_cache <%= @ssl_session_cache %>;
24+
ssl_session_tickets <%= @ssl_session_tickets %>;
25+
ssl_session_timeout <%= @ssl_session_timeout %>;
26+
27+
<% if @ssl_dhparam %>
28+
ssl_dhparam <%= @ssl_dhparam %>;
29+
<% end %>
30+
31+
<% if @ssl_password_file %>
32+
ssl_password_file '<%= @ssl_password_file %>';
33+
<% end %>
34+
<% end %>
35+
36+
## Real IP Module Config
37+
## http://nginx.org/en/docs/http/ngx_http_realip_module.html
38+
<% if @real_ip_header %>
39+
real_ip_header <%= @real_ip_header %>;
40+
<% end %>
41+
<% if @real_ip_recursive %>
42+
real_ip_recursive <%= @real_ip_recursive %>;
43+
<% end %>
44+
<% @real_ip_trusted_addresses.each do |trusted_address| %>
45+
set_real_ip_from <%= trusted_address %>;
46+
<% end %>
47+
48+
## HSTS Config
49+
## https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
50+
<% unless @hsts_max_age.nil? || @hsts_max_age <= 0 %>
51+
add_header Strict-Transport-Security "max-age=<%= @hsts_max_age -%>
52+
<% if @hsts_include_subdomains %>; includeSubdomains<% end %>";
53+
<% end %>
54+
55+
## Individual nginx logs for this GitLab vhost
56+
access_log <%= @log_directory %>/gitlab_pages_access.log gitlab_access;
57+
error_log <%= @log_directory %>/gitlab_pages_error.log <%= @error_log_level%>;
58+
59+
# Define custom error pages
60+
error_page 403 /403.html;
61+
error_page 404 /404.html;

files/gitlab-cookbooks/gitlab/templates/default/nginx-gitlab-pages-http.conf.erb

Lines changed: 36 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -23,101 +23,63 @@ server {
2323
}
2424
<% end %>
2525

26+
<% if @namespace_in_path %>
27+
## Experimental - Handle requests having namespace in path
28+
## See https://gitlab.com/gitlab-org/gitlab/-/issues/211677
2629
server {
2730
<% @listen_addresses.each do |listen_address| %>
2831
listen <%= listen_address %>:<%= @listen_port %><% if @proxy_protocol %> proxy_protocol<% end %><% if @https %> ssl<% if @http2_enabled %> http2<% end %><% end %>;
2932
<% end %>
30-
server_name ~^(?<group>.*)\.<%= @fqdn_regex %>$;
31-
server_tokens off; ## Don't show the nginx version number, a security best practice
33+
server_name ~^<%= @fqdn_regex %>$;
3234

33-
## Disable symlink traversal
34-
disable_symlinks on;
35+
<%= render "nginx-gitlab-pages-http-common-server.erb" %>
3536

36-
<% if @https %>
37-
## Strong SSL Security
38-
## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
39-
ssl_certificate <%= @ssl_certificate %>;
40-
ssl_certificate_key <%= @ssl_certificate_key %>;
41-
<% if @ssl_client_certificate %>
42-
ssl_client_certificate <%= @ssl_client_certificate%>;
43-
<% end %>
44-
<% if @ssl_verify_client %>
45-
ssl_verify_client <%= @ssl_verify_client%>;
46-
ssl_verify_depth <%= @ssl_verify_depth%>;
47-
<% end %>
37+
# Pass when namespace in path to pages daemon after the rewrite
38+
location ~ ^/(?<namespace>[^/]+)/(?<project>.*)$ {
39+
## Rewrite remove namespace from path
40+
rewrite ^/([^/]+)/(.*)$ /$2 break;
4841

49-
# GitLab needs backwards compatible ciphers to retain compatibility with Java IDEs
50-
ssl_ciphers '<%= @ssl_ciphers %>';
51-
ssl_protocols <%= @ssl_protocols %>;
52-
ssl_prefer_server_ciphers <%= @ssl_prefer_server_ciphers %>;
53-
ssl_session_cache <%= @ssl_session_cache %>;
54-
ssl_session_tickets <%= @ssl_session_tickets %>;
55-
ssl_session_timeout <%= @ssl_session_timeout %>;
42+
<% @proxy_set_headers.each do |header| %>
43+
<% next if header[1].nil? %>
44+
<% if header[0] == "Host" %>
45+
## Put namespace back in host from path
46+
proxy_set_header <%= header[0] %> <%= "$1."+header[1] %>;
47+
<% else %>
48+
proxy_set_header <%= header[0] %> <%= header[1] %>;
49+
<% end %>
50+
<% end %>
51+
proxy_set_header X-Gitlab-Namespace-In-Path $namespace;
5652

57-
<% if @ssl_dhparam %>
58-
ssl_dhparam <%= @ssl_dhparam %>;
59-
<% end %>
53+
<%= render "nginx-gitlab-pages-http-common-server.erb" %>
6054

61-
<% if @ssl_password_file %>
62-
ssl_password_file '<%= @ssl_password_file %>';
63-
<% end %>
55+
## Put namespace in path from host before sending it to the user
56+
<% @proxy_redirect.each do |redirect| %>
57+
proxy_redirect <%= redirect[0] %> <%= redirect[1] %>;
6458
<% end %>
59+
}
6560

66-
## Real IP Module Config
67-
## http://nginx.org/en/docs/http/ngx_http_realip_module.html
68-
<% if @real_ip_header %>
69-
real_ip_header <%= @real_ip_header %>;
70-
<% end %>
71-
<% if @real_ip_recursive %>
72-
real_ip_recursive <%= @real_ip_recursive %>;
73-
<% end %>
74-
<% @real_ip_trusted_addresses.each do |trusted_address| %>
75-
set_real_ip_from <%= trusted_address %>;
76-
<% end %>
61+
<%= @custom_gitlab_server_config %>
62+
}
63+
<% end %>
7764

78-
## HSTS Config
79-
## https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
80-
<% unless @hsts_max_age.nil? || @hsts_max_age <= 0 %>
81-
add_header Strict-Transport-Security "max-age=<%= @hsts_max_age -%>
82-
<% if @hsts_include_subdomains %>; includeSubdomains<% end %>";
83-
<% end %>
65+
server {
66+
<% @listen_addresses.each do |listen_address| %>
67+
listen <%= listen_address %>:<%= @listen_port %><% if @proxy_protocol %> proxy_protocol<% end %><% if @https %> ssl<% if @http2_enabled %> http2<% end %><% end %>;
68+
<% end %>
69+
server_name ~^(?<group>.*)\.<%= @fqdn_regex %>$;
8470

85-
## Individual nginx logs for this GitLab vhost
86-
access_log <%= @log_directory %>/gitlab_pages_access.log gitlab_access;
87-
error_log <%= @log_directory %>/gitlab_pages_error.log <%= @error_log_level%>;
71+
<%= render "nginx-gitlab-pages-http-common-server.erb" %>
8872

89-
# Pass everything to pages daemon
73+
# Pass everything to pages daemon when namespace in host
9074
location / {
9175
<% @proxy_set_headers.each do |header| %>
9276
<% next if header[1].nil? %>
9377
proxy_set_header <%= header[0] %> <%= header[1] %>;
9478
<% end %>
79+
proxy_hide_header X-Gitlab-Namespace-In-Path;
9580

96-
# Prevent NGINX from caching pages in response to the pages `Cache-Control`
97-
# header.
98-
#
99-
# Browsers already respect this directive and Pages can handle the request
100-
# volume without help from NGINX.
101-
#
102-
# If this changes in the future, ensure `proxy_cache_key` is set to a value
103-
# like `$scheme$host$request_uri`, as the default value does not take the
104-
# Pages hostname into account, leading to incorrect responses being served.
105-
#
106-
# See https://gitlab.com/gitlab-org/gitlab-pages/issues/73
107-
proxy_cache off;
108-
109-
<% if @proxy_custom_buffer_size -%>
110-
proxy_buffers 8 <%= @proxy_custom_buffer_size %>;
111-
proxy_buffer_size <%= @proxy_custom_buffer_size %>;
112-
<% end -%>
113-
114-
proxy_http_version 1.1;
115-
proxy_pass http://<%= @pages_listen_proxy %>;
81+
<%= render "nginx-gitlab-pages-http-common-location.erb" %>
11682
}
11783

118-
# Define custom error pages
119-
error_page 403 /403.html;
120-
error_page 404 /404.html;
121-
12284
<%= @custom_gitlab_server_config %>
12385
}

spec/chef/cookbooks/gitlab-pages/recipes/gitlab-pages_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@
255255
redirects_max_path_segments: 50,
256256
redirects_max_rule_count: 2000,
257257
enable_disk: true,
258+
namespace_in_path: true,
258259
env: {
259260
GITLAB_CONTINUOUS_PROFILING: "stackdriver?service=gitlab-pages",
260261
},
@@ -329,6 +330,7 @@
329330
redirects-max-path-segments=50
330331
redirects-max-rule-count=2000
331332
header=X-XSS-Protection: 1; mode=block;;X-Content-Type-Options: nosniff;;Test: Header
333+
namespace-in-path=true
332334
EOS
333335

334336
expect(chef_run).to render_file("/var/opt/gitlab/pages/gitlab-pages-config").with_content(expected_content)

0 commit comments

Comments
 (0)