Allow changing instances + add nginx_rewrites table + optimizations

This commit is contained in:
Daniel Winzen
2019-09-22 21:24:27 +02:00
parent 7ec0f76f35
commit ae925a2000
7 changed files with 143 additions and 95 deletions

View File

@ -23,7 +23,7 @@ const INDEX_MD5S=[ //MD5 sums of index.hosting.html files that should be considd
const REQUIRE_APPROVAL=false; //require admin approval of new sites? true/false
const ENABLE_SHELL_ACCESS=true; //allows users to login via ssh, when disabled only (s)ftp is allowed - run setup.php to migrate existing accounts
const ADMIN_PASSWORD='MY_PASSWORD'; //password for admin interface
const SERVICE_INSTANCES=['1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']; //one character per instance - run multiple tor+php-fpm instances for load balancing, remove all but one instance if you expect less than 100 accounts. Adding new instances is always possible at a later time, just removing one takes some manual cleanup for now - run setup.php after change
const SERVICE_INSTANCES=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's']; //one character per instance - run multiple tor+php-fpm instances for load balancing, remove all but one instance if you expect less than 200 accounts. - run setup.php after change
const DISABLED_PHP_VERSIONS=[]; //php versions still installed on the system but no longer offered for new accounts
const PHP_VERSIONS=[4 => '7.3']; //currently active php versions
const DEFAULT_PHP_VERSION='7.3'; //default php version
@ -81,7 +81,6 @@ server {
}
}
location /phpmyadmin {
root /usr/share;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_param DOCUMENT_ROOT /html;
@ -113,6 +112,7 @@ const MAX_NUM_USER_DOMAINS = 3; //maximum number of clearnet domains a user may
const SKIP_USER_CHROOT_UPDATE = true; //skips updating user chroots when running setup.php
const DEFAULT_QUOTA_SIZE = 10 * 1024 * 1024; //per user disk quota in kb - Defaults to 10 GB
const DEFAULT_QUOTA_FILES = 100000; //per user file quota - by default allow no more than 100000 files
const NUM_GUARDS = 50; //number of tor guard relays to distribute the load on
function get_onion_v2($pkey) : string {
$keyData = openssl_pkey_get_details($pkey);
@ -312,36 +312,65 @@ function check_captcha_error() {
return false;
}
function rewrite_torrc(PDO $db, string $key){
$torrc="ClientUseIPv6 1
function rewrite_torrc(PDO $db, string $instance){
$update_onion=$db->prepare('UPDATE onions SET private_key=? WHERE onion=?;');
$torrc='ClientUseIPv6 1
ClientUseIPv4 1
SOCKSPort 0
MaxClientCircuitsPending 1024
NumEntryGuards 15
NumDirectoryGuards 15
NumPrimaryGuards 15
";
$stmt=$db->prepare('SELECT onions.onion, users.system_account, onions.num_intros, onions.enable_smtp, onions.version, onions.max_streams, onions.enabled FROM onions LEFT JOIN users ON (users.id=onions.user_id) WHERE onions.instance = ? AND onions.enabled IN (1, -2) AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete!=1;');
$stmt->execute([$key]);
while($tmp=$stmt->fetch(PDO::FETCH_NUM)){
if($tmp[6]==1){
$socket=$tmp[1];
}else{
$socket='suspended';
}
$torrc.="HiddenServiceDir /var/lib/tor-instances/$key/hidden_service_$tmp[0].onion
HiddenServiceNumIntroductionPoints $tmp[2]
HiddenServiceVersion $tmp[4]
NumEntryGuards '.NUM_GUARDS.'
NumDirectoryGuards '.NUM_GUARDS.'
NumPrimaryGuards '.NUM_GUARDS.'
';
$stmt=$db->prepare('SELECT onions.onion, users.system_account, onions.num_intros, onions.enable_smtp, onions.version, onions.max_streams, onions.enabled, onions.private_key FROM onions LEFT JOIN users ON (users.id=onions.user_id) WHERE onions.instance = ? AND onions.enabled IN (1, -2) AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete!=1;');
$stmt->execute([$instance]);
while($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
if(!file_exists("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion")){
if($tmp['version']==2){
//php openssl implementation has some issues, re-export using native openssl
$pkey=openssl_pkey_get_private($tmp['private_key']);
openssl_pkey_export($pkey, $exported);
openssl_pkey_free($pkey);
$priv_key=shell_exec('echo ' . escapeshellarg($exported) . ' | openssl rsa');
//save hidden service
mkdir("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion", 0700);
file_put_contents("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/private_key", $priv_key);
chmod("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/private_key", 0600);
chown("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/", "_tor-$instance");
chown("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/private_key", "_tor-$instance");
chgrp("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/", "_tor-$instance");
chgrp("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/private_key", "_tor-$instance");
$update_onion->execute([$priv_key, $tmp['onion']]);
}elseif($tmp['version']==3){
$priv_key=base64_decode($tmp['private_key']);
//save hidden service
mkdir("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion", 0700);
file_put_contents("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/hs_ed25519_secret_key", $priv_key);
chmod("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/hs_ed25519_secret_key", 0600);
chown("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/", "_tor-$instance");
chown("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/hs_ed25519_secret_key", "_tor-$instance");
chgrp("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/", "_tor-$instance");
chgrp("/var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion/hs_ed25519_secret_key", "_tor-$instance");
}
}
if($tmp['enabled']==1){
$socket=$tmp['system_account'];
}else{
$socket='suspended';
}
$torrc.="HiddenServiceDir /var/lib/tor-instances/$instance/hidden_service_$tmp[onion].onion
HiddenServiceNumIntroductionPoints $tmp[num_intros]
HiddenServiceVersion $tmp[version]
HiddenServiceMaxStreamsCloseCircuit 1
HiddenServiceMaxStreams $tmp[5]
HiddenServiceMaxStreams $tmp[max_streams]
HiddenServicePort 80 unix:/var/run/nginx/$socket
";
if($tmp[3]){
if($tmp['enable_smtp']){
$torrc.="HiddenServicePort 25\n";
}
}
file_put_contents("/etc/tor/instances/$key/torrc", $torrc);
exec("service tor@$key reload");
file_put_contents("/etc/tor/instances/$instance/torrc", $torrc);
exec('systemctl reload '.escapeshellarg("tor@$instance"));
}
function private_key_to_onion(string $priv_key) : array {
@ -433,8 +462,27 @@ function ed25519_seckey_expand(string $seed) : string {
function rewrite_nginx_config(PDO $db){
$nginx='';
$rewrites = [];
// rewrite rules
$stmt = $db->query('SELECT user_id, regex, replacement, flag, ifnotexists FROM nginx_rewrites;');
while($tmp = $stmt->fetch(PDO::FETCH_ASSOC)){
if(!isset($rewrites[$tmp['user_id']])){
$rewrites[$tmp['user_id']] = '';
}
if($tmp['ifnotexists']){
$rewrites[$tmp['user_id']] .= "if (!-e \$request_filename) {\n\t\t";
}
$rewrites[$tmp['user_id']] .= "rewrite '$tmp[regex]' '$tmp[replacement]'";
if(!empty($tmp['flag'])){
$rewrites[$tmp['user_id']] .= " $tmp[flag]";
}
$rewrites[$tmp['user_id']] .= ";\n\t";
if($tmp['ifnotexists']){
$rewrites[$tmp['user_id']] .= "}\n\t";
}
}
// onions
$stmt=$db->query("SELECT users.system_account, users.php, users.autoindex, onions.onion FROM users INNER JOIN onions ON (onions.user_id=users.id) WHERE onions.enabled IN (1, -2) AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete!=1;");
$stmt=$db->query("SELECT users.system_account, users.php, users.autoindex, onions.onion, users.id FROM users INNER JOIN onions ON (onions.user_id=users.id) WHERE onions.enabled IN (1, -2) AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete!=1;");
while($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
if($tmp['php']>0){
$php_location="
@ -456,7 +504,11 @@ function rewrite_nginx_config(PDO $db){
error_log /home/$tmp[system_account]/logs/error.log notice;
disable_symlinks on from=/home/$tmp[system_account];
autoindex $autoindex;
location / {
";
if(isset($rewrites[$tmp['id']])){
$nginx .= $rewrites[$tmp['id']];
}
$nginx .= "location / {
try_files \$uri \$uri/ =404;$php_location
}
}
@ -464,7 +516,7 @@ function rewrite_nginx_config(PDO $db){
}
// clearnet domains
$stmt=$db->query("SELECT users.system_account, users.php, users.autoindex, domains.domain FROM users INNER JOIN domains ON (domains.user_id=users.id) WHERE domains.enabled = 1 AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete != 1;");
$stmt=$db->query("SELECT users.system_account, users.php, users.autoindex, domains.domain, users.id FROM users INNER JOIN domains ON (domains.user_id=users.id) WHERE domains.enabled = 1 AND users.id NOT IN (SELECT user_id FROM new_account) AND users.todelete != 1;");
while($tmp=$stmt->fetch(PDO::FETCH_ASSOC)){
if($tmp['php']>0){
$php_location="
@ -486,7 +538,11 @@ function rewrite_nginx_config(PDO $db){
error_log /home/$tmp[system_account]/logs/error.log notice;
disable_symlinks on from=/home/$tmp[system_account];
autoindex $autoindex;
location / {
";
if(isset($rewrites[$tmp['id']])){
$nginx .= $rewrites[$tmp['id']];
}
$nginx .= "location / {
try_files \$uri \$uri/ =404;$php_location
}
}
@ -504,7 +560,7 @@ function rewrite_nginx_config(PDO $db){
";
}
file_put_contents("/etc/nginx/streams-enabled/hosted_sites", $nginx);
exec("service nginx reload");
exec('systemctl reload nginx');
}
function rewrite_php_config(PDO $db, string $key){
@ -529,7 +585,7 @@ listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 75
pm.max_children = 50
pm.process_idle_timeout = 10s;
chroot = /home/$tmp[system_account]
php_admin_value[memory_limit] = 256M
@ -540,7 +596,7 @@ php_admin_value[session.save_path] = /tmp
";
}
file_put_contents("/etc/php/$version/fpm/pool.d/$key/www.conf", $php);
exec("service php$version-fpm@$key restart");
exec('systemctl restart '.escapeshellarg("php$version-fpm@$key"));
}
}
@ -602,7 +658,7 @@ function get_new_tor_instance(PDO $db){
}
function add_user_onion(PDO $db, int $user_id, string $onion, string $priv_key, int $onion_version) {
$stmt=$db->prepare('INSERT INTO onions (user_id, onion, private_key, version, enabled, instance) VALUES (?, ?, ?, ?, 2, ?);');
$stmt=$db->prepare('INSERT INTO onions (user_id, onion, private_key, version, enabled, enable_smtp, instance) VALUES (?, ?, ?, ?, 1, 0, ?);');
$stmt->execute([$user_id, $onion, $priv_key, $onion_version, get_new_tor_instance($db)]);
}