- Java module's [home]({{< relref "/unit/howto/source.md#modules-java" >}}) directory | -| **Python** | Python's **sys.path** [directories](https://docs.python.org/3/library/sys.html#sys.path) | -| **Ruby** | - Ruby's header, interpreter, and library [directories](https://idiosyncratic-ruby.com/42-ruby-config.html): **rubyarchhdrdir**, **rubyhdrdir**, **rubylibdir**, **rubylibprefix**, **sitedir**, and **topdir**
- Ruby's gem installation directory (**gem env gemdir**)
- Ruby's entire gem path list (**gem env gempath**) | -{{
Using "uidmap", "gidmap"
- - -The **uidmap** and **gidmap** options are available only if the underlying OS -supports [user namespaces](https://man7.org/linux/man-pages/man7/user_namespaces.7.html) - -If **uidmap** is omitted but **credential** isolation is enabled,the effective -UID (EUID) of the application process in the host namespace is mapped to the -same UID in the container namespace; the same applies to **gidmap** and GID, -respectively. This means that the configuration below: - -```json -{ - "user": "some_user", - "isolation": { - "namespaces": { - "credential": true - } - } -} -``` - -Is equivalent to the following (assuming **some_user**'s EUID and EGID are -both equal to 1000): - -```json -{ - "user": "some_user", - "isolation": { - "namespaces": { - "credential": true - }, - - "uidmap": [ - { - "host": "1000", - "container": "1000", - "size": 1 - } - ], - - "gidmap": [ - { - "host": "1000", - "container": "1000", - "size": 1 - } - ] - } -} -``` ---- -Unit doesn't detect freezes, so the hanging process stays on the app's process pool. | -{{
The default is 1. | -| **spare** | Minimum number of idle processes that Unit tries to maintain for an app. When the app is started, **spare** idles are launched; Unit passes new requests to existing idles, forking new idles to keep the **spare** level if **max** allows. When busy processes complete their work and turn idle again, Unit terminates extra idles after **idle_timeout**. | -{{
Updating Go apps to run on Unit
- - - -Unit uses [cgo](https://pkg.go.dev/cmd/cgo) to invoke C code from Go, -so check the following prerequisites: - -- The `CGO_ENABLED` variable is set to **1**: - - ```console - go env CGO_ENABLED - - 0 - ``` - - ```console - go env -w CGO_ENABLED=1 - ``` - -- If you installed Unit from the - [official packages]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}), - install the development package: - - - Debian, Ubuntu - - ```console - apt install unit-dev - ``` - - - Amazon, Fedora, RHEL - - ```console - yum install unit-devel - ``` - -- If you installed Unit from - [source]({{< relref "/unit/howto/source/" >}}), - install the include files and libraries: - - ```console - make libunit-install - ``` - -In the **import** section, list the **unit.nginx.org/go** package: - -```go -import ( - ... - "unit.nginx.org/go" - ... -) -``` - -Replace the **http.ListenAndServe** call with **unit.ListenAndServe**: - -```go -func main() { - ... - http.HandleFunc("/", handler) - ... - // http.ListenAndServe(":8080", nil) - unit.ListenAndServe(":8080", nil) - ... -} -``` - -If you haven't done so yet, initialize the Go module for your app: - -```console -go mod init example.com/app # Arbitrary module designation - - go: creating new go.mod: module example.com/app -``` - -Install the newly added dependency and build your application: - -```console -go get unit.nginx.org/go@{{< param "unitversion" >}} - - go: downloading unit.nginx.org - -go build -o app app.go # Executable name and Application source code -``` - -If you update Unit to a newer version, repeat the two commands above -to rebuild your app. - -The resulting executable works as follows: - -- When you run it standalone, the **unit.ListenAndServe** call - falls back to **http** functionality. - -- When Unit runs it, **unit.ListenAndServe** directly communicates - with Unit's router process, ignoring the address supplied as its first argument - and relying on the - [listener's settings]({{< relref "/unit/configuration.md#configuration-listeners" >}}) - instead. - ---- - -Supply your **.js** pathname here and start the file itself with a proper shebang:
`#!/usr/bin/env node`
**Note:** Make sure to `chmod +x` the file you list here so Unit can start it. | -| **arguments** | Array of strings; command-line arguments to be passed to the app. The example below is equivalent to **/www/apps/node-app/app.js --tmp-files /tmp/node-cache**. | - -{{
The default is **index.php**. | -| **options** | Object; [defines]({{< relref "/unit/configuration.md#configuration-php-options" >}}) the **php.ini** location and options. | -| **script** | String; filename of a **root**-based PHP script that serves all requests to the app. | -| **targets** | Object; defines application sections with [custom]({{< relref "/unit/configuration.md#configuration-php-targets" >}}) **root**, **script**, and **index** values. | - -{{
- The objects override the settings from any ***.ini** files
- The **admin** object can only set what's [listed](https://www.php.net/manual/en/ini.list.php) as **PHP_INI_SYSTEM**; for other modes, set **user**
- Neither **admin** nor **user** can set directives listed as [php.ini only](https://www.php.net/manual/en/ini.list.php) except for **disable_classes** and **disable_functions** | -| **file** | String; pathname of the **php.ini** file with [PHP configuration directives](https://www.php.net/manual/en/ini.list.php). | - -{{
**Note:** Unit does *not* support passing arguments to factories. *(since 1.33.0)* | -| **home** | String; path to the app's [virtual environment](https://packaging.python.org/en/latest/tutorials/installing-packages/#creating-virtual-environments). Absolute or relative to **working_directory**.
**Note:** The Python version used to run the app is determined by **type**; for performance, Unit doesn't use the command-line interpreter from the virtual environment. | -| **path** | String or an array of strings; additional Python module lookup paths. These values are prepended to **sys.path**. | -| **prefix** | String; **SCRIPT_NAME** context value for WSGI or the **root_path** context value for ASGI. Should start with a slash (**/**). | -| **protocol** | String; hints Unit that the app uses a certain interface. Can be **asgi** or **wsgi**. | -| **targets** | Object; app sections with [custom]({{< relref "/unit/configuration.md#configuration-python-targets" >}}) **module** and **callable** values. | -| **thread_stack_size** | Integer; stack size of a worker thread (in bytes, multiple of memory page size; the minimum value is usually architecture specific). The default is usually system dependent and can be set with `ulimit -s
`"filesystem": [`
`"/tmp/",`
`"/var/tmp/"`
`]`
`}` | -| **module_init_handler** | String; name of the module initialization function. If you use Unit with the official `unit-wasm` [package]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}), the value is language specific; see the [SDK](https://github.com/nginx/unit-wasm/) documentation for details. Otherwise, use the name of your custom implementation. It is invoked by the WebAssembly language module at language module startup, after the WebAssembly module was initialized. | -| **module_end_handler** | String; name of the module finalization function. If you use Unit with the official `unit-wasm` [package]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}), the value is language specific; see the [SDK](https://github.com/nginx/unit-wasm/) documentation for details. Otherwise, use the name of your custom implementation. It is invoked by the WebAssembly language module at language module shutdown. | -| **request_init_handler** | String; name of the request initialization function. If you use Unit with the official `unit-wasm` [package]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}), the value is language specific; see the [SDK](https://github.com/nginx/unit-wasm/) documentation for details. Otherwise, use the name of your custom implementation. It is invoked by the WebAssembly language module at the start of each request. | -| **request_end_handler** | String; name of the request finalization function. If you use Unit with the official `unit-wasm` [package]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}), the value is language specific; see the [SDK](https://github.com/nginx/unit-wasm/) documentation for details. Otherwise, use the name of your custom implementation. It is invoked by the WebAssembly language module at the end of each request, when the headers and the request body were received. | -| **response_end_handler** | String; name of the response finalization function. If you use Unit with the official `unit-wasm` [package]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}), the value is language specific; see the [SDK](https://github.com/nginx/unit-wasm/) documentation for details. Otherwise, use the name of your custom implementation. It is invoked by the WebAssembly language module at the end of each response, when the headers and the response body were sent. | -{{
It takes a URL to either a gRPC or HTTP(S) endpoint. | -| **protocol** | Determines the protocol used to communicate with the endpoint.
Can be either *http(s)* or *grpc*. | -| **batch_size** | Number of spans to cache before triggering a transaction with the configured endpoint. This is optional.
This allows the user to cache up to N spans before the OpenTelemetry (OTEL) background thread sends spans over the network to the collector.
If specified, it must be a positive integer. | -| **sampling_ratio** | Percentage of requests to trace.
This allows the user to only trace anywhere from 0% to 100% of requests that hit Unit. In high throughput environments this percentage should be lower. This allows the user to save space in storing span data, and to collect request metrics like time to decode headers and whatnot without storing massive amounts of duplicate superfluous data.
If specified, it must be a positive floating point number. | - -{{
No configuration files used
- -The control API is the single source of truth about Unit's configuration. -There are no configuration files that can or should be manipulated; -this is a deliberate design choice made to avoid issues such as: - -- Undetected invalid states: - Configuration files can be saved in an invalid state, - and the issue won't be seen until reload or startup. - The control API avoids this by validating configuration changes on the fly. - -- Too broad or too narrow configuration file permissions: - If a configuration file is inaccessible, it can't be loaded; - if it's public,sensitive data may leak. - The control API has a single manageable point of entry. - -- Unpredictable behavior: - In a configuration file hierarchy, it's easy to lose track and misconfigure something. - With the control API, the entire configuration is a single, organized, and navigatable entity. -Replicating Unit states
- -Although Unit is fully dynamic, sometimes you just want to copy an existing setup -without extra modification. Unit's -[state directory]({{< relref "/unit/howto/source.md#source-config-src-state" >}}) -are interchangeable as long as Unit version stays the same, -so you can use a shortcut to replicate a Unit instance. Also, this works with the -Docker [images]({{< relref "/unit/howto/docker.md" >}}). - -{{< call-out "warning" >}} -Unit's state can change its structure between versions -and must not be edited by external means. -{{< /call-out >}} - -On the machine where the *reference* Unit instance runs, -find out where the state is stored: - -```console -unitd -h - - --state DIRECTORY set state directory name - default: "/path/to/reference/unit/state" # The value we're looking for -``` - -Double-check that the state location isn't overridden at startup: - -```console -ps ax | grep unitd - ... - unit: main v1.34.1 [unitd --state /runtime/path/to/reference/unit/state ... ] # The runtime value overrides the default -``` - -Repeat these commands on the second machine to see where the target instance -stores its state. - -Stop both Unit instances, for example, running the following command as root: - -```console -systemctl stop unit -``` - -{{< call-out "note" >}} -Stop and start commands may differ if Unit was installed from a -[non-official]({{Welcome to NGINX Unit!
-If you see this page, the NGINX Unit web server is successfully - installed and working. Further configuration is required. -
-For online documentation and support, please refer to
- unit.nginx.org.
-
Thank you for using NGINX Unit.
- - -``` - -Now, Unit should -[listen]({{< relref "/unit/configuration.md#configuration-listeners" >}}) -on a port that -[routes]({{< relref "/unit/configuration.md#configuration-routes" >}}) -the incoming requests to a **share** action, -which serves the file: - -```json -{ - "listeners": { - "127.0.0.1:8080": { - "pass": "routes" - } - }, - - "routes": [ - { - "action": { - "share": "/www/data$uri" - } - } - ] -} -``` - -To configure Unit, **PUT** this snippet to the **/config** section via the -[control socket]({{as a JSON value in the HTTP response body. | -| **POST** | Updates the *array* at the request URI,
appending the JSON value from the HTTP request body. | -| **PUT** | Replaces the entity at the request URI
and returns a status message in the HTTP response body.| -| **DELETE**| Deletes the entity at the request URI
and returns a status message in the HTTP response body.| -{{
Hello, World!
') - - with Configurator() as config: - config.add_route('hello', '/') - config.add_view(hello_world, route_name='hello') - - # Callables' name is used in Unit configuration - app = config.make_wsgi_app() - - # serve(app, host='0.0.0.0', port=6543) - ``` - - Note that we've dropped the server code; also, mind that Unit imports - the module, so the **if __name__ == '__main__'** idiom would be - irrelevant. - - {{% /tab %}} - {{% tab name="INI-Based" %}} - - To load the - [configuration](https://docs.pylonsproject.org/projects/pyramid/en/latest/quick_tutorial/ini.html), - we place a **wsgi.py** file next to **development.ini** in **/path/to/app/**: - - ```python - from pyramid.paster import get_app, setup_logging - - # Callables' name is used in Unit configuration - app = get_app('development.ini') - setup_logging('development.ini') - ``` - - This [sets up](https://docs.pylonsproject.org/projects/pyramid/en/latest/api/paster.html) - the WSGI application for Unit; if the **.ini**'s pathname is - relative, provide the appropriate **working_directory** in Unit - configuration. - - {{% /tab %}} - {{< /tabs >}} - -4. Change ownership: - - {{< include "unit/howto_change_ownership.md" >}} - -5. Next, [prepare]({{< relref "/unit/configuration.md#configuration-python" >}}) - the Pyramid configuration for Unit (use real values for **type**, **home**, - and **path**): - - ```json - { - "listeners": { - "*:80": { - "pass": "applications/pyramid" - } - }, - "applications": { - "pyramid": { - "type": "python 3.Y", - "type_comment": "Must match language module version and virtual environment version", - "working_directory": "/path/to/app/", - "working_directory_comment": "Path to the application directory; use a real path in your configuration", - "path": "/path/to/app/", - "path_comment": "Path to the application directory; use a real path in your configuration", - "home": "/path/to/app/venv/", - "home_comment": "Path to the virtual environment, if any", - "module": "wsgi", - "module_comment": "WSGI module filename with extension omitted", - "callable": "app", - "callable_comment": "Name of the callable in the module to run" - } - } - } - ``` - -6. Upload the updated configuration. - - {{< include "unit/howto_upload_config.md" >}} - - After a successful update, your app should be available on the listener’s IP - address and port: - - ```console - $ curl http://localhost - -Hello, World!
- ``` diff --git a/content/unit/howto/frameworks/quart.md b/content/unit/howto/frameworks/quart.md deleted file mode 100644 index 81368a71d..000000000 --- a/content/unit/howto/frameworks/quart.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: Quart -weight: 1400 -toc: true -nd-docs: DOCS-1744 ---- - - -To run apps built with the [Quart](https://pgjones.gitlab.io/quart/index.html) web framework using Unit: - -1. Install [Unit]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}) with a Python 3.5+ language module. - -2. Create a virtual environment to install Quart`s - [PIP package](https://pgjones.gitlab.io/quart/tutorials/installation.html), - for instance: - - ```console - $ cd /path/to/app/ # Path to the application directory; use a real path in your configuration - $ python --version # Make sure your virtual environment version matches the module version - Python X.Y.Z # Major version, minor version, and revision number - $ python -m venv venv # Arbitrary name of the virtual environment - $ source venv/bin/activate # Name of the virtual environment from the previous command - $ pip install quart - $ deactivate - ``` - - {{< call-out "warning" >}} - Create your virtual environment with a Python version that matches the - language module from Step 1 up to the minor number (**X.Y** in - this example). Also, the app **type** in Step 5 must - [resolve]({{< relref "/unit/configuration.md#configuration-apps-common" >}}) - to a similarly matching version; Unit doesn't infer it from the environment. - {{< /call-out >}} - - -3. Let's try a WebSocket-enabled version of a - [tutorial app](https://pgjones.gitlab.io/quart/tutorials/deployment.html), - saving it as **/path/to/app/asgi.py**: - - ```python - from quart import Quart, websocket - - app = Quart(__name__) - - @app.route('/') - async def hello(): - return 'Hello, World!
' - - # Let's add WebSocket support to the app as well - @app.websocket('/ws') - async def ws(): - while True: - await websocket.send('Hello, World!') - ``` - -4. Change ownership: - - {{< include "unit/howto_change_ownership.md" >}} - -5. Next, [prepare]({{< relref "/unit/configuration.md#configuration-python" >}}) - the Quart configuration for Unit (use real values for **type**, **home**, - and **path**): - - ```json - { - "listeners": { - "*:80": { - "pass": "applications/quart" - } - }, - "applications": { - "quart": { - "type": "python 3.Y", - "type_comment": "Must match language module version and virtual environment version", - "path": "/path/to/app/", - "path_comment": "Path to the ASGI module", - "home": "/path/to/app/venv/", - "home_comment": "Path to the virtual environment, if any", - "module": "asgi", - "module_comment": "ASGI module filename with extension omitted", - "callable": "app", - "callable_comment": "Name of the callable in the module to run" - } - } - } - ``` - -6. Upload the updated configuration. - - {{< include "unit/howto_upload_config.md" >}} - - After a successful update, your app should be available on the listener’s IP - address and port: - - ```console - $ curl http://localhost - -Hello, World!
- ``` - - ```console - $ wscat -c ws://localhost/ws - - < Hello, World! - < Hello, World! - < Hello, World! - ... - ``` diff --git a/content/unit/howto/frameworks/rails.md b/content/unit/howto/frameworks/rails.md deleted file mode 100644 index 5b2dbbe19..000000000 --- a/content/unit/howto/frameworks/rails.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Ruby on Rails -weight: 1600 -toc: true -nd-docs: DOCS-1759 ---- - -To run apps based on the [Ruby on Rails](https://rubyonrails.org) framework -using Unit: - -1. Install [Unit]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}) with a Ruby language module. - -2. [Install](https://guides.rubyonrails.org/getting_started.html#creating-a-new-rails-project-installing-rails) - Ruby on Rails and create or deploy your app. Here, we use Ruby on Rails's [basic template](https://guides.rubyonrails.org/getting_started.html#creating-the-blog-application): - - ```console - $ cd /path/to/ # Path where the application directory will be created; use a real path in your configuration - ``` - - ```console - $ rails new app # Arbitrary app name; becomes the application directory name - ``` - - This creates the app's directory tree at **/path/to/app/**; its - **public/** subdirectory contains the static files, while the entry - point is **/path/to/app/config.ru**. - -3. Change ownership: - - {{< include "unit/howto_change_ownership.md" >}} - -4. Next, - [prepare]({{< relref "/unit/configuration.md#configuration-ruby" >}}) - the Ruby on Rails configuration (use real values for **share** and - **working_directory**): - - ```json - { - "listeners": { - "*:80": { - "pass": "routes" - } - }, - "routes": [ - { - "action": { - "share": "/path/to/app/public$uri", - "share_comment": "Serves static files", - "fallback": { - "pass": "applications/rails" - } - } - } - ], - "applications": { - "rails": { - "type": "ruby", - "script": "config.ru", - "script_comment": "All requests are handled by a single script, relative to working_directory", - "working_directory": "/path/to/app/", - "working_directory_comment": "Path to the application directory, needed here for 'require_relative' directives; use a real path in your configuration" - } - } - } - ``` - -5. Upload the updated configuration. - - {{< include "unit/howto_upload_config.md" >}} - - After a successful update, your app should be available on the listener’s IP - address and port: - -  - diff --git a/content/unit/howto/frameworks/responder.md b/content/unit/howto/frameworks/responder.md deleted file mode 100644 index 7662c8085..000000000 --- a/content/unit/howto/frameworks/responder.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: Responder -weight: 1500 -toc: true -nd-docs: DOCS-1740 ---- - -# Responder - -To run apps built with the [Responder](https://responder.kennethreitz.org/) web framework using Unit: - -1. Install [Unit]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}) with a Python 3.6+ language module. - -2. Create a virtual environment to install Responder’s -[PIP package](https://responder.kennethreitz.org/#installing-responder), -for instance: - - ```console - $ cd /path/to/app/ # Path to the application directory; use a real path in your configuration - $ python --version # Make sure your virtual environment version matches the module version - Python X.Y.Z # Major version, minor version, and revision number - $ python -m venv venv # Arbitrary name of the virtual environment - $ source venv/bin/activate # Name of the virtual environment from the previous command - $ pip install responder - $ deactivate - ``` - - {{< call-out "warning" >}} - Create your virtual environment with a Python version that matches the - language module from Step 1 up to the minor number (**X.Y** in - this example). Also, the app **type** in Step 5 must - [resolve]({{< relref "/unit/configuration.md#configuration-apps-common" >}}) - to a similarly matching version; Unit doesn't infer it from the environment. - {{< /call-out >}} - - -3. Let's try a Unit-friendly version of a [tutorial app](https://responder.kennethreitz.org/quickstart.html#declare-a-web-service), - saving it as **/path/to/app/asgi.py**: - - ```python - import responder - - app = responder.API() - - @app.route("/") - def hello_world(req, resp): - resp.text = "Hello, World!" - - @app.route("/hello/{who}") - def hello_to(req, resp, *, who): - resp.text = f"Hello, {who}!" - ``` - - The **app.run()** call is omitted because **app** will be directly - run by Unit as an ASGI [callable](https://github.com/kennethreitz/responder/blob/c6f3a7364cfa79805b0d51eea011fe34d9bd331a/responder/api.py#L501). - -4. Change ownership: - - {{< include "unit/howto_change_ownership.md" >}} - - -5. Next, [prepare]({{< relref "/unit/configuration.md#configuration-python" >}}) the Responder configuration for - Unit (use real values for **type**, **home**, and **path**): - - ```json - { - "listeners": { - "*:80": { - "pass": "applications/responder" - } - }, - "applications": { - "responder": { - "type": "python 3.Y", - "type_comment": "Must match language module version and virtual environment version", - "path": "/path/to/app/", - "path_comment": "Path to the ASGI module", - "home": "/path/to/app/venv/", - "home_comment": "Path to the virtual environment, if any", - "working_directory": "/path/to/app/", - "working_directory_comment": "Path to the directory where Responder creates static_dir and templates_dir", - "module": "asgi", - "module_comment": "ASGI module filename with extension omitted", - "callable": "app", - "callable_comment": "Name of the callable in the module to run" - } - } - } - ``` - -6. Upload the updated configuration. - - {{< include "unit/howto_upload_config.md" >}} - - After a successful update, your app should be available on the listener’s IP - address and port: - - ```console - $ curl http://localhost - - Hello, World! - ``` - - ```console - $ curl http://localhost/hello/JohnDoe - - Hello, JohnDoe! - ``` - diff --git a/content/unit/howto/frameworks/sanic.md b/content/unit/howto/frameworks/sanic.md deleted file mode 100644 index 1e8cce187..000000000 --- a/content/unit/howto/frameworks/sanic.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -title: Sanic -weight: 1700 -toc: true -nd-docs: DOCS-1756 ---- - -To run apps built with the [Sanic](https://sanic.dev/) web framework -using Unit: - -1. Install [Unit]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}) with a Python 3.7+ language module. - -2. Create a virtual environment to install Sanic's - [PIP package](https://sanic.dev/en/guide/getting-started.html), for - instance: - - ```console - $ cd /path/to/app/ # Path to the application directory; use a real path in your configuration - $ python --version # Make sure your virtual environment version matches the module version - Python X.Y.Z # Major version, minor version, and revision number - $ python -m venv venv # Arbitrary name of the virtual environment - $ source venv/bin/activate # Name of the virtual environment from the previous command - $ pip install sanic - $ deactivate - ``` - -3. Let's try a version of a [tutorial app](ttps://sanic.dev/en/guide/basics/response.html#methods), - saving it as **/path/to/app/asgi.py**: - - ```python - from sanic import Sanic - from sanic.response import json - - app = Sanic() - - @app.route("/") - async def test(request): - return json({"hello": "world"}) - ``` - -4. Change ownership: - - {{< include "unit/howto_change_ownership.md" >}} - - -5. Next, [prepare]({{< relref "/unit/configuration.md#configuration-python" >}}) - the Sanic configuration for Unit (use real values for **type**, **home**, and - **path**): - - ```json - { - "listeners": { - "*:80": { - "pass": "applications/sanic" - } - }, - "applications": { - "sanic": { - "type": "python 3.Y", - "type_comment": "Must match language module version and virtual environment version", - "path": "/path/to/app/", - "path_comment": "Path to the ASGI module", - "home": "/path/to/app/venv/", - "home_comment": "Path to the virtual environment, if any", - "module": "asgi", - "module_comment": "ASGI module filename with extension omitted", - "callable": "app", - "callable_comment": "Name of the callable in the module to run" - } - } - } - ``` - -6. Upload the updated configuration. - - {{< include "unit/howto_upload_config.md" >}} - - After a successful update, your app should be available on the listener’s IP - address and port: - - ```console - $ curl http://localhost - - {"hello":"world"} - ``` - diff --git a/content/unit/howto/frameworks/springboot.md b/content/unit/howto/frameworks/springboot.md deleted file mode 100644 index ba55ca0a8..000000000 --- a/content/unit/howto/frameworks/springboot.md +++ /dev/null @@ -1,122 +0,0 @@ ---- -title: Spring Boot -weight: 1800 -toc: true -nd-docs: DOCS-1758 ---- - -To run apps based on the [Spring Boot](https://spring.io/projects/spring-boot) frameworks using Unit: - -1. Install [Unit]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}) with a Java language module. - -2. Create your Spring Boot project; we'll use the [quickstart](https://spring.io/quickstart) - example, creating it atZope - Auto-generated default page
- - This is Page Template index_html. - - - ``` - -[app-link]: https://zope.readthedocs.io/en/latest/INSTALL.html diff --git a/content/unit/howto/integration.md b/content/unit/howto/integration.md deleted file mode 100644 index 506c5c822..000000000 --- a/content/unit/howto/integration.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: NGINX integration -toc: true -weight: 500 -nd-docs: DOCS-1705 ---- - -Unit is a potent and versatile server in its own right. However, if you're -used to NGINX's rich feature set, you can deploy it in front of Unit; one -notable use case for NGINX here is securing the Unit control socket. - -## Fronting Unit with NGINX - -Configure a [listener]({{< relref "/unit/configuration.md#configuration-listeners" >}}) in Unit: - -```json -{ - "127.0.0.1:8080": { - "comment_127.0.0.1:8080": "Socket address where NGINX proxies requests", - "pass": "...", - "comment_pass": "Unit's internal request destination", - "forwarded": { - "client_ip": "X-Forwarded-For", - "comment_client_ip": "The header field set by NGINX", - "source": [ - "127.0.0.1" - ], - "comment_source": "The IP address where NGINX runs" - } - } -} -``` - -Here, **forwarded** is optional; it enables identifying the -[originating IPs]({{< relref "/unit/configuration.md#configuration-listeners-xff" >}}) -of requests proxied from **source**. - -In NGINX configuration, create an upstream in the **http** context, adding -the listener's socket as a **server**: - -```nginx -http { - upstream unit_backend { - server 127.0.0.1:8080; # Unit's listener socket address - } - - server { - location /unit/ { # Arbitrary location - proxy_pass http://unit_backend; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Unit's listener must list the same name in client_ip/header - } - } -} -``` - -A more compact alternative would be a direct **proxy_pass** in your -**location**: - -```nginx -http { - server { - location /unit/ { # Arbitrary location - proxy_pass http://127.0.0.1:8080; # Unit's listener socket address - proxy_set_header Host $host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # Unit's listener must list the same name in client_ip/header - } - } -} -``` - -The **proxy_set_header X-Forwarded-For** directives work together with the -listener's **client_ip** option. - -For details, see the [NGINX documentation](https://nginx.org). Commercial -support and advanced features are [also available](https://www.nginx.com). - -## Securely proxying Unit's control API {#nginx-secure-api} - -By default, Unit exposes its -[control API]({{< relref "/unit/controlapi.md#configuration-mgmt" >}}) -via a UNIX domain socket. These sockets aren't network accessible, so the API is -local only. To enable secure remote access, you can use NGINX as a reverse proxy. - -{{< call-out "warning" >}} -Avoid exposing an unprotected control socket to public networks. Use NGINX -or a different solution such as SSH for security and authentication. -{{< /call-out >}} - -Use this configuration template for NGINX (replace placeholders in -**ssl_certificate**, **ssl_certificate_key**, -**ssl_client_certificate**, **allow**, **auth_basic_user_file**, -and **proxy_pass** with real values): - -```nginx -server { - - # Configure SSL encryption - listen 443 ssl; - - ssl_certificate /path/to/ssl/cert.pem; # Path to your PEM file; use a real path in your configuration - ssl_certificate_key /path/to/ssl/cert.key; # Path to your key file; use a real path in your configuration - - # SSL client certificate validation - ssl_client_certificate /path/to/ca.pem; # Path to certification authority PEM file; use a real path in your configuration - ssl_verify_client on; - - # Network ACLs - allow 1.2.3.4; # Replicate and update as needed with allowed IPs and network CIDRs - deny all; - - # HTTP Basic authentication - auth_basic on; - auth_basic_user_file /path/to/htpasswd; # Path to your htpasswd file - - location / { - proxy_pass http://unix:/path/to/control.unit.sock; # Path to Unit's control socket - } -} -``` - -The same approach works for an IP-based control socket: - -```nginx -location / { - proxy_pass http://127.0.0.1:8080; # Unit's control socket address -} -``` diff --git a/content/unit/howto/modules.md b/content/unit/howto/modules.md deleted file mode 100644 index 78b9277bb..000000000 --- a/content/unit/howto/modules.md +++ /dev/null @@ -1,351 +0,0 @@ ---- -title: Working with language modules -weight: 700 -toc: true -nd-docs: DOCS-1707 ---- - -Languages supported by Unit fall into these two categories: - -- [External]({{< relref "/unit/howto/modules.md#modules-ext" >}}) - (Go, Node.js): Run outside Unit with an - interface layer to the native runtime. -- [Embedded]({{< relref "/unit/howto/modules.md#modules-emb" >}}) - (Java, Perl, PHP, Python, Ruby, WebAssembly): - Execute in runtimes that Unit loads at startup. - -For any specific language and its version, Unit needs a language module. - -{{< call-out "note" >}} -The commands in this document starting with a hash (#) must be run as root or -with superuser privileges. -{{< /call-out >}} - -## External language modules {#modules-ext} - -External modules are regular language libraries or packages that you install -like any other. They provide common web functionality, communicating with Unit -from the app's runspace. - -In Go, Unit support is implemented with a package that you -[import]({{< relref "/unit/configuration.md#configuration-go" >}}) -in your apps to make them Unit-aware. - -In Node.js, Unit is supported by an `npm`-hosted [package](https://www.npmjs.com/package/unit-http) that you -[require]({{< relref "/unit/configuration.md#configuration-nodejs" >}}) -in your app code. You can -[install]({{< relref "/unit/installation.md#installation-nodejs-package" >}}) -the package from the `npm` repository; -otherwise, [build]({{< relref "/unit/howto/source.md#modules-nodejs" >}}) -it for your version of Node.js using Unit's sources. - -For WebAssembly, Unit delegates bytecode execution to the -[Wasmtime](https://wasmtime.dev/) runtime that is installed with the -[language module]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}) -module or during a -[source build]({{< relref "/unit/howto/source.md#source-wasm" >}}). - -## Embedded language modules {#modules-emb} - -Embedded modules are shared libraries that Unit loads at startup. Query Unit -to find them in your system: - -```console -$ unitd -h - - ... - --log FILE set log filename - default: /default/path/to/unit.log # This is the default log path which can be overridden at runtime - - --modules DIRECTORY set modules directory name - default: /default/modules/path/ # This is the default modules path which can be overridden at runtime - -$ ps ax | grep unitd # Check whether the defaults were overridden at launch - ... - unit: main v1.34.1 [unitd --log /runtime/path/to/unit.log --modules /runtime/modules/path/ ... ] # If this option is set, its value is used at runtime - -$ ls /path/to/modules # Use runtime value if the default was overridden - - java.unit.so php.unit.so ruby.unit.so wasm_wasi_component.unit.so - perl.unit.so python.unit.so wasm.unit.so - -``` - -To clarify the module versions, check the {ref}`Unit logDetails
- - -Specific upgrade steps depend on your installation method: - -- The recommended option is to use our official - [packages]({{< relref "/unit/installation.md#installation-precomp-pkgs" >}}) - or Docker - [images]({{< relref "/unit/installation.md#installation-docker" >}}); - with them, it's just a matter of updating - **unit-*** packages with your package manager of choice or - switching to a newer image. - -- If you use a third-party installation - [method]({{< relref "/unit/installation.md#installation-community-repos" >}}), - consult the maintainer's documentation for details. - -- If you install Unit from - [source files]({{< relref "/unit/howto/source.md" >}}), - rebuild and reinstall Unit and its modules from scratch. - -Control socket
- - - -If you use a UNIX control socket, ensure it is available to **root** -only: - -```console -$ unitd -h - - ... - --control ADDRESS set address of control API socket - default: "unix:/default/path/to/control.unit.sock" # Build-time setting, can be overridden - -$ ps ax | grep unitd - - ... unit: main {{< param "unitversionv" >}} [... --control /path/to/control.sock ...] # Make sure to check for runtime overrides - -# ls -l /path/to/control.unit.sock # If it's overridden, use the runtime setting - - srw------- 1 root root 0 ... /path/to/control.unit.sock - -``` - -UNIX domain sockets aren't network accessible; for remote access, use -[NGINX]({{< relref "/unit/howto/integration.md#nginx-secure-api" >}}) oor a solution such as SSH: - -```console -$ ssh -N -L ./here.sock:/path/to/control.unit.sock root@unit.example.com & # Local socket | Socket on the Unit server; use a real path in your command | Unit server hostname -``` - -```console -$ curl --unix-socket ./here.sock # Use the local socket to configure Unit - - { - "certificates": {}, - "config": { - "listeners": {}, - "applications": {} - } - } -``` - -If you prefer an IP-based control socket, avoid public IPs; they expose the -[control API]({{< relref "/unit/controlapi.md#configuration-api" >}}) -and all its capabilities. This means your Unit instance can be manipulated by -whomever is physically able to connect: - -```console -# unitd --control 203.0.113.14:8080 -``` - -```console -$ curl 203.0.113.14:8080 - - { - "certificates": {}, - "config": { - "listeners": {}, - "applications": {} - } - } -``` - -Instead, opt for the loopback address to ensure all access is local to your -server: - -```console -# unitd --control 127.0.0.1:8080 -``` - -```console -$ curl 203.0.113.14:8080 - - curl: (7) Failed to connect to 203.0.113.14 port 8080: Connection refused -``` - -However, any processes local to the same system can access the local socket, -which calls for additional measures. A go-to solution would be using NGINX -to [proxy]({{< relref "/unit/howto/integration.md#nginx-secure-api" >}}) -Unit's control API. - -State directory
- - - -The state directory stores Unit's internal configuration between launches. -Avoid manipulating it or relying on its contents even if tempted to do so. -Instead, use only the control API to manage Unit's configuration. - -Also, the state directory should be available only to **root** (or the -user that the **main** -[process]({{< relref "/unit/howto/security.md#security-apps" >}}) -runs as): - -```console -$ unitd -h - - ... - --state DIRECTORY set state directory name - default: /default/path/to/unit/state/ # Build-time setting, can be overridden -``` - -```console -$ ps ax | grep unitd - - ... unit: main {{< param "unitversionv" >}} [... --state /path/to/unit/state/ ...] # Make sure to check for runtime overrides -``` - -```console -# ls -l /path/to/unit/state/ # If it's overridden, use the runtime setting - - drwx------ 2 root root 4096 ... -``` - -Details
- - - - -Some considerations: - -- Mind that - [variables]({{< relref "/unit/configuration.md#configuration-variables-native" >}}) - contain arbitrary user-supplied request values; variable-based **pass** values in - [listeners]({{< relref "/unit/configuration.md#configuration-listeners" >}}) - and - [routes]({{< relref "/unit/configuration.md#configuration-routes-action" >}}) - must account for malicious requests, or the requests must be properly filtered. - -- Create - [matching rules]({{< relref "/unit/configuration.md#configuration-routes-matching" >}}) - to formalize the restrictions of your Unit instance and the apps it runs. - -- Configure - [shares]({{< relref "/unit/configuration.md#configuration-static" >}}) - only for directories and files you intend to make public. - -File permissions
- - - -To configure file permissions for your apps, check Unit's build-time and -run-time options first: - -```console -$ unitd -h - - ... - --user USER # set non-privileged processes to run as specified user | default: unit_user (Build-time setting, can be overridden) - - --group GROUP set non-privileged processes to run as specified group - default: user's primary group -``` - -```console -$ ps ax | grep unitd - - ... unit: main {{< param "unitversionv" >}} [... --user unit_user --group unit_group ...] # Make sure to check for runtime overrides -``` - -In particular, this is the account the router process runs as. Use this -information to set up permissions for the app code or binaries and shared -static files. The main idea is to limit each app to its own files and -directories while simultaneously allowing Unit's router process to access -static files for all apps. - -Specifically, the requirements are as follows: - -- All apps should run as different users so that the permissions can be - configured properly. Even if you run a single app, it's reasonable to - create a dedicated user for added flexibility. - -- An app's code or binaries should be reachable for the user the app runs - as; the static files should be reachable for the router process. Thus, - each part of an app's directory path must have execute permissions - assigned for the respective users. - -- An app's directories should not be available to other apps or - non-privileged system users. The router process should be able to access - the app's static file directories. Accordingly, the app's directories - must have read and execute permissions assigned for the respective users. - -- The files and directories that the app is designed to update should - be writable only for the user the app runs as. - -- The app code should be readable (and executable in case of - [external]({{< relref "/unit/howto/modules.md#modules-ext" >}}) apps) - for the user the app runs as; the static content should be readable for the - router process. - -A detailed walkthrough to guide you through each requirement: - -1. If you have several independent apps, running them with a single user -account poses a security risk. Consider adding a separate system user -and group per each app: - - ```console - # useradd -M app_user # Add user account without home directory - ``` - - ```console - # groupadd app_group - ``` - - ```console - # usermod -L app_user # Deny interactive login - ``` - - ```console - # usermod -a -G app_group app_user # Add user to the group - ``` - - Even if you run a single app, this helps if you add more apps or need to - decouple permissions later. - -1. It's important to add Unit's non-privileged user account to *each* app -group: - - ```console - # usermod -a -G app_group unit_user - ``` - - Thus, Unit's router process can access each app's directory and serve - files from each app's shares. - -1. A frequent source of issues is the lack of permissions for directories -inside a directory path needed to run the app, so check for that if in -doubt. Assuming your app code is stored at **/path/to/app/**: - - ```console - # ls -l / - - # drwxr-xr-x some_user some_group path # Permissions are OK - ``` - - ```console - # ls -l /path/ - - # drwxr-x--- some_user some_group to # Permissions are too restrictive - ``` - - This may be a problem because the **to/** directory isn't owned by - **app_user:app_group** and denies all permissions to non-owners (as - the **---** sequence tells us), so a fix can be warranted: - - ```console - # chmod o+rx /path/to/ # Add read/execute permissions for non-owners - ``` - - Another solution is to add **app_user** to **some_group** - (assuming this was not done before): - - ```console - # usermod -a -G some_group app_user - ``` - -1. Having checked the directory tree, assign ownership and permissions for -your app's directories, making them reachable for Unit and the app: - - ```console - # chown -R app_user:app_group /path/to/app/ # Assign ownership for the app code | Path to the application directory; use a real path in your command - ``` - - ```console - # chown -R app_user:app_group /path/to/static/app/files/ # Assign ownership for the static files | Can be outside the app directory tree; use a real path in your command - ``` - - ```console - # find /path/to/app/ -type d -exec chmod u=rx,g=rx,o= {} \; # Path to the application directory; use a real path in your command | Add read/execute permissions to app code directories for user and group - ``` - - ```console - # find /path/to/static/app/files/ -type d -exec chmod u=rx,g=rx,o= {} \; # Can be outside the app directory tree; use a real path in your command | Add read/execute permissions to static file directories for user and group - ``` - -1. If the app needs to update specific directories or files, make sure -they're writable for the app alone: - - ```console - # chmod u+w /path/to/writable/file/or/directory/ # Add write permissions for the user only; the group shouldn't have them | Repeat for each file or directory that must be writable - ``` - - In case of a writable directory, you may also want to prevent non-owners - from messing with its files: - - ```console - # chmod +t /path/to/writable/directory/ # Sticky bit prevents non-owners from deleting or renaming files | Repeat for each directory that must be writable - - ``` - - {{< call-out "note" >}} - Usually, apps store and update their data outside the app code - directories, but some apps may mix code and data. In such a case, - assign permissions on an individual basis, making sure you understand - how the app uses each file or directory: is it code, read-only - content, or writable data. - {{< /call-out >}} - -1. For [embedded]({{< relref "/unit/howto/modules.md#modules-emb" >}}) - apps, it's usually enough to make the - app code and the static files readable: - - ```console - # find /path/to/app/code/ -type f -exec chmod u=r,g=r,o= {} \; # Path to the application's code directory; use a real path in your command | Add read rights to app code for user and group - ``` - - ```console - # find /path/to/static/app/files/ -type f -exec chmod u=r,g=r,o= {} \; # Can be outside the app directory tree; use a real path in your command | Add read rights to static files for user and group - ``` - -1. For - [external]({{< relref "/unit/howto/modules.md#modules-ext" >}}) - apps, additionally make the app code or binaries executable: - - ```console - # find /path/to/app/ -type f -exec chmod u=rx,g=rx,o= {} \; # Path to the application directory; use a real path in your command | Add read and execute rights to app code for user and group - ``` - - ```console - # find /path/to/static/app/files/ -type f -exec chmod u=r,g=r,o= {} \; # Can be outside the app directory tree; use a real path in your command | Add read rights to static files for user and group - ``` - -1. To run a single app, [configure]({{< relref "/unit/configuration.md" >}}) - Unit as follows: - - ```json - { - "listeners": { - "*:80": { /* Or another suitable socket address */ - "pass": "routes" - } - }, - - "routes": [ - { - "action": { - "share": "/path/to/static/app/files/$uri", - /* Router process needs read and execute permissions to serve static content from this directory */ - "fallback": { - "pass": "applications/app" - } - } - } - ], - - "applications": { - "app": { - "type": "...", - "user": "app_user", - "group": "app_group" - } - } - } - ``` - -1. To run several apps side by side, - [configure]({{< relref "/unit/configuration.md" >}}) - them with appropriate user and group names. The following - configuration distinguishes apps based on the request URI, but you can - implement another scheme such as different listeners: - - ```json - { - "listeners": { - "*:80": { /* Or another suitable socket address */ - "pass": "routes" - } - }, - - "routes": [ - { - "match": { - "uri": "/app1/*" /* Arbitrary matching condition */ - }, - - "action": { - "share": "/path/to/static/app1/files/$uri", - /* Router process needs read and execute permissions to serve static content from this directory */ - "fallback": { - "pass": "applications/app1" - } - } - }, - - { - "match": { - "uri": "/app2/*" /* Arbitrary matching condition */ - }, - - "action": { - "share": "/path/to/static/app2/files/$uri", - /* Router process needs read and execute permissions to serve static content from this directory */ - "fallback": { - "pass": "applications/app2" - } - } - } - ], - - "applications": { - "app1": { - "type": "...", - "user": "app_user1", - "group": "app_group1" - }, - - "app2": { - "type": "...", - "user": "app_user2", - "group": "app_group2" - } - } - } - ``` - -{{< call-out "note" >}} -As usual with permissions, different steps may be required if you use -ACLs. -{{< /call-out >}} -App internals
- - - -Unfortunately, quite a few web apps are built in a manner that mixes their -source code, data, and configuration files with static content, which calls -for complex access restrictions. The situation is further aggravated by the -inevitable need for maintenance activities that may leave a footprint of -extra files and directories unrelated to the app's operation. The issue has -several aspects: - -- Storage of code and data at the same locations, which usually happens by -(insufficient) design. You neither want your internal data and code files -to be freely downloadable nor your user-uploaded data to be executable as -code, so configure your routes and apps to prevent both. - -- Exposure of configuration data. Your app-specific settings, **.ini** -or **.htaccess** files, and credentials are best kept hidden from -prying eyes, and your routing configuration should reflect that. - -- Presence of hidden files from versioning, backups by text editors, and -other temporary files. Instead of carving your configuration around -these, it's best to keep your app free of them altogether. - -If these can't be avoided, investigate the inner workings of the app to -prevent exposure, for example: - -```json - { - "routes": { - "app": [ - { - "match": { - "uri": [ - "*.php", - "*.php/*" - ] - /* Handles requests that target PHP scripts to avoid having them served as static files */ - }, - - "action": { - "pass": "applications/app/direct" - } - }, - { - "match": { - "uri": [ - "!/sensitive/*", /* Restricts access to a directory with sensitive data */ - "!/data/*", /* Restricts access to a directory with sensitive data */ - "!/app_config_values.ini", /* Restricts access to a specific file */ - "!*/.*", /* Restricts access to hidden files and directories */ - "!*~" /* Restricts access to temporary files */ - ] - /* Protects files and directories best kept hidden */ - }, - - "action": { - "share": "/path/to/app/static$uri", - /* Serves valid requests with static content | Path to the application's static file directory; use a real path in your configuration */ - - "types": [ - "image/*", - "text/*", - "application/javascript" - ] - /* Limits file types served from the share */ - - "fallback": { - "pass": "applications/app/index" - } - /* Relays all requests not yet served to a catch-all app target */ - } - } - ] - } - } - -``` - -However, this does not replace the need to set up file permissions; use both -[matching rules]({{< relref "/unit/configuration.md#configuration-routes-matching" >}}) -and per-app user -permissions to manage access. For more info and real-life examples, refer -to our app [how-tos]({{< relref "/unit/howto/" >}}). -and the 'File Permissions' callout above. -Unit's process summary
- - - -Unit's processes are detailed [elsewhere](https://www.nginx.com/blog/introducing-nginx-unit/), -but here's a synopsis of the different roles they have: - -{{; by default, **root**. | Runs as a daemon, spawning Unit's non-privileged and app processes; requires numerous system capabilities and privileges for operation. | -| **Controller** | No | Set by `--user` and `--group` options at [build]({{< relref "/unit/howto/source.md#source-config-src" >}}) or [execution]({{< relref "/unit/howto/source.md#source-startup" >}})
; by default, **unit**. | Serves the control API, accepting reconfiguration requests, sanitizing them, and passing them to other processes for implementation. | -| **Discovery** | No | Set by `--user` and `--group` options at [build]({{< relref "/unit/howto/source.md#source-config-src" >}}) or [execution]({{< relref "/unit/howto/source.md#source-startup" >}})
; by default, **unit**. | Discovers the language modules in the module directory at startup, then quits. | -| **Router** | No | Set by `--user` and `--group` options at [build]({{< relref "/unit/howto/source.md#source-config-src" >}}) or [execution]({{< relref "/unit/howto/source.md#source-startup" >}})
; by default, **unit**. | Serves client requests, accepting them, processing them on the spot, passing them to app processes, or proxying them further; requires access to static content paths you configure. | -| **App processes** | No | Set by per-app **user** and **group** [options]({{< relref "/unit/configuration.md#configuration-applications" >}})
; by default, `--user` and `--group` values. | Serve client requests that are routed to apps; require access to paths and namespaces you configure for the app. | -{{
Details
- - - -Unit can maintain two different logs: - -- A general-purpose log that is enabled by default and can be switched to -debug mode for verbosity. - -- An access log that is off by default but can be enabled via the control -API. - -If you enable debug-mode or access logging, rotate these logs with tools -such as `logrotate` to avoid overgrowth. A sample -`logrotate` [configuration](https://man7.org/linux/man-pages/man8/logrotate.8.html#CONFIGURATION_FILE_DIRECTIVES): - -```none -/path/to/unit.log { # Use a real path in your configuration - daily - missingok - rotate 7 - compress - delaycompress - nocreate - notifempty - su root root - postrotate - if [ -f `/path/to/unit.pid` ]; then - /bin/kill -SIGUSR1 `cat /path/to/unit.pid` # Use a real path in your configuration - fi - endscript -} -``` - -To figure out the log and PID file paths: - -```console -$ unitd -h - - ... - --pid FILE set pid filename - default: "/default/path/to/unit.pid" # Build-time setting, can be overridden - - --log FILE set log filename - default: "/default/path/to/unit.log " # Build-time setting, can be overridden - -$ ps ax | grep unitd - - ... unit: main {{< param "unitversionv" >}} [... --pid /path/to/unit.pid --log /path/to/unit.log...] # Make sure to check for runtime overrides -``` - -Another issue is the logs' accessibility. Logs are opened and updated by -the -[main process]({{< relref "/unit/howto/security.md#security-apps" >}}) -that usually runs as **root**. -However, to make them available for a certain consumer, you may need to -enable access for a dedicated user that the consumer runs as. - -Perhaps, the most straightforward way to achieve this is to assign log -ownership to the consumer's account. Suppose you have a log utility running -as **log_user:log_group**: - -```console -# chown log_user:log_group :/path/to/unit.log # If it's overridden, use the runtime setting -``` - -```console -curl -X PUT -d '"/path/to/access.log"' \ - --unix-socket /path/to/control.unit.sock \ - http://localhost/config/access_log -``` - - -```console -# chown log_user:log_group /path/to/access.log # Use a real path in your command> -``` - -If you change the log file ownership, adjust your `logrotate` -settings accordingly: - -```none -/path/to/unit.log { - ... - su log_user log_group - ... -} -``` - -{{< call-out "note" >}} -As usual with permissions, different steps may be required if you use -ACLs. -{{< /call-out >}} - -Enabling njs
- - - -To build Unit with [njs](https://nginx.org/en/docs/njs/) support, -download the `njs` code to the same parent directory as the Unit code. - -**0.8.2** is the latest version of `njs` that Unit supports. -Make sure you are in the correct branch before configuring the binaries. - -```console -$ git clone https://github.com/nginx/njs.git -``` - -```console -$ cd njs -``` - -```console -$ git checkout -b 0.8.2 0.8.2 -``` - -Next, configure and build the `njs` binaries. Make sure to use the -`--no-zlib` and `--no-libxml2` options to avoid -conflicts with Unit's dependencies: - -```console -$ ./configure --no-zlib --no-libxml2 && make # Ensures Unit can link against the resulting library -``` - -Point to the resulting source and build directories when -[configuring]({{< relref "/unit/howto/source.md#source-config-src-njs" >}}) -the Unit code. - ---- -Enabling WebAssembly
- - -{{< tabs name="source-enable-webassembly" >}} -{{% tab name="wasm-wasi-component" %}} - -To build Unit with support for the WebAssembly Component Model, -you need **rust** version 1.76.0+, **cargo** and the developer -package for **clang** as mentioned in the -[Required Software]({{< relref "/unit/howto/source.md#source-prereq-build" >}}) -section. - -Next please refer to -[Configuring Modules - WebAssembly]({{< relref "/unit/howto/source.md#modules-webassembly" >}}) -for further instructions. - -{{% /tab %}} -{{% tab name="unit-wasm" %}} - -{{< call-out "warning" >}} -The **unit-wasm** module is deprecated. We recommend using **wasm-wasi-component** instead, -available in Unit 1.32.0 and later, which supports WebAssembly Components using -standard WASI 0.2 interfaces. -{{< /call-out >}} - -To build Unit with the [WebAssembly](https://webassembly.org) -language module, you need the [Wasmtime](https://wasmtime.dev) runtime. -Download the C API [files](https://github.com/bytecodealliance/wasmtime/releases/) -suitable for your OS and architecture to the same parent directory as the Unit code, -for example: - -```console - $ cd .. -``` - -```console -$ wget -O- https://github.com/bytecodealliance/wasmtime/releases/download/v12.0.0/wasmtime-v12.0.0-x86_64-linux-c-api.tar.xz \ - | tar Jxf - # Unpacks to the current directory -``` - -Point to the resulting **include** and **lib** directories when -[configuring]({{< relref "/unit/howto/source.md#source-modules-webassemble" >}}) -the Unit code. - -To build WebAssembly apps that run on Unit, you need -the -[wasi-sysroot](https://github.com/WebAssembly/wasi-sdk) SDK: - -```console -$ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sysroot-20.0.tar.gz | tar zxf - -``` - -When building the apps, add the following environment variable: - -```console - WASI_SYSROOT=/path/to/wasi-sysroot-dir/ # wasi-sysroot directory -``` - -{{% /tab %}} -{{< /tabs >}} -For language-specific details, run `./configure
The default is **cc**. | -| **--cc-opt=options**, **--ld-opt=options** | Extra options for the C compiler and linker. | -| **--group=name**, **--user=name** | Group name and username to run Unit's non-privileged [processes]({{< relref "/unit/howto/security.md#security-apps" >}}).
The defaults are **--user**'s primary group and **nobody**, respectively. | -| **--debug** | Turns on the [debug log]({{< relref "/unit/troubleshooting.md#troubleshooting-dbg-log" >}}). | -| **--no-ipv6** | Turns off IPv6 support. | -| **--no-unix-sockets** | Turns off UNIX domain sockets support for control and routing. | -| **--openssl** | Turns on OpenSSL support. Make sure OpenSSL (1.0.1+) header files and libraries are in your compiler's path; it can be set with the **--cc-opt** and **--ld-opt** options or the **CFLAGS** and **LDFLAGS** environment variables when running `./configure`.
For details of TLS configuration in Unit, see [configuration-ssl]({{< relref "/unit/certificates#configuration-ssl" >}}). | - -{{
The default is **/usr/local**. | -| **--exec-prefix=EXEC_PREFIX** | Destination directory prefix for the executable directories only.
The default is the **PREFIX** value. | -| **--bindir=BINDIR**, **--sbindir=SBINDIR** | Directory paths for client and server executables.
The defaults are **EXEC_PREFIX/bin** and **EXEC_PREFIX/sbin**. | -| **--includedir=INCLUDEDIR**, **--libdir=LIBDIR** | Directory paths for `libunit` header files and libraries.
The defaults are **PREFIX/include** and **EXEC_PREFIX/lib**. | -| **--modulesdir=MODULESDIR** | Directory path for Unit's language [modules]({{< relref "/unit/howto/modules.md" >}}).
The default is **LIBDIR/unit/modules**. | -| **--datarootdir=DATAROOTDIR**, **--mandir=MANDIR** | Directory path for **unitd(8)** data storage and its subdirectory where the `man` page is installed.
The defaults are **PREFIX/share** and **DATAROOTDIR/man**. | -| **--localstatedir=LOCALSTATEDIR** | Directory path where Unit stores its runtime state, PID file, control socket, and logs.
The default is **PREFIX/var**. | -| **--libstatedir=LIBSTATEDIR** | Directory path where Unit's runtime state (configuration, certificates, other resources) is stored between runs. If you migrate your installation, copy the entire directory.
**Warning:** The directory is sensitive and must be owned by **root** with **700** permissions. Don't change its contents externally; use the config API to ensure integrity.
The default is **LOCALSTATEDIR/run/unit**. | -| **--logdir=LOGDIR**, **--log=LOGFILE** | Directory path and filename for Unit's [log]({{< relref "/unit/troubleshooting.md#troubleshooting-log" >}}).
The defaults are **LOCALSTATEDIR/log/unit** and **LOGDIR/unit.log**. | -| **--runstatedir=RUNSTATEDIR** | Directory path where Unit stores its PID file and control socket.
The default is **LOCALSTATEDIR/run/unit**. | -| **--pid=pathname** | Pathname for the PID file of Unit's `main` [process]({{< relref "/unit/howto/security.md#security-apps" >}}).
The default is **RUNSTATEDIR/unit.pid**. | -| **--control=SOCKET** | [Control API]({{< relref "/unit/controlapi.md#configuration-mgmt" >}}) socket address in IPv4, IPv6, or UNIX domain format:
`$ ./configure --control=127.0.0.1:8080`
`$ ./configure --control=[::1]:8080`
`$ ./configure --control=unix:/path/to/control.unit.sock` (Note the `unix:` prefix).
**Warning:** Avoid exposing an unprotected control socket in public networks. Use [NGINX]({{< relref "/unit/howto/integration.md#nginx-secure-api" >}}) or a different solution such as SSH for security and authentication.
The default is **unix:RUNSTATEDIR/control.unit.sock**, created as **root** with **600** permissions. | -| **--tmpdir=TMPDIR** | Defines the temporary file storage location (used to dump large request bodies). The default value is **/tmp**. | - -{{
The default is **go**. | -| **--go-path=directory** | Custom directory path for Go package installation.
The default is **$GOPATH**. | - -{{
The default is the **java.home** setting. | -| **--jars=directory** | Directory path for Unit's custom **.jar** files.
The default is the Java module path. | -| **--lib-path=directory** | Directory path for the **libjvm.so** library.
The default is based on JDK settings. | -| **--local-repo=directory** | Directory path for the local **.jar** repository.
The default is **$HOME/.m2/repository/**. | -| **--repo=directory** | URL path for the remote Maven repository.
The default is **http://central.maven.org/maven2/**. | -| **--module=basename** | Resulting module's name (**
The default is **java**. | - -{{
By default, the module is installed globally [(recommended)](/unit/installation.md#installation-nodejs-package). | -| **--node=pathname** | Specific Node.js executable pathname, also used in [make]({{< relref "/unit/howto/source.md#source-bld-src-emb" >}}) targets.
The default is **node**. | -| **--npm=pathname** | Specific `npm` executable pathname.
The default is **npm**. | -| **--node-gyp=pathname** | Specific `node-gyp` executable pathname.
The default is **node-gyp**. | - -{{
The default is **perl**. | -| **--module=basename** | Resulting module's name (**
The default is the filename of the `--perl` executable. | - -{{
The default is **php-config**. | -| **--lib-path=directory** | Directory path of the `libphp` library file (**libphp*.so** or **libphp*.a**), usually available with an `--enable-embed` PHP build. | -| **--lib-static** | Links the static `libphp` library (**libphp*.a**) instead of the dynamic one (**libphp*.so**); requires `--lib-path`. | -| **--module=basename** | Resulting module's name (**
The default is `--config`'s filename minus the `-config` suffix; thus, **--config=/path/php7-config** yields **php7.unit.so**. | - -{{
The default is **python-config**. | -| **--lib-path=directory** | Custom directory path of the Python runtime library to use with Unit. | -| **--module=basename** | Resulting module's name (**
The default is `--config`'s filename minus the `-config` suffix; thus, **/path/python3-config** turns into **python3**. | - -{{
The default is the filename of the `--ruby` executable. | -| **--ruby=pathname** | Specific Ruby executable pathname.
The default is **ruby**. | -{{
The default is **wasmtime**. | -| **--include-path=path**| The directory path to the runtime's header files. | -| **--lib-path=path** | The directory path to the runtime's library files. | -| **--rpath=
If specified without a value, assumes the **--lib-path** value. | -{{
`# unitd --control 127.0.0.1:8080`
`# unitd --control [::1]:8080`
`# unitd --control unix:/path/to/control.unit.sock` | -| **--control-mode** | Sets the permission of the UNIX domain control socket. Default: 0600 | -| **--control-user** | Sets the owner of the UNIX domain control socket. | -| **--control-group** | Sets the group of the UNIX domain control socket. | -| **--group name**, **--user name**| Group name and user name used to run Unit's non-privileged [processes]({{< relref "/unit/howto/security.md#security-apps" >}}). | -| **--log pathname** | Pathname for Unit's [log]({{< relref "/unit/troubleshooting.md#troubleshooting-log" >}}). | -| **--modules directory** | Directory path for Unit's language [modules]({{< relref "/unit/howto/modules.md" >}}) (***.unit.so** files). | -| **--pid pathname** | Pathname for the PID file of Unit's **main** [process]({{< relref "/unit/howto/security.md#security-apps" >}}). | -| **--state directory** | Directory path for Unit's state storage. | -| **--tmp directory** | Directory path for Unit's temporary file storage. | -{{
Repo installation script
- - We provide a [script](https://github.com/nginx/unit/tree/master/tools>) - that adds our official repos on the systems we support: - - ```console - wget https://raw.githubusercontent.com/nginx/unit/master/tools/setup-unit && chmod +x setup-unit - ``` - - Run the following command as root: - - ```console - ./setup-unit repo-config - ``` - - Use it at your discretion; explicit steps are provided below - for each distribution. -Working with multiple Node.js versions
- -To use Unit with multiple Node.js versions side by side, we recommend -[Node Version Manager](https://github.com/nvm-sh/nvm). - -```console -$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/x.y.z/install.sh | bash # Replace x.y.z with the nvm version -``` - -Install the versions you need and select the one you want to use with Unit: - -```console -$ nvm install 18 -``` - -```console -$ nvm install 16 -``` - -```console -$ nvm use 18 - Now using node v18.12.1 (npm v8.19.2) # Note the version numbers -``` - -Having selected the specific version, install the `node-gyp` module: - -```console -$ npm install -g node-gyp -``` - -Next, clone the Unit source code to build a `unit-http` module for the selected -Node.js version: - -```console -$ git clone https://github.com/nginx/unit -``` - -```console -$ cd unit -``` - -```console -$ pwd - /home/user/unit # Note the path to the source code -``` - -```console -$ ./configure -``` - -```console -$ ./configure nodejs - - configuring nodejs module - checking for node ... found - + node version v18.12.1 # Should be the version selected with nvm - checking for npm ... found - + npm version `8.19.2 # Should be the version selected with npm - checking for node-gyp ... found - + node-gyp version v9.3.0 -``` - -Point to Unit's header files and libraries in the source code directory -to build the module: - -```console -$ CPPFLAGS="-I/home/user/unit/include/" LDFLAGS="-L/home/user/unit/lib/" \ - make node-install -``` - -```console -$ npm list -g - - /home/vagrant/.nvm/versions/node/v18.12.1/lib - ├── corepack@0.14.2 - ├── node-gyp@9.3.0 - ├── npm@8.19.2 - └── unit-http@1.29.0 -``` - -That's all; use the newly built module to run your -[Node.js apps]({{< relref "/unit/configuration.md#configuration-nodejs" >}}) -on Unit as usual. -Customizing language versions in Docker images
- -To build a custom language version image, clone and rebuild the sources locally -with Docker installed: - -```console -$ make build-Image tags for pre-1.29.1 Unit versions
- -Before Unit 1.29.1 was released, our Docker images were available -from the official [NGINX repository](https://hub.docker.com/r/nginx/unit/) -on Docker Hub. - -Images with pre-1.22.0 Unit versions
- -Before Unit 1.22.0 was released, the following tagging scheme was used: - -{{**cert.pem** to **/certificates/cert**. | -| **.json** | [Configuration snippets]({{< relref "/unit/controlapi.md#configuration-mgmt" >}}), uploaded to the **/config** section of Unit's configuration. | -| **.sh** | Shell scripts, run after the **.pem** and **.json** files are uploaded. Use shebang in your scripts to specify a custom shell;
must be executable. | - -{{
To receive all OSS release announcements from NGINX, join the general mailing list [here](https://mailman.nginx.org/mailman/listinfo/nginx-announce). | -| **Security alerts** | Please report security issues to [security-alert@nginx.org](mailto:security-alert@nginx.org), specifically mentioning NGINX Unit in the subject and following the [CVSS v3.1](https://www.first.org/cvss/v3.1/specification-document) specification. | - -{{