Halloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run ScanHalloween DealsAmazon USOctober picks are moving - compare before checkoutAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk10 min

How to Configure NGINX for a Self-Hosted GitLab Server

A practical guide to configuring GitLab’s bundled NGINX or an external reverse proxy, including HTTPS termination, forwarding headers, trusted proxies, auxiliary services, and recovery steps.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The reliable way to put a self-hosted GitLab server behind NGINX is to choose one NGINX owner for the public listener, keep GitLab’s public URL accurate, and pass the original host and HTTPS scheme in forwarding headers. Linux package installations include bundled NGINX by default, but an existing NGINX can take over ports 80 and 443 when you disable the bundled service and grant the external web-server user access.

Choose who owns ports 80 and 443

There are two supported designs. In the bundled design, the Linux package manages NGINX and generates its configuration from /etc/gitlab/gitlab.rb. In the external design, your existing NGINX owns the public listeners and reverse-proxies requests to GitLab. Do not let both instances compete for the same address and port.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Decision point Bundled NGINX External NGINX
Public listener GitLab’s package-managed NGINX binds the configured addresses and ports. Your existing NGINX binds ports 80 and/or 443.
Configuration owner GitLab generates the server configuration from gitlab.rb. You maintain the public reverse-proxy server block; GitLab still manages its application services.
TLS termination Usually terminates in the GitLab-managed NGINX. Can terminate at the external NGINX or at another upstream load balancer.
Proxy headers Generated defaults are based on external_url and GitLab settings. You must preserve the public host, port, client address, and scheme explicitly.
Auxiliary services Registry, Pages, and KAS use their own NGINX setting hashes. The external proxy needs routing for each published service, while each GitLab service still has separate settings.

Use the bundled option when you want the package to generate and maintain the GitLab-facing NGINX configuration. Use an external instance when NGINX is already a shared ingress, when certificates are centralized, or when one proxy must serve several applications. The rest of this guide keeps the two paths separate so that a setting intended for one topology is not accidentally applied to the other.

Set the public URL before changing proxy behavior

GitLab builds links, redirects, cookie scope, and scheme checks from its public URL. Set external_url to the address users actually enter, including https:// when users reach GitLab over HTTPS. Do not substitute an internal hostname or backend port for the public address.

#1 Best Overall
Recipe Book to Write in Your Own Recipes, Spiral Blank Cookbook 150 Recipes
  • 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.
external_url 'https://gitlab.example.com'

The hostname in this value must match the host that the browser sends to NGINX. If a proxy terminates TLS, GitLab can still use an HTTPS external_url; the connection from that proxy to the GitLab-side listener may be plain HTTP. That distinction is what lets GitLab generate HTTPS links without requiring encryption on every internal hop.

Configure the bundled NGINX

Keep the package-managed listener

Bundled NGINX is the default for GitLab Linux package installations. Put supported values in /etc/gitlab/gitlab.rb, then regenerate the service configuration:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo gitlab-ctl reconfigure

GitLab owns the generated server block in this topology. Avoid editing generated files directly: a later reconfigure can replace those edits. For a normal single-host installation, the essential inputs are the correct external_url, the intended certificate and key settings if GitLab is terminating TLS, and any service-specific NGINX options documented for your GitLab version.

Put custom directives in the supported extension point

If you need a custom server block or a narrowly scoped NGINX directive, use GitLab’s custom configuration mechanism rather than replacing the generated root configuration. The package supports an include directory configured with nginx['custom_nginx_config']. For example:

nginx['custom_nginx_config'] = '/etc/gitlab/nginx/custom'

Create the directory structure and place only the additional files there:

sudo mkdir -p /etc/gitlab/nginx/custom/sites-available
sudo mkdir -p /etc/gitlab/nginx/custom/sites-enabled
sudo ln -s /etc/gitlab/nginx/custom/sites-available/example.conf 
  /etc/gitlab/nginx/custom/sites-enabled/example.conf

After changing an included file, reload the GitLab-managed NGINX without rebuilding every service:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo gitlab-ctl hup nginx

A restart is another option when a reload is not sufficient. Do not redefine GitLab’s generated root or /assets locations. GitLab notes that added locations may require proxy_cache off, HTTP/1.1, and an upstream of http://gitlab-workhorse so that application behavior is preserved.

Move the public listener to an existing NGINX

Disable the bundled listener and identify the web-server user

For an external NGINX, edit /etc/gitlab/gitlab.rb and disable the package-managed NGINX. Also tell GitLab which operating-system user your external NGINX uses. Debian and Ubuntu commonly use www-data; RHEL and CentOS commonly use nginx.

nginx['enable'] = false
web_server['external_users'] = ['www-data']

Replace www-data with the account that actually runs your external NGINX. The account needs the access GitLab documents for the sockets, files, and application endpoints used by the reverse proxy. Apply the change:

sudo gitlab-ctl reconfigure

Only after this reconfigure should the external NGINX take over the public address. If another service already occupies port 80 or 443, resolve that listener conflict before testing GitLab.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Create an external reverse-proxy server block

The internal destination is deployment-specific, so do not copy a guessed address or port. Point proxy_pass at the GitLab endpoint that your installation exposes to the external NGINX. The important part is that every GitLab path reaches the same upstream and that the public request metadata is retained.

server {
    listen 443 ssl;
    server_name gitlab.example.com;

    # Configure ssl_certificate and ssl_certificate_key for this host.

    location / {
        proxy_pass http://<gitlab-internal-host>:<gitlab-internal-port>;
        proxy_set_header Host $http_host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Ssl on;
    }
}

Use the public hostname in server_name and in the Host header. X-Forwarded-Proto must be https for an HTTPS client, and X-Forwarded-Port must describe the public port. GitLab specifically calls out X-Forwarded-Ssl, X-Forwarded-For, and X-Forwarded-Port; generated configurations also use X-Forwarded-Proto when external_url is HTTPS.

If the external NGINX also accepts plain HTTP, use a separate port-80 server that redirects to the public HTTPS URL. The HTTPS proxy request must still send the forwarding headers shown above. A redirect loop usually means the proxy is telling GitLab that the internal HTTP hop is the public scheme, rather than reporting the browser’s original HTTPS request.

Terminate TLS at a proxy without redirect loops

When a load balancer or external NGINX terminates TLS before GitLab’s generated listener, keep the public URL set to HTTPS but configure the GitLab-side NGINX listener for plain HTTP:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
gitlab_rails['nginx']['listen_port'] = 80
gitlab_rails['nginx']['listen_https'] = false

Then apply the settings:

sudo gitlab-ctl reconfigure

This arrangement is appropriate when GitLab’s own generated NGINX still handles the internal request. If you have disabled the bundled listener and proxy directly to another GitLab endpoint, use the equivalent topology-specific backend settings and still preserve the public HTTPS headers at the external proxy. The key rule is consistent scheme reporting: the browser sees HTTPS, external_url remains HTTPS, and the proxy tells GitLab that the original request was HTTPS even if the backend connection is HTTP.

Rank #2
Pipilo Press Blank Family Cookbook Recipe Binder - 6.5 x 8.2 in Hardcover Spiral Bound - 90 Ruled Pages with Memo Pocket - Write In Your Own Recipes & Meal Planning Notebook
  • 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

Do not “fix” a loop by changing external_url to an internal HTTP URL. That can stop one redirect while producing insecure links, incorrect clone URLs, and inconsistent callback behavior.

Apply changes in the right order

  1. Record the topology. Write down which process owns ports 80 and 443, where TLS ends, the public hostname, and the exact internal GitLab endpoint.
  2. Edit gitlab.rb. Set external_url; disable bundled NGINX and set web_server['external_users'] only when using an external instance. Add GitLab-side listener settings when a proxy fronts a GitLab-managed listener.
  3. Reconfigure GitLab. Run sudo gitlab-ctl reconfigure after changing gitlab.rb.
  4. Install or update the external server block. Preserve Host, X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto, and, for TLS termination, X-Forwarded-Ssl.
  5. Reload the correct NGINX. For GitLab-managed NGINX, use sudo gitlab-ctl hup nginx after custom include changes. Reload your standalone NGINX using its normal service procedure after changing its server block.
  6. Test from the public hostname. Check the sign-in page, a project page, repository clone URLs, file uploads, and any published Registry, Pages, or KAS endpoint. Test both HTTP redirection and HTTPS if both are exposed.

Certificate replacement is a separate operational case. GitLab notes that changing certificate files without changing gitlab.rb may not be acted on by gitlab-ctl reconfigure alone. Follow the certificate deployment and reload procedure for the component that terminates TLS, then reload that NGINX.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Make client IP handling trustworthy

Forwarded client addresses are security-sensitive. If NGINX is itself behind another proxy, list the actual address ranges of that trusted proxy in GitLab’s real-IP settings. Do not trust every address or blindly trust values supplied by internet clients.

gitlab_rails['nginx']['real_ip_trusted_addresses'] = ['10.20.0.0/16', '192.0.2.15/32']
gitlab_rails['nginx']['real_ip_header'] = 'X-Forwarded-For'
gitlab_rails['nginx']['real_ip_recursive'] = 'on'

The networks above are examples of syntax only; replace them with the addresses used by your own upstream proxy. These settings affect the client IP recorded in logs and the addresses GitLab treats as trusted. Set them only after mapping every hop in the chain. Reconfigure GitLab after changing the file.

Use the PROXY protocol only when every client supports it

HAProxy and some load balancers can send the PROXY protocol, which carries connection metadata outside ordinary HTTP headers. If your upstream is configured that way, enable the matching GitLab setting and configure the trusted upstream addresses:

gitlab_rails['nginx']['proxy_protocol'] = true

A listener configured for PROXY-protocol traffic expects that protocol on incoming connections. Health checks, monitoring probes, direct administrative requests, and any other clients must use the same protocol or they can fail before HTTP processing begins. Do not enable this option merely because an upstream proxy exists; enable it only when the listener’s clients consistently send PROXY protocol.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configure Registry, Pages, and KAS separately

GitLab’s Rails application and its auxiliary services do not share one universal NGINX hash. Modern package configuration uses separate sections such as:

  • gitlab_rails['nginx'] for the Rails application.
  • registry['nginx'] for the Container Registry.
  • gitlab_pages['nginx'] for GitLab Pages.
  • gitlab_kas['nginx'] for the Kubernetes Agent Server.

A setting placed in one service’s hash does not automatically propagate to the others. If both GitLab and the Registry must redirect HTTP to HTTPS, configure the redirect behavior for both services. The same principle applies to listener ports, trusted proxy addresses, real-IP processing, and proxy protocol: verify each published service’s own configuration instead of assuming the Rails setting covers it.

Diagnose common failures by symptom

“The change you wanted was rejected” or a 422 CSRF error

Check the request metadata before changing Rails or disabling CSRF protection. Confirm that the external proxy sends the public Host, the original X-Forwarded-Proto, the public X-Forwarded-Port, and the TLS indicator expected by your topology. A proxy that sends http for an HTTPS browser request can make GitLab reject the session or redirect to the wrong scheme.

Redirects alternate between HTTP and HTTPS

Compare three values: external_url, the scheme visible to the browser, and X-Forwarded-Proto received by GitLab. For TLS termination at the proxy, keep external_url as HTTPS, set the GitLab-side listener to HTTP where applicable, and send X-Forwarded-Proto https (plus X-Forwarded-Ssl on) on the proxied request. Do not expose two competing GitLab NGINX listeners with different scheme assumptions.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Logs show the proxy’s address instead of the user’s

Verify the complete proxy chain and set real_ip_trusted_addresses to the actual upstream ranges. Pair it with real_ip_header = 'X-Forwarded-For' and enable recursive processing only when the chain requires it. If an untrusted hop can inject the header, the recorded client address is not reliable.

Connections fail immediately after enabling PROXY protocol

The listener is now expecting a PROXY-protocol preamble. Ensure that the load balancer, health checks, and direct clients all use the protocol. If some clients cannot, disable the option on that listener or isolate those clients behind a listener with matching expectations.

A custom location breaks assets or streaming behavior

Do not replace GitLab’s generated root or /assets locations. Review custom locations for the settings GitLab identifies as important: proxy_cache off, proxy_http_version 1.1, and proxy_pass http://gitlab-workhorse; where appropriate. For supported header overrides, GitLab recommends the proxy_set_headers setting in gitlab.rb rather than incompatible proxy_set_header directives in a custom server configuration.

Changing a certificate appears to have no effect

Reconfigure only regenerates settings from gitlab.rb; it does not necessarily redeploy a certificate file that changed in place. Confirm which NGINX terminates TLS, deploy the certificate according to that component’s SSL procedure, and perform the required reload or restart.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Production checklist

  • The public hostname in external_url matches the browser-facing hostname.
  • Exactly one intended NGINX owns each public listener.
  • The external NGINX account is declared with web_server['external_users'] when bundled NGINX is disabled.
  • Every proxied request preserves Host, X-Forwarded-For, X-Forwarded-Port, and X-Forwarded-Proto; TLS termination also preserves X-Forwarded-Ssl.
  • GitLab-side HTTP listener settings are used when TLS ends before a GitLab-managed listener.
  • Trusted proxy ranges represent real infrastructure, not the whole internet.
  • PROXY protocol is enabled only when all clients and health checks send it.
  • Registry, Pages, and KAS settings are reviewed independently.
  • Changes in gitlab.rb are followed by sudo gitlab-ctl reconfigure; custom GitLab-managed NGINX changes are followed by sudo gitlab-ctl hup nginx.
  • Certificate updates include the appropriate deployment and NGINX reload procedure.

With those boundaries in place, NGINX can terminate HTTPS, preserve the request identity GitLab needs, and route the Rails application and auxiliary services without redirect or CSRF surprises.

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.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.