Join the NGINX Unit Community Call on June 7, 2023

NGINX Unit
v. 1.30.0

App Samples§

Note

These steps assume Unit was already installed with the language module for each app.

Go§

Let’s configure the following basic app, saved as /www/app.go:

package main

import (
    "io";
    "net/http";
    "unit.nginx.org/go"
)

func main() {
    http.HandleFunc("/",func (w http.ResponseWriter, r *http.Request) {
        io.WriteString(w, "Hello, Go on Unit!")
    })
    unit.ListenAndServe(":8080", nil)
}

First, create a Go module, go get Unit’s package, and build your application:

$ go mod init example.com/app
$ go get unit.nginx.org/go@1.30.0
$ go build -o /www/app /www/app.go

Upload the app config to Unit and test it:

# curl -X PUT --data-binary '{
  "listeners": {
      "*:8080": {
          "pass": "applications/go"
      }
  },
  "applications": {
      "go": {
          "type": "external",
          "working_directory": "/www/",
          "executable": "/www/app"
      }
  }
  }' --unix-socket /path/to/control.unit.sock http://localhost/config/

$ curl http://localhost:8080

    Hello, Go on Unit!

Try this sample out with the Dockerfile here or use a more elaborate app example:

package main

import (
    "crypto/sha256";
    "fmt";
    "io";
    "io/ioutil";
    "encoding/json";
    "net/http";
    "strings";
    "unit.nginx.org/go"
)

func formatRequest(r *http.Request) string {

    h := make(map[string]string)
    m := make(map[string]string)
    t := make(map[string]interface{})

    m["message"] = "Unit reporting"
    m["agent"] = "NGINX Unit 1.30.0"

    body, _ := ioutil.ReadAll(r.Body)
    m["body"] = fmt.Sprintf("%s", body)

    m["sha256"] = fmt.Sprintf("%x", sha256.Sum256([]byte(m["body"])))

    data, _ := json.Marshal(m)
    for name, _ := range r.Header {
        h[strings.ToUpper(name)] = r.Header.Get(name)
    }
    _ = json.Unmarshal(data, &t)
    t["headers"] = h

    js, _ := json.MarshalIndent(t, "", "    ")

    return fmt.Sprintf("%s", js)
}

func main() {
    http.HandleFunc("/",func (w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Content-Type", "application/json; charset=utf-8")
        io.WriteString(w, formatRequest(r))
    })
    unit.ListenAndServe(":8080", nil)
}

Java§

Let’s configure the following basic app, saved as /www/index.jsp:

<%@ page language="java" contentType="text/plain" %>
<%= "Hello, JSP on Unit!" %>

Upload the app config to Unit and test it:

# curl -X PUT --data-binary '{
  "listeners": {
      "*:8080": {
          "pass": "applications/java"
      }
  },
  "applications": {
      "java": {
          "type": "java",
          "webapp": "/www/"
      }
  }
  }' --unix-socket /path/to/control.unit.sock http://localhost/config/

$ curl http://localhost:8080

    Hello, JSP on Unit!

Try this sample out with the Dockerfile here or use a more elaborate app example (you’ll need to download and add the json-simple library to your app’s classpath option):

<%@ page language="java" contentType="application/json; charset=utf-8" %>
<%@ page import="com.github.cliftonlabs.json_simple.JsonObject" %>
<%@ page import="com.github.cliftonlabs.json_simple.Jsoner" %>
<%@ page import="java.io.BufferedReader" %>
<%@ page import="java.math.BigInteger" %>
<%@ page import="java.nio.charset.StandardCharsets" %>
<%@ page import="java.security.MessageDigest" %>
<%@ page import="java.util.Enumeration" %>
<%
JsonObject r = new JsonObject();

r.put("message", "Unit reporting");
r.put("agent", "NGINX Unit 1.30.0");

JsonObject headers = new JsonObject();
Enumeration h = request.getHeaderNames();
while (h.hasMoreElements()) {
    String name = (String)h.nextElement();
    headers.put(name, request.getHeader(name));
}
r.put("headers", headers);

BufferedReader  br = request.getReader();
String          body = "";
String          line = br.readLine();
while (line != null) {
    body += line;
    line = br.readLine();
}
r.put("body", body);

MessageDigest   md = MessageDigest.getInstance("SHA-256");
byte[]          bytes = md.digest(body.getBytes(StandardCharsets.UTF_8));
BigInteger      number = new BigInteger(1, bytes);
StringBuilder   hex = new StringBuilder(number.toString(16));
r.put("sha256", hex.toString());

out.println(Jsoner.prettyPrint((Jsoner.serialize(r))));
%>

Node.js§

Let’s configure the following basic app, saved as /www/app.js:

#!/usr/bin/env node

require("unit-http").createServer(function (req, res) {
    res.writeHead(200, {"Content-Type": "text/plain"});
    res.end("Hello, Node.js on Unit!")
}).listen()

Make it executable and link the Node.js language package you’ve installed earlier:

$ cd /www
$ chmod +x app.js
$ npm link unit-http

Upload the app config to Unit and test it:

# curl -X PUT --data-binary '{
  "listeners": {
      "*:8080": {
          "pass": "applications/node"
      }
  },
  "applications": {
      "node": {
          "type": "external",
          "working_directory": "/www/",
          "executable": "app.js"
      }
  }
  }' --unix-socket /path/to/control.unit.sock http://localhost/config/

$ curl http://localhost:8080

    Hello, Node.js on Unit!

Try this sample out with the Dockerfile here or use a more elaborate app example:

#!/usr/bin/env node

const cr = require("crypto")
const bd = require("body")
require("unit-http").createServer(function (req, res) {
    bd (req, res, function (err, body) {
        res.writeHead(200, {"Content-Type": "application/json; charset=utf-8"})

        var r = {
            "agent":    "NGINX Unit 1.30.0",
            "message":  "Unit reporting"
        }

        r["headers"] = req.headers
        r["body"] = body
        r["sha256"] = cr.createHash("sha256").update(r["body"]).digest("hex")

        res.end(JSON.stringify(r, null, "    ").toString("utf8"))
    })
}).listen()

Note

You can run a version of the same app without requiring the unit-http module explicitly.

Perl§

Let’s configure the following basic app, saved as /www/app.psgi:

my $app = sub {
    return [
        "200",
        [ "Content-Type" => "text/plain" ],
        [ "Hello, Perl on Unit!" ],
    ];
};

Upload the app config to Unit and test it:

# curl -X PUT --data-binary '{
  "listeners": {
      "*:8080": {
          "pass": "applications/perl"
      }
  },
  "applications": {
      "perl": {
          "type": "perl",
          "working_directory": "/www/",
          "script": "/www/app.psgi"
      }
  }
  }' --unix-socket /path/to/control.unit.sock http://localhost/config/

$ curl http://localhost:8080

    Hello, Perl on Unit!

Try this sample out with the Dockerfile here or use a more elaborate app example:

use strict;

use Digest::SHA qw(sha256_hex);
use JSON;
use Plack;
use Plack::Request;

my $app = sub {
    my $env = shift;
    my $req = Plack::Request->new($env);
    my $res = $req->new_response(200);
    $res->header("Content-Type" => "application/json; charset=utf-8");

    my $r = {
        "message"   => "Unit reporting",
        "agent"     => "NGINX Unit 1.30.0",
        "headers"   => $req->headers->psgi_flatten(),
        "body"      => $req->content,
        "sha256"    => sha256_hex($req->content),
    };

    my $json = JSON->new();
    $res->body($json->utf8->pretty->encode($r));

    return $res->finalize();
};

PHP§

Let’s configure the following basic app, saved as /www/index.php:

<?php echo "Hello, PHP on Unit!"; ?>

Upload the app config to Unit and test it:

# curl -X PUT --data-binary '{
  "listeners": {
      "*:8080": {
          "pass": "applications/php"
      }
  },
  "applications": {
      "php": {
          "type": "php",
          "root": "/www/"
      }
  }
  }' --unix-socket /path/to/control.unit.sock http://localhost/config/

$ curl http://localhost:8080

    Hello, PHP on Unit!

Try this sample out with the Dockerfile here or use a more elaborate app example:

<?php

header("Content-Type: application/json; charset=utf-8");

$r = array (
   "message" => "Unit reporting",
   "agent"   => "NGINX Unit 1.30.0"
);

foreach ($_SERVER as $header => $value)
   if (strpos($header, "HTTP_") === 0)
      $r["headers"][$header] = $value;

$r["body"] = file_get_contents("php://input");
$r["sha256"] = hash("sha256", $r["body"]);

echo json_encode($r, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);

?>

Python§

Let’s configure the following basic app, saved as /www/wsgi.py:

def application(environ, start_response):
    start_response("200 OK", [("Content-Type", "text/plain")])
    return (b"Hello, Python on Unit!")

Upload the app config to Unit and test it:

# curl -X PUT --data-binary '{
  "listeners": {
      "*:8080": {
          "pass": "applications/python"
      }
  },
  "applications": {
      "python": {
          "type": "python",
          "path": "/www/",
          "module": "wsgi"
      }
  }
  }' --unix-socket /path/to/control.unit.sock http://localhost/config/

$ curl http://localhost:8080

    Hello, Python on Unit!

Try this sample out with the Dockerfile here or use a more elaborate app example:

import hashlib, json

def application(env, start_response):
    start_response("200 OK", [("Content-Type",
                               "application/json; charset=utf-8")])

    r = {}

    r["message"] = "Unit reporting"
    r["agent"] = "NGINX Unit 1.30.0"

    r["headers"] = {}
    for header in [_ for _ in env.keys() if _.startswith("HTTP_")]:
        r["headers"][header] = env[header]

    bytes = env["wsgi.input"].read()
    r["body"] = bytes.decode("utf-8")
    r["sha256"] = hashlib.sha256(bytes).hexdigest()

    return json.dumps(r, indent=4).encode("utf-8")

Ruby§

Let’s configure the following basic app, saved as /www/config.ru:

app = Proc.new do |env|
    ["200", {
        "Content-Type" => "text/plain",
    }, ["Hello, Ruby on Unit!"]]
end

run app

Upload the app config to Unit and test it:

# curl -X PUT --data-binary '{
  "listeners": {
      "*:8080": {
          "pass": "applications/ruby"
      }
  },
  "applications": {
      "ruby": {
          "type": "ruby",
          "working_directory": "/www/",
          "script": "config.ru"
      }
  }
  }' --unix-socket /path/to/control.unit.sock http://localhost/config/

$ curl http://localhost:8080

    Hello, Ruby on Unit!

Try this sample out with the Dockerfile here or use a more elaborate app example:

require "digest"
require "json"

app = Proc.new do |env|
    body = env["rack.input"].read
    r = {
        "message" => "Unit reporting",
        "agent"   => "NGINX Unit 1.30.0",
        "body"    => body,
        "headers" => env.select { |key, value| key.include?("HTTP_") },
        "sha256"  => Digest::SHA256.hexdigest(body)
    }

    ["200", {
        "Content-Type" => "application/json; charset=utf-8",
    }, [JSON.pretty_generate(r)]]
end;

run app