Dokku uses nginx as its server for routing requests to specific applications. By default, access and error logs are written for each app to `/var/log/nginx/${APP}-access.log` and `/var/log/nginx/${APP}-error.log` respectively
By default, the `web` process is the only process proxied by the nginx proxy implementation. Proxying to other process types may be handled by a custom `nginx.conf.sigil` file, as generally described [below](/docs/networking/proxies/nginx.md#customizing-the-nginx-configuration)
Nginx will proxy the requests in a [round-robin balancing fashion](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#upstream) to the different deployed (scaled) containers running the `web` proctype. This way, the host's resources can be fully leveraged for single-threaded applications (e.g. `dokku ps:scale node-js-app web=4` on a 4-core machine).
> Due to how the plugin is implemented, if an app successfully starts up `web` containers but fails to deploy some other containers, nginx may eventually stop routing requests. Users should revert their code in these cases, or manually trigger `dokku proxy:build-config $APP` in order to ensure requests route to the new web containers.
When an app is created but not yet deployed, has no `web` process type, or has no running web processes, Dokku generates a minimal nginx configuration that returns `502 Bad Gateway` responses. This ensures that:
- The app's domain resolves and returns a non-200 status code, allowing monitoring tools to detect the issue.
- SSL certificate provisioning tools such as letsencrypt can function, as an nginx server is listening on the domain.
- The `nginx.conf.d/` include directory is available for plugin customization.
The 502 error page includes auto-retry JavaScript that will automatically reload the page when the application becomes available.
Once the app is deployed with running `web` processes, the placeholder configuration is automatically replaced with the full proxy configuration.
The nginx server can be reloaded via `nginx:reload`. This validates the current nginx configuration and, if valid, signals nginx to reload without restarting the running process. This is the preferred command after editing files in `/etc/nginx/conf.d/` directly.
```shell
dokku nginx:reload
```
If the configuration is invalid, the command exits non-zero and prints the validation error without reloading.
You may check nginx access logs via the `nginx:access-logs` command. This assumes that app access logs are being stored in `/var/log/nginx/$APP-access.log`, as is the default in the generated `nginx.conf`.
```shell
dokku nginx:access-logs node-js-app
```
You may also follow the logs by specifying the `-t` flag.
You may check nginx error logs via the `nginx:error-logs` command. This assumes that app error logs are being stored in `/var/log/nginx/$APP-error.log`, as is the default in the generated `nginx.conf`.
App-supplied `nginx.conf.sigil` files are pre-validated automatically at the start of every deploy, immediately after the template is extracted from the source tree and before the build phase runs. The template is rendered with sigil and run through `nginx -t` against a minimal wrapper config; if validation fails, the deploy is aborted before any build work begins. To bypass this behavior, set `disable-custom-config` to `true` (see "Disabling custom nginx config" below).
It may also be desired to validate an nginx config outside of the deployment process. To do so, run the `nginx:validate-config` command. With no arguments, this will validate all app nginx configs, one at a time. A minimal wrapper nginx config is generated for each app's nginx config, upon which `nginx -t` will be run.
As app nginx configs are actually executed within a shared context, it is possible for an individual config to be invalid when being validated standalone but _also_ be valid within the global server context. As such, the exit code for the `nginx:validate-config` command is the exit code of `nginx -t` against the server's real nginx config.
The `nginx:report` command also takes a `--format` flag, with the valid options including `stdout` (default) and `json`. The `json` output format can be used for automation purposes:
```shell
dokku nginx:report node-js-app --format json
```
The `--format` flag cannot be combined with an info flag.
These are provided as an alternative to the generic Nginx error page, are shared for _all_ applications, and their contents are located on disk at `/var/lib/dokku/data/nginx-vhosts/dokku-errors`. To customize them for a specific app, create a custom `nginx.conf.sigil` as described above and change the paths to point elsewhere.
On fresh apt installs, Dokku ships a catch-all default site at `/etc/nginx/conf.d/00-default-vhost.conf` that rejects requests whose Host header (or TLS SNI) does not match any deployed app. The catch-all uses [`ssl_reject_handshake on`](https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_reject_handshake) for HTTPS and [`return 444`](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return) for HTTP. Both close the connection without sending a response.
The `00-` prefix forces nginx to load this file before `/etc/nginx/conf.d/dokku.conf`, so its `default_server` markers establish the default for each port before any per-app server blocks are loaded.
On systems running nginx older than 1.19.4 (e.g., Debian Bullseye, which ships nginx 1.18.0), `ssl_reject_handshake` is not available. The postinst detects this and installs an HTTP-only variant instead:
```nginx
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
access_log off;
return 444;
}
```
On these systems, HTTPS requests to unknown hosts are not rejected by the catch-all - nginx falls through to the lexicographically first port-443 server block and presents that block's certificate, the same behavior as before 0.38.0.
The catch-all does not affect TLS handshakes for legitimate apps. nginx selects the matching server block via SNI before completing the handshake; only requests that have no matching app fall through to the catch-all.
| Request | Result |
| --- | --- |
| HTTPS to a configured app's hostname (with matching SNI) and the app has a cert | Handshake completes with the app's cert. Catch-all not consulted. |
| HTTPS to a configured app's hostname when the app has no cert configured | Handshake rejected by the catch-all on nginx 1.19.4+. On older nginx, falls through to the lexicographically first port-443 server block and presents its cert, producing a cert-mismatch error. |
| HTTPS to the server's IP with no SNI, or with an SNI matching no app | Handshake rejected on nginx 1.19.4+. On older nginx, falls through to the first port-443 server block. |
| HTTP to a configured app's hostname | Routed normally to that app. Catch-all not consulted. |
| HTTP to a hostname matching no app | Catch-all `return 444`. |
#### Conflicting upstream nginx default vhost
A fresh nginx install ships its own default vhost that also claims port 80 with `default_server`, which would cause `nginx -t` to fail with `a duplicate default server for 0.0.0.0:80` once the dokku catch-all is in place. To avoid this, the dokku postinst renames any of the following files in place to `${path}.dokku-disabled` instead of deleting them, preserving any local customizations:
-`/etc/nginx/sites-enabled/default`
-`/etc/nginx/sites-available/default`
-`/etc/nginx/conf.d/default.conf`
To recover an original file, inspect the `.dokku-disabled` sibling.
#### Disabling the catch-all on first install
Select "No" at the `dokku/install_default_site` debconf prompt, or pre-seed the answer before installing:
#### Installing the catch-all on upgraded or non-apt installs
Existing dokku installs upgraded from earlier versions do not get the catch-all installed automatically; the upgrade leaves their nginx configuration untouched. To install it manually, copy the shipped template into place and reload nginx:
If the upstream nginx default vhost is also active, disable it first (e.g. `mv /etc/nginx/sites-enabled/default{,.disabled}`) to avoid a duplicate-default-server error.
As an alternative to the catch-all file, you may push an app to your Dokku host with a name like `00-default`. As long as it lists first in `ls /home/dokku/*/nginx.conf | head`, it will be used as the default nginx vhost.
Dokku uses a templating library by the name of [sigil](https://github.com/gliderlabs/sigil) to generate nginx configuration for each app. This may be overridden by committing the [default configuration template](https://github.com/dokku/dokku/blob/master/plugins/nginx-vhosts/templates/nginx.conf.sigil) to a file named `nginx.conf.sigil`.
- The `WORKDIR` of the Docker image for deploys resulting from `git:from-image` and `git:load-image` commands.
- The root of the source code tree for all other deploys (git push, `git:from-archive`, `git:sync`).
Sometimes it may be desirable to set a different path for a given app, e.g. when deploying from a monorepo. This can be done via the `nginx-conf-sigil-path` property:
The value is the path to the desired file _relative_ to the base search directory, and will never be treated as absolute paths in any context. If that file does not exist within the repository, Dokku will continue the build process as if the repository has no `nginx.conf.sigil`.
The `nginx-conf-sigil-path` property can also be set globally. The global default is `nginx.conf.sigil`, and the global value is used when no app-specific value is set.
> The [default template](https://github.com/dokku/dokku/blob/master/plugins/nginx-vhosts/templates/nginx.conf.sigil) may change with new releases of Dokku. Please refer to the appropriate template file version for your Dokku version, and make sure to look out for changes when you upgrade.
While enabled by default, using a custom nginx config can be disabled via `nginx:set`. This may be useful in cases where you do not want to allow users to override any higher-level customization of app nginx config.
Finally, each process type has it's network listeners - a list of IP:PORT pairs for the respective app containers - exposed via an `.DOKKU_APP_${PROCESS_TYPE}_LISTENERS` variable - the `PROCESS_TYPE` will be upper-cased with hyphens transformed into underscores. Users can use the new variables to expose non-web processes via the nginx proxy.
> Application environment variables are available for use in custom templates. To do so, use the form of `{{ var "FOO" }}` to access a variable named `FOO`.
The example above uses additional configuration files directly on the Dokku host. Unlike the `nginx.conf.sigil` file, these additional files will not be copied over from your application repo, and thus need to be placed in the `/home/dokku/node-js-app/nginx.conf.d/` directory manually.
For PHP Buildpack users, you will also need to provide a `Procfile` and an accompanying `nginx.conf` file to customize the nginx config _within_ the container. The following are example contents for your `Procfile`
The nginx plugin exposes a variety of properties configurable via the `nginx:set` command. The properties are used to configure the generated `nginx.conf` file from the `nginx.conf.sigil` template. The value precedence is app-specific, then global, and finally the Dokku default.
Additionally, setting an empty value will result in reverting the value back to it's default. For app-specific values, this means that Dokku will revert to the globally specified (or global default) value.
```shell
# default the value back to the global value for node-js-app
dokku nginx:set node-js-app property-name
# use the dokku default as the global value
dokku nginx:set --global property-name
```
Changing these value globally or on a per-app basis will require rebuilding the nginx config via the `proxy:build-config` command.
| nginx-service-command | | string | Full path to an executable script or binary to invoke instead of the system's init process when interacting with nginx |
| proxy-buffer-size | `8k` (# is os pagesize) | string | Size of the buffer used for reading the first part of proxied server response |
| proxy-buffering | `on` | string | Enables or disables buffering of responses from the proxied server |
| proxy-buffers | `8 8k` | string | Number and size of the buffers used for reading the proxied server response, for a single connection |
| proxy-busy-buffers-size | `16k` | string | Limits the total size of buffers that can be busy sending a response to the client while the response is not yet fully read. |
> Users with apps that contain a custom `nginx.conf.sigil` file will need to modify the files to respect the new `NGINX_BIND_ADDRESS_IPV4` and `NGINX_BIND_ADDRESS_IPV6` variables.
This is useful in cases where the proxying should be internal to a network or if there are multiple network interfaces that should respond with different content.
> if you enable the header and a subsequent deploy of your application results in an HTTP deploy (for whatever reason), the way the header works means that a browser will not attempt to request the HTTP version of your site if the HTTPS version fails until the max-age is reached.
Properties:
-`hsts`
-`hsts-include-subdomains`
-`hsts-max-age`
-`hsts-preload`
If SSL certificates are present, HSTS will be automatically enabled.
#### Running behind another proxy — configuring `X-Forwarded-*` headers
> [!WARNING]
> These values should only be modified if there is an intermediate Load balancer or CDN between the user and the Dokku server hosting your application.
Properties:
-`x-forwarded-for-value`
-`x-forwarded-port-value`
-`x-forwarded-proto-value`
-`x-forwarded-ssl`
Dokku's default Nginx configuration passes the de-facto standard HTTP headers [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For), [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto), and `X-Forwarded-Port` to your application.
These headers indicate the IP address of the original client making the request, the protocol of the original request (HTTP or HTTPS), and the port number of the original request, respectively.
If you have another HTTP proxy sitting in between the end user and your server (for example, a load balancer, or a CDN), then the values of these headers will contain information about (e.g. the IP address of) the closest proxy, and not the end user.
To fix this, assuming that the other proxy also passes `X-Forwarded-*` headers, which in turn contain information about the end user, you can tell Nginx include those values in the `X-Forwarded-*` headers that it sends to your application. You can do this via `nginx:set`, like so:
Otherwise, if it's possible for clients to make HTTP requests directly against your server, bypassing the other proxy, or if the other proxy is not configured to set these headers, then a client can basically pass any arbitrary values for these headers (which your app then presumably reads) and thereby fake an IP address, for example.
There's also the `X-Forwarded-Ssl` header which a less common alternative to `X-Forwarded-Proto` — and because of that, isn't included in Dokku's default Nginx configuration. It can be turned `on` if need be:
```shell
# force-setting value to `on`
dokku nginx:set node-js-app x-forwarded-ssl on
```
#### Changing log path
> [!WARNING]
> The defaults should not be changed without verifying that the paths will be writeable by nginx.
Properties:
-`access-log-path`
-`error-log-path`
These setting can be useful for enabling or disabling logging by setting the values to `off`.
Prior to changing the log-format, log formats should be specified at a file such as `/etc/nginx/conf.d/00-log-formats.conf`. This will ensure they are available within your app's nginx context. For instance, the following may be added to the above file. It only needs to be specified once to be used for all apps.
```nginx
# /etc/nginx/conf.d/00-log-formats.conf
# escape=json was added in nginx 1.11.8
log_format json_combined escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request":"$request",'
'"status":"$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"request_time":"$request_time",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent"'
'}';
```
#### Specifying a read timeout
> [!NOTE]
> All numeric values _must_ have a trailing time value specified (`s` for seconds, `m` for minutes).
Properties:
-`proxy-read-timeout`
#### Specifying a custom client_max_body_size
> [!NOTE]
> All numerical values _must_ have a trailing size unit specified (`k` for kilobytes, `m` for megabytes).
Properties:
-`client-max-body-size`
This property is commonly used to increase the max file upload size.
Changing this value when using the PHP buildpack (or any other buildpack that uses an intermediary server) will require changing the value in the server config shipped with that buildpack. Consult your buildpack documentation for further details.
See the [customizing hostnames documentation](/docs/configuration/domains.md#customizing-hostnames) for more information on how to configure domains for your app.
See the [enabling and disabling vhosts documentation](/docs/configuration/domains.md#enabling-and-disabling-vhosts) for more information on how to disable domain usage for your app.
See the [proxy documentation](/docs/networking/proxy-management.md) for more information on how to disable nginx as the proxy implementation for your app.
See the [proxy documentation](/docs/networking/proxy-management.md#regenerating-proxy-config) for more information on how to rebuild the nginx proxy configuration for your app.