A redirect balancer between several hosts.
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 10
Watchers: 4
Forks: 0
Open Issues: 0
Type:project
Requires
- php: >=8.0
- ext-ctype: *
- ext-iconv: *
- ext-pcntl: *
- ext-redis: *
- bentools/uri-factory: ^2.2
- clue/redis-react: ^2.4
- nyholm/dsn: ^2.0
- react/http: ^1.2
- symfony/console: 5.2.*
- symfony/dotenv: 5.2.*
- symfony/flex: ^1.3.1
- symfony/framework-bundle: 5.2.*
- symfony/yaml: 5.2.*
Requires (Dev)
- clue/block-react: ^1.4
- pestphp/pest: ^1.0
- phpstan/phpstan: ^0.12.79
- squizlabs/php_codesniffer: ^3.5
Conflicts
Replaces
This package is not auto-updated.
Last update: 2024-12-17 05:22:41 UTC
README
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
}