Nginx in stream mode should be able to do what you need.
https://docs.nginx.com/nginx/admin-guide/load-balancer/tcp-udp-load-balancer/Edit:
The generic tcp proxy works just fine.
Seems like adding and removing backends dynamically only affects new incoming connections. You'll need a creative way to kill existing.
A shell script to rotate config, then stopping and starting nginx seems to do the job. Not awesome though.
Here's a short load balance example on Ubuntu 18.04 to get you started.
apt-get install -y nginx-extras
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig
cat <>/etc/nginx/nginx.conf
stream {
server {
listen 3333;
proxy_pass mining_backend;
}
upstream mining_backend {
server stratum.kano.is:3333;
server stratum.slushpool.com:3333;
}
}
EOF
nginx -t
nginx -s reload
Edit Part 2:
By installing nginx-extras instead of plain nginx, you have access to lua for the creative reset component. Use the examples in the link above to dynamically add/remove your desired pool backend(s), then force the miners to reconnect with the lua block below.
location /drop_connections {
default_type 'text/plain';
content_by_lua_block {
os.execute("(sleep 1; ps aux | grep 'nginx: worker process' | grep -v $$ | awk '{print $2}' | xargs kill -9) &")
ngx.say('dropped')
}
}
Edit Part 3:
While putting it all together, I discovered the backend api are part of nginx+ and not the community version.
With lua available, we can quickly skip that and make it happen with a little rearranging:
First update /etc/nginx/nginx.conf.
stream {
server {
listen 3333;
proxy_pass mining_backend;
}
upstream mining_backend {
include /etc/nginx/mining.conf;
}
}
Then grant the nginx child processes the ability to tweak nginx related configuration.
touch /etc/nginx/mining.conf
chown www-data:www-data /etc/nginx/mining.conf
echo "server stratum.kano.is:3333;" > /etc/nginx/mining.conf
cp /etc/sudoers /etc/sudoers.orig
echo "www-data ALL = NOPASSWD:/usr/sbin/nginx" >> /etc/sudoers
Finally, in the server directive of /etc/nginx/sites-enabled/default:
location /switch_to_kano {
default_type 'text/plain';
content_by_lua_block {
os.execute("(sleep 1; echo 'server stratum.kano.is:3333;' > /etc/nginx/mining.conf) &")
os.execute("(sleep 2; sudo /usr/sbin/nginx -s reload) &")
os.execute("(sleep 3; ps aux | grep 'nginx: worker process' | grep -v $$ | awk '{print $2}' | xargs kill -9) &")
ngx.header["Content-type"] = "text/plain"
ngx.say('switching to kano.is')
}
}
location /switch_to_slush {
default_type 'text/plain';
content_by_lua_block {
os.execute("(sleep 1; echo 'server stratum.slushpool.com:3333;' > /etc/nginx/mining.conf) &")
os.execute("(sleep 2; sudo /usr/sbin/nginx -s reload) &")
os.execute("(sleep 3; ps aux | grep 'nginx: worker process' | grep -v $$ | awk '{print $2}' | xargs kill -9) &")
ngx.header["Content-type"] = "text/plain"
ngx.say('switching to slushpool')
}
}
My local end results of this setup:
Miner mined when connected to stratum+tcp://[myip]:3333, and changes to the targeted pool when my browser hits http://[myip]/switch_to_kano & http://[myip]/switch_to_slush.
That was interesting in theory and neat to see working.