SSL and SSH keys upload from Haproxy-WI
Improved error notifications
pull/19/head
Aidaho12 2018-04-26 19:03:48 +06:00
parent a648d5cfcc
commit e59f47eed9
11 changed files with 323 additions and 68 deletions

View File

@ -1,7 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import html import html
import cgi import cgi
import cgitb; cgitb.enable()
import os import os
import funct import funct
import sql import sql
@ -18,10 +17,8 @@ funct.page_for_admin(level = 2)
hap_configs_dir = config.get('configs', 'haproxy_save_configs_dir') hap_configs_dir = config.get('configs', 'haproxy_save_configs_dir')
cert_path = config.get('haproxy', 'cert_path') cert_path = config.get('haproxy', 'cert_path')
listhap = sql.get_dick_permit() listhap = sql.get_dick_permit()
form = cgi.FieldStorage()
form = cgi.FieldStorage()
if form.getvalue('mode') is not None: if form.getvalue('mode') is not None:
serv = form.getvalue('serv') serv = form.getvalue('serv')
@ -112,6 +109,11 @@ if form.getvalue('mode') is not None:
funct.logging(serv, "add.py add new %s" % name) funct.logging(serv, "add.py add new %s" % name)
print('<div class="line3">') print('<div class="line3">')
MASTERS = sql.is_master(serv)
for master in MASTERS:
if master[0] != None:
funct.upload_and_restart(master[0], cfg)
if funct.upload_and_restart(serv, cfg): if funct.upload_and_restart(serv, cfg):
print('<meta http-equiv="refresh" content="30; url=add.py?add=%s&conf=%s">' % (name, config_add)) print('<meta http-equiv="refresh" content="30; url=add.py?add=%s&conf=%s">' % (name, config_add))
@ -128,6 +130,7 @@ print('<div id="tabs">'
'<li><a href="#listen">Listen</a></li>' '<li><a href="#listen">Listen</a></li>'
'<li><a href="#frontend">Frontend</a></li>' '<li><a href="#frontend">Frontend</a></li>'
'<li><a href="#backend">Backend</a></li>' '<li><a href="#backend">Backend</a></li>'
'<li><a href="#ssl">Upload certs</a></li>'
'</ul>' '</ul>'
'<div id="listen">' '<div id="listen">'
'<form name="add-listner" action="add.py">' '<form name="add-listner" action="add.py">'
@ -173,7 +176,7 @@ print('</select>'
'</span>' '</span>'
'<div id="https-hide-listen" style="display: none;">' '<div id="https-hide-listen" style="display: none;">'
'<br /><span class="tooltip tooltipTop">Enter name to pem file, or press down:</span><br />' '<br /><span class="tooltip tooltipTop">Enter name to pem file, or press down:</span><br />'
'<input type="text" name="cert" placeholder="some_cert.pem" class="form-control" size="39" id="path-cert-listen"><br />' '<input type="text" name="cert" placeholder="some_cert.pem" class="form-control" size="39" id="path-cert-listen"> or upload: <input type="file" name="file"><br />'
'<label for="ssl-check-listen" style="margin-top: 5px;">Disable ssl verify on servers?</label><input type="checkbox" id="ssl-check-listen" name="ssl-check" value="ssl-check" checked>' '<label for="ssl-check-listen" style="margin-top: 5px;">Disable ssl verify on servers?</label><input type="checkbox" id="ssl-check-listen" name="ssl-check" value="ssl-check" checked>'
'</div>' '</div>'
'</td>' '</td>'
@ -440,8 +443,38 @@ print('</select>'
funct.get_button("Add Backend") funct.get_button("Add Backend")
print('</td>' print('</td>'
'</tr>' '</tr>'
'</form></div></table>' '</form></table></div>'
'</div></div>') '<div id="ssl">'
'<table>'
'<tr class="overviewHead">'
'<td class="padding10 first-collumn">Upload ssl pem certs</td>'
'<td>'
'Name pem file'
'</td>'
'<td>'
'<span title="This pem key will be used to create https connection with haproxy">Key(?)</span>'
'</td>'
'</tr>'
'<tr style="width: 50%;">'
'<td class="first-collumn" valign="top" style="padding-top: 15px;">'
'<select required id="serv4">'
'<option disabled selected>Choose server</option>')
for i in listhap:
print('<option value="%s">%s</option>' % (i[2], i[1]))
print('</select></td>'
'<td valign="top" style="padding-top: 27px;">'
'<input type="text" id="ssl_name" class="form-control">'
'</td>'
'<td style="padding-top: 15px; padding-bottom: 15px;">'
'<textarea id="ssl_cert" cols="50" rows="5"></textarea><br /><br />'
'<a class="ui-button ui-widget ui-corner-all" id="ssl_key_upload" title="Upload ssl cert">Upload</a>'
'</td>'
'</table>'
'<div id="ajax-ssl"></div>'
'</div>')
funct.footer() funct.footer()

View File

@ -177,6 +177,7 @@ def links():
print('<li><a href=/cgi-bin/add.py#listner title="Add single listen" class="add head-submenu">Add listen</a></li>' print('<li><a href=/cgi-bin/add.py#listner title="Add single listen" class="add head-submenu">Add listen</a></li>'
'<li><a href=/cgi-bin/add.py#frontend title="Add single frontend" class="add head-submenu">Add frontend</a></li>' '<li><a href=/cgi-bin/add.py#frontend title="Add single frontend" class="add head-submenu">Add frontend</a></li>'
'<li><a href=/cgi-bin/add.py#backend title="Add single backend" class="add head-submenu">Add backend</a></li>' '<li><a href=/cgi-bin/add.py#backend title="Add single backend" class="add head-submenu">Add backend</a></li>'
'<li><a href=/cgi-bin/add.py#ssl title="Upload SSL cert" class="cert head-submenu">SSL</a></li>'
'<li><a href=/cgi-bin/config.py title="Edit Config" class="edit head-submenu">Edit</a> </li>') '<li><a href=/cgi-bin/config.py title="Edit Config" class="edit head-submenu">Edit</a> </li>')
print('</li>') print('</li>')
if is_admin(level = 2): if is_admin(level = 2):
@ -318,7 +319,8 @@ def get_config(serv, cfg):
sftp.close() sftp.close()
ssh.close() ssh.close()
except Exception as e: except Exception as e:
print('<div class="alert alert-danger">' + str(e) + ' Please check IP, and SSH settings</div>') print('<center><div class="alert alert-danger">' + str(e) + ' Please check IP, and SSH settings</div>')
sys.exit()
def show_config(cfg): def show_config(cfg):
print('<div style="margin-left: 16%" class="configShow">') print('<div style="margin-left: 16%" class="configShow">')
@ -363,6 +365,20 @@ def show_config(cfg):
print('</span>' + line + '</span><br />') print('</span>' + line + '</span><br />')
print('</div></div>') print('</div></div>')
conf.close conf.close
def upload(serv, path, file, **kwargs):
full_path = path + file
try:
ssh = ssh_connect(serv)
except Exception as e:
print('<div class="alert alert-danger">Connect fail: %s</div>' % e)
try:
sftp = ssh.open_sftp()
file = sftp.put(file, full_path)
sftp.close()
except Exception as e:
print('<div class="alert alert-danger">Upload fail: %s</div>' % e)
def upload_and_restart(serv, cfg, **kwargs): def upload_and_restart(serv, cfg, **kwargs):
tmp_file = tmp_config_path + "/" + get_data('config') + ".cfg" tmp_file = tmp_config_path + "/" + get_data('config') + ".cfg"

View File

@ -45,7 +45,7 @@ proxy =
[haproxy] [haproxy]
#Command for restart HAproxy service #Command for restart HAproxy service
restart_command = service haproxy restart restart_command = systemctl reload haproxy
status_command = systemctl status haproxy status_command = systemctl status haproxy
#Username and password for Stats web page HAproxy #Username and password for Stats web page HAproxy
stats_user = admin stats_user = admin

View File

@ -1,14 +1,17 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import html import html
import cgi import cgi
import os
import json import json
import subprocess import subprocess
import funct import funct
import sql
import ovw import ovw
from configparser import ConfigParser, ExtendedInterpolation from configparser import ConfigParser, ExtendedInterpolation
path_config = "haproxy-webintarface.config" path_config = "haproxy-webintarface.config"
config = ConfigParser(interpolation=ExtendedInterpolation()) config = ConfigParser(interpolation=ExtendedInterpolation())
config.read(path_config) config.read(path_config)
funct.check_config() funct.check_config()
@ -23,8 +26,37 @@ if form.getvalue('getcert') is not None and serv is not None:
commands = [ "ls -1t /etc/ssl/certs/ |grep pem" ] commands = [ "ls -1t /etc/ssl/certs/ |grep pem" ]
funct.ssh_command(serv, commands, ip="1") funct.ssh_command(serv, commands, ip="1")
if form.getvalue('ssh_cert'):
ssh_keys = config.get('ssh', 'ssh_keys')
try:
with open(ssh_keys, "w") as conf:
conf.write(form.getvalue('ssh_cert'))
except IOError:
print('<div class="alert alert-danger">Can\'t save ssh keys file. Check ssh keys path in config</div>')
else:
print('<div class="alert alert-success">Ssh key was save into: %s </div>' % ssh_keys)
if serv and form.getvalue('ssl_cert'):
if form.getvalue('ssl_name') is None:
print('<div class="alert alert-danger">Please enter name pem file</div>')
else:
name = form.getvalue('ssl_name') + '.pem'
cert_path = config.get('haproxy', 'cert_path')
try:
with open(name, "w") as ssl_cert:
ssl_cert.write(form.getvalue('ssl_cert'))
except IOError:
print('<div class="alert alert-danger">Can\'t save ssh keys file. Check ssh keys path in config</div>')
else:
print("Save ok")
MASTERS = sql.is_master(serv)
for master in MASTERS:
if master[0] != None:
funct.upload(master[0], cert_path, name)
funct.upload(serv, cert_path, name)
os.system("rm -f %s" % name)
if backend is not None: if backend is not None:
cmd='echo "show backend" |nc %s 1999' % serv cmd='echo "show backend" |nc %s 1999' % serv

View File

@ -25,6 +25,7 @@ print('<script src="/inc/users.js"></script>'
'<li><a href="#groups">Groups</a></li>' '<li><a href="#groups">Groups</a></li>'
'<li><a href="#servers">Servers</a></li>' '<li><a href="#servers">Servers</a></li>'
'<li><a href="#roles">Roles</a></li>' '<li><a href="#roles">Roles</a></li>'
'<li><a href="#cert">Ssh certs</a></li>'
'</ul>' '</ul>'
'<div id="users">' '<div id="users">'
'<table class="overview" id="ajax-users">' '<table class="overview" id="ajax-users">'
@ -194,4 +195,26 @@ for role in ROLES:
print('<td>%s</td>' % (role[2])) print('<td>%s</td>' % (role[2]))
print('</tr>') print('</tr>')
print('</table>') print('</table>'
'</div>'
'<div id="cert">'
'<table id="ssh">'
'<tr class="overviewHead" style="width: 50%;">'
'<td class="padding10 first-collumn">Upload ssh pem certs</td>'
'<td>'
'<span title="Private key. Note: The public key must be pre-installed on all servers to which you plan to connect">Key(?)</span>'
'</td>'
'<td></td>'
'</tr>'
'<tr style="width: 50%;">'
'<td class="first-collumn" valign="top" style="padding-top: 15px;">'
'<b>Note:</b> Somthing about ssh keys'
'</td>'
'<td style="padding-top: 15px;">'
'<textarea id="ssh_cert" cols="50" rows="5"></textarea><br /><br />'
'<a class="ui-button ui-widget ui-corner-all" id="ssh_key_upload" title="Upload ssh key" onclick="uploadSsh()">Upload</a>'
'</td>'
'<td></td>'
'</table>'
'<div id="ajax-ssh"></div>'
'</div></div>')

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

After

Width:  |  Height:  |  Size: 270 KiB

View File

@ -56,6 +56,11 @@
font-family: "Font Awesome 5 Solid"; font-family: "Font Awesome 5 Solid";
content: "\f067"; content: "\f067";
} }
.cert::before {
display: none;
font-family: "Font Awesome 5 Solid";
content: "\f0a3";
}
.edit::before { .edit::before {
display: none; display: none;
font-family: "Font Awesome 5 Solid"; font-family: "Font Awesome 5 Solid";

View File

@ -655,4 +655,30 @@ $( function() {
autoFocus: true, autoFocus: true,
minLength: -1 minLength: -1
}); });
$( "#ssl_key_upload" ).click(function() {
$('.alert-danger').remove();
$.ajax( {
url: "options.py",
data: {
serv: $('#serv4').val(),
ssl_cert: $('#ssl_cert').val(),
ssl_name: $('#ssl_name').val()
},
type: "GET",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('alert') != '-1') {
$("#ajax-ssl").append(data);
} else if (data == "Save ok ") {
$('.alert-danger').remove();
$("#ssl").addClass( "update", 1000 );
setTimeout(function() {
$( "#ssl").removeClass( "update" );
}, 2500 );
} else {
$("#ajax-ssl").append('<div class="alert alert-danger">Something wrong, check and try again</div>');
}
}
} );
});
}); });

View File

@ -534,10 +534,11 @@ a:focus {
color: #a94442; color: #a94442;
background-color: #f2dede; background-color: #f2dede;
border-color: #ebccd1; border-color: #ebccd1;
width: 230px; width: 330px;
display: block; display: block;
margin-top: 15px; margin-top: 15px;
margin-bottom: -50px; margin-bottom: -50px;
margin-left: 20px;
} }
.alert-success { .alert-success {
color: #3c763d; color: #3c763d;

View File

@ -302,3 +302,26 @@ function updateServer(id) {
} }
} ); } );
} }
function uploadSsh() {
$('.alert-danger').remove();
$.ajax( {
url: "options.py",
data: {
ssh_cert: $('#ssh_cert').val()
},
type: "GET",
success: function( data ) {
data = data.replace(/\s+/g,' ');
if (data.indexOf('alert-danger') != '-1') {
$("#ajax-ssh").append(data);
} else {
$('.alert-danger').remove();
$("#ssh").addClass( "update", 1000 );
setTimeout(function() {
$( "#ssh").removeClass( "update" );
}, 2500 );
$("#ajax-ssh").append(data);
}
}
} );
}

View File

@ -5,6 +5,7 @@ HOME_HAPROXY_WI=haproxy-wi
echo "Choose DB: (1)Sqlite or (2)Mysql? Default: Sqlite" echo "Choose DB: (1)Sqlite or (2)Mysql? Default: Sqlite"
read DB read DB
if [[ $DB == 2 ]];then if [[ $DB == 2 ]];then
echo "Mysql server is (1)remote or (2)local?" echo "Mysql server is (1)remote or (2)local?"
read REMOTE read REMOTE
@ -30,10 +31,13 @@ fi
if [[ -n "$CHHOME_HAPROXY" ]];then if [[ -n "$CHHOME_HAPROXY" ]];then
HOME_HAPROXY_WI=$CHHOME_HAPROXY HOME_HAPROXY_WI=$CHHOME_HAPROXY
fi fi
echo "################################"
echo ""
echo ""
echo -e "Installing Required Software" echo -e "Installing Required Software"
echo ""
echo ""
echo "################################"
if [[ $MINSTALL == 1 ]];then if [[ $MINSTALL == 1 ]];then
yum -y install mariadb mariadb-server mysql-devel yum -y install mariadb mariadb-server mysql-devel
fi fi
@ -42,32 +46,56 @@ yum -y install epel-release && yum -y install git ncat net-tools lshw python34 p
if [ $? -eq 1 ] if [ $? -eq 1 ]
then then
echo "Unable to install Required Packages Please check Yum config" echo "################################"
exit 1 echo ""
echo ""
echo "Unable to install Required Packages Please check Yum config"
echo ""
echo ""
echo "################################"
exit 1
fi fi
echo "################################"
echo ""
echo ""
echo -e "Updating Apache config and Configuring Virtual Host" echo -e "Updating Apache config and Configuring Virtual Host"
echo ""
if [[ $(cat /etc/httpd/conf/httpd.conf |grep "Listen 80") == "Listen 80" ]];then echo ""
sed -i '0,/Listen 80/s//Listen 8080/' /etc/httpd/conf/httpd.conf echo "################################"
if [[ $(cat /etc/httpd/conf/httpd.conf |grep "Listen $PORT") != "Listen %PORT" ]];then
sed -i "0,/^Listen .*/s//Listen $PORT/" /etc/httpd/conf/httpd.conf
fi fi
echo "################################"
echo ""
echo ""
echo -e "Checking for Apache Vhost config" echo -e "Checking for Apache Vhost config"
echo ""
echo ""
echo "################################"
touch /etc/httpd/conf.d/haproxy-wi.conf touch /etc/httpd/conf.d/haproxy-wi.conf
/bin/cat /etc/httpd/conf.d/haproxy-wi.conf /bin/cat /etc/httpd/conf.d/haproxy-wi.conf
if [ $? -eq 1 ] if [ $? -eq 1 ]
then then
echo "Didnt Sense exisitng installation Proceeding ...." echo "################################"
echo ""
exit 1 echo ""
echo "Didnt Sense exisitng installation Proceeding ...."
echo ""
echo ""
echo "################################"
exit 1
else else
echo "################################"
echo -e "Creating VirtulHost for Apache" echo ""
echo ""
echo -e "Creating VirtulHost for Apache"
echo ""
echo ""
echo "################################"
cat << EOF > /etc/httpd/conf.d/haproxy-wi.conf cat << EOF > /etc/httpd/conf.d/haproxy-wi.conf
<VirtualHost *:$PORT> <VirtualHost *:$PORT>
ServerName haprox-wi.example.com ServerName haprox-wi.example.com
@ -88,18 +116,30 @@ cat << EOF > /etc/httpd/conf.d/haproxy-wi.conf
EOF EOF
fi fi
echo "################################"
echo ""
echo ""
echo -e " Testing config" echo -e " Testing config"
echo ""
echo ""
echo "################################"
/usr/sbin/apachectl configtest /usr/sbin/apachectl configtest
if [ $? -eq 1 ] if [ $? -eq 1 ]
then then
echo "apache Configuration Has failed, Please verify Apache Config" echo "apache Configuration Has failed, Please verify Apache Config"
exit 1 echo ""
echo ""
echo "################################"
exit 1
fi fi
echo "################################"
echo ""
echo ""
echo -e "Getting Latest software from The repository" echo -e "Getting Latest software from The repository"
echo ""
echo ""
echo "################################"
mkdir /var/www/$HOME_HAPROXY_WI mkdir /var/www/$HOME_HAPROXY_WI
/usr/bin/git clone https://github.com/Aidaho12/haproxy-wi.git /var/www/$HOME_HAPROXY_WI /usr/bin/git clone https://github.com/Aidaho12/haproxy-wi.git /var/www/$HOME_HAPROXY_WI
@ -108,9 +148,13 @@ then
echo "Unable to clone The repository Please check connetivity to Github" echo "Unable to clone The repository Please check connetivity to Github"
exit 1 exit 1
fi fi
echo "################################"
echo ""
echo ""
echo -e "Installing required Python Packages" echo -e "Installing required Python Packages"
echo ""
echo ""
echo "################################"
/usr/bin/pip3 install -r /var/www/$HOME_HAPROXY_WI/requirements.txt /usr/bin/pip3 install -r /var/www/$HOME_HAPROXY_WI/requirements.txt
if [ $? -eq 1 ] if [ $? -eq 1 ]
@ -118,51 +162,87 @@ then
echo "Unable to install Required Packages, Please check Pip error log and Fix the errors and Rerun the script" echo "Unable to install Required Packages, Please check Pip error log and Fix the errors and Rerun the script"
exit 1 exit 1
else else
echo "################################"
echo -e "Installation Succesful" echo ""
echo ""
echo -e "Installation Succesful"
echo ""
echo ""
echo "################################"
fi fi
if [[ $MINSTALL = 1 ]];then if [[ $MINSTALL = 1 ]];then
echo -e "starting databse and applying config" echo "################################"
echo ""
echo ""
echo -e "starting databse and applying config"
echo ""
echo ""
echo "################################"
systemctl enable mariadb
systemctl start mariadb
systemctl enable mariadb if [ $? -eq 1 ]
systemctl start mariadb then
echo "################################"
echo ""
echo ""
echo "Can't start Mariadb"
echo ""
echo ""
echo "################################"
exit 1
fi
if [ $? -eq 1 ] if [ $? -eq 1 ]
then then
echo "Can't start Mariadb" echo "################################"
exit 1 echo ""
fi echo ""
echo "Unable to start Mariadb Service Please check logs"
echo ""
echo ""
echo "################################"
exit 1
else
if [ $? -eq 1 ] mysql -u root -e "create database haproxywi";
then mysql -u root -e "grant all on haproxywi.* to 'haproxy-wi'@'%' IDENTIFIED BY 'haproxy-wi';"
echo "Unable to start Mariadb Service Please check logs" mysql -u root -e "grant all on haproxywi.* to 'haproxy-wi'@'localhost' IDENTIFIED BY 'haproxy-wi';"
exit 1 mysql -u root -e "flush privileges;"
else
mysql -u root -e "create database haproxywi";
mysql -u root -e "grant all on haproxywi.* to 'haproxy-wi'@'%' IDENTIFIED BY 'haproxy-wi';"
mysql -u root -e "grant all on haproxywi.* to 'haproxy-wi'@'localhost' IDENTIFIED BY 'haproxy-wi';"
mysql -u root -e "flush privileges;"
echo "################################"
echo -e "Databse has been created Succesfully and User permissions added" echo ""
echo ""
echo -e "Databse has been created Succesfully and User permissions added"
echo ""
echo ""
echo "################################"
fi fi
fi fi
if [[ $DB == 2 ]];then if [[ $DB == 2 ]];then
echo -e "Setting Application to use Mysql As a backend" echo "################################"
echo ""
sed -i '0,/enable = 0/s//enable = 1/' /var/www/$HOME_HAPROXY_WI/cgi-bin/haproxy-webintarface.config echo ""
echo -e "Setting Application to use Mysql As a backend"
echo ""
echo ""
echo "################################"
sed -i '0,/enable = 0/s//enable = 1/' /var/www/$HOME_HAPROXY_WI/cgi-bin/haproxy-webintarface.config
fi fi
if [[ -n $IP ]];then if [[ -n $IP ]];then
sed -i "0,/mysql_host = 127.0.0.1/s//mysql_host = $IP/" /var/www/$HOME_HAPROXY_WI/cgi-bin/haproxy-webintarface.config sed -i "0,/mysql_host = 127.0.0.1/s//mysql_host = $IP/" /var/www/$HOME_HAPROXY_WI/cgi-bin/haproxy-webintarface.config
fi fi
echo "################################"
echo ""
echo ""
echo -e " Starting Services" echo -e " Starting Services"
echo ""
echo ""
echo "################################"
systemctl enable httpd ; systemctl restart httpd systemctl enable httpd ; systemctl restart httpd
systemctl enable haproxy ; systemctl start haproxy systemctl enable haproxy ; systemctl start haproxy
@ -170,17 +250,33 @@ echo -e " Starting Services"
if [ $? -eq 1 ] if [ $? -eq 1 ]
then then
echo "Services Has Not been started, Please check error logs" echo "################################"
echo ""
echo ""
echo "Services Has Not been started, Please check error logs"
echo ""
echo ""
echo "################################"
else else
echo "################################"
echo -e "Services have been started, Please Evaluate the tool by adding a host / DNS ectry for /etc/hosts file. \n This can be done by adding an entry like this \n 192.168.1.100 haprox-wi.example.com" echo ""
echo ""
echo -e "Services have been started, Please Evaluate the tool by adding a host / DNS ectry for /etc/hosts file. \n This can be done by adding an entry like this \n 192.168.1.100 haprox-wi.example.com"
echo ""
echo ""
echo "################################"
fi fi
sed -i "s|^fullpath = .*|fullpath = /var/www/$HOME_HAPROXY_WI|g" /var/www/$HOME_HAPROXY_WI/cgi-bin/haproxy-webintarface.config sed -i "s|^fullpath = .*|fullpath = /var/www/$HOME_HAPROXY_WI|g" /var/www/$HOME_HAPROXY_WI/cgi-bin/haproxy-webintarface.config
echo "################################"
echo ""
echo ""
echo -e " Thank You for Evaluating Haproxy-wi" echo -e " Thank You for Evaluating Haproxy-wi"
echo ""
echo ""
echo "################################"
echo "Edit firewalld" echo "Edit firewalld"
firewall-cmd --zone=public --add-port=$PORT/tcp --permanent firewall-cmd --zone=public --add-port=$PORT/tcp --permanent