Introduction
This document outlines the steps and configuration required to install JFrog Platform using the official NGINX Ingress Controller. With the Kubernetes community ingress-nginx controller being deprecated, this guide validates nginx/nginx-ingress as a supported alternative and highlights the necessary changes from the previous ingress setup. It covers the installation of the NGINX Ingress Controller, updated Artifactory Helm configurations for TLS, non-TLS, and Docker subdomain deployments, and key considerations for a successful migration.
This document describes:
-
Required changes compared to the old ingress configuration
-
Installation of NGINX Ingress Controller
-
Artifactory Helm values for TLS, non-TLS, and Docker subdomain setups
Resolution
Old Ingress Configuration (Reference)
The following snippet represents the earlier ingress configuration that relied on Kubernetes ingress-nginx annotations:
artifactory:
nginx:
enabled: false
ingress:
enabled: true
defaultBackend:
enabled: true
hosts:
- <nginx-ingress-svc-external-hostname or dns hostname>
routerPath: /
artifactoryPath: /artifactory/
className: "nginx"
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: "0"
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^/(v2)/token /artifactory/api/docker/null/v2/token;
rewrite ^/(v2)/([^\/]*)(/.*) /artifactory/api/docker/$2/$1$3;
tls:
- secretName: nginx-tls
hosts:
- <nginx-ingress-svc-external-hostname or dns hostname>
Install NGINX Ingress Controller
Note
This step is performed and managed by the customer. JFrog does not install, configure, or manage, and has no control over it.
Install the official NGINX Ingress Controller using Helm. Snippet support must be explicitly enabled.
helm repo add nginx https://helm.nginx.com/stable
helm repo update
helm install nginx-ingress nginx/nginx-ingress \
--set controller.enableSnippets=true \
-n nginx-ingress --create-namespace
Note
This controller uses `nginx.org/*` annotations instead of `nginx.ingress.kubernetes.io/*`. See the [F5 NGINX IC documentation on snippets] for details.
Note
The example above installs the controller with the default ingress class name `nginx`. If a custom class name is used (e.g., via `--set controller.ingressClass=nginx-f5`), ensure the `className` field in the Artifactory `values.yaml` is updated to match.
Install JFrog Platform
For full installation instructions, refer to the JFrog Platform Helm installation documentation.
The `ingress:` configuration examples below apply to both the standalone Artifactory chart (`jfrog/artifactory`) and the full JFrog Platform chart (`jfrog/jfrog-platform`). The ingress block is identical in both. Pass the relevant snippet as part of your `values.yaml` when running your `helm install` or `helm upgrade` command.
Option 1: With TLS Enabled
artifactory:
nginx:
enabled: false
ingress:
enabled: true
defaultBackend:
enabled: true
hosts:
- <nginx-ingress-svc-external-hostname or dns hostname>
routerPath: /
artifactoryPath: /artifactory/
className: "nginx"
annotations:
nginx.org/client-max-body-size: "0"
nginx.org/proxy-read-timeout: "600"
nginx.org/proxy-send-timeout: "600"
nginx.org/location-snippets: |
rewrite ^/(v2)/token /artifactory/api/docker/null/v2/token;
rewrite ^/(v2)/([^\/]*)(/.*) /artifactory/api/docker/$2/$1$3;
tls:
- secretName: nginx-tls
hosts:
- <nginx-ingress-svc-external-hostname or dns hostname>
Option 2: Without TLS
artifactory:
nginx:
enabled: false
ingress:
enabled: true
defaultBackend:
enabled: true
hosts:
- <nginx-ingress-svc-external-hostname or dns hostname>
routerPath: /
artifactoryPath: /artifactory/
className: "nginx"
annotations:
nginx.org/client-max-body-size: "0"
nginx.org/proxy-read-timeout: "600"
nginx.org/proxy-send-timeout: "600"
nginx.org/redirect-to-https: "false"
nginx.org/location-snippets: |
rewrite ^/(v2)/token /artifactory/api/docker/null/v2/token;
rewrite ^/(v2)/([^\/]*)(/.*) /artifactory/api/docker/$2/$1$3;
Option 3: With Docker Subdomain Access (TLS)
Use this configuration to allow Docker clients to access Artifactory using the subdomain access method, where each Docker repository is exposed on its own subdomain (e.g., `<repo>.artifactory.example.com`).
The F5 NGINX IC achieves subdomain routing using:
-
`nginx.org/server-snippets` — a regex on the `$host` variable with a named capture group to extract the repository name from the subdomain.
-
`nginx.org/location-snippets` — rewrite rules to route Docker API requests to the correct Artifactory Docker repository, plus the `X-JFrog-Override-Base-Url` header so Artifactory generates correct Docker registry URLs in responses.
Additional Prerequisites
Before applying this configuration, ensure the following are in place in addition to the base prerequisites above:
- A wildcard TLS certificate covering `*.artifactory.example.com`.
- A wildcard DNS record pointing `*.artifactory.example.com` to the Ingress Controller's external IP.
artifactory:
nginx:
enabled: false
ingress:
enabled: true
defaultBackend:
enabled: false
hosts:
- artifactory.example.com
- '*.artifactory.example.com'
routerPath: /
artifactoryPath: /artifactory/
className: "nginx"
annotations:
nginx.org/client-max-body-size: "0"
nginx.org/proxy-read-timeout: "2400s"
nginx.org/proxy-send-timeout: "2400s"
nginx.org/proxy-buffers: "40 128k"
nginx.org/proxy-busy-buffers-size: "128k"
nginx.org/server-snippets: |
set $repo "docker";
if ($host ~* "^(?<captured_repo>.+)\.artifactory\.example\.com$") {
set $repo $captured_repo;
}
nginx.org/location-snippets: |
rewrite ^/(v1|v2)/(.*) /artifactory/api/docker/$repo/$1/$2 break;
rewrite ^/(v1|v2)/ /artifactory/api/docker/$repo/$1/ break;
proxy_set_header X-JFrog-Override-Base-Url $scheme://$host;
tls:
- secretName: artifactory-tls
hosts:
- artifactory.example.com
- "*.artifactory.example.com"
Make sure to replace `artifactory.example.com` with the actual DNS hostname or service name. Escape dots in the regex accordingly (e.g., `artifactory\.example\.com`).
Notes
- The `hosts` and `tls` sections must include both the base domain (`artifactory.example.com`) and the wildcard (`*.artifactory.example.com`).
- `defaultBackend` is set to `false` because the wildcard host entry handles all subdomain requests. A separate default backend is not needed.
- The default `$repo` value (`"docker"`) is used when accessing the base domain directly (without a subdomain prefix). Change this to match your default Docker repository name if different.
- The timeouts in this option (`2400s`) are set higher than Options 1 and 2 (`600`) to accommodate large Docker image layer push/pull operations.
- The `X-JFrog-Override-Base-Url` header ensures Artifactory returns correct Docker registry URLs in responses. Without it, Docker clients may receive redirect URLs pointing to the wrong hostname. See the JFrog HTTP Settings documentation for more details
Explanation on the Annotations Used
Annotation
|
Description
|
nginx.org/client-max-body-size: "0"
|
Removes the request body size limit (allows unlimited upload size)
|
nginx.org/proxy-read-timeout: "600"
|
Sets the maximum time (in seconds) NGINX waits to read a response from the backend
|
nginx.org/proxy-send-timeout: "600"
|
Sets the maximum time (in seconds) NGINX waits to send a request to the backend
|
nginx.org/redirect-to-https: "false"
|
Disables automatic redirection from HTTP to HTTPS
|
nginx.org/location-snippets
|
Injects custom NGINX rewrite rules to route Docker v2 registry and token requests to Artifactory.
|
nginx.org/server-snippets
|
Injects custom NGINX server-level directives; used here to extract the Docker repository name from the request subdomain.
|
nginx.org/proxy-buffers / nginx.org/proxy-busy-buffers-size
|
Tune the NGINX proxy buffer sizes; recommended for large Docker layer transfers.
|
Validate JFrog Platform Access
Verify that the JFrog Platform is reachable through the Ingress by calling the [Router health check endpoint] (see here), which reports the health of all platform services (not just Artifactory):
curl https://<hostname>/router/api/v1/system/health
A 200 response means all the services are healthy.
Notes & Considerations
-
Docker registry traffic requires the rewrite rules defined in `location-snippets`.
-
`controller.enableSnippets=true` is mandatory for custom rewrite rules in all configurations.
-
Ensure `className: nginx` matches the ingress class created by the controller.
-
Ensure `className: nginx` matches the ingress class name used when the controller was installed. If a custom class name was used, update `className` in the Artifactory `values.yaml` accordingly.
-
The timeouts in Options 1 and 2 are set to `600` seconds (sufficient for standard artifact operations). Option 3 uses `2400s` to accommodate large Docker image layer push/pull operations, which can take significantly longer.
-
For production, CA-signed certificates are recommended instead of self-signed ones.
-
For Docker subdomain access (Option 3), a wildcard TLS certificate and wildcard DNS record are required in addition to the base prerequisites.
-
The `X-JFrog-Override-Base-Url` header (Option 3) is required for correct Docker registry URL generation in Artifactory responses.
NGINX Ingress Migration – Configuration Comparison
Aspect
|
Deprecated ingress-nginx
|
NGINX Ingress Controller
|
Change
|
Ingress class
|
className: "nginx"
|
className: "nginx"
|
No change
|
Body size limit
|
nginx.ingress.kubernetes.io/proxy-body-size: "0"
|
nginx.org/client-max-body-size: "0"
|
Annotation key updated
|
Read timeout
|
nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
|
nginx.org/proxy-read-timeout: "600"
|
Annotation key updated
|
Send timeout
|
nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
|
nginx.org/proxy-send-timeout: "600"
|
Annotation key updated
|
Custom rewrites
|
nginx.ingress.kubernetes.io/configuration-snippet
|
nginx.org/location-snippets
|
Annotation key updated
|
Docker v2 routing
|
Supported via rewrite rules
|
Supported via rewrite rules
|
No functional change
|
TLS configuration
|
Standard Kubernetes TLS secret
|
Standard Kubernetes TLS secret
|
No change
|
Artifactory paths
|
/ and /artifactory/
|
/ and /artifactory/
|
No change
|
Docker subdomain access
|
Via server-alias regex annotation
|
Via nginx.org/server-snippets + nginx.org/location-snippets
|
Annotation approach updated
|
Conclusion
NGINX Ingress Controller works as a supported replacement for the deprecated ingress-nginx setup and has been validated with Artifactory for TLS, non-TLS, and Docker subdomain configurations. The migration requires only ingress annotation key changes, with no functional impact on routing or behavior, and no changes to the JFrog installation or deployment process are needed. For Docker subdomain access, additional wildcard DNS and TLS prerequisites apply.