For a Linux package installation, GitLab normally runs its bundled NGINX. Keep that arrangement when GitLab should own ports 80 and 443; use an external NGINX when another web server, load balancer, or central TLS policy must own those ports. In the external design, disable GitLab’s listener, grant the external NGINX account access, terminate TLS at the front proxy, and pass the original host and HTTPS-related forwarding headers to GitLab.
Need a server to try this on? Antihost offers Linux VPS plans with NVMe storage, full root access and a 14-day free trial.
The settings that prevent most redirect and 422 CSRF failures are the public external_url, the GitLab-side HTTP listener used behind a TLS proxy, and consistent Host, X-Forwarded-Proto, X-Forwarded-Ssl, X-Forwarded-For, and X-Forwarded-Port headers.
As an Amazon Associate I earn from qualifying purchases.
The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Choose who owns NGINX and ports 80/443
There are two supported layouts. Decide this before editing configuration, because enabling both listeners on the same address causes a bind conflict and makes certificate ownership unclear.
| Decision point | Bundled NGINX | External NGINX |
|---|---|---|
| Public listener | GitLab’s packaged NGINX owns ports 80 and 443. | An existing NGINX instance owns the public listeners and reverse-proxies to GitLab. |
| Certificate termination | Configured in GitLab’s generated NGINX configuration. | Usually terminates at the external proxy; GitLab receives HTTP on its internal listener. |
| Configuration source | Service-specific keys in /etc/gitlab/gitlab.rb generate the server configuration. |
The external server block is managed outside GitLab, while GitLab’s bundled listener is disabled. |
| Proxy headers | Generated defaults are derived from external_url and GitLab settings. |
You must preserve the public host, scheme, port, and client address in the proxy configuration. |
| Additional services | Registry, Pages, and KAS still have their own NGINX setting hashes. | Each service needs its own hostname, listener, and forwarding policy when it is published through the external proxy. |
Use bundled NGINX when GitLab is the web-server owner
This is the default for Linux package installations and the least moving-parts option. GitLab generates the server blocks, chooses the internal upstreams, and applies changes when you run sudo gitlab-ctl reconfigure. It is generally the right choice for a single GitLab host with no existing reverse-proxy standard.
#1 Best Overall
- B5 Recipe Book: This hardcover blank recipe book measures 10''×7.3'', containing 150 blank pages, comes with 1 sheet of DIY category stickers, perfect for writing down your own recipes and organizing them in one place.
- Practical Layout - 5 pages of conversion charts show you everything you'll ever need to know in the kitchen. The table of contents will help organize your personal favorite recipes. A back pocket is designed for loose items.
- Easy to Use - This blank cookbook is made of high-quality paper with a beautiful hardcover for long-term use. The sturdy gold double-wire spiral binding makes writing easier and page turning smoother.
- Make Your Own Recipes - This blank cookbook has up to 150 blank pages for you to write in your own recipes, with plenty of space to record ingredients and instructions. You can write down all the special tips for your family members.
- Thoughtful Gift - A personalized recipe book makes a thoughtful gift for your children or newlyweds, and a great gift for housewarming, weddings, bridal showers, anniversaries, or any other occasion.
Use external NGINX when another layer must own the edge
Choose this layout if a shared NGINX fleet already handles several applications, if a load balancer terminates TLS, or if your network policy requires one process to bind 80 and 443. GitLab remains responsible for the Rails application and its internal web endpoint; the external NGINX process is responsible for accepting client connections and forwarding every GitLab path.
Prepare the GitLab URL and operating-system account
Set GitLab’s public URL to the address users type, including the public scheme. For example, a deployment intended to be reached at https://gitlab.example.com should use that HTTPS URL as its external_url. Do not substitute an internal hostname merely because the application traffic between NGINX and GitLab is plain HTTP.
For an external NGINX installation, identify the Unix account running that NGINX process. Debian and Ubuntu commonly use www-data; RHEL and CentOS commonly use nginx. GitLab’s documented external-server setup requires that account to be specified so generated files and sockets are accessible to the proxy.
- Back up
/etc/gitlab/gitlab.rbbefore changing it. - Confirm that DNS for the public hostname resolves to the external NGINX or load balancer.
- Ensure only the intended process will bind each public port.
- Record the actual internal GitLab address and port; those values depend on the installation and must not be guessed.
Configure GitLab’s bundled NGINX
Leave the bundled listener enabled and make changes through /etc/gitlab/gitlab.rb. GitLab will regenerate its NGINX configuration, so editing generated files directly is not a durable change.
-
Set or verify the public URL:
external_url 'https://gitlab.example.com' -
Keep the packaged NGINX enabled (the default). Add only the service-specific options you need, such as the listen port, HTTPS behavior, certificate paths, or real-IP policy.
-
Apply the file:
sudo gitlab-ctl reconfigure -
Open the public URL and verify that the browser remains on the expected hostname and scheme. Test a sign-in, a project page, and a repository operation rather than checking only the landing page.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
When GitLab owns TLS, its generated configuration can redirect HTTP to HTTPS and serve the certificate. If another service already occupies 80 or 443, do not try to make the bundled listener share that address; switch to the external layout instead.
Configure an external NGINX reverse proxy
1. Disable the bundled listener and identify the external user
Edit /etc/gitlab/gitlab.rb:
nginx['enable'] = false
web_server['external_users'] = ['www-data']
Use the account that actually runs NGINX on your distribution; replace www-data with nginx on systems where that is the service account. The important points are disabling GitLab’s listener and explicitly granting the external web-server user access.
Apply the change before starting the front-end proxy:
sudo gitlab-ctl reconfigure
2. Create the external server block
The external server must preserve the public host and forward all GitLab paths to the internal endpoint used by your installation. The endpoint is deployment-specific, so the following template deliberately uses a code variable rather than asserting a universal address or port:
Free tools Windows power users keep installed
One-click scans. No signup required.
server {
listen 80;
server_name gitlab.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name gitlab.example.com;
ssl_certificate /path/to/your/certificate.pem;
ssl_certificate_key /path/to/your/private-key.pem;
location / {
proxy_pass http://{{GITLAB_INTERNAL_ENDPOINT}};
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
}
}
Replace the double-curly-brace value with the real GitLab endpoint in your environment. Do not copy an address from an unrelated deployment. Keep the public Host header intact; using an internal hostname there can make GitLab generate links that users cannot resolve. The HTTPS listener should send X-Forwarded-Proto https, X-Forwarded-Ssl on, and the public port so GitLab can reconstruct the original request.
3. Verify reachability before debugging Rails
Reload the external NGINX only after its configuration test passes. Confirm that the proxy process can connect to the internal GitLab endpoint, that the firewall permits that connection, and that the endpoint speaks the protocol named in proxy_pass. A 502 at this stage is normally an endpoint, socket-permission, listener, or firewall problem rather than a CSRF setting.
Terminate HTTPS at the proxy without redirect loops
When the external proxy handles TLS, GitLab’s application-side NGINX listener should be plain HTTP. Keep the public URL HTTPS so generated links and redirects remain secure, but tell the GitLab-side listener not to expect certificates:
gitlab_rails['nginx']['listen_port'] = 80
gitlab_rails['nginx']['listen_https'] = false
Then apply the file:
sudo gitlab-ctl reconfigure
This setting changes the internal listener, not the public URL. The external NGINX still listens on 443 and sends the forwarding headers shown above. A redirect loop usually means one of these facts is inconsistent: the public URL says HTTPS, the proxy reports HTTP, or GitLab’s internal listener is configured to redirect while the proxy is already performing that redirect.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Forwarding headers and CSRF validation
GitLab uses the forwarded host, scheme, port, and client address when constructing redirects and validating browser requests. Missing or contradictory values can produce an apparently random mix of wrong-scheme redirects, “The change you wanted was rejected,” and Can't verify CSRF token authenticity Completed 422 Unprocessable.
| Header | Value at an HTTPS-terminating NGINX | Why it matters |
|---|---|---|
Host |
The public host supplied by the browser, commonly $http_host. |
Preserves absolute links, cookies, and virtual-host selection. |
X-Forwarded-Proto |
https |
Tells GitLab the original request used HTTPS. |
X-Forwarded-Ssl |
on |
Explicitly marks the original connection as SSL/TLS. |
X-Forwarded-Port |
443 for the public HTTPS listener. |
Prevents redirects and generated URLs from selecting the internal port. |
X-Forwarded-For |
$proxy_add_x_forwarded_for |
Retains the originating client address through one or more proxies. |
Check these headers before changing application cookies, CSRF settings, or Rails behavior. If a load balancer sits in front of NGINX, determine which hop is allowed to set each header and prevent untrusted clients from supplying values directly.
Rank #2
- Create a Culinary Legacy: The Pipilo Press Blank Family Cookbook Recipe Binder offers a timeless platform for chronicling beloved recipes. With its hardcover and spiral binding, this recipe book to write in your own recipes ensures durability and ease of use for generations
- Thoughtful Gifting Choice: This book for writing recipes is an ideal present for various occasions, adding a personal touch to celebrations. Its elegant design makes it perfect for moms cookbook DIY projects or anyone passionate about preserving family traditions
- Durable Design Features: Constructed with a 300gsm cardstock cover and matte lamination, this cookbook you can write in ensures longevity. Its spiral-bound format provides convenient access to pages, making it a practical tool for everyday use
- Organized Recipe Storage: The included memo pocket offers a space to store handwritten notes or recipe cards, enhancing its functionality. This feature transforms the recipe book for moms into a sentimental family memento
- Ample Writing Space: Measuring 6.5 x 8.2 inches, this blank spiral family recipe cookbook offers plenty of room for detailed notes. It is perfect for jotting down ingredients, preparation methods, and serving suggestions for a complete culinary record
Set trusted proxies and real client IP handling
If NGINX receives traffic from another proxy, GitLab must know which source addresses are trusted to provide the client address. Add the actual proxy address ranges to gitlab_rails['nginx']['real_ip_trusted_addresses']. Pair that with the header your upstream really sends:
gitlab_rails['nginx']['real_ip_header'] = 'X-Forwarded-For'
gitlab_rails['nginx']['real_ip_recursive'] = 'on'
Use real_ip_recursive = 'on' when the chain contains multiple trusted proxies and you need NGINX to walk the forwarded list. Do not add broad, untrusted networks merely to make an address appear in logs: these settings affect both the client IP recorded by GitLab and which forwarded values it trusts.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWhen the upstream uses the PROXY protocol
HAProxy and some load balancers can send a PROXY-protocol preamble instead of relying only on HTTP headers. If your upstream is configured that way, enable the matching GitLab setting and trust the upstream addresses:
gitlab_rails['nginx']['proxy_protocol'] = true
A listener configured for PROXY protocol expects that protocol on every connection. Health checks, direct administrative requests, and emergency clients that do not send it will fail. Configure those checks through a PROXY-aware path or use a separate listener; do not enable the option on a port that also accepts ordinary HTTP connections.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Configure Registry, Pages, and KAS separately
GitLab’s Rails application is not the only service that may have an NGINX listener. Modern configuration separates the hashes:
Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Scan for outdated or missing drivers - takes under a minute3Clear out junk files and repair common Windows errors| Service | Configuration hash | Important implication |
|---|---|---|
| GitLab Rails application | gitlab_rails['nginx'] |
Controls the main web application listener and its proxy-related settings. |
| Container Registry | registry['nginx'] |
Registry redirects, ports, and headers must be configured here as well. |
| Pages | gitlab_pages['nginx'] |
Pages hostnames and listener behavior are independent of the Rails hash. |
| KAS | gitlab_kas['nginx'] |
Kubernetes agent traffic has its own NGINX settings and proxy requirements. |
Changing one hash does not propagate to the others. If both GitLab and the Registry must redirect HTTP to HTTPS, configure the redirect and forwarding behavior explicitly for each service and hostname.
Add custom NGINX server blocks safely
GitLab supports adding custom server configuration through an include directory rather than by editing generated files. Set nginx['custom_nginx_config'] to include the directory you manage, create its sites-available and sites-enabled subdirectories, and enable a file with a symlink:
nginx['custom_nginx_config'] = 'include /etc/gitlab/nginx/sites-enabled/*;'
sudo mkdir -p /etc/gitlab/nginx/sites-available /etc/gitlab/nginx/sites-enabled
sudo ln -s /etc/gitlab/nginx/sites-available/example.conf /etc/gitlab/nginx/sites-enabled/example.conf
sudo gitlab-ctl hup nginx
Use a full restart instead of hup only when your change requires it. Avoid redefining GitLab’s generated root and /assets locations. For a new location that proxies to the GitLab Workhorse upstream, GitLab notes that you may need proxy_cache off, proxy_http_version 1.1, and proxy_pass http://gitlab-workhorse;. Overriding a generated location without those details can break uploads, streaming responses, or asset delivery.
Apply changes and handle certificates correctly
Most edits to /etc/gitlab/gitlab.rb take effect only after:
Recommended Free Tools
sudo gitlab-ctl reconfigure
Afterward, reload the relevant NGINX process and inspect its error log if the listener does not come up. A certificate replacement is different: if the certificate files changed but gitlab.rb did not, reconfigure alone may not deploy the new material or trigger the required reload. Follow the certificate deployment and reload procedure for the component terminating TLS, then verify the served certificate from the public endpoint.
Troubleshoot the common failure modes
“Completed 422 Unprocessable” or a rejected form
- Inspect the request as it reaches the external proxy and confirm the public
Host,X-Forwarded-Proto https,X-Forwarded-Ssl on, andX-Forwarded-Port 443values. - Confirm
external_urluses the same public hostname and HTTPS scheme. - Check that an intermediate load balancer is not overwriting those headers with internal values.
- Only after the headers are correct, investigate cookies or application-level settings.
Redirects alternate between HTTP and HTTPS
Compare the public URL, the proxy’s scheme headers, and the GitLab-side listener options. For TLS termination at NGINX, the GitLab-side values should be listen_port = 80 and listen_https = false, while the proxy reports HTTPS to GitLab and redirects its own port-80 requests.
Logs show the proxy address instead of the user
Add the real upstream proxy ranges to real_ip_trusted_addresses, select the header actually emitted by that upstream, and enable recursive processing only when the chain requires it. Reconfigure and then make a fresh request; old log lines will not be rewritten.
GitLab works but Registry, Pages, or KAS does not
Check the service’s own NGINX hash and hostname. Main Rails settings do not automatically configure auxiliary services, and a redirect applied to one service does not imply that another service has the same policy.
NGINX returns 502 or fails to reload
Validate the external endpoint, socket permissions, firewall path, and protocol first. For a reload failure, run the NGINX configuration test, inspect the exact file and line reported, and check for duplicate listeners or an invalid include. If you changed a generated GitLab setting, run sudo gitlab-ctl reconfigure before testing the resulting configuration again.
Operational checklist
- One clearly identified process owns each public 80 and 443 listener.
external_urlmatches the hostname and public scheme users see.- External mode has
nginx['enable'] = falseand the correct external web-server user. - TLS termination is consistent with
gitlab_rails['nginx']['listen_port']andlisten_https. - The proxy preserves
Host,X-Forwarded-Proto,X-Forwarded-Ssl,X-Forwarded-Port, andX-Forwarded-For. - Trusted proxy ranges match the actual network path.
- PROXY protocol is enabled only when every client of that listener sends it.
- Registry, Pages, and KAS settings are handled in their own hashes.
- Every GitLab configuration edit is followed by
sudo gitlab-ctl reconfigure, and custom NGINX edits are followed by a safe reload. - After a certificate change, the TLS-terminating component is explicitly redeployed or reloaded.
Further NGINX reference
For directives beyond GitLab’s integration points, NGINX Cookbook, 3rd Edition from O’Reilly is a general NGINX web-server and reverse-proxy reference. It is broader than GitLab; use GitLab’s own configuration keys and service procedures for the packaged installation.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




