Phorklift is an HTTP server and proxy daemon, with clear, powerful and dynamic configuration.

Overview

Phorklift is an HTTP server and proxy daemon, with clear, powerful and dynamic configuration.

Common Features

  • High performance and low memory usage.

  • Modular mechanism, similar to Nginx.

  • HTTP/1.x and HTTP/2 (except server-push)

  • Reload configuration.

  • Static file service, proxy, ACL, gzip, etc.

In short, Phorklift targets production-level.

Key Features

Feature: Configuration in Lua.

It's a very natural choice when Lua is embed.

Lua is simple and powerful. Correspondingly, Phorklift's configuration is always short and clear for most cases, while it can also provide powerful description capabilities for some specific cases.

In order to highlight Phorklift configuration's feature, the examples in the following sections mainly show the usage of Lua's function and look a bit complex. However usually you may not need that, and then Lua behaves like other configurations. Here is a simple example:

Listen "443" {
    ssl = {
        certificate = "certs/cert.pem",
        private_key = "certs/priv.pem",
    },
    network = {
        send_timeout = 10,
    },
    static = "html/",  -- provide static file service
}

Here are a tutorial and more examples.

Feature: Lua Embed.

This is inspired by the Lua-nginx module from OpenResty, but we are more comprehensive. Lua is no longer just a module.

Here is a configuration example to log requests only status-code >= 400 or reacting slower than 1 second:

access_log = {
    filter = function()
        return phl.resp.status_code >= 400 or phl.resp.react_ms > 1000
    end,
}

where phl is a built-in Lua package.

Another example on the request rate limit key. If the request is from a login user then use the user-id as a key, or use the client IP.

limit_req = {
    key = function()
        local user_id = phl.req.get_cookie("id")
        return user_id and user_id or phl.conn.client_ip
    end
}

Going further, different weight can be set for each request:

100) and limit/100 or 1 end -- higher VIP level has higher limit local user_id = phl.req.get_cookie("id") local vip = get_vip_level(user_id) if vip then weight = weight / vip end return weight end, } ">
limit_req = {
    weight = function()
        local weight = 1 -- default value

        -- bigger `limit` argument means bigger weight
        local limit = phl.req.get_uri_query("limit")
        if limit then
            limit = tonumber(limit)
            weight = (limit > 100) and limit/100 or 1
        end

        -- higher VIP level has higher limit
        local user_id = phl.req.get_cookie("id")
        local vip = get_vip_level(user_id)
        if vip then
            weight = weight / vip
        end

        return weight
    end,
}

Thanks to Lua's light-weight coroutine, the script can be written like blocking mode. Let's see the get_vip_level() in last example:

local function get_vip_level(user_id)
    local r = phl.subrequest("@get_user_info", {args={user_id=user_id}})
    if r.status_code ~= 200 then
        return nil
    end

    local info = cjson.decode(r.body)
    return tonumber(info.vip_level)
end

phl.subrequest() creates a Phorklift sub-request, and returns after it finishes. But Phorklift switches to process other events during this time. So the script looks like blocking but the underlying is asynchronous.

If you are used to Lua-nginx module, you will feel familiar.

These are all very simple examples. However it is easy to write complex applications.

Feature: Dynamic Configration.

Dynamic configuration enables some components to be created/updated/deleted during running.

This is Phorklift's killer!

By now, built-in Upstream and Path support dynamic configuration. You can make any components in you module to support dynamic easily if necessary.

Let's take the forward proxy as example which uses upstream. Usually one upstream defines a group of static hostname or IP addresses, so it's suitable for reverse proxy:

local upstream_origin = {
    "origin1.example.com",
    "origin2.example.com",
}

However for forward proxy, the addresses are not static but decided by the request's Host header. You can not write the addresses into configuration file, but can only know them on receiving requests. So here is the dynamic:

local upstream_hello_dynamic = {
    dynamic = {
        get_name = function() return phl.req.host end,
        get_conf = function(name) return { name } end,
    }
}

There is no static addresses in this upstream, but a dynamic member which contains 2 functions: get_name() returns a string as the name of sub-upstream for this request; and get_conf() returns the configuration of the sub-upstream according to the name.

For example, for a request with header "Host: xxx.example.com", get_name() returns "xxx.example.com", and get_conf() returns {"xxx.example.com"} which is a valid upstream configuration. Then Phorklift creates a new sub-upstream with this configuration to serve this request, and also cache it for later use. The following requests with same Host will hit the cache and need not to call get_conf() again.

Forward proxy is realized! This seems nothing special, but more powerful functions can be achieved through more complex get_name() and get_conf().

Here is another example of dynamic upstream for service discovery:

local upstream_service_discovery = {
    dynamic = {
        idle_timeout = 3600,
        check_interval = 60,

        get_name = function()
            return string.match(phl.req.uri_path, '/(%w+)/')
        end,

        get_conf = function(name)
            local redis = require "luapkgs/phl_redis"
            local conf = redis.query_once("127.0.0.1:6379", "get "..name)
            if not conf then  -- query failure
                return phl.HTTP_500
            end

            if conf == redis.Null then  -- miss or deleted
                return phl.HTTP_404
            end

            return phl.HTTP_200, conf
        end,
    }
}

For example, for a request with URL "/img/big/123.jpg", get_name() returns "img"; and get_conf() queries the upstream's configuration for "img" from Redis, where should be an entry with key="img" and value is arbitrary valid upstream configuration string. The following requests with "/img/" prefix will use this sub-upstream directly in 60 seconds (defined by check_interval=60 above). After 60 seconds, Phorklift will query Redis again to check whether the configuration is deleted or modified. Then the administrator only need to create, delete and modify the name-configuration entries in Redis to realize the service discovery.

Compared to last forward proxy example, get_conf() return one more value, the status code, to indicate status. Besides, the returned conf is string but not Lua table, and Phorklift will load the string into Lua table.

Here the Redis is just an example. You can query the configuration from local file, another HTTP server, etc.

Dynamic Upstream handles upstream configuration only, while dynamic Path handles path configuration which includes most of Phorklift's commands, such as the limit_req in the above example. It's much more powerful.

Feature: Clean Code.

Probably all programers will think their codes are clean. But I really try my best to keep Phorklift's code clean.

In addition, Phorklift is written from the ground-up so there is no "legacy code" by now.

Here is a unfair comparison with Nignx. You will find that it's much easier to develop with Phorklift than nginx.

Feature: Detailed Statistics.

It meets most of the monitoring needs. No need to analyze logs anymore.

See stats command in reference for more detail. [TODO]

Disadvantages

  • Lack of security and stability verification.

  • Fewer functions and modules.

  • Linux only.

All because of being young. Hope these problems will disappear as we grow.

Licence

GPLv2.

Status

Phorklift is still under development and not stable yet.

The main functions and frames have been realized. At least the functions and configuration mentioned in this document have been realized.

I publish it now (June 2021) mainly to collect opinions and suggestions. If you are interested, please try it and feedback. Thanks!

Next Reading

More ducuments.

You might also like...
A socket daemon to multiplex connections from and to iOS devices

usbmuxd A socket daemon to multiplex connections from and to iOS devices. Features usbmuxd stands for "USB multiplexing daemon". This daemon is in cha

Dhcpd is a dhcp daemon uses dhcp-{project} libs on this repository

dhcpd Dhcpd is a dhcp server daemon. Uses dhcp-lease dhcp-network Dependencies cunit sqlite3 (for lease module) python3 (for lease module) features sq

An optimized Webcash mining daemon.

Webminer An experimental vector-accelerated CPU miner for the Webcash electronic payment network. Webminer is tested and known to work on recent versi

tiny HTTP parser written in C (used in HTTP::Parser::XS et al.)
tiny HTTP parser written in C (used in HTTP::Parser::XS et al.)

PicoHTTPParser Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase, Shigeo Mitsunari PicoHTTPParser is a tiny, primitive, fast HTTP r

cuehttp is a modern c++ middleware framework for http(http/https)/websocket(ws/wss).

cuehttp 简介 cuehttp是一个使用Modern C++(C++17)编写的跨平台、高性能、易用的HTTP/WebSocket框架。基于中间件模式可以方便、高效、优雅的增加功能。cuehttp基于boost.asio开发,使用picohttpparser进行HTTP协议解析。内部依赖了nl

A very simple, fast, multithreaded, platform independent HTTP and HTTPS server and client library implemented using C++11 and Boost.Asio.

A very simple, fast, multithreaded, platform independent HTTP and HTTPS server and client library implemented using C++11 and Boost.Asio. Created to be an easy way to make REST resources available from C++ applications.

Cross-platform, efficient, customizable, and robust asynchronous HTTP/WebSocket server C++14 library with the right balance between performance and ease of use

What Is RESTinio? RESTinio is a header-only C++14 library that gives you an embedded HTTP/Websocket server. It is based on standalone version of ASIO

Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution
Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and 10K connections problem solution

CppServer Ultra fast and low latency asynchronous socket server & client C++ library with support TCP, SSL, UDP, HTTP, HTTPS, WebSocket protocols and

websocket and http client and server library, coming with ws, a command line swiss army knife utility

Hello world IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use an

Releases(v0.0.1)
Owner
null
H2O - the optimized HTTP/1, HTTP/2, HTTP/3 server

H2O - an optimized HTTP server with support for HTTP/1.x, HTTP/2 and HTTP/3 (experimental) Copyright (c) 2014-2019 DeNA Co., Ltd., Kazuho Oku, Tatsuhi

H2O 10.2k Dec 30, 2022
a CLAT configuration daemon for OpenBSD

GELATOD(8) - System Manager's Manual NAME gelatod - a CLAT configuration daemon SYNOPSIS gelatod [-dv] DESCRIPTION gelatod is a CLAT (Customer-side tr

Florian Obser 7 Dec 14, 2022
C++ API: http server with local dynamic or precompiled repository containers

libnavajo Framework to develop easily web interfaces in your C++ applications Libnavajo makes it easy to run an HTTP server into your own application,

null 60 Jan 29, 2022
Dohd is a minimalist DNS-over-HTTPS daemon that redirects all DoH queries to a local DNS server running on localhost:53 (UDP)

dohd Dohd (pron. doh-dee) is a minimalist DNS-over-HTTPS daemon that redirects all DoH queries to a local DNS server running on localhost:53 (UDP). Fe

Dyne.org 16 Dec 1, 2022
Gromox - Groupware server backend with MAPI/HTTP, RPC/HTTP, IMAP, POP3 and PHP-MAPI support for grommunio

Gromox is the central groupware server component of grommunio. It is capable of serving as a replacement for Microsoft Exchange and compatibles. Conne

grommunio 139 Dec 26, 2022
A collection of C++ HTTP libraries including an easy to use HTTP server.

Proxygen: Facebook's C++ HTTP Libraries This project comprises the core C++ HTTP abstractions used at Facebook. Internally, it is used as the basis fo

Facebook 7.7k Jan 4, 2023
A flexible tool for redirecting a given program's TCP traffic to SOCKS5 or HTTP proxy.

graftcp English | 简体中文 Introduction graftcp can redirect the TCP connection made by the given program [application, script, shell, etc.] to SOCKS5 or

mingang.he 1.3k Dec 26, 2022
A project designed for the esp8266 D1 Mini or the esp8266 D1 Mini PRO to provide a wifi http server and dns server.

PS4 Server 9.00 This is a project designed for the esp8266 D1 Mini or the esp8266 D1 Mini PRO to provide a wifi http server and dns server. this is fo

null 14 Nov 28, 2022
reverse proxy with web server and preview page

Reverse Proxy Dependencies Go Make Suport Termux (android/afsd kernel) linux (kernel) Install: Termux: 1 step: Install Go-lang, Git and Make pkg insta

AlbâniaSecurity-RT 9 Dec 8, 2022
A simple SIP server (proxy) for handling VoIP calls based on SIP using C++

Sip Server A simple sip server for handling VoIP calls based on sip protocol. Features Registration Of Users The server supports registration process.

null 8 Nov 3, 2022