A redirect balancer between several hosts.

1.0 2021-04-19 10:28 UTC

This package is not auto-updated.

Last update: 2024-11-05 04:48:54 UTC


README

CI Workflow Codecov

302

This is a load balancer that doesn't act as a load balancer.

It is a redirect balancer. Instead of forwarding traffic to a specific host/port, it returns a 302 response with a different location.

Typical usage is that your entrypoint is https://example.com/foo and you want to redirect your traffic to a pool made of https://01.example.com and https://02.example.com, by keeping path and query string intact.

It is built with PHP 8 on top of ReactPHP. Because it answers very short responses and runs within a loop, it can easily handle thousands of requests/s without blinking an eye.

Build

Build is optional (you can simply run php bin/console serve) but will produce an optimized, single-file executable PHAR.

PHP 8, Composer and Box are globally required on your computer.

To build the application, run:

./bin/build

It will land in bin/302.

Usage

Live balancing (no persistence - for testing purposes or prototyping)

php bin/302 serve \
--host=0.0.0.0 \
--port=8080 \
--pick=random \ # or round-robin
example1.org \
example2.org \
example3.org
GET http://0.0.0.0:8080/foo?bar=baz

HTTP/1.1 302 Found 
Location: http://example2.org/foo?bar=baz

Persisted storage (Redis)

# Expose the REDIS_DSN variable if necessary, default is:
export REDIS_DSN="redis://localhost:6379"
php bin/302 serve --host=0.0.0.0 --port=8080

App will run, but user agent will get 503 errors because the server pool is empty.

Add a server to the pool

php bin/302 server:add example1.org

This command can be run while 302 serve is running, no need to restart the app!

Remove a server from the pool

php bin/302 server:remove example1.org

This command can be run while 302 serve command is running, no need to restart the app!

List servers in the pool

php bin/302 server:list

Tests

./vendor/bin/pest

Deployment

Example Supervisor config

After building the app, you can easily create a supervisor recipe to load it on startup:

[program:302]
command=php /usr/local/bin/302 serve --host=127.0.0.1 --port=80%(process_num)02d
user=www-data
numprocs=4
startsecs=1
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d
environment = APP_LOG_DIR=/var/log/302

With the above config, 302 will run on 127.0.0.1:8000, 127.0.0.1:8001, 127.0.0.1:8002 and 127.0.0.1:8003.

Round-robin will be shared across the instances (since they share the same Redis instance).

CORS / SSL termination

302 has no built-in CORS nor SSL termination, but this can be handled by any web server with reverse-proxy capabilities (Apache, Nginx, Caddy, ...).

Caddyfile example

If you're using Caddy, here's an example Caddyfile:

example.org {
    @get {
        method GET
    }
    @options {
        method OPTIONS
    }
    header Access-Control-Allow-Origin *
    header Access-Control-Allow-Redirect true
    respond @options 200
    reverse_proxy @get 127.0.0.1:8000 127.0.0.1:8001 127.0.0.1:8002 127.0.0.1:8003
}