diff --git a/source/conf.py b/source/conf.py index 8abcd5ae..c82d12f7 100644 --- a/source/conf.py +++ b/source/conf.py @@ -5,8 +5,8 @@ project = 'NGINX Unit' author = 'NGINX, Inc.' copyright = '2017-2024' -version = '1.31.1' -release_date = 'Oct 19, 2023' +version = '1.32.0' +release_date = 'Feb 27, 2024' release = version needs_sphinx = '6.2' @@ -39,3 +39,4 @@ sys.path.append(os.path.abspath('./exts')) extensions = ['inline', 'nxt', 'subs', 'github'] +smartquotes_action = 'qe' diff --git a/source/configuration.rst b/source/configuration.rst index d69192df..98670d6f 100644 --- a/source/configuration.rst +++ b/source/configuration.rst @@ -1,6 +1,6 @@ - .. meta:: +.. meta:: :og:description: Create and maintain a working configuration using - listeners, routes, apps, and upstreams. + listeners, routes, apps, and upstreams. .. include:: include/replace.rst @@ -34,9 +34,9 @@ the object's name can be: ***:80** - On Linux-based systems, - `abstract UNIX sockets `__ - can be used as well: - **unix:@abstract_socket**. + `abstract UNIX sockets `__ + can be used as well: + **unix:@abstract_socket**. .. note:: @@ -1783,6 +1783,10 @@ There's a number of built-in variables available: * - **remote_addr** - Remote IP address of the request. + * - **request_id** + - Contains a string generated with random data. Can be used as a unique + request identifier. + * - **request_line** - Entire `request line @@ -1840,6 +1844,7 @@ There's a number of built-in variables available: `path `__. + These variables can be used with: - **pass** in @@ -2589,7 +2594,7 @@ are allowed by a :ref:`regex pattern `. If no MIME types match the request, a 403 "Forbidden" response is -returned. You can pair that behaviour with a +returned. You can pair that behavior with a :ref:`fallback ` option that will be called when a 40x response would be returned. @@ -5018,45 +5023,45 @@ Besides the you have: .. list-table:: - :header-rows: 1 + :header-rows: 1 * - Option - Description * - **script** (required) - String; - rack script pathname, - including the **.ru** extension, - for instance: - **/www/rubyapp/script.ru**. + rack script pathname, + including the **.ru** extension, + for instance: + **/www/rubyapp/script.ru**. * - **hooks** - String; - pathname of the **.rb** file - setting the event hooks - invoked during the app's lifecycle. + pathname of the **.rb** file + setting the event hooks + invoked during the app's lifecycle. * - **threads** - Integer; - number of worker threads - per :ref:`app process `. - When started, - each app process creates this number of threads - to handle requests. + number of worker threads + per :ref:`app process `. + When started, + each app process creates this number of threads + to handle requests. - The default is **1**. + The default is **1**. Example: .. code-block:: json { - "type": "ruby", - "processes": 5, - "user": "www", - "group": "www", - "script": "/www/cms/config.ru", - "hooks": "hooks.rb" + "type": "ruby", + "processes": 5, + "user": "www", + "group": "www", + "script": "/www/cms/config.ru", + "hooks": "hooks.rb" } The **hooks** script @@ -5080,16 +5085,16 @@ for example: # Runs once at app load. on_worker_boot do - File.write("./worker_boot.#{Process.pid}", "worker boot") + File.write("./worker_boot.#{Process.pid}", "worker boot") end # Runs at worker process boot. on_thread_boot do - @mutex.synchronize do - # Avoids a race condition that may crash the app. - File.write("./thread_boot.#{Process.pid}.#{Thread.current.object_id}", - "thread boot") - end + @mutex.synchronize do + # Avoids a race condition that may crash the app. + File.write("./thread_boot.#{Process.pid}.#{Thread.current.object_id}", + "thread boot") + end end # Runs at worker thread boot. @@ -5128,194 +5133,224 @@ to your app. WebAssembly =========== -First, make sure to install Unit along with the -:ref:`WebAssembly language module `. - -Besides the -:ref:`common options `, -you have: - -.. list-table:: - :header-rows: 1 - - * - Option - - Description - - * - **module** (required) - - String; - WebAssembly module pathname, - including the **.wasm** extension, - for instance: - **/www/wasmapp/module.wasm**. - - * - **request_handler** (required) - - String; - name of the request handler function. - If you use Unit with the official :program:`unit-wasm` - :ref:`package `, - the value is language specific; - see the `SDK `__ - documentation for details. - Otherwise, use the name of your custom implementation. - - The runtime calls this handler, - providing the address - of the shared memory block - used to pass data in and out the app. - - * - **malloc_handler** (required) - - String; - name of the memory allocator function. - If you use Unit with the official :program:`unit-wasm` - :ref:`package `, - the value is language specific; - see the `SDK `__ - documentation for details. - Otherwise, use the name of your custom implementation. - - The runtime calls this handler at language module startup - to allocate the shared memory block - used to pass data in and out the app. - - * - **free_handler** (required) - - String; - name of the memory deallocator function. - If you use Unit with the official :program:`unit-wasm` - :ref:`package `, - the value is language specific; - see the `SDK `__ - documentation for details. - Otherwise, use the name of your custom implementation. - - The runtime calls this handler at language module shutdown - to free the shared memory block - used to pass data in and out the app. - - * - **access** - - Object; - its only array member, **filesystem**, lists directories - to which the application has access: - - .. code-block:: json +.. tabs:: + :prefix: unit-wasm + :toc: - "access": { - "filesystem": [ - "/tmp/", - "/var/tmp/" - ] - } + .. tab:: wasm-wasi-component - * - **module_init_handler**, + First, make sure to install Unit along with the + :ref:`WebAssembly language module `. - - String; - name of the module initilization function. - If you use Unit with the official :program:`unit-wasm` - :ref:`package `, - the value is language specific; - see the `SDK `__ - documentation for details. - Otherwise, use the name of your custom implementation. + Besides the + :ref:`common options `, + you have: - It is invoked by the WebAssembly language module - at language module startup, - after the WebAssembly module was initialised. + .. list-table:: + :header-rows: 1 - * - **module_end_handler** + * - Option + - Description + * - **component** (required) + - String; WebAssembly component pathname, including the **.wasm** + extension, for instance: "/var/www/wasm/component.wasm" + * - **access** + - Object; its only array member, **filesystem**, lists + directories to which the application has access: + + .. code-block:: json + + "access": { + "filesystem": [ + "/tmp/", + "/var/tmp/" + ] + } - - String; - name of the module finalization function. - If you use Unit with the official :program:`unit-wasm` - :ref:`package `, - the value is language specific; - see the `SDK `__ - documentation for details. - Otherwise, use the name of your custom implementation. + Example: - It is invoked by the WebAssembly language module - at language module shutdown. + .. code-block:: json - * - **request_init_handler** + { + "listeners": { + "127.0.0.1:8080": { + "pass": "applications/wasm" + } + }, + "applications": { + "wasm": { + "type": "wasm-wasi-component", + "component": "/var/www/app/component.wasm", + "access": { + "filesystem": [ + "/tmp/", + "/var/tmp/" + ] + } + } + } + } - - String; - name of the request initialization function. - If you use Unit with the official :program:`unit-wasm` - :ref:`package `, - the value is language specific; - see the `SDK `__ - documentation for details. - Otherwise, use the name of your custom implementation. + .. note:: + A good, first Rust-based project is available at + `sunfishcode/hello-wasi-http `__. + It also includes all the important steps to get started with WebAssembly, WASI, and Rust. - It is invoked by the WebAssembly language module - at the start of each request. + .. tab:: unit-wasm - * - **request_end_handler** + .. warning:: + The `unit-wasm` module is deprecated. + We recommend using `wasm-wasi-component` instead, which supports + WebAssembly Components using standard WASI 0.2 interfaces. + The `wasm-wasi-component` module is available in Unit 1.32 and later. - - String; - name of the request finalization function. - If you use Unit with the official :program:`unit-wasm` - :ref:`package `, - the value is language specific; - see the `SDK `__ - documentation for details. - Otherwise, use the name of your custom implementation. + First, make sure to install Unit along with the + :ref:`WebAssembly language module `. - It is invoked by the WebAssembly language module - at the end of each request, - when the headers and the request body were received. + Besides the + :ref:`common options `, + you have: - * - **response_end_handler** + .. list-table:: + :header-rows: 1 - - String; - name of the response finalization function. - If you use Unit with the official :program:`unit-wasm` - :ref:`package `, - the value is language specific; - see the `SDK `__ - 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. + * - Option + - Description + * - **module** (required) + - String; WebAssembly module pathname, including the **.wasm** extension, + for instance: **applications/wasmapp/module.wasm**. + * - **request_handler** (required) + - String; name of the request handler function. If you use Unit + with the official :program:`unit-wasm` :ref:`package `, + the value is language specific; see the + `SDK `__ documentation for details. + Otherwise, use the name of your custom implementation. + + The runtime calls this handler, providing the address of the + shared memory block used to pass data in and out the app. + * - **malloc_handler** (required) + - String; name of the memory allocator function. See note above regarding + language-specific handlers in the official `unit-wasm` package. + + The runtime calls this handler at language module startup to allocate + the shared memory block used to pass data in and out the app. + * - **free_handler** (required) + - String; name of the memory deallocator function. See note above regarding + language-specific handlers in the official `unit-wasm` package. + + The runtime calls this handler at language module shutdown to free + the shared memory block used to pass data in and out the app. + * - **access** + - Object; its only array member, **filesystem**, lists directories + the application can access: + + .. code-block:: json + + "access": { + "filesystem": [ + "/tmp/", + "/var/tmp/" + ] + } -Example: + * - **module_init_handler**, + - String; + name of the module initilization function. + If you use Unit with the official :program:`unit-wasm` + :ref:`package `, + the value is language specific; + see the `SDK `__ + 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 :program:`unit-wasm` + :ref:`package `, + the value is language specific; + see the `SDK `__ + 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 :program:`unit-wasm` + :ref:`package `, + the value is language specific; + see the `SDK `__ + 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 :program:`unit-wasm` + :ref:`package `, + the value is language specific; + see the `SDK `__ + 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 :program:`unit-wasm` + :ref:`package `, + the value is language specific; + see the `SDK `__ + documentation for details. + Otherwise, use the name of your custom implementation. -.. code-block:: json + It is invoked by the WebAssembly language module + at the end of each response, + when the headers and the response body were sent. - { - "type": "wasm", - "module": "/www/webassembly/unitapp.wasm", - "request_handler": "my_custom_request_handler", - "malloc_handler": "my_custom_malloc_handler", - "free_handler": "my_custom_free_handler", - "access": { - "filesystem": [ - "/tmp/", - "/var/tmp/" - ] - }, + Example: - "module_init_handler": "my_custom_module_init_handler", - "module_end_handler": "my_custom_module_end_handler", - "request_init_handler": "my_custom_request_init_handler", - "request_end_handler": "my_custom_request_end_handler", - "response_end_handler": "my_custom_response_end_handler" - } + .. code-block:: json -Use these handlers -to add custom runtime logic -to your app; -for a detailed discussion of their usage and requirements, -see the -`SDK `__ -source code and documentation. + { + "type": "wasm", + "module": "/www/webassembly/unitapp.wasm", + "request_handler": "my_custom_request_handler", + "malloc_handler": "my_custom_malloc_handler", + "free_handler": "my_custom_free_handler", + "access": { + "filesystem": [ + "/tmp/", + "/var/tmp/" + ] + }, + "module_init_handler": "my_custom_module_init_handler", + "module_end_handler": "my_custom_module_end_handler", + "request_init_handler": "my_custom_request_init_handler", + "request_end_handler": "my_custom_request_end_handler", + "response_end_handler": "my_custom_response_end_handler" + } -.. note:: + Use these handlers to add custom runtime logic to your app; for a detailed + discussion of their usage and requirements, see the + `SDK `__ source code and documentation. - For WASM-based examples, - see our - :ref:`Rust and C samples `. + .. note:: + For WASM-based examples, see our :ref:`Rust and C samples `. .. _configuration-stngs: @@ -5521,6 +5556,8 @@ Example of a CLF line: Custom log formatting ===================== +.. _custom-log-format: + The **access_log** option can be also set to an object to customize both the log path @@ -5575,3 +5612,64 @@ to define the log format: "format": "`${host + ': ' + uri}`" } } + + +====================== +Conditional access log +====================== + +.. _conditional-access-log: + +The **access_log** can be dynamically turned on and off by using the **if** option: + +.. list-table:: + :header-rows: 1 + + * - Option + - Description + + * - **if** + - if the value is empty, 0, false, null, or undefined, + the logs will not be recorded. + +This feature lets users set conditions to determine whether access logs are +recorded. The **if** option supports a string and JavaScript code. +If its value is empty, 0, false, null, or undefined, the logs will not be +recorded. And the '!' as a prefix inverses the condition. + +Example without NJS: + +.. code-block:: json + + { + "access_log": { + "if": "$cookie_session", + "path": "..." + } + } + +All requests using a session cookie named **session** will be logged. + +We can add ! to inverse the condition. + +.. code-block:: json + + { + "access_log": { + "if": "!$cookie_session", + "path": "..." + } + } + +Now, all requests without a session cookie will be logged. + +Example with NJS and the use of a template literal: + +.. code-block:: json + + { + "access_log": { + "if": "`${uri == '/health' ? false : true}`", + "path": "..." + } + } \ No newline at end of file diff --git a/source/howto/modules.rst b/source/howto/modules.rst index 8145c565..ba8e36a8 100644 --- a/source/howto/modules.rst +++ b/source/howto/modules.rst @@ -34,6 +34,13 @@ In Node.js, Unit is supported by an :program:`npm`-hosted `package otherwise, :ref:`build ` it for your version of Node.js using Unit's sources. +For WebAssembly, Unit delegates bytecode execution to the +`Wasmtime `_ +runtime that is installed with the +:ref:`language module ` +module or during +a :ref:`source build `. + .. _modules-emb: ************************* diff --git a/source/howto/samples.rst b/source/howto/samples.rst index ce1ef5dd..e6b3a7d7 100644 --- a/source/howto/samples.rst +++ b/source/howto/samples.rst @@ -548,134 +548,234 @@ Try this sample out with the Dockerfile :download:`here .. _sample-wasm: -*********** -WebAssembly -*********** +****************** +WebAssembly (Wasm) +****************** -Instead of dealing with bytecode, -let's build a Unit-capable Rust app -and compile it into WebAssembly. +.. tabs:: + :prefix: web-assembly + :toc: -.. note:: + .. tab:: wasm-wasi-component - Currently, WebAssembly support is provided as a Technology Preview. - This includes support - for compiling Rust and C code into Unit-compatible WebAssembly, - using our SDK in the form of the the :program:`libunit-wasm` library. - For details, see our :program:`unit-wasm` - `repository `__ - on GitHub. + Instead of dealing with bytecode, + let's build a Unit-capable Rust app + and compile it into a WebAssembly (Wasm) component. -First, install the WebAssembly-specific Rust tooling: + Make sure you have the Rust toolchain (cargo, rustc, etc.) installed. + We recommend using `rustup `__ to get started. -.. code-block:: console + This example was built with **rustc** version 1.76.0. - $ rustup target add wasm32-wasi + Start by adding the wasm32-wasi support as a compilation target for **rustc** -Next, initialize a new Rust project with a library target -(apps are loaded by Unit's WebAssembly module as dynamic libraries). -Then, add our **unit-wasm** crate -to enable the :program:`libunit-wasm` library: + .. code-block:: console -.. code-block:: console + $ rustup target add wasm32-wasi - $ cargo init --lib wasm_on_unit - $ cd wasm_on_unit/ - $ cargo add unit-wasm + Next, install cargo component. This simplifies building a WebAssembly + component from Rust Code, making it the recommended method. -Append the following to **Cargo.toml**: + .. code-block:: console -.. code-block:: toml + $ cargo install cargo-component - [lib] - crate-type = ["cdylib"] + Currently, the fastest way to get started with WebAssembly components using WASI + 0.2 wasi-http API is the **hello-wasi-http** demo application by + Dan Gohman. Clone the repository and build the component running + the following command: -Save some sample code from our :program:`unit-wasm` repo as **src/lib.rs**: + .. code-block:: console -.. code-block:: console + $ git clone https://github.com/sunfishcode/hello-wasi-http + $ cd hello-wasi-http + $ cargo component build - wget -O src/lib.rs https://raw.githubusercontent.com/nginx/unit-wasm/main/examples/rust/echo-request/src/lib.rs + The output of the build command should be similar to this: -Build the Rust module with WebAssembly as the target: + .. code-block:: console -.. code-block:: console + $ cargo component build + Compiling hello-wasi-http v0.0.0 (/home/unit-build/hello-wasi-http) + Finished dev [unoptimized + debuginfo] target(s) in 0.17s + Creating component /home/unit-build/hello-wasi-http/target/wasm32-wasi/debug/hello_wasi_http.wasm + $ - $ cargo build --target wasm32-wasi + This creates a WebAssembly component you can deploy on Unit using the + following Unit configuration. Make sure you point the **component** path + to the WebAssembly component you have just created. Create a + **config.json** file: -This yields the -**target/wasm32-wasi/debug/wasm_on_unit.wasm** file -(path may depend on other options). + .. code-block:: json -Upload the :ref:`app config ` to Unit and test it: + { + "listeners": { + "127.0.0.1:8080": { + "pass": "applications/wasm" + } + }, + "applications": { + "wasm": { + "type": "wasm-wasi-component", + "component": "/home/unit-build/hello-wasi-http/target/wasm32-wasi/debug/hello_wasi_http.wasm" + } + } + } -.. code-block:: console + Apply the Unit configuration by using the CLI: - # curl -X PUT --data-binary '{ - "listeners": { - "127.0.0.1:8080": { - "pass": "applications/wasm" - } - }, - - "applications": { - "wasm": { - "type": "wasm", - "module": ":nxt_ph:`/path/to/wasm_on_unit `/target/wasm32-wasi/debug/wasm_on_unit.wasm", - "request_handler": "uwr_request_handler", - "malloc_handler": "luw_malloc_handler", - "free_handler": "luw_free_handler", - "module_init_handler": "uwr_module_init_handler", - "module_end_handler": "uwr_module_end_handler" - } - } - }' --unix-socket :nxt_ph:`/path/to/control.unit.sock ` http://localhost/config/ + .. code-block:: console - $ curl http://localhost:8080 + $ unitc /config < config.json - * Welcome to WebAssembly in Rust on Unit! [libunit-wasm (0.1.0/0x00010000)] * + Or by sending it manually to Units control API: - [Request Info] - REQUEST_PATH = / - METHOD = GET - VERSION = HTTP/1.1 - QUERY = - REMOTE = 127.0.0.1 - LOCAL_ADDR = 127.0.0.1 - LOCAL_PORT = 8080 - SERVER_NAME = localhost + .. code-block:: console -Further, -you can research the Unit-based WebAssembly app internals in more depth. -Clone the :program:`unit-wasm` repository -and build the examples in C and Rust -(may require :program:`clang` and :program:`lld`): + $ cat config.json | curl -X PUT -d @- --unix-socket /path/to/control.unit.sock http://localhost/config/ -.. code-block:: console + Congratulations! You have created your very first WebAssembly component + on Unit! Send a GET Request to your configured listener. - $ git clone https://github.com/nginx/unit-wasm/ - $ cd unit-wasm - $ make help # Explore your options first - $ make WASI_SYSROOT=:nxt_ph:`/path/to/wasi-sysroot/ ` examples # C examples - $ make WASI_SYSROOT=:nxt_ph:`/path/to/wasi-sysroot/ ` examples-rust # Rust examples + .. code-block:: console -.. note:: + $ curl http://localhost:8080 + + .. tab:: unit-wasm + + .. warning:: + Unit 1.32.0 and later support the WebAssembly component + Model and WASI 0.2 APIs. + We recommend to use the new implementation. + + Instead of dealing with bytecode, let's build a Unit-capable + Rust app and compile it into WebAssembly. + + .. note:: + + Currently, WebAssembly support is provided as a Technology Preview. + This includes support + for compiling Rust and C code into Unit-compatible WebAssembly, + using our SDK in the form of the the :program:`libunit-wasm` library. + For details, see our :program:`unit-wasm` + `repository `__ + on GitHub. + + First, install the WebAssembly-specific Rust tooling: + + .. code-block:: console + + $ rustup target add wasm32-wasi + + Next, initialize a new Rust project with a library target + (apps are loaded by Unit's WebAssembly module as dynamic libraries). + Then, add our **unit-wasm** crate + to enable the :program:`libunit-wasm` library: + + .. code-block:: console + + $ cargo init --lib wasm_on_unit + $ cd wasm_on_unit/ + $ cargo add unit-wasm + + Append the following to **Cargo.toml**: + + .. code-block:: toml + + [lib] + crate-type = ["cdylib"] + + Save some sample code from our :program:`unit-wasm` repo as **src/lib.rs**: + + .. code-block:: console + + wget -O src/lib.rs https://raw.githubusercontent.com/nginx/unit-wasm/main/examples/rust/echo-request/src/lib.rs + + Build the Rust module with WebAssembly as the target: + + .. code-block:: console + + $ cargo build --target wasm32-wasi + + This yields the + **target/wasm32-wasi/debug/wasm_on_unit.wasm** file + (path may depend on other options). + + Upload the :ref:`app config ` to Unit and test it: + + .. code-block:: console + + # curl -X PUT --data-binary '{ + "listeners": { + "127.0.0.1:8080": { + "pass": "applications/wasm" + } + }, + + "applications": { + "wasm": { + "type": "wasm", + "module": ":nxt_ph:`/path/to/wasm_on_unit `/target/wasm32-wasi/debug/wasm_on_unit.wasm", + "request_handler": "uwr_request_handler", + "malloc_handler": "luw_malloc_handler", + "free_handler": "luw_free_handler", + "module_init_handler": "uwr_module_init_handler", + "module_end_handler": "uwr_module_end_handler" + } + } + }' --unix-socket :nxt_ph:`/path/to/control.unit.sock ` http://localhost/config/ + + $ curl http://localhost:8080 + + * Welcome to WebAssembly in Rust on Unit! [libunit-wasm (0.3.0/0x00030000)] * + + [Request Info] + REQUEST_PATH = / + METHOD = GET + VERSION = HTTP/1.1 + QUERY = + REMOTE = 127.0.0.1 + LOCAL_ADDR = 127.0.0.1 + LOCAL_PORT = 8080 + SERVER_NAME = localhost + + [Request Headers] + Host = localhost:8080 + User-Agent = curl/8.2.1 + Accept = */* + + Further, + you can research the Unit-based WebAssembly app internals in more depth. + Clone the :program:`unit-wasm` repository + and build the examples in C and Rust + (may require :program:`clang` and :program:`lld`): + + .. code-block:: console + + $ git clone https://github.com/nginx/unit-wasm/ + $ cd unit-wasm + $ make help # Explore your options first + $ make WASI_SYSROOT=:nxt_ph:`/path/to/wasi-sysroot/ ` examples # C examples + $ make WASI_SYSROOT=:nxt_ph:`/path/to/wasi-sysroot/ ` examples-rust # Rust examples + + .. note:: - If the above commands fail like this: + If the above commands fail like this: - .. code-block:: console + .. code-block:: console - wasm-ld: error: cannot open .../lib/wasi/libclang_rt.builtins-wasm32.a: No such file or directory - clang: error: linker command failed with exit code 1 (use -v to see invocation) + wasm-ld: error: cannot open .../lib/wasi/libclang_rt.builtins-wasm32.a: No such file or directory + clang: error: linker command failed with exit code 1 (use -v to see invocation) - Download and install the library to :program:`clang`'s run-time dependency directory: + Download and install the library to :program:`clang`'s run-time dependency directory: - .. code-block:: console + .. code-block:: console - $ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz \ - | tar zxf - # Unpacks to lib/wasi/ in the current directory - $ clang -print-runtime-dir # Double-check the run-time directory, which is OS-dependent + $ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz \ + | tar zxf - # Unpacks to lib/wasi/ in the current directory + $ clang -print-runtime-dir # Double-check the run-time directory, which is OS-dependent - :nxt_ph:`/path/to/runtime/dir `/linux + :nxt_ph:`/path/to/runtime/dir `/linux - # mkdir :nxt_ph:`/path/to/runtime/dir `/wasi # Note the last part of the pathname - # cp :nxt_hint:`lib/wasi/ `libclang_rt.builtins-wasm32.a :nxt_ph:`/path/to/runtime/dir `/wasi/ + # mkdir :nxt_ph:`/path/to/runtime/dir `/wasi # Note the last part of the pathname + # cp :nxt_hint:`lib/wasi/ `libclang_rt.builtins-wasm32.a :nxt_ph:`/path/to/runtime/dir `/wasi/ diff --git a/source/howto/source.rst b/source/howto/source.rst index ded8f613..124f292f 100644 --- a/source/howto/source.rst +++ b/source/howto/source.rst @@ -147,39 +147,62 @@ revision numbers, respectively); omit the packages you won't use. .. nxt_details:: Enabling WebAssembly :hash: source-wasm - To build Unit with the `WebAssembly `__ - language module, - you need the - `Wasmtime `__ - runtime. - Download it C API - `files `__ - suitable for your OS and architecture - to the same parent directory - as the Unit code, - for example: + .. tabs:: + :prefix: source-enable-webassembly + :toc: - .. code-block:: console + .. tab:: wasm-wasi-component - $ cd .. - $ 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 + 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 + :ref:`Required Software Section `. - Point to the resulting **include** and **lib** directories when - :ref:`configuring ` the Unit code. + Next please refer to + :ref:`Configuring Modules - WebAssembly ` for + further instructions. - To build WebAssembly apps that run on Unit, you will also need - the `wasi-sysroot `__ SDK: + .. tab:: unit-wasm - .. code-block:: console + .. 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. - $ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sysroot-20.0.tar.gz | tar zxf - + To build Unit with the `WebAssembly `__ + language module, + you need the + `Wasmtime `__ + runtime. + Download the C API + `files `__ + suitable for your OS and architecture + to the same parent directory + as the Unit code, + for example: - When building the apps, add the following environment variable: + .. code-block:: console - .. code-block:: console + $ cd .. + $ 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 + :ref:`configuring ` the Unit code. + + To build WebAssembly apps that run on Unit, you need + the `wasi-sysroot `__ SDK: + + .. code-block:: console - WASI_SYSROOT=:nxt_ph:`/path/to/wasi-sysroot-dir/ ` + $ 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: + + .. code-block:: console + + WASI_SYSROOT=:nxt_ph:`/path/to/wasi-sysroot-dir/ ` .. _source-config-src: @@ -726,6 +749,22 @@ and place module-specific instructions in the **Makefile**. .. tab:: WebAssembly + .. _modules-webassembly: + + When you run :program:./configure wasm-wasi-component, + the script configures a module to support running WebAssembly + components on Unit. + + The module doesn't accept any extra configuration parameters. + The module's basename is wasm-wasi-component. + + .. tab:: Unit-Wasm + + .. warning:: + Unit 1.32.0 and later support the WebAssembly Component Model and WASI + 0.2 APIs. + We recommend using the new implementation. + When you run :program:`./configure wasm`, the script configures a module to support running WebAssembly applications on Unit. Available command options: diff --git a/source/installation.rst b/source/installation.rst index 71f636b8..ad7012a7 100644 --- a/source/installation.rst +++ b/source/installation.rst @@ -63,6 +63,7 @@ App languages and platforms that Unit can run - Perl |_| 5.12 or later - Python |_| 2.6, 2.7, 3 - Ruby |_| 2.0 or later +- WebAssembly Components WASI |_| 0.2 Optional dependencies: @@ -76,6 +77,8 @@ Optional dependencies: `njs `__ scripting language +- Wasmtime for WebAssembly Support + .. _installation-precomp-pkgs: @@ -127,8 +130,8 @@ they're available for: The packages include core executables, developer files, and support for individual languages. -We also maintain a Homebrew :ref:`tap ` for macOS users -and a :ref:`module ` for Node.js +We also maintain a Homebrew :ref:`tap ` for +macOS users and a :ref:`module ` for Node.js at the `npm `_ registry. .. note:: diff --git a/source/news.rst b/source/news.rst index 72bdf79a..3162fc61 100644 --- a/source/news.rst +++ b/source/news.rst @@ -5,6 +5,7 @@ News .. toctree:: :hidden: + 2024 2023 2022 2021 @@ -21,6 +22,8 @@ Most recent updates (to get them automatically, subscribe to our `RSS feed You can also browse our archives: +- :doc:`news/2024/index` + - :doc:`news/2023/index` - :doc:`news/2022/index` diff --git a/source/news/2024/index.rst b/source/news/2024/index.rst new file mode 100644 index 00000000..c2f06546 --- /dev/null +++ b/source/news/2024/index.rst @@ -0,0 +1,13 @@ +############ +News of 2024 +############ + +News archive for the year 2024. + +.. nxt_news_entry:: + :author: Unit Team + :description: Version 1.32.0 Adds Support for WebAssembly Components + :email: unit-owner@nginx.org + :title: Unit 1.32.0 Released + :url: news/2024/unit-1.32.0-released + :date: 2024-02-27 \ No newline at end of file diff --git a/source/news/2024/unit-1.32.0-released.rst b/source/news/2024/unit-1.32.0-released.rst new file mode 100644 index 00000000..523358a8 --- /dev/null +++ b/source/news/2024/unit-1.32.0-released.rst @@ -0,0 +1,286 @@ +:orphan: + +#################### +Unit 1.32.0 Released +#################### + + +Unit 1.32.0 comes with a new language module for WebAssembly that supports +the WASI 0.2 HTTP world so that WebAssembly Components implementing this +interface can be hosted on Unit. + +This new language module improves upon the existing WebAssembly support. We +recommend all users to use this new implementation for WebAssembly. We consider +the old **unit-wasm** module deprecated now. + +Additionally, we are adding the following features: + +- Enhanced the :doc:`NJS (NGINX JavaScript) experience <../../scripting>` by making all Unit variables + accessible from JavaScript + +- Added support for + :ref:`conditional access logging `, to help + you filter the requests that are logged + +- Added support for changing Unit's control socket permissions + +- Added a :ref:`new variable `, **request_id** + +...and much more! Keep reading to learn more about what changed since 1.31.1. + +************************************************************************ +WebAssembly: Support for Wasm components and the WASI 0.2 API +************************************************************************ + +Since the release of Unit 1.31.0 in August 2023 and the announcement of our +technology preview for WebAssembly, a lot has changed an happened in the +WebAssembly ecosystem. + +So we evolved and with 1.32.0, we are happy to announce the support for the +WebAssembly Component Model using the WASI 0.2 APIs. This opens the +possibilities to run Wasm Components compatible with the WASI 0.2 APIs on Unit +without having a need to rebuild them. This is also the first Language Module +for Unit that was driven by the Community. Special thanks to Alex Crichton +for the contribution! + +We are preparing a blog post where we will dive deeper into the details of the +new WebAssembly language module. Stay tuned! + +******************************************************************* +Enhanced scripting support - Use Unit-variables in NGINX JavaScript +******************************************************************* + +Using JavaScript in Unit's configuration unlocks almost endless opportunities. +A simple Unit configuration can be used to decide where a request should be +routed or rewritten to by creating the values for **pass** and **rewrite** +dynamically inside a JavaScript function. + +Previously JavaScript modules had access to a +:doc:`limited set of objects and scalars <../../scripting>`. Now JavaScript has +access to all of :ref:`Unit's variables ` through +the vars object. + +In the following sample configuration, we set the **Cache-Control** header +based on the HTTP method. We do this by accessing the method variable as +**vars.method**. When the method starts with a "P" (POST, PUT, PATCH), +we do not want to cache the response. For all other methods we set a **max-age** +of 3600 seconds. + +.. code-block:: json + + { + "action": { + "pass": "applications/my_app", + "response_headers": { + "Cache-Control": "`${vars.method.startsWith('P') ? 'no-cache' : 'max-age=3600'}`" + } + } + } + + +.. _conditional-access-logging-news: +************************** +Conditional access logging +************************** + +Access logs are a great way to monitor the traffic sent to Unit. +However, you might find that certain requests, such as regular +health checks and automated UI tests, aren't ones you want +cluttering up your logs. While these checks are crucial for monitoring +the health of your services or web applications, they can significantly +increase the volume of data in your access logs, leading to unnecessary noise. + +With conditional access logging, you can define rules to decide if a request +should be logged or not. + +.. code-block:: json + + { + "access_log": { + "if": "`${uri == '/health' ? false : true}`", + "path": "/var/log/unit/access.log", + "format": "`${host + ': ' + uri}`" + } + } + +In this example we don't want to log any health checks sent to Unit. +As shown in our example, to get the maximum out of the newly added **if** +option, you can combine it with our JavaScript scripting feature, but this +is not a must. + +The **if** option also supports simple string validation to check if a value +is present in a request or not. + +.. code-block:: json + + { + "access_log": { + "if": "$cookie_session", + "path": "…" + } + } + +In this example Unit will check the existence of a Cookie named session +and only log requests when it exists. + +**************** +CLI enhancements +**************** + +The **unitc** command line tool is a convenient way of applying and editing Unit +configuration without constructing lengthy **curl(1)** commands or knowing where +the control socket is located. Unit 1.32.0 includes two useful enhancements to +**unitc** that are included in the official packages. + +A Docker container ID can now be specified as the configuration target. +To access the configuration of a local Unit container, use the **docker://** +scheme to specify the container ID or name. + +It is now also possible to convert Unit's configuration to and from YAML. +This can be convenient when a more compact format is desirable, such as when +storing it in a source control system. YAML format also provides an elegant way +of displaying Unit's usage statistics without the noise" of JSON. + +Let's combine these two enhancements to display a compact form of Unit's usage +statistics from a Docker container: + +.. code-block:: bash + + $ unitc docker://f4f3d9e918e6 /status --format YAML + connections: + accepted: 1067 + active: 13 + idle: 4 + closed: 1050 + requests: + total: 1307 + applications: + my_app: + processes: + running: 14 + starting: 0 + idle: 4 + requests: + active: 10 + +Note that the `yq(1) `__ tool is required +for YAML format conversion. + + +********************** +Unit is now on GitHub! +********************** + +This release is special! Special for us and the Community! As you may have +noticed we have moved more and more of our development and planning workloads +from our old systems to `GitHub `__. + +GitHub is no longer just a read-only mirror. It now serves as the primary +source for our source code and tests. We invite you to create +`issues `__, contribute through +`pull requests `__, or join our +`discussions `__. There are many +ways to get involved with us. + +We've also fully transitioned the development and maintenance of unit.nginx.org +to the `Github unit-docs `__ repository. +We look forward to pull requests and issues that will improve our documentation. + +************************************* +Changes in behavior and other updates +************************************* + +========================================================================== +Docker image uses **stderr**, so now you can send **access_log** to stdout +========================================================================== + +With 1.32.0 the **unit.log** file is symlinked to the container's +**/dev/stderr** instead of **/dev/stdout**. This leaves room for the +*access_log* to be redirected to **/dev/stdout** and will not populate +the Unit log messages to **stdout** which might be scraped by log collectors. + +======================================================= +unit.nginx.org/download/ is now sources.nginx.org/unit/ +======================================================= + +We have moved the location of the Unit tarballs from "unit.nginx.org/download/" +to a new, central source archive for NGINX: +`sources.nginx.org/unit/ `__. + +The old link is currently proxying to the new location, but officially +deprecated now! Please update to the new location "sources.nginx.org/unit/". + +************ +Wall of fame +************ + +Special Thanks to all external contributors helping us +making Unit better! With 1.32.0 we would like to send a shout out to: + +- Alejandro Colomar +- Alex Crichton +- Andrei Vasiliu +- Chris Adams +- David Carlier +- Dean Coakley +- rustedsword +- Hippolyte Pello +- Javier Evans + +************** +Full Changelog +************** + +.. code-block:: none + + Changes with Unit 1.32.0 27 Feb 2024 + + *) Feature: WebAssembly Components using WASI interfaces defined in + wasi:http/proxy@0.2.0. + + *) Feature: conditional access logging. + + *) Feature: NJS variables access. + + *) Feature: $request_id variable contains a string that is formed using + random data and can be used as a unique request identifier. + + *) Feature: options to set control socket permissions. + + *) Feature: Ruby arrays in response headers, improving compatibility + with Rack v3.0. + + *) Feature: Python bytearray response bodies for ASGI applications. + + *) Bugfix: router could crash while sending large files. Thanks to + rustedsword. + + *) Bugfix: serving static files from a network filesystem could lead to + error. + + *) Bugfix: "uidmap" and "gidmap" isolation options validation. + + *) Bugfix: abstract UNIX socket name could be corrupted during + configuration validation. Thanks to Alejandro Colomar. + + *) Bugfix: HTTP header field value encoding could be misinterpreted in + Python module. + + *) Bugfix: Node.js http.createServer() accepts and ignores the "options" + argument, improving compatibility with strapi applications, among + others. + + *) Bugfix: ServerRequest.flushHeaders() implemented in Node.js module to + make it compatible with Next.js. + + *) Bugfix: ServerRequest.httpVersion variable format in Node.js module. + + *) Bugfix: Node.js module handles standard library imports prefixed with + "node:", making it possible to run newer Nuxt applications, among + others. + + *) Bugfix: Node.js tarball location changed to avoid build/install + errors. + + *) Bugfix: Go module sets environment variables necessary for building + on macOS/arm64 systems. \ No newline at end of file diff --git a/source/scripting.rst b/source/scripting.rst index d69db7d2..2ed2a961 100644 --- a/source/scripting.rst +++ b/source/scripting.rst @@ -3,19 +3,12 @@ Scripting ######### NGINX Unit's :doc:`control API ` supports -JavaScript expressions, -including function calls, -in the form of +JavaScript expressions, including function calls, in the form of `template literals `__ -written in the -:program:`njs` -`dialect `__ -of JavaScript. -They can be used -with these -:doc:`configuration ` -options: +written in +`NGINX JavaScript `__ ( :program:`njs` ). +They can be used with these :doc:`configuration ` options: - **pass** in :ref:`listeners ` @@ -41,9 +34,12 @@ options: to enable HTTP redirects. - **format** in the - :ref:`access log ` + :ref:`access log ` to customize Unit's log output. +- **if** in the + :ref:`access log ` + to dynamically turn Unit's logging on and off. As its JavaScript engine, Unit uses the :program:`njs` library, @@ -54,10 +50,8 @@ or .. warning:: - Unit 1.31+ doesn't support - pre-0.8 :program:`njs` - `versions `__; - please update. + Unit 1.32.0 and later require + `njs 0.8.2 `__. Some request properties are exposed as :program:`njs` objects or scalars: @@ -115,7 +109,11 @@ are exposed as :program:`njs` objects or scalars: `__ ("." and "..", "//"). -Template lterals are wrapped in backticks. + * - **vars** + - Object + - Unit :ref:`variables `; vars.method is **$method**. + +Template literals are wrapped in backticks. To use a literal backtick in a string, escape it: **\\\\`** (escaping backslashes @@ -170,9 +168,8 @@ so add the module's name to **settings/js_module**: .. note:: - Mind that the **js_module** option - can be a string or an array, - so choose the appropriate HTTP method. + Please note that the **js_module** option + can be a string or an array; choose the appropriate HTTP method. Now, the **http.route()** function can be used with Unit-supplied header field values: @@ -256,7 +253,7 @@ issued by :program:`curl`: } -This uses a series of transformations +This example uses a series of transformations to log the request's date, IP, URI, and all its headers: @@ -268,6 +265,19 @@ and all its headers: "format": "`@timestamp=${new Date().toISOString()} ip=${remoteAddr} uri=${uri} ${Object.keys(headers).map(k => 'req.' + k + '=\"' + headers[k] + '\"').join(' ')}\n`" } +The next example will add the **Cache-Control** Header based on the HTTP Request method: + +.. code-block:: json + + { + "action": { + "pass": "applications/my_app", + "response_headers": { + "Cache-Control": "`${vars.method.startsWith('P') ? 'no-cache' : 'max-age=3600'}`" + } + } + } + + For further reference, -see the :program:`njs` -`documentation `__. +see the `njs documentation `__. \ No newline at end of file