2023-10-19 06:23:25 +02:00
#!/usr/bin/python3
2023-10-19 06:20:12 +02:00
import subprocess , os , random , string , sys , shutil , socket , time , io
if sys . version_info . major != 3 :
print ( "Please run with python3." )
sys . exit ( 1 )
rPath = os . path . dirname ( os . path . realpath ( __file__ ))
rPackages = [ "cpufrequtils" , "iproute2" , "python" , "net-tools" , "dirmngr" , "gpg-agent" , "software-properties-common" , "libmaxminddb0" , "libmaxminddb-dev" , "mmdb-bin" , "libcurl4" , "libgeoip-dev" , "libxslt1-dev" , "libonig-dev" , "e2fsprogs" , "wget" , "mariadb-server" , "sysstat" , "alsa-utils" , "v4l-utils" , "mcrypt" , "certbot" , "iptables-persistent" , "libjpeg-dev" , "libpng-dev" , "php-ssh2" , "xz-utils" , "zip" , "unzip" ]
rRemove = [ "mysql-server" ]
rMySQLCnf = '# XUI \n [client] \n port = 3306 \n\n [mysqld_safe] \n nice = 0 \n\n [mysqld] \n user = mysql \n port = 3306 \n basedir = /usr \n datadir = /var/lib/mysql \n tmpdir = /tmp \n lc-messages-dir = /usr/share/mysql \n skip-external-locking \n skip-name-resolve \n bind-address = * \n\n key_buffer_size = 128M \n myisam_sort_buffer_size = 4M \n max_allowed_packet = 64M \n myisam-recover-options = BACKUP \n max_length_for_sort_data = 8192 \n query_cache_limit = 0 \n query_cache_size = 0 \n query_cache_type = 0 \n expire_logs_days = 10 \n max_binlog_size = 100M \n max_connections = 8192 \n back_log = 4096 \n open_files_limit = 20240 \n innodb_open_files = 20240 \n max_connect_errors = 3072 \n table_open_cache = 4096 \n table_definition_cache = 4096 \n tmp_table_size = 1G \n max_heap_table_size = 1G \n\n innodb_buffer_pool_size = 10G \n innodb_buffer_pool_instances = 10 \n innodb_read_io_threads = 64 \n innodb_write_io_threads = 64 \n innodb_thread_concurrency = 0 \n innodb_flush_log_at_trx_commit = 0 \n innodb_flush_method = O_DIRECT \n performance_schema = 0 \n innodb-file-per-table = 1 \n innodb_io_capacity = 20000 \n innodb_table_locks = 0 \n innodb_lock_wait_timeout = 0 \n\n sql_mode = "NO_ENGINE_SUBSTITUTION" \n\n [mariadb] \n\n thread_cache_size = 8192 \n thread_handling = pool-of-threads \n thread_pool_size = 12 \n thread_pool_idle_timeout = 20 \n thread_pool_max_threads = 1024 \n\n [mysqldump] \n quick \n quote-names \n max_allowed_packet = 16M \n\n [mysql] \n\n [isamchk] \n key_buffer_size = 16M'
rConfig = '; XUI Configuration \n ; ----------------- \n ; Your username and password will be encrypted and \n ; saved to the \' credentials \' file in this folder \n ; automatically. \n ; \n ; To change your username or password, modify BOTH \n ; below and XUI will read and re-encrypt them. \n\n [XUI] \n hostname = "127.0.0.1" \n database = "xui" \n port = 3306 \n server_id = 1 \n license = "" \n\n [Encrypted] \n username = " %s " \n password = " %s "'
rRedisConfig = "bind * \n protected-mode yes \n port 6379 \n tcp-backlog 511 \n timeout 0 \n tcp-keepalive 300 \n daemonize yes \n supervised no \n pidfile /home/xui/bin/redis/redis-server.pid \n loglevel warning \n logfile /home/xui/bin/redis/redis-server.log \n databases 1 \n always-show-logo yes \n stop-writes-on-bgsave-error no \n rdbcompression no \n rdbchecksum no \n dbfilename dump.rdb \n dir /home/xui/bin/redis/ \n slave-serve-stale-data yes \n slave-read-only yes \n repl-diskless-sync no \n repl-diskless-sync-delay 5 \n repl-disable-tcp-nodelay no \n slave-priority 100 \n requirepass #PASSWORD# \n maxclients 655350 \n lazyfree-lazy-eviction no \n lazyfree-lazy-expire no \n lazyfree-lazy-server-del no \n slave-lazy-flush no \n appendonly no \n appendfilename \" appendonly.aof \"\n appendfsync everysec \n no-appendfsync-on-rewrite no \n auto-aof-rewrite-percentage 100 \n auto-aof-rewrite-min-size 64mb \n aof-load-truncated yes \n aof-use-rdb-preamble no \n lua-time-limit 5000 \n slowlog-log-slower-than 10000 \n slowlog-max-len 128 \n latency-monitor-threshold 0 \n notify-keyspace-events \"\"\n hash-max-ziplist-entries 512 \n hash-max-ziplist-value 64 \n list-max-ziplist-size -2 \n list-compress-depth 0 \n set-max-intset-entries 512 \n zset-max-ziplist-entries 128 \n zset-max-ziplist-value 64 \n hll-sparse-max-bytes 3000 \n activerehashing yes \n client-output-buffer-limit normal 0 0 0 \n client-output-buffer-limit slave 256mb 64mb 60 \n client-output-buffer-limit pubsub 32mb 8mb 60 \n hz 10 \n aof-rewrite-incremental-fsync yes \n save 60 1000 \n server-threads 4 \n server-thread-affinity true"
rSysCtl = '# XUI.one \n\n net.ipv4.tcp_congestion_control = bbr \n net.core.default_qdisc = fq \n net.ipv4.tcp_rmem = 8192 87380 134217728 \n net.ipv4.udp_rmem_min = 16384 \n net.core.rmem_default = 262144 \n net.core.rmem_max = 268435456 \n net.ipv4.tcp_wmem = 8192 65536 134217728 \n net.ipv4.udp_wmem_min = 16384 \n net.core.wmem_default = 262144 \n net.core.wmem_max = 268435456 \n net.core.somaxconn = 1000000 \n net.core.netdev_max_backlog = 250000 \n net.core.optmem_max = 65535 \n net.ipv4.tcp_max_tw_buckets = 1440000 \n net.ipv4.tcp_max_orphans = 16384 \n net.ipv4.ip_local_port_range = 2000 65000 \n net.ipv4.tcp_no_metrics_save = 1 \n net.ipv4.tcp_slow_start_after_idle = 0 \n net.ipv4.tcp_fin_timeout = 15 \n net.ipv4.tcp_keepalive_time = 300 \n net.ipv4.tcp_keepalive_probes = 5 \n net.ipv4.tcp_keepalive_intvl = 15 \n fs.file-max=20970800 \n fs.nr_open=20970800 \n fs.aio-max-nr=20970800 \n net.ipv4.tcp_timestamps = 1 \n net.ipv4.tcp_window_scaling = 1 \n net.ipv4.tcp_mtu_probing = 1 \n net.ipv4.route.flush = 1 \n net.ipv6.route.flush = 1'
rSystemd = '[Unit] \n SourcePath=/home/xui/service \n Description=XUI.one Service \n After=network.target \n StartLimitIntervalSec=0 \n\n [Service] \n Type=simple \n User=root \n Restart=always \n RestartSec=1 \n ExecStart=/bin/bash /home/xui/service start \n ExecRestart=/bin/bash /home/xui/service restart \n ExecStop=/bin/bash /home/xui/service stop \n\n [Install] \n WantedBy=multi-user.target'
rChoice = "23456789abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ"
rVersions = {
"14.04" : "trusty" ,
"16.04" : "xenial" ,
"18.04" : "bionic" ,
"20.04" : "focal" ,
"22.04" : "jammy"
}
class col :
HEADER = ' \033 [95m'
OKBLUE = ' \033 [94m'
OKGREEN = ' \033 [92m'
WARNING = ' \033 [93m'
FAIL = ' \033 [91m'
ENDC = ' \033 [0m'
BOLD = ' \033 [1m'
UNDERLINE = ' \033 [4m'
def generate ( length = 32 ): return '' . join ( random . choice ( rChoice ) for i in range ( length ))
def getIP ():
s = socket . socket ( socket . AF_INET , socket . SOCK_DGRAM )
s . connect (( "8.8.8.8" , 80 ))
return s . getsockname ()[ 0 ]
def printc ( rText , rColour = col . OKBLUE , rPadding = 0 ):
rLeft = int ( 30 - ( len ( rText ) / 2 ))
rRight = ( 60 - rLeft - len ( rText ))
print ( " %s |--------------------------------------------------------------| %s " % ( rColour , col . ENDC ))
for i in range ( rPadding ): print ( " %s | | %s " % ( rColour , col . ENDC ))
print ( " %s | %s%s%s | %s " % ( rColour , " " * rLeft , rText , " " * rRight , col . ENDC ))
for i in range ( rPadding ): print ( " %s | | %s " % ( rColour , col . ENDC ))
print ( " %s |--------------------------------------------------------------| %s " % ( rColour , col . ENDC ))
print ( " " )
if __name__ == "__main__" :
##################################################
# START #
##################################################
try : rVersion = os . popen ( 'lsb_release -sr' ) . read () . strip ()
except : rVersion = None
if not rVersion in rVersions :
printc ( "Unsupported Operating System" )
sys . exit ( 1 )
if not os . path . exists ( "./xui.tar.gz" ) and not os . path . exists ( "./xui_trial.tar.gz" ):
print ( "Fatal Error: xui.tar.gz is missing. Please download it from XUI billing panel." )
sys . exit ( 1 )
printc ( "XUI" , col . OKGREEN , 2 )
rHost = "127.0.0.1" ; rServerID = 1 ; rUsername = generate () ; rPassword = generate ()
rDatabase = "xui"
rPort = 3306
if os . path . exists ( "/home/xui/" ):
printc ( "XUI Directory Exists!" )
while True :
rAnswer = input ( "Continue and overwrite? (Y / N) : " )
if rAnswer . upper () in [ "Y" , "N" ]: break
if rAnswer == "N" : sys . exit ( 1 )
##################################################
# UPGRADE #
##################################################
printc ( "Preparing Installation" )
for rFile in [ "/var/lib/dpkg/lock-frontend" , "/var/cache/apt/archives/lock" , "/var/lib/dpkg/lock" , "/var/lib/apt/lists/lock" ]:
if os . path . exists ( rFile ):
try : os . remove ( rFile )
except : pass
printc ( "Updating system" )
os . system ( "sudo apt-get update" )
os . system ( "sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install software-properties-common" )
if rVersion in rVersions :
printc ( "Adding repo: Ubuntu %s " % rVersion )
os . system ( "sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8" )
os . system ( "sudo add-apt-repository -y 'deb [arch=amd64,arm64,ppc64el] http://ams2.mirrors.digitalocean.com/mariadb/repo/10.6/ubuntu %s main'" % rVersions [ rVersion ])
os . system ( "sudo add-apt-repository -y ppa:maxmind/ppa" )
os . system ( "sudo apt-get update" )
for rPackage in rRemove :
printc ( "Removing %s " % rPackage )
os . system ( "sudo apt-get remove %s -y" % rPackage )
for rPackage in rPackages :
printc ( "Installing %s " % rPackage )
os . system ( "sudo DEBIAN_FRONTEND=noninteractive apt-get -yq install %s " % rPackage )
try : subprocess . check_output ( "getent passwd xui" . split ())
except :
printc ( "Creating user" )
os . system ( "sudo adduser --system --shell /bin/false --group --disabled-login xui" )
if not os . path . exists ( "/home/xui" ): os . mkdir ( "/home/xui" )
##################################################
# INSTALL #
##################################################
printc ( "Installing XUI" )
if os . path . exists ( "./xui.tar.gz" ):
os . system ( 'sudo tar -zxvf "./xui.tar.gz" -C "/home/xui/"' )
os . system ( 'sudo wget https://raw.githubusercontent.com/amidevous/xtream-ui-ubuntu20.04/master/install-dep.sh -O /root/install-dep.sh && sudo bash /root/install-dep.sh' )
os . system ( 'sudo rm -f /root/install-dep.sh' )
os . system ( 'sudo wget https://raw.githubusercontent.com/amidevous/xui.one/master/build-php.sh -O /root/build-php.sh && sudo bash /root/build-php.sh' )
os . system ( 'sudo rm -rf /root/build-php.sh' )
if not os . path . exists ( "/home/xui/status" ):
printc ( "Failed to extract! Exiting" )
sys . exit ( 1 )
elif os . path . exists ( "./xui_trial.tar.gz" ):
os . system ( 'sudo tar -zxvf "./xui_trial.tar.gz" -C "/home/xui/"' )
if not os . path . exists ( "/home/xui/status" ):
printc ( "Failed to extract! Exiting" )
sys . exit ( 1 )
##################################################
# MYSQL #
##################################################
printc ( "Configuring MySQL" )
rCreate = True
if os . path . exists ( "/etc/mysql/my.cnf" ):
if open ( "/etc/mysql/my.cnf" , "r" ) . read ( 5 ) == "# XUI" : rCreate = False
if rCreate :
rFile = io . open ( "/etc/mysql/my.cnf" , "w" , encoding = "utf-8" )
rFile . write ( rMySQLCnf )
rFile . close ()
os . system ( "sudo service mariadb restart" )
rExtra = ""
rRet = os . system ( "mysql -u root -e \" SELECT VERSION(); \" " )
if rRet != 0 :
while True :
rExtra = " -p %s " % input ( "Root MySQL Password: " )
rRet = os . system ( "mysql -u root %s -e \" SELECT VERSION(); \" " % rExtra )
if rRet == 0 : break
else : printc ( "Invalid password! Please try again." )
os . system ( 'sudo mysql -u root %s -e "DROP DATABASE IF EXISTS xui; CREATE DATABASE IF NOT EXISTS xui;"' % rExtra )
os . system ( 'sudo mysql -u root %s -e "DROP DATABASE IF EXISTS xui_migrate; CREATE DATABASE IF NOT EXISTS xui_migrate;"' % rExtra )
os . system ( 'sudo mysql -u root %s xui < "/home/xui/bin/install/database.sql"' % rExtra )
os . system ( 'sudo mysql -u root %s -e "CREATE USER \' %s \' @ \' localhost \' IDENTIFIED BY \' %s \' ;"' % ( rExtra , rUsername , rPassword ))
os . system ( 'sudo mysql -u root %s -e "GRANT ALL PRIVILEGES ON xui.* TO \' %s \' @ \' localhost \' ;"' % ( rExtra , rUsername ))
os . system ( 'sudo mysql -u root %s -e "GRANT ALL PRIVILEGES ON xui_migrate.* TO \' %s \' @ \' localhost \' ;"' % ( rExtra , rUsername ))
os . system ( 'sudo mysql -u root %s -e "GRANT ALL PRIVILEGES ON mysql.* TO \' %s \' @ \' localhost \' ;"' % ( rExtra , rUsername ))
os . system ( 'sudo mysql -u root %s -e "GRANT GRANT OPTION ON xui.* TO \' %s \' @ \' localhost \' ;"' % ( rExtra , rUsername ))
os . system ( 'sudo mysql -u root %s -e "CREATE USER \' %s \' @ \' 127.0.0.1 \' IDENTIFIED BY \' %s \' ;"' % ( rExtra , rUsername , rPassword ))
os . system ( 'sudo mysql -u root %s -e "GRANT ALL PRIVILEGES ON xui.* TO \' %s \' @ \' 127.0.0.1 \' ;"' % ( rExtra , rUsername ))
os . system ( 'sudo mysql -u root %s -e "GRANT ALL PRIVILEGES ON xui_migrate.* TO \' %s \' @ \' 127.0.0.1 \' ;"' % ( rExtra , rUsername ))
os . system ( 'sudo mysql -u root %s -e "GRANT ALL PRIVILEGES ON mysql.* TO \' %s \' @ \' 127.0.0.1 \' ;"' % ( rExtra , rUsername ))
os . system ( 'sudo mysql -u root %s -e "GRANT GRANT OPTION ON xui.* TO \' %s \' @ \' 127.0.0.1 \' ;"' % ( rExtra , rUsername ))
os . system ( 'sudo mysql -u root %s -e "FLUSH PRIVILEGES;"' % rExtra )
rConfigData = rConfig % ( rUsername , rPassword )
rFile = io . open ( "/home/xui/config/config.ini" , "w" , encoding = "utf-8" )
rFile . write ( rConfigData )
rFile . close ()
##################################################
# CONFIGURE #
##################################################
printc ( "Configuring System" )
if not "/home/xui/" in open ( "/etc/fstab" ) . read ():
rFile = io . open ( "/etc/fstab" , "a" , encoding = "utf-8" )
rFile . write ( " \n tmpfs /home/xui/content/streams tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777,size=90% 0 0 \n tmpfs /home/xui/tmp tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777,size=6G 0 0" )
rFile . close ()
if os . path . exists ( "/etc/init.d/xuione" ): os . remove ( "/etc/init.d/xuione" )
if os . path . exists ( "/etc/systemd/system/xui.service" ): os . remove ( "/etc/systemd/system/xui.service" )
if not os . path . exists ( "/etc/systemd/system/xuione.service" ):
rFile = io . open ( "/etc/systemd/system/xuione.service" , "w" , encoding = "utf-8" )
rFile . write ( rSystemd )
rFile . close ()
os . system ( "sudo chmod +x /etc/systemd/system/xuione.service" )
os . system ( "sudo systemctl daemon-reload" )
os . system ( "sudo systemctl enable xuione" )
print ( "Custom sysctl.conf - If you have your own custom sysctl.conf, type N or it will be overwritten. If you don't know what a sysctl configuration is, type Y as it will correctly set your TCP settings and open file limits." )
print ( " " )
while True :
rAnswer = input ( "Overwrite sysctl configuration? Recommended! (Y / N): " )
if rAnswer . upper () in [ "Y" , "N" ]: break
if rAnswer . upper () == "Y" :
try : os . system ( "sudo modprobe ip_conntrack" )
except : pass
try :
rFile = io . open ( "/etc/sysctl.conf" , "w" , encoding = "utf-8" )
rFile . write ( rSysCtl )
rFile . close ()
os . system ( "sudo sysctl -p >/dev/null 2>&1" )
rFile = open ( "/home/xui/config/sysctl.on" , "w" )
rFile . close ()
except : print ( "Failed to write to sysctl file." )
else :
if os . path . exists ( "/home/xui/config/sysctl.on" ): os . remove ( "/home/xui/config/sysctl.on" )
if not "DefaultLimitNOFILE=655350" in open ( "/etc/systemd/system.conf" ) . read ():
os . system ( "sudo echo \"\n DefaultLimitNOFILE=655350 \" >> \" /etc/systemd/system.conf \" " )
os . system ( "sudo echo \"\n DefaultLimitNOFILE=655350 \" >> \" /etc/systemd/user.conf \" " )
if not os . path . exists ( "/home/xui/bin/redis/redis.conf" ):
rFile = io . open ( "/home/xui/bin/redis/redis.conf" , "w" , encoding = "utf-8" )
rFile . write ( rRedisConfig )
rFile . close ()
##################################################
# ACCESS CODE #
##################################################
rCodeDir = "/home/xui/bin/nginx/conf/codes/"
rHasAdmin = None
for rCode in os . listdir ( rCodeDir ):
if rCode . endswith ( ".conf" ):
if rCode . split ( "." )[ 0 ] == "setup" : os . remove ( rCodeDir + "setup.conf" )
elif "/home/xui/admin" in open ( rCodeDir + rCode , "r" ) . read (): rHasAdmin = rCode
if not rHasAdmin :
rCode = generate ( 8 )
os . system ( 'sudo mysql -u root %s -e "USE xui; INSERT INTO access_codes(code, type, enabled, groups) VALUES( \' %s \' , 0, 1, \' [1] \' );"' % ( rExtra , rCode ))
rTemplate = open ( rCodeDir + "template" ) . read ()
rTemplate = rTemplate . replace ( "#WHITELIST#" , "" )
rTemplate = rTemplate . replace ( "#TYPE#" , "admin" )
rTemplate = rTemplate . replace ( "#CODE#" , rCode )
rTemplate = rTemplate . replace ( "#BURST#" , "500" )
rFile = io . open ( " %s%s .conf" % ( rCodeDir , rCode ), "w" , encoding = "utf-8" )
rFile . write ( rTemplate )
rFile . close ()
else : rCode = rHasAdmin . split ( "." )[ 0 ]
##################################################
# FINISHED #
##################################################
os . system ( "sudo mount -a >/dev/null 2>&1" )
os . system ( "sudo chown xui:xui -R /home/xui >/dev/null 2>&1" )
os . system ( "sudo systemctl daemon-reload" )
os . system ( "sudo systemctl start xuione" )
time . sleep ( 10 )
os . system ( "sudo /home/xui/status 1" )
os . system ( "sudo /home/xui/bin/php/bin/php /home/xui/includes/cli/startup.php >/dev/null 2>&1" )
rFile = io . open ( rPath + "/credentials.txt" , "w" , encoding = "utf-8" )
rFile . write ( "MySQL Username: %s \n MySQL Password: %s " % ( rUsername , rPassword ))
2023-10-19 06:23:25 +02:00
rFile . write ( " \n Continue Setup: http:// %s / %s " % ( rUsername , rPassword ))
2023-10-19 06:20:12 +02:00
rFile . close ()
printc ( "Installation completed!" , col . OKGREEN , 2 )
printc ( "Continue Setup: http:// %s / %s " % ( getIP (), rCode ))
print ( " " )
printc ( "Your mysql credentials have been saved to:" )
printc ( rPath + "/credentials.txt" )
print ( " " )
printc ( "Please move this file somewhere safe!" )