Ubuntu 22.04 Nginx Unit 應用伺服器

Ubuntu 22.04 Nginx Unit Application Server

Nginx Unit 是一款輕量級、動態的應用伺服器,由 Nginx 團隊開發。它支援多種程式語言,包括 Python、PHP、Go、Node.js、Java、Perl 和 Ruby,並且可以透過 RESTful API 進行動態設定,無需重啟服務。

Nginx Unit 概述

Nginx Unit 的主要特點:

  • 多語言支援:單一伺服器可同時運行多種程式語言的應用程式
  • 動態設定:透過 JSON API 即時更新設定,無需重啟服務
  • 輕量高效:採用非同步事件驅動架構,資源消耗低
  • 安全隔離:每個應用程式在獨立的程序中運行
  • TLS 支援:內建 SSL/TLS 終止功能

安裝 Nginx Unit

新增官方套件庫

首先安裝必要的套件:

1
2
sudo apt update
sudo apt install -y curl apt-transport-https gnupg2

新增 Nginx Unit 官方 GPG 金鑰和套件庫:

1
2
3
4
5
# 新增 GPG 金鑰
curl -fsSL https://unit.nginx.org/keys/nginx-keyring.gpg | sudo gpg --dearmor -o /usr/share/keyrings/nginx-keyring.gpg

# 新增套件庫
echo "deb [signed-by=/usr/share/keyrings/nginx-keyring.gpg] https://packages.nginx.org/unit/ubuntu/ jammy unit" | sudo tee /etc/apt/sources.list.d/unit.list

安裝 Unit 核心與語言模組

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
sudo apt update

# 安裝 Unit 核心
sudo apt install -y unit

# 安裝語言模組(依需求選擇)
sudo apt install -y unit-python3.10   # Python 3.10
sudo apt install -y unit-php          # PHP
sudo apt install -y unit-go           # Go
sudo apt install -y unit-nodejs       # Node.js (外部模組)

啟動服務

1
2
3
sudo systemctl enable unit
sudo systemctl start unit
sudo systemctl status unit

設定架構

Nginx Unit 使用 JSON 格式進行設定,主要透過 Unix socket 進行 API 操作:

1
2
# 預設 socket 位置
/var/run/control.unit.sock

查看目前設定

1
sudo curl --unix-socket /var/run/control.unit.sock http://localhost/config

設定結構

Unit 的設定主要包含以下區塊:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
    "listeners": {
        "*:8080": {
            "pass": "applications/myapp"
        }
    },
    "applications": {
        "myapp": {
            "type": "python",
            "path": "/var/www/myapp",
            "module": "wsgi"
        }
    },
    "routes": [],
    "upstreams": {}
}

部署 Python 應用

建立 Python 應用程式

1
sudo mkdir -p /var/www/python-app

建立 WSGI 應用程式 /var/www/python-app/wsgi.py

1
2
3
4
5
def application(environ, start_response):
    status = '200 OK'
    headers = [('Content-Type', 'text/html; charset=utf-8')]
    start_response(status, headers)
    return [b'<h1>Hello from Python!</h1>']

設定 Unit

建立設定檔 python-config.json

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
    "listeners": {
        "*:8080": {
            "pass": "applications/python-app"
        }
    },
    "applications": {
        "python-app": {
            "type": "python 3.10",
            "path": "/var/www/python-app",
            "module": "wsgi",
            "processes": 2
        }
    }
}

套用設定:

1
2
sudo curl -X PUT --unix-socket /var/run/control.unit.sock \
    -d @python-config.json http://localhost/config

部署 PHP 應用

建立 PHP 應用程式

1
sudo mkdir -p /var/www/php-app

建立 /var/www/php-app/index.php

1
2
3
4
5
<?php
echo "<h1>Hello from PHP!</h1>";
echo "<p>Server Time: " . date('Y-m-d H:i:s') . "</p>";
phpinfo();
?>

設定 Unit

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{
    "applications": {
        "php-app": {
            "type": "php",
            "root": "/var/www/php-app",
            "index": "index.php",
            "processes": {
                "max": 10,
                "spare": 2
            }
        }
    },
    "listeners": {
        "*:8081": {
            "pass": "applications/php-app"
        }
    }
}

套用設定:

1
2
sudo curl -X PUT --unix-socket /var/run/control.unit.sock \
    -d @php-config.json http://localhost/config/applications/php-app

部署 Node.js 應用

建立 Node.js 應用程式

1
sudo mkdir -p /var/www/node-app

建立 /var/www/node-app/app.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const http = require('http');

module.exports = {
    createServer: function() {
        return http.createServer((req, res) => {
            res.writeHead(200, {'Content-Type': 'text/html'});
            res.end('<h1>Hello from Node.js!</h1>');
        });
    }
};

設定 Unit(使用外部模組)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
    "applications": {
        "node-app": {
            "type": "external",
            "working_directory": "/var/www/node-app",
            "executable": "/usr/bin/node",
            "arguments": ["app.js"]
        }
    },
    "listeners": {
        "*:8082": {
            "pass": "applications/node-app"
        }
    }
}

路由設定

Nginx Unit 提供強大的路由功能,可以根據 URI、主機名、Header 等進行流量分發:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
    "listeners": {
        "*:80": {
            "pass": "routes"
        }
    },
    "routes": [
        {
            "match": {
                "uri": "/api/*"
            },
            "action": {
                "pass": "applications/python-app"
            }
        },
        {
            "match": {
                "uri": "/admin/*"
            },
            "action": {
                "pass": "applications/php-app"
            }
        },
        {
            "action": {
                "share": "/var/www/static$uri"
            }
        }
    ]
}

進階路由條件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
    "routes": [
        {
            "match": {
                "host": "api.example.com",
                "method": ["GET", "POST"],
                "headers": {
                    "Accept": "*application/json*"
                }
            },
            "action": {
                "pass": "applications/api-backend"
            }
        }
    ]
}

SSL/TLS 設定

上傳憑證

首先將憑證與私鑰合併:

1
cat /etc/ssl/certs/server.crt /etc/ssl/private/server.key > bundle.pem

上傳憑證到 Unit:

1
2
sudo curl -X PUT --unix-socket /var/run/control.unit.sock \
    --data-binary @bundle.pem http://localhost/certificates/main-cert

設定 TLS 監聽器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
    "listeners": {
        "*:443": {
            "pass": "routes",
            "tls": {
                "certificate": "main-cert"
            }
        }
    }
}

強制 HTTPS 重導向

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
{
    "routes": [
        {
            "match": {
                "scheme": "http"
            },
            "action": {
                "return": 301,
                "location": "https://$host$request_uri"
            }
        }
    ]
}

動態設定更新

Nginx Unit 最大的優勢是可以即時更新設定,無需重啟服務:

更新特定應用程式

1
2
3
# 更新 Python 應用的程序數量
sudo curl -X PUT --unix-socket /var/run/control.unit.sock \
    -d '4' http://localhost/config/applications/python-app/processes

新增監聽器

1
2
sudo curl -X PUT --unix-socket /var/run/control.unit.sock \
    -d '{"pass": "applications/php-app"}' http://localhost/config/listeners/*:9000

刪除設定

1
2
3
# 刪除特定監聽器
sudo curl -X DELETE --unix-socket /var/run/control.unit.sock \
    http://localhost/config/listeners/*:9000

查看應用程式狀態

1
sudo curl --unix-socket /var/run/control.unit.sock http://localhost/status

輸出範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    "connections": {
        "accepted": 1234,
        "active": 5,
        "idle": 10,
        "closed": 1219
    },
    "requests": {
        "total": 5678
    },
    "applications": {
        "python-app": {
            "processes": {
                "running": 2,
                "starting": 0,
                "idle": 2
            },
            "requests": {
                "active": 0
            }
        }
    }
}

參考資料

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy