Просмотр исходного кода

Merge pull request #3 from hestiacp/master

Sync fork with master
ifaist0s 5 лет назад
Родитель
Сommit
2588413e8e
100 измененных файлов с 5054 добавлено и 1333 удалено
  1. 51 15
      CHANGELOG.md
  2. 14 16
      ISSUE_TEMPLATE.md
  3. 21 4
      README.md
  4. 7 0
      SECURITY.md
  5. 7 3
      bin/v-add-dns-record
  6. 1 0
      bin/v-add-firewall-chain
  7. 18 4
      bin/v-add-letsencrypt-domain
  8. 3 1
      bin/v-add-web-domain-ssl
  9. 6 5
      bin/v-add-web-php
  10. 5 2
      bin/v-change-dns-record
  11. 4 0
      bin/v-change-mail-account-password
  12. 0 9
      bin/v-change-sys-webmail
  13. 4 3
      bin/v-change-user-password
  14. 4 0
      bin/v-copy-user-package
  15. 18 7
      bin/v-list-dns-records
  16. 4 0
      bin/v-list-firewall
  17. 1 1
      bin/v-list-sys-db-status
  18. 3 0
      bin/v-list-sys-services
  19. 6 1
      bin/v-restart-system
  20. 1 0
      bin/v-restore-user
  21. 1 11
      bin/v-suspend-dns-record
  22. 1 1
      bin/v-suspend-mail-account
  23. 1 11
      bin/v-unsuspend-dns-record
  24. 1 1
      bin/v-unsuspend-mail-account
  25. 35 2
      bin/v-update-letsencrypt-ssl
  26. 35 18
      bin/v-update-sys-hestia-git
  27. 1 1
      bin/v-update-user-stats
  28. 1 1
      func/db.sh
  29. 5 0
      func/domain.sh
  30. 1 1
      func/rebuild.sh
  31. 25 3
      func/upgrade.sh
  32. 1 1
      install/deb/exim/exim4.conf.template
  33. 1 1
      install/deb/fail2ban/jail.local
  34. 1 0
      install/deb/nginx/phpmyadmin.inc
  35. 1 1
      install/deb/php-fpm/multiphp.tpl
  36. 0 1
      install/deb/templates/web/nginx/php-fpm/default.stpl
  37. 0 1
      install/deb/templates/web/nginx/php-fpm/default.tpl
  38. 1 1
      install/deb/templates/web/php-fpm/default.tpl
  39. 1 1
      install/deb/templates/web/php-fpm/no-php.tpl
  40. 1 1
      install/deb/templates/web/php-fpm/socket.tpl
  41. 2376 0
      install/deb/themes/dark.css
  42. 56 7
      install/deb/themes/flat.css
  43. 57 36
      install/hst-install-debian.sh
  44. 59 36
      install/hst-install-ubuntu.sh
  45. 2 2
      install/hst-install.sh
  46. 18 203
      install/upgrade/versions/latest.sh
  47. 224 0
      install/upgrade/versions/previous/1.1.0.sh
  48. 20 0
      install/upgrade/versions/previous/1.1.1.sh
  49. 1 1
      src/deb/hestia/control
  50. 1 1
      src/deb/hestia/postinst
  51. 1 1
      src/deb/nginx/control
  52. 1 1
      src/deb/php/control
  53. 71 68
      src/deb/php/php.ini
  54. 1 1
      src/hst_autocompile.sh
  55. 2 1
      web/add/dns/index.php
  56. 6 0
      web/add/web/index.php
  57. 1 1
      web/add/webapp/index.php
  58. 1 1
      web/css/jquery-custom-dialogs.css
  59. 209 137
      web/css/styles.min.css
  60. 4 2
      web/edit/dns/index.php
  61. 5 0
      web/edit/server/index.php
  62. 352 348
      web/inc/i18n/cn.php
  63. 1 1
      web/inc/i18n/en.php
  64. 2 2
      web/inc/i18n/es.php
  65. 773 0
      web/inc/i18n/hr.php
  66. 8 5
      web/reset/index.php
  67. 21 6
      web/restart/system/index.php
  68. 0 4
      web/src/app/WebApp/Installers/LaravelSetup.php
  69. 0 4
      web/src/app/WebApp/Installers/SymfonySetup.php
  70. 22 10
      web/templates/admin/add_cron.html
  71. 15 11
      web/templates/admin/add_db.html
  72. 14 10
      web/templates/admin/add_dns.html
  73. 24 10
      web/templates/admin/add_dns_rec.html
  74. 14 10
      web/templates/admin/add_firewall.html
  75. 24 20
      web/templates/admin/add_firewall_banlist.html
  76. 14 10
      web/templates/admin/add_ip.html
  77. 14 10
      web/templates/admin/add_mail.html
  78. 14 10
      web/templates/admin/add_mail_acc.html
  79. 14 10
      web/templates/admin/add_package.html
  80. 14 10
      web/templates/admin/add_user.html
  81. 14 11
      web/templates/admin/add_web.html
  82. 15 11
      web/templates/admin/edit_backup_exclusions.html
  83. 14 10
      web/templates/admin/edit_cron.html
  84. 15 11
      web/templates/admin/edit_db.html
  85. 15 11
      web/templates/admin/edit_dns.html
  86. 25 11
      web/templates/admin/edit_dns_rec.html
  87. 15 11
      web/templates/admin/edit_firewall.html
  88. 15 11
      web/templates/admin/edit_ip.html
  89. 21 14
      web/templates/admin/edit_mail.html
  90. 15 11
      web/templates/admin/edit_mail_acc.html
  91. 15 11
      web/templates/admin/edit_package.html
  92. 15 11
      web/templates/admin/edit_server.html
  93. 14 10
      web/templates/admin/edit_server_bind9.html
  94. 14 10
      web/templates/admin/edit_server_dovecot.html
  95. 14 10
      web/templates/admin/edit_server_httpd.html
  96. 14 10
      web/templates/admin/edit_server_mysql.html
  97. 14 10
      web/templates/admin/edit_server_nginx.html
  98. 14 10
      web/templates/admin/edit_server_pgsql.html
  99. 14 10
      web/templates/admin/edit_server_php.html
  100. 14 10
      web/templates/admin/edit_server_service.html

+ 51 - 15
CHANGELOG.md

@@ -3,29 +3,60 @@ All notable changes to this project will be documented in this file.
 
 ## [CURRENT] - Development
 ### Features
+- Added support for configuring individual TTL per DNS record. Thanks to @jaapmarcus
+
+### Bugfixes
+- Disable Apache2 Server Status Module by default.
+- Do not allow to change the password of a non-hestia user. Thanks to Alexandre Zanni!
+- Use sury repository for Apache2 packages.
+- Check whether Nginx, Apache2 and MariaDB are selected for installation prior to adding third party repositories.
+- Remove duplicated set-cookie line in default fpm config.
+- Adjust let's encrypt validation check for idn domains, thanks to @zanami!
+- Set backup download location on restore for ftp/sftp, thanks to @Daniyal-Javani!
+- Ignore empty lines when listing firewall rules.
+- Changing email account password would fail when similar account names are found.
+- Preserve email quota when (un)suspending and rebuilding mail account.
+- Cleanup temporary file after running v-list-sys-services.
+- Don't calculate /home folder size in v-list-sys-info.
+- Cleanup temporary files when uploading custom SSL cert from WebUi.
+- Cleanup temporary files when adding/renewing letsencrypt SSL cert.
+
+## [1.1.1] - 2020-03-24 - Hotfix
+### Features
+- No new features introduced with v1.1.1, this is strictly a security/bug fix release.
+
+### Bugfixes
+- Fixed phpMyAdmin blowfish and tmp directory issues.
+- Added additional verification of host domain in password reset. Thanks to @FalzoMAD and @mmetince!
+- Fixed issue with rc.local not executing properly.
+- Rework of Let's Encrypt routine to use progressive delay between validation retries.
+- Fixed syntax issue in v-list-sys-db-status which prevented main functions from loading.
+- Removed /home size reporting when running v-list-sys-info due to performance issues.
+- Updated installer to use Ubuntu key server for Hestia APT repository.
+- Fixed duplicate demo mode check in v-change-user-password.
+
+## [1.1.0] - 2020-03-11 - Major Release (Feature / Quality Update)
+### Features
 - Added support for custom user interface themes.
-- Adjusted default font size for improved readability.
-- Added read only/demo mode function if DEMO_MODE is set to yes in hestia.conf.
+- Introduced official Dark and Flat themes.
+- Added read-only/demo mode - DEMO_MODE must be set to yes in hestia.conf to enable.
 - Added php-imagick module to installer and upgrade scripts.
 - Added recidive filter function to fail2ban.
-- Refactored MultiPHP functionality. MultiPHP will be enabled by default on new installations.
-- Allowed admin user to add or remove PHP versions from webui (edit/server->"Web Server" page).
+- Improved and refactored Multi-PHP functionality. 
+- Multi-PHP will be enabled by default on new installations.
+- Allow admin user to add/remove PHP versions from Web UI (Server -> Configure -> Web Server).
 - Extended v-extract-fs-archive to allow archive testing and extracting only specific paths (for tar)
 - Allow renaming of existing packages from console (v-rename-package).
-- Webmail IP address is now inherited from web domain when using multiple IPs.
-- Exim now uses the web domain IP if it exists.
-- Public IP is now used when updating webmail DNS record.
-- Added PHP 7.4 to MultiPHP.
-- Add Support for Debian 10 (Buster).
+- Added PHP 7.4 to Multi-PHP.
+- Addded official support for Debian 10 (Buster).
 
 ### Bugfixes
 - Added a detection of web root for add .well-known ACME challenge.
 - Reworked Let's Encrypt ACME staging to use Hestia code standards.
 - Fixed issues with incorrect font rendering on Windows and Linux.
 - Fixed issues with Let's Encrypt - use Nginx for Let's Encrypt ACME request if present.
-- Reworked v-add-sys-ip, removed CentOS/Red Hat support and reworked conditions.
+- Reworked v-add-sys-ip, removed deprecated CentOS/Red Hat code and reworked conditions.
 - Enabled HSTS and force SSL on v-add-letsencrypt-host.
-- Prevented login action for webmail in list user view.
 - Removed hardcoded mail in HELO data (cosmetic fix).
 - Fixed SFTP server validation check - thanks @dbannik.
 - Implemented security warning message when creating web domains with the default admin account.
@@ -57,18 +88,23 @@ All notable changes to this project will be documented in this file.
 - Fixed MultiPHP upgrade script to update all web templates.
 - Fixed report issue link in installer scripts.
 - Fixed database user authentification on backup restore.
-- Added robots.txt for roundcube webmail to prevent search bot crawling.
+- Added robots.txt for Roundcube webmail to prevent search bot crawling.
 - Re-Enable force ssl function on let's encrypt certification renew.
-- Added official postgresql repository to be up to date.
+- Added official PostgreSQL repository so system stays up-to-date with latest available upstream packages.
 - Hardening MySQL configuration, prevent local infile.
 - Fixed lograte bug and cleans up the messed up nginx/apache2 log permissions.
 - Fixed IfModule mpm_itk.c for apache2 templates.
-- Added mpm_itk for Deb10 single php installation only.
-- Hardening nginx configuration, drop TLSv1.1 support.
+- Added mpm_itk for Debian 10 (non Multi-PHP installations only.)
+- Hardening nginx configuration, dropped support for TLSv1.1.
 - Fixed excluding folders named "logs" from restore backup, thanks to @davidgolsen.
 - Fixed typo in delete psql database part, thanks to @joshbmarshall.
 - Split long txt records to 255 chunks to prevent bind issues, thanks to @setiseta.
 - Fixed missing restart routine for vsftp on v-add-letsencrypt-host.
+- Show amount of disk space consumed by /home when running v-list-sys-info.
+- Remove broken /webmail alias from previous versions.
+- Webmail IP address is now inherited from web domain when using multiple IPs.
+- Exim now uses the web domain IP if it exists.
+- Fix incorrect MX record for DNS domains using the Office 365 template.
 
 ## [1.0.6] - 2019-09-24 - Hotfix
 ### Bugfixes

+ 14 - 16
ISSUE_TEMPLATE.md

@@ -1,11 +1,13 @@
-### The content below is simply a template. 
+### Please fill in the relevant sections below and remove those which do not apply.
 
-**To better assist in troubleshooting and aid with our debugging processes, we ask that you please delete any unnecessary sections below when filling out your issue report.**
+**To help aid our developers in debugging your issue we ask that you include as much information as possible, including the configuration of your server and troubleshooting steps already performed.**
 
-**Important: Please DO NOT include any personal or sensitive information in your issue reports, including usernames, passwords, or email addresses.**
+**Please DO NOT include any personal or sensitive information in your issue reports, including usernames or passwords!**
+
+===
 
 ### In a few words, please describe the issue that you're experiencing:
-Please enter your response here (e.g. When I try adding a web domain, an error message appeared stating that the php-fpm pool did not exist).
+Please enter your answer here (e.g. When I try adding a web domain, an error message appeared stating that the php-fpm pool did not exist).
 
 ### What steps did you take when the issue occured? 
 1. Ex.: Log into the Hestia Control Panel using Firefox
@@ -14,22 +16,25 @@ Please enter your response here (e.g. When I try adding a web domain, an error m
 4. Ex.: Attempted to add a domain and received an error.
 
 ### Expected behavior:
-Please enter your response here (e.g. the web domain should have been added successfully).
+Please enter your answer here (e.g. the web domain should have been added successfully).
+
+### Does this issue always occur, or is it intermittent?
+Please enter your answer here (e.g. it happens every time I try to perform the steps above).
 
 ### Operating system distribution and release:
-Please enter your response here (e.g. Ubuntu 18.04.3 LTS)
+Please enter your answer here (e.g. Ubuntu 18.04.3 LTS)
 
 ### Which version of Hestia Control Panel is currently installed?
 You can find this information in $HESTIA/conf/hestia.conf by running the following command:
 `grep VERSION $HESTIA/conf/hestia.conf`
 
-Please enter your response here (e.g. 1.0.6)
+Please enter your answer here (e.g. 1.1.0)
 
 ### Which branch are you using?
-Please enter your response here (e.g release, master, etc.)
+Please enter your answer here (e.g release, master, etc.)
 
 ### When did this issue occur? After a clean installation, or after an upgrade?
-Please enter your response here (e.g the feature stopped working after upgrading to the latest release)
+Please enter your answer here (e.g the feature stopped working after upgrading to the latest release)
 
 **Note:** If you have upgraded from an older release on an existing server, please let us know which version was previously installed if at all possible.
 
@@ -40,13 +45,6 @@ Please enter your response here (e.g the feature stopped working after upgrading
 - PHP-FPM + Multi-PHP
 - Other (please specify)
 
-### Which of the following server roles are installed on your server?
-- DNS
-- Mail (Dovecot + Exim)
-- Mail (Exim only)
-- MySQL (MariaDB)
-- PostgreSQL
-
 ### In order to better assist, please post any relevant log information below:
 Tip: Most log files can be found under ***/var/log/***.
 

+ 21 - 4
README.md

@@ -1,7 +1,12 @@
 [Hestia Control Panel](https://www.hestiacp.com/)
 ==================================================
-**Current stable release:** Version 1.0.6, released on September 26th, 2019.<br>
-**Current development release:** Version 1.1.0, release date yet to be determined.
+**Current stable release:** Version 1.1.1, released on March 26th, 2020.<br>
+**Current development release:** Version 1.1.2.
+<br><br>
+**Due to a change of the repository infrastructure, please install the new key before you upgrade your existing installations:**
+```bash
+wget -qO - https://gpg.hestiacp.com/deb_signing.key | sudo apt-key add -
+```
 
 **Welcome!**
 ---------------------------- 
@@ -29,7 +34,7 @@ What does Hestia Control Panel support?
 ----------------------------
 * Standard Web Server (Apache/NGINX) with PHP
 * PHP Web Application Server (NGINX + PHP-FPM)
-* Multiple PHP versions (5.6 - 7.3)
+* Multiple PHP versions (5.6 - 7.4, with 7.3 currently as default for optimal compatibility)
 * DNS Server (Bind) with clustering capabilities
 * Mail Server (Exim/Dovecot) with Anti-Virus and Anti-Spam (ClamAV and SpamAssassin)
 * Database functionality (MariaDB/PostgreSQL)
@@ -37,7 +42,7 @@ What does Hestia Control Panel support?
 
 Supported operating systems:
 ----------------------------
-* Debian 8 or 9
+* Debian 8, 9, 10
 * Ubuntu 16.04 LTS or Ubuntu 18.04 LTS (the latest LTS release is recommended)
 * **NOTE:** Hestia Control Panel must be installed on top of a fresh operating system installation to ensure proper functionality.
 
@@ -116,3 +121,15 @@ If you would like to help our developers cover their time and infrastucture cost
 License
 =============================
 Hestia Control Panel is licensed under [GPL v3](https://github.com/hestiacp/hestiacp/blob/master/LICENSE) license, and is based on the [VestaCP](https://www.vestacp.com/) project.<br>
+
+Copyright
+=============================
+"Hestia Control Panel", "HestiaCP", and the Hestia logo are original copyright of hestiacp.com and the following restrictions apply:
+
+**You are allowed to:**
+- use the names "Hestia Control Panel", "HestiaCP", or the Hestia logo in any context directly related to the application or the project. This includes the application itself, local communities and news or blog posts.
+
+**You are not allowed to:**
+- sell or redistribute the application under the name "Hestia Control Panel", "HestiaCP", or similar derivatives, including the use of the Hestia logo in any brand or marketing materials related to revenue generating activities,
+- use the names "Hestia Control Panel", "HestiaCP", or the Hestia logo in any context that is not related to the project,
+- alter the name "Hestia Control Panel", "HestiaCP", or the Hestia logo in any way.

+ 7 - 0
SECURITY.md

@@ -0,0 +1,7 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+If you have discovered a vulnerability in Hestia Control Panel,
+let our development team know via e-mail at info@hestiacp.com and
+we will respond as soon as possible.

+ 7 - 3
bin/v-add-dns-record

@@ -1,6 +1,6 @@
 #!/bin/bash
 # info: add dns record
-# options: USER DOMAIN RECORD TYPE VALUE [PRIORITY] [ID] [RESTART]
+# options: USER DOMAIN RECORD TYPE VALUE [PRIORITY] [ID] [RESTART] [TTL]
 #
 # The call is used for adding new DNS record. Complex records of TXT, MX and
 # SRV types can be used by a filling in the 'value' argument. The function also
@@ -23,6 +23,8 @@ dvalue=$(idn -t --quiet -u "$5" )
 priority=$6
 id=$7
 restart=$8
+ttl=$9
+
 if [ -z "$priority" ]; then
     priority=10
 fi
@@ -69,7 +71,7 @@ format_domain_idn
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '5' "$#" 'USER DOMAIN RECORD TYPE VALUE [PRIORITY] [ID] [RESTART]'
+check_args '5' "$#" 'USER DOMAIN RECORD TYPE VALUE [PRIORITY] [ID] [RESTART] [TTL]'
 is_format_valid 'user' 'domain' 'record' 'rtype' 'dvalue'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
@@ -82,6 +84,7 @@ is_format_valid 'id'
 is_object_new "dns/$domain" 'ID' "$id"
 is_dns_fqnd "$rtype" "$dvalue"
 is_dns_nameserver_valid "$domain" "$rtype" "$dvalue"
+is_format_valid 'ttl'
 
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
@@ -100,7 +103,8 @@ date=$(echo "$time_n_date" |cut -f 2 -d \ )
 zone="$USER_DATA/dns/$domain.conf"
 dns_rec="ID='$id' RECORD='$record' TYPE='$rtype' PRIORITY='$priority'"
 dns_rec="$dns_rec VALUE='$dvalue' SUSPENDED='no' TIME='$time' DATE='$date'"
-echo "$dns_rec" >> $zone
+[ ! -z "$ttl" ] && dns_rec="$dns_rec TTL='$ttl'"
+echo "$dns_rec" >> $zone;
 chmod 660 $zone
 
 # Sorting records

+ 1 - 0
bin/v-add-firewall-chain

@@ -62,6 +62,7 @@ case $chain in
     WEB)        port='80,443'; protocol=TCP  ;;
     DB)         port='3306,5432'; protocol=TCP  ;;
     HESTIA)     port=$hestiaport; protocol=TCP  ;;
+    RECIDIVE)   port='1:65535'; protocol=TCP  ;;
     *)          check_args '2' "$#" 'CHAIN PORT' ;;
 esac
 

+ 18 - 4
bin/v-add-letsencrypt-domain

@@ -134,7 +134,10 @@ fi
 # Check if dns records exist for requested domain/aliases
 if [ "$proto" = "http-01" ]; then
     for identifier in $(echo $domain,$aliases |tr ',' '\n' |sort -u); do
-        if ! nslookup "${identifier}" >/dev/null 2>&1 ; then
+        if [[ "$identifier" = *[![:ascii:]]* ]]; then
+            identifier=$(idn -t --quiet -a $identifier)
+        fi
+        if ! nslookup "${identifier}" > /dev/null 2>&1 ; then
             check_result $E_NOTEXIST "DNS record for $identifier doesn't exist"
         fi
     done
@@ -285,6 +288,7 @@ for auth in $authz; do
         validation='valid'
     else
         validation='pending'
+        sleep 5
     fi
 
     # Doing pol check on status
@@ -326,7 +330,7 @@ for auth in $authz; do
             fi
             check_result $E_CONNECT "Let's Encrypt domain validation timeout"
         fi
-        sleep 1
+        sleep $((i*2))
     done
     if [ "$validation" = 'invalid' ]; then
         # Delete DNS CAA record
@@ -339,7 +343,7 @@ for auth in $authz; do
                     $BIN/v-delete-dns-record $user $domain $caa_record
                 fi
             fi
-        fi    
+        fi
         check_result $E_CONNECT "Let's Encrypt domain verification failed"
     fi
 done
@@ -356,6 +360,7 @@ nonce=$(echo "$answer" |grep -i nonce |cut -f2 -d \ |tr -d '\r\n')
 status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
 certificate=$(echo "$answer"|grep 'certificate":' |cut -f4 -d '"')
 if [[ "$status" -ne 200 ]]; then
+    [ -d "$ssl_dir" ] && rm -rf "$ssl_dir"
     check_result $E_CONNECT "Let's Encrypt finalize bad status $status"
 fi
 
@@ -363,6 +368,7 @@ fi
 answer=$(query_le_v2 "$certificate" "" "$nonce" "$ssl_dir/$domain.pem")
 status=$(echo "$answer"|grep HTTP/ |tail -n1 |cut -f 2 -d ' ')
 if [[ "$status" -ne 200 ]]; then
+    [ -d "$ssl_dir" ] && rm -rf "$ssl_dir"
     check_result $E_NOTEXIST "Let's Encrypt downloading signed cert failed status:$status"
 fi
 
@@ -399,11 +405,12 @@ if [ -z "$mail" ]; then
     [[ "$ssl_force" = "yes" ]] && $BIN/v-add-web-domain-ssl-force $user $domain > /dev/null 2>&1
 else
     ssl_enabled="$(get_object_value 'mail' 'DOMAIN' "$root_domain" '$SSL')"
-    [[ "$ssl_enabled" = "yes" ]] && $BIN/v-delete-mail-domain-ssl $user $root_domain >/dev/null 2>&1
+    [[ "$ssl_enabled" = "yes" ]] && $BIN/v-delete-mail-domain-ssl $user $root_domain > /dev/null 2>&1
     $BIN/v-add-mail-domain-ssl $user $root_domain $ssl_dir
 fi
 
 if [ "$?" -ne '0' ]; then
+    [ -d "$ssl_dir" ] && rm -rf "$ssl_dir"
     touch $HESTIA/data/queue/letsencrypt.pipe
     sed -i "/ $domain /d" $HESTIA/data/queue/letsencrypt.pipe
     send_notice 'LETSENCRYPT' "$domain certificate installation failed"
@@ -422,13 +429,17 @@ fi
 if [ -z "$mail" ]; then
     if [ -z "$LETSENCRYPT" ]; then
         add_object_key "web" 'DOMAIN' "$domain" 'LETSENCRYPT' 'FTP_USER'
+        add_object_key "web" 'DOMAIN' "$domain" 'LETSENCRYPT_FAIL_COUNT' 'LETSENCRYPT'
     fi
     update_object_value 'web' 'DOMAIN' "$domain" '$LETSENCRYPT' 'yes'
+    update_object_value 'web' 'DOMAIN' "$domain" '$LETSENCRYPT_FAIL_COUNT' "0"
 else
     if [ -z "$LETSENCRYPT" ]; then
         add_object_key "mail" 'DOMAIN' "$root_domain" 'LETSENCRYPT'
+        add_object_key "mail" 'DOMAIN' "$root_domain" 'LETSENCRYPT_FAIL_COUNT' 'LETSENCRYPT'
     fi
     update_object_value 'mail' 'DOMAIN' "$root_domain" '$LETSENCRYPT' 'yes'
+    update_object_value 'mail' 'DOMAIN' "$root_domain" '$LETSENCRYPT_FAIL_COUNT' "0"
 fi
 
 # Remove challenge folder if exist
@@ -436,6 +447,9 @@ if [ ! -z "$well_known" ]; then
     rm -fr $well_known
 fi
 
+# Remove temporary SSL folder
+[ -d "$ssl_dir" ] && rm -rf "$ssl_dir"
+
 #----------------------------------------------------------#
 #                        Hestia                            #
 #----------------------------------------------------------#

+ 3 - 1
bin/v-add-web-domain-ssl

@@ -109,7 +109,6 @@ if [ ! -z "$PROXY_SYSTEM" ] && [ ! -z "$PROXY" ]; then
     add_web_config "$PROXY_SYSTEM" "$PROXY.stpl"
 fi
 
-
 #----------------------------------------------------------#
 #                       Hestia                             #
 #----------------------------------------------------------#
@@ -121,6 +120,9 @@ increase_user_value "$user" '$U_WEB_SSL'
 update_object_value 'web' 'DOMAIN' "$domain" '$SSL_HOME' "$SSL_HOME"
 update_object_value 'web' 'DOMAIN' "$domain" '$SSL' "yes"
 
+# Enabling automatic SSL redirection
+$BIN/v-add-web-domain-ssl-force "$user" "$domain"
+
 # Restarting web server
 $BIN/v-restart-web $restart
 check_result $? "Web restart failed" >/dev/null

+ 6 - 5
bin/v-add-web-php

@@ -55,19 +55,20 @@ check_hestia_demo_mode
 mph="php$version-mbstring php$version-bcmath php$version-cli php$version-curl
      php$version-fpm php$version-gd php$version-intl php$version-mysql
      php$version-soap php$version-xml php$version-zip php$version-mbstring
-     php$version-json php$version-bz2 php$version-pspell php$version-imagick php$version-pgsql"
+     php$version-json php$version-bz2 php$version-pspell php$version-imagick php$version-pgsql
+     php$version-imap php$version-ldap"
 
 # Check is version is 7.1 or below to add mcrypt
 if [[ `echo "$version 7.2" | awk '{print ($1 < $2)}'` == 1 ]]; then
     mph="$mph php$version-mcrypt"
 fi
 
-if [ -z "$DB_SYSTEM" -o "$DB_SYSTEM" = "mysql" ]; then
-    mph=$(echo "$mph" | sed -e "s/php$version-pgsql//")
+if ! echo "$DB_SYSTEM" | grep -w 'mysql' >/dev/null; then
+    mph=$(echo "$mph" | sed -e "s/php$version-mysql//")
 fi
 
-if [ -z "$DB_SYSTEM" -o "$DB_SYSTEM" = "pgsql" ]; then
-    mph=$(echo "$mph" | sed -e "s/php$version-mysql//")
+if ! echo "$DB_SYSTEM" | grep -w 'pgsql' >/dev/null; then
+    mph=$(echo "$mph" | sed -e "s/php$version-pgsql//")
 fi
 
 # Install php packages

+ 5 - 2
bin/v-change-dns-record

@@ -1,6 +1,6 @@
 #!/bin/bash
 # info: change dns domain record
-# options: USER DOMAIN ID VALUE [PRIORITY] [RESTART]
+# options: USER DOMAIN ID VALUE [PRIORITY] [RESTART] [TTL]
 #
 # The function for changing DNS record.
 
@@ -19,6 +19,7 @@ type=$5
 dvalue=$(idn -t --quiet -u "$6" )
 priority=$7
 restart=$8
+ttl=$9
 
 # Includes
 source $HESTIA/func/main.sh
@@ -35,7 +36,7 @@ format_domain_idn
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '6' "$#" 'USER DOMAIN ID RECORD TYPE VALUE [PRIORITY] [RESTART]'
+check_args '6' "$#" 'USER DOMAIN ID RECORD TYPE VALUE [PRIORITY] [RESTART] [TTL]'
 is_format_valid 'user' 'domain' 'id' 'record' 'type' 'dvalue'
 is_system_enabled "$DNS_SYSTEM" 'DNS_SYSTEM'
 is_object_valid 'user' 'USER' "$user"
@@ -43,6 +44,7 @@ is_object_unsuspended 'user' 'USER' "$user"
 is_object_valid 'dns' 'DOMAIN' "$domain"
 is_object_unsuspended 'dns' 'DOMAIN' "$domain"
 is_object_valid "dns/$domain" 'ID' "$id"
+is_format_valid 'ttl'
 
 # Perform verification if read-only mode is enabled
 check_hestia_demo_mode
@@ -84,6 +86,7 @@ date=$(echo "$time_n_date" |cut -f 2 -d \ )
 # Adding record
 dns_rec="ID='$id' RECORD='$record' TYPE='$type' PRIORITY='$priority'"
 dns_rec="$dns_rec VALUE='$dvalue' SUSPENDED='no' TIME='$time' DATE='$date'"
+[ ! -z "$ttl" ] && dns_rec="$dns_rec TTL='$ttl'"
 echo "$dns_rec" >> $USER_DATA/dns/$domain.conf
 
 # Sorting records

+ 4 - 0
bin/v-change-mail-account-password

@@ -55,6 +55,10 @@ salt=$(generate_password "$PW_MATRIX" "8")
 md5="{MD5}$($BIN/v-generate-password-hash md5 $salt <<<$password)"
 
 if [[ "$MAIL_SYSTEM" =~ exim ]]; then
+    quota=$(get_object_value "mail/$domain" 'ACCOUNT' "$account" '$QUOTA')
+    if [ "$quota" = 'unlimited' ]; then
+        quota=0
+    fi
     sed -i "/^$account:/d" $HOMEDIR/$user/conf/mail/$domain/passwd
     str="$account:$md5:$user:mail::$HOMEDIR/$user::userdb_quota_rule=*:storage=${quota}M"
     echo $str >> $HOMEDIR/$user/conf/mail/$domain/passwd

+ 0 - 9
bin/v-change-sys-webmail

@@ -45,15 +45,6 @@ for user in $($HESTIA/bin/v-list-sys-users plain); do
     done
 done
 
-# Update global directory alias configuration
-if [ "$WEB_SYSTEM" = "apache2" ]; then
-    sed -i "s|Alias \/$OLD_ALIAS|Alias \/$NEW_ALIAS|gI" /etc/apache2/conf.d/roundcube.conf
-fi
-if [ -e "/etc/nginx/conf.d/webmail.inc" ]; then
-    sed -i "s|location \/$OLD_ALIAS|location \/$NEW_ALIAS|gI" /etc/nginx/conf.d/webmail.inc
-    sed -i "s|location ~ ^\/$OLD_ALIAS|location ~ ^\/$NEW_ALIAS|gI" /etc/nginx/conf.d/webmail.inc
-fi
-
 #----------------------------------------------------------#
 #                       Hestia                             #
 #----------------------------------------------------------#

+ 4 - 3
bin/v-change-user-password

@@ -13,6 +13,10 @@
 user=$1
 password=$2; HIDE=2
 
+# Importing system enviroment  as we run this script
+# mostly by cron wich not read it by itself
+source /etc/profile
+
 # Includes
 source $HESTIA/func/main.sh
 source $HESTIA/conf/hestia.conf
@@ -42,9 +46,6 @@ if [ "$user" = 'admin' ] && [ -e "$HESTIA/web/reset.admin" ]; then
     rm -f $HESTIA/web/reset.admin
 fi
 
-# Perform verification if read-only mode is enabled
-check_hestia_demo_mode
-
 
 #----------------------------------------------------------#
 #                       Hestia                             #

+ 4 - 0
bin/v-copy-user-package

@@ -16,6 +16,10 @@ new_package=$2
 source $HESTIA/func/main.sh
 source $HESTIA/conf/hestia.conf
 
+
+# Perform verification if read-only mode is enabled
+check_hestia_demo_mode
+
 #----------------------------------------------------------#
 #                       Action                             #
 #----------------------------------------------------------#

+ 18 - 7
bin/v-list-dns-records

@@ -24,7 +24,9 @@ json_list() {
     objects=$(grep ID $USER_DATA/dns/$domain.conf |wc -l)
     echo "{"
     while read str; do
+        unset TTL
         parse_object_kv_list "$str"
+        [ -z "$TTL" ] && TTL="$zone_ttl"
         VALUE=$(echo "$VALUE" |sed -e 's/"/\\"/g' -e "s/%quote%/'/g")
         echo -n '    "'$ID'": {
         "RECORD": "'$RECORD'",
@@ -34,7 +36,8 @@ json_list() {
         "ID": "'$ID'",
         "SUSPENDED": "'$SUSPENDED'",
         "TIME": "'$TIME'",
-        "DATE": "'$DATE'"
+        "DATE": "'$DATE'",
+        "TTL": "'$TTL'"
     }'
         if [ "$i" -lt "$objects" ]; then
             echo ','
@@ -49,11 +52,13 @@ json_list() {
 # SHELL list function
 shell_list() {
     IFS=$'\n'
-    echo "ID^RECORD^TYPE^VALUE^DATE"
-    echo "--^------^----^-----^----"
+    echo "ID^RECORD^TYPE^VALUE^DATE^TTL"
+    echo "--^------^----^-----^----^----"
     while read str; do
+        unset TTL
         parse_object_kv_list "$str"
-        echo "$ID^$RECORD^$TYPE^${VALUE:0:30}^$DATE"
+        [ -z "$TTL" ] && TTL="$zone_ttl"
+        echo "$ID^$RECORD^$TYPE^${VALUE:0:30}^$DATE^$TTL"
     done < <(cat $USER_DATA/dns/$domain.conf)
 }
 
@@ -61,22 +66,26 @@ shell_list() {
 plain_list() {
     IFS=$'\n'
     while read str; do
+        unset TTL
         parse_object_kv_list "$str"
+        [ -z "$TTL" ] && TTL="$zone_ttl"
         VALUE=$(echo "$VALUE" |sed -e "s/%quote%/\\'/g")
         echo -ne "$ID\t$RECORD\t$TYPE\t$PRIORITY\t$VALUE\t"
-        echo -e "$SUSPENDED\t$TIME\t$DATE"
+        echo -e "$SUSPENDED\t$TIME\t$DATE\t$TTL"
     done < <(cat $USER_DATA/dns/$domain.conf)
 }
 
 # CSV list function
 csv_list() {
     IFS=$'\n'
-    echo "ID,RECORD,TYPE,PRIORITY,VALUE,SUSPENDED,TIME,DATE"
+    echo "ID,RECORD,TYPE,PRIORITY,VALUE,SUSPENDED,TIME,DATE,TTL"
     while read str; do
+        unset TTL
         parse_object_kv_list "$str"
+        [ -z "$TTL" ] && TTL="$zone_ttl"
         VALUE=$(echo "$VALUE" |sed -e "s/%quote%/\\'/g")
         echo -n "$ID,$RECORD,$TYPE,$PRIORITY,\"$VALUE\","
-        echo "$SUSPENDED,$TIME,$DATE"
+        echo "$SUSPENDED,$TIME,$DATE,$TTL"
     done < <(cat $USER_DATA/dns/$domain.conf)
 }
 
@@ -95,6 +104,8 @@ is_object_valid 'dns' 'DOMAIN' "$domain"
 #                       Action                             #
 #----------------------------------------------------------#
 
+zone_ttl="$(get_object_value 'dns' 'DOMAIN' "$domain" '$TTL')"
+
 # Listing data
 case $format in
     json)   json_list ;;

+ 4 - 0
bin/v-list-firewall

@@ -22,6 +22,7 @@ json_list() {
     objects=$(grep RULE $HESTIA/data/firewall/rules.conf |wc -l)
     echo "{"
     while read str; do
+        [[ -z "$str" ]] && continue;
         parse_object_kv_list "$str"
         echo -n '    "'$RULE'": {
         "ACTION": "'$ACTION'",
@@ -49,6 +50,7 @@ shell_list() {
     echo "RULE^ACTION^PROTO^PORT^IP^SPND^DATE"
     echo "----^------^-----^----^--^----^----"
     while read str; do
+        [[ -z "$str" ]] && continue;
         parse_object_kv_list "$str"
         echo "$RULE^$ACTION^$PROTOCOL^$PORT^$IP^$SUSPENDED^$DATE"
     done < <(cat $HESTIA/data/firewall/rules.conf)
@@ -58,6 +60,7 @@ shell_list() {
 plain_list() {
     IFS=$'\n'
     while read str; do
+        [[ -z "$str" ]] && continue;
         parse_object_kv_list "$str"
         echo -ne "$RULE\t$ACTION\t$PROTOCOL\t$PORT\t$IP\t$COMMENT\t"
         echo -e "$SUSPENDED\t$TIME\t$DATE"
@@ -69,6 +72,7 @@ csv_list() {
     IFS=$'\n'
     echo "RULE,ACTION,PROTOCOL,PORT,IP,COMMENT,SUSPENDED,TIME,DATE"
     while read str; do
+        [[ -z "$str" ]] && continue;
         parse_object_kv_list "$str"
         echo -n "$RULE,$ACTION,$PROTOCOL,$PORT,$IP,\"$COMMENT\","
         echo "$SUSPENDED,$TIME,$DATE"

+ 1 - 1
bin/v-list-sys-db-status

@@ -13,7 +13,7 @@
 #format=${1-shell}
 
 # Includes
-#source $HESTIA/func/main.sh
+source $HESTIA/func/main.sh
 source $HESTIA/conf/hestia.conf
 
 #----------------------------------------------------------#

+ 3 - 0
bin/v-list-sys-services

@@ -297,6 +297,9 @@ case $format in
     shell)  shell_list |column -t ;;
 esac
 
+if [ -f "$tmp_file" ]; then
+    rm -f "$tmp_file"
+fi
 
 #----------------------------------------------------------#
 #                       Hestia                             #

+ 6 - 1
bin/v-restart-system

@@ -11,6 +11,7 @@
 
 # Argument definition
 restart=$1
+delay=$2
 
 # Includes
 source $HESTIA/func/main.sh
@@ -20,7 +21,7 @@ source $HESTIA/func/main.sh
 #                    Verifications                         #
 #----------------------------------------------------------#
 
-check_args '1' "$#" 'RESTART'
+check_args '1' "$#" 'RESTART [DELAY]'
 
 
 # Perform verification if read-only mode is enabled
@@ -31,6 +32,10 @@ check_hestia_demo_mode
 #----------------------------------------------------------#
 
 if [  "$restart" = 'yes' ]; then
+    if [ "$delay" ]; then
+        echo "The server will restart in $delay seconds..."
+        sleep $delay
+    fi
     /sbin/reboot
 fi
 

+ 1 - 0
bin/v-restore-user

@@ -41,6 +41,7 @@ ftpc() {
     /usr/bin/ftp -n $HOST $PORT <<EOF
     quote USER $USERNAME
     quote PASS $PASSWORD
+    lcd $BACKUP
     binary
     $1
     $2

+ 1 - 11
bin/v-suspend-dns-record

@@ -48,17 +48,7 @@ check_hestia_demo_mode
 #                       Action                             #
 #----------------------------------------------------------#
 
-line=$(grep "ID='$id'" $USER_DATA/dns/$domain.conf)
-parse_object_kv_list "$line"
-sed -i "/^ID='$id'/d" $USER_DATA/dns/$domain.conf
-
-# Adding record
-dns_rec="ID='$id' RECORD='$RECORD' TYPE='$TYPE' PRIORITY='$PRIORITY'"
-dns_rec="$dns_rec VALUE='$VALUE' SUSPENDED='yes' TIME='$TIME' DATE='$DATE'"
-echo "$dns_rec" >> $USER_DATA/dns/$domain.conf
-
-# Sorting records
-sort_dns_records
+update_object_value "dns/$domain" 'ID' "$id"  '$SUSPENDED' "yes"
 
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then

+ 1 - 1
bin/v-suspend-mail-account

@@ -54,7 +54,7 @@ if [[ "$MAIL_SYSTEM" =~ exim ]]; then
       quota=0                                                                                              
     fi
     sed -i "/^$account:/d" $HOMEDIR/$user/conf/mail/$domain/passwd
-    str="$account:SUSPENDED:$user:mail::$HOMEDIR/$user:$quota"
+    str="$account:SUSPENDED:$user:mail::$HOMEDIR/$user::userdb_quota_rule=*:storage=${quota}M"
     echo $str >> $HOMEDIR/$user/conf/mail/$domain/passwd
 fi
 

+ 1 - 11
bin/v-unsuspend-dns-record

@@ -44,17 +44,7 @@ is_object_valid "dns/$domain" 'ID' "$id"
 #                       Action                             #
 #----------------------------------------------------------#
 
-line=$(grep "ID='$id'" $USER_DATA/dns/$domain.conf)
-parse_object_kv_list "$line"
-sed -i "/^ID='$id'/d" $USER_DATA/dns/$domain.conf
-
-# Adding record
-dns_rec="ID='$id' RECORD='$RECORD' TYPE='$TYPE' PRIORITY='$PRIORITY'"
-dns_rec="$dns_rec VALUE='$VALUE' SUSPENDED='no' TIME='$TIME' DATE='$DATE'"
-echo "$dns_rec" >> $USER_DATA/dns/$domain.conf
-
-# Sorting records
-sort_dns_records
+update_object_value "dns/$domain" 'ID' "$id"  '$SUSPENDED' "no"
 
 # Updating zone
 if [[ "$DNS_SYSTEM" =~ named|bind ]]; then

+ 1 - 1
bin/v-unsuspend-mail-account

@@ -52,7 +52,7 @@ if [[ "$MAIL_SYSTEM" =~ exim ]]; then
         quota=0
     fi
     sed -i "/^$account:/d" $HOMEDIR/$user/conf/mail/$domain/passwd
-    str="$account:$md5:$user:mail::$HOMEDIR/$user:$quota"
+    str="$account:$md5:$user:mail::$HOMEDIR/$user::userdb_quota_rule=*:storage=${quota}M"
     echo $str >> $HOMEDIR/$user/conf/mail/$domain/passwd
 fi
 

+ 35 - 2
bin/v-update-letsencrypt-ssl

@@ -24,12 +24,24 @@ source $HESTIA/conf/hestia.conf
 
 # Set LE counter
 lecounter=0
+max_LE_failures=30
 
 # Checking user certificates
 for user in $($HESTIA/bin/v-list-sys-users plain); do
     USER_DATA=$HESTIA/data/users/$user
 
     for domain in $(search_objects 'web' 'LETSENCRYPT' 'yes' 'DOMAIN'); do
+
+        domain_suspended="$(get_object_value 'web' 'DOMAIN' "$domain" '$SUSPENDED')"
+        if [ "$domain_suspended" = "yes" ]; then
+            continue
+        fi
+
+        fail_counter="$(get_object_value 'web' 'DOMAIN' "$domain" '$LETSENCRYPT_FAIL_COUNT')"
+        if [[ "$fail_counter" -gt "$max_LE_failures" ]]; then
+            continue
+        fi
+
         crt_data=$(openssl x509 -text -in $USER_DATA/ssl/$domain.crt)
         not_after=$(echo "$crt_data" |grep "Not After" |cut -f 2,3,4 -d :)
         expiration=$(date -d "$not_after" +%s)
@@ -48,12 +60,28 @@ for user in $($HESTIA/bin/v-list-sys-users plain); do
             aliases=$(echo "$aliases" |sed -e ':a;N;$!ba;s/\n/,/g')
             msg=$($BIN/v-add-letsencrypt-domain $user $domain $aliases)
             if [ $? -ne 0 ]; then
-                echo "$domain $msg"
+                log_event $E_INVALID "$domain $msg"
+                if [ -z "$fail_counter" ]; then
+                    add_object_key "web" 'DOMAIN' "$domain" 'LETSENCRYPT_FAIL_COUNT' 'LETSENCRYPT'
+                fi
+                ((fail_counter++))
+                update_object_value 'web' 'DOMAIN' "$domain" '$LETSENCRYPT_FAIL_COUNT' "$fail_counter"
             fi
         fi
     done
 
     for domain in $(search_objects 'mail' 'LETSENCRYPT' 'yes' 'DOMAIN'); do
+
+        domain_suspended="$(get_object_value 'mail' 'DOMAIN' "$domain" '$SUSPENDED')"
+        if [ "$domain_suspended" = "yes" ]; then
+            continue
+        fi
+
+        fail_counter="$(get_object_value 'mail' 'DOMAIN' "$domain" '$LETSENCRYPT_FAIL_COUNT')"
+        if [[ "$fail_counter" -gt "$max_LE_failures" ]]; then
+            continue
+        fi
+
         crt_data=$(openssl x509 -text -in $USER_DATA/ssl/mail.$domain.crt)
         not_after=$(echo "$crt_data" |grep "Not After" |cut -f 2,3,4 -d :)
         expiration=$(date -d "$not_after" +%s)
@@ -67,7 +95,12 @@ for user in $($HESTIA/bin/v-list-sys-users plain); do
             ((lecounter++))
             msg=$($BIN/v-add-letsencrypt-domain $user $domain ' ' yes)
             if [ $? -ne 0 ]; then
-                echo "$domain $msg"
+                log_event $E_INVALID "$domain $msg"
+                if [ -z "$fail_counter" ]; then
+                    add_object_key "mail" 'DOMAIN' "$domain" 'LETSENCRYPT_FAIL_COUNT' 'LETSENCRYPT'
+                fi
+                ((fail_counter++))
+                update_object_value 'mail' 'DOMAIN' "$domain" '$LETSENCRYPT_FAIL_COUNT' "$fail_counter"
             fi
         fi
     done

+ 35 - 18
bin/v-update-sys-hestia-git

@@ -90,19 +90,13 @@ if [ ! -z "$1" ]; then
         exit 1
     else
         /usr/local/hestia/bin/v-change-sys-config-value 'RELEASE_BRANCH' "$branch"
-        echo "Changed update release branch to $branch from GitHub repository."
+        echo "Changed release branch to $branch."
     fi
 else
     source /usr/local/hestia/conf/hestia.conf
     branch=$RELEASE_BRANCH
 fi
 
-if [ ! -z "$2" ]; then
-    install=$2
-else
-    install="y"
-fi
-
 if [ -z "$branch" ]; then
     echo "No branch detected, please provide one using: v-update-sys-hestia-git branch"
     exit
@@ -373,19 +367,42 @@ fi
 #
 #################################################################################
 
-if [ "$install" = 'yes' ] || [ "$install" = 'y' ]; then
-    echo "!!! Development builds should not be installed on systems with live production data without understanding the potential risks involved. !!!"
-    read -p 'Do you want to proceed the package installation? [y/n] ' answer
+# Define package installation functions
+warning_message() {
+    echo ""
+    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+    echo "WARNING - Development builds should not be installed on"
+    echo "systems with live production data without understanding"
+    echo "the potential risks that are involved!"
+    echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+    echo ""
+}
+
+install_build() {
+    echo "Installing packages..."
+    for i in $DEB_DIR/*.deb; do
+        # Install all available packages
+        dpkg -i $i
+    done
+    # Remove temporary files
+    rm -rf $BUILD_DIR
+}
+
+# Define installation routine
+
+if [ "$install" = "yes" ]; then 
+    install_build
+else
+    warning_message
+    read -p "Do you wish to proceed with the installation? [y/n] " answer
     if [ "$answer" = 'y' ] || [ "$answer" = 'Y'  ]; then
-        echo "Installing packages..."
-        for i in $DEB_DIR/*.deb; do
-            # Install all available packages
-            dpkg -i $i
-        done
+        install_build
         unset $answer
-        # Remove temporary files
-        rm -rf $BUILD_DIR
     else
-        check_result 1 "Package installation cancelled..."
+        echo "Installation of development build aborted."
+        echo "Removing temporary files..."
+        rm -rf $BUILD_DIR
+        unset $answer
+        echo ""
     fi
 fi

+ 1 - 1
bin/v-update-user-stats

@@ -73,7 +73,7 @@ for user in $user_list; do
     fi
     USER_DATA=$HESTIA/data/users/$user
     source $USER_DATA/user.conf
-    next_month=$(date +'%m/01/%y' -d "$(date +%Y-%m-%d) 1 month")
+    next_month=$(date +'%m/01/%y' -d "$(date +%Y-%m-15) 1 month")
     DATE=$(date -d "$next_month -1day" +%F)
 
     # Compiling report string

+ 1 - 1
func/db.sh

@@ -55,7 +55,7 @@ mysql_query() {
 
 mysql_dump() {
     err="/tmp/e.mysql"
-    mysqldump --defaults-file=$mycnf --single-transaction -r $1 $2 2> $err
+    mysqldump --defaults-file=$mycnf --single-transaction --routines -r $1 $2 2> $err
     if [ '0' -ne "$?" ]; then
         rm -rf $tmpdir
         if [ "$notify" != 'no' ]; then

+ 5 - 0
func/domain.sh

@@ -436,6 +436,7 @@ is_dns_domain_new() {
 update_domain_zone() {
     domain_param=$(grep "DOMAIN='$domain'" $USER_DATA/dns.conf)
     parse_object_kv_list "$domain_param"
+    local zone_ttl="$TTL"
     SOA=$(idn --quiet -a -t "$SOA")
     if [ -z "$SERIAL" ]; then
         SERIAL=$(date +'%Y%m%d01')
@@ -456,11 +457,15 @@ update_domain_zone() {
 " > $zn_conf
     fields='$RECORD\t$TTL\tIN\t$TYPE\t$PRIORITY\t$VALUE'
     while read line ; do
+        unset TTL
         IFS=$'\n'
         for key in $(echo $line|sed "s/' /'\n/g"); do
             eval ${key%%=*}="${key#*=}"
         done
 
+        # inherit zone TTL if record lacks explicit TTL value
+        [ -z "$TTL" ] && TTL="$zone_ttl"
+
         RECORD=$(idn --quiet -a -t "$RECORD")
         if [ "$TYPE" = 'CNAME' ] || [ "$TYPE" = 'MX' ]; then
             VALUE=$(idn --quiet -a -t "$VALUE")

+ 1 - 1
func/rebuild.sh

@@ -557,7 +557,7 @@ rebuild_mail_domain_conf() {
             if [ "$QUOTA" = 'unlimited' ]; then
                 QUOTA=0
             fi
-            str="$account:$MD5:$user:mail::$HOMEDIR/$user:$QUOTA"
+            str="$account:$MD5:$user:mail::$HOMEDIR/$user::userdb_quota_rule=*:storage=${QUOTA}M"
             echo $str >> $HOMEDIR/$user/conf/mail/$domain/passwd
             for malias in ${ALIAS//,/ }; do
                 echo "$malias@$domain_idn:$account@$domain_idn" >> $dom_aliases

+ 25 - 3
func/upgrade.sh

@@ -147,6 +147,20 @@ upgrade_start_routine() {
 
     # Upgrade to Version 1.1.0
     if [ $VERSION = "1.0.6" ]; then
+        source $HESTIA/install/upgrade/versions/latest.sh
+        VERSION="1.1.0"
+        upgrade_refresh_config
+    fi
+
+    # Upgrade to Version 1.1.1
+    if [ $VERSION = "1.1.0" ]; then
+        source $HESTIA/install/upgrade/versions/latest.sh
+        VERSION="1.1.1"
+        upgrade_refresh_config
+    fi
+
+    # Upgrade to Version 1.1.2
+    if [ $VERSION = "1.1.1" ]; then
         source $HESTIA/install/upgrade/versions/latest.sh
         VERSION="$new_version"
         upgrade_refresh_config
@@ -173,7 +187,7 @@ upgrade_phpmyadmin() {
 
             # Download latest phpMyAdmin release
             wget --quiet https://files.phpmyadmin.net/phpMyAdmin/$pma_v/phpMyAdmin-$pma_v-all-languages.tar.gz
-        
+
             # Unpack files
             tar xzf phpMyAdmin-$pma_v-all-languages.tar.gz
 
@@ -184,8 +198,8 @@ upgrade_phpmyadmin() {
             cp -rf phpMyAdmin-$pma_v-all-languages/* /usr/share/phpmyadmin
 
             # Set config and log directory
-            sed -i "s|define('CONFIG_DIR', '');|define('CONFIG_DIR', '/etc/phpmyadmin/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
-            sed -i "s|define('TEMP_DIR', './tmp/');|define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
+            sed -i "s|define('CONFIG_DIR', ROOT_PATH);|define('CONFIG_DIR', '/etc/phpmyadmin/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
+            sed -i "s|define('TEMP_DIR', ROOT_PATH . 'tmp/');|define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
 
             # Create temporary folder and change permissions
             if [ ! -d /usr/share/phpmyadmin/tmp ]; then
@@ -227,6 +241,14 @@ upgrade_rebuild_users() {
 }
 
 upgrade_restart_services() {
+    # Refresh user interface theme
+    if [ "$THEME" ]; then
+        if [ "$THEME" != "default" ]; then
+            echo "(*) Applying user interface updates..."
+            $BIN/v-change-sys-theme $THEME
+        fi
+    fi
+
     echo "(*) Restarting services..."
     sleep 5
     if [ ! -z "$MAIL_SYSTEM" ]; then

+ 1 - 1
install/deb/exim/exim4.conf.template

@@ -64,7 +64,7 @@ tls_on_connect_ports = 465
 never_users = root
 host_lookup = *
 rfc1413_hosts = *
-rfc1413_query_timeout = 5s
+rfc1413_query_timeout = 0s
 ignore_bounce_errors_after = 2d
 timeout_frozen_after = 7d
 

+ 1 - 1
install/deb/fail2ban/jail.local

@@ -48,7 +48,7 @@ maxretry = 5
 [recidive]
 enabled  = true
 filter   = recidive
-action   = hestia[name=HESTIA]
+action   = hestia[name=RECIDIVE]
 logpath  = /var/log/fail2ban.log
 maxretry = 5
 findtime = 86400

+ 1 - 0
install/deb/nginx/phpmyadmin.inc

@@ -2,6 +2,7 @@ location /phpmyadmin {
     alias /usr/share/phpmyadmin/;
 
     location ~ /(libraries|setup) {
+        deny all;
         return 404;
     }
 

+ 1 - 1
install/deb/php-fpm/multiphp.tpl

@@ -17,7 +17,7 @@ pm.status_path = /status
 
 php_admin_value[upload_tmp_dir] = /home/%user%/tmp
 php_admin_value[session.save_path] = /home/%user%/tmp
-php_admin_value[open_basedir] = /home/%user%/web/%domain%/public_html:/home/%user%/web/%domain%/public_shtml:/home/%user%/tmp:/var/www/html:/etc/phpmyadmin:/var/lib/phpmyadmin:/etc/roundcube:/var/lib/roundcube:/var/log/roundcube:/tmp:/bin:/usr/bin:/usr/local/bin:/usr/share:/opt
+php_admin_value[open_basedir] = /home/%user%/web/%domain%/public_html:/home/%user%/web/%domain%/public_shtml:/home/%user%/tmp:/var/www/html:/etc/phpmyadmin:/var/lib/phpmyadmin:/etc/roundcube:/var/lib/roundcube:/tmp:/bin:/usr/bin:/usr/local/bin:/usr/share:/opt
 php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f admin@%domain%
 
 env[PATH] = /usr/local/bin:/usr/bin:/bin

+ 0 - 1
install/deb/templates/web/nginx/php-fpm/default.stpl

@@ -19,7 +19,6 @@ server {
         location ~* ^.+\.(jpeg|jpg|png|gif|bmp|ico|svg|css|js)$ {
             expires     max;
             fastcgi_hide_header "Set-Cookie";
-            fastcgi_hide_header "Set-Cookie";
         }
 
         location ~ [^/]\.php(/|$) {

+ 0 - 1
install/deb/templates/web/nginx/php-fpm/default.tpl

@@ -14,7 +14,6 @@ server {
         location ~* ^.+\.(jpeg|jpg|png|gif|bmp|ico|svg|css|js)$ {
             expires     max;
             fastcgi_hide_header "Set-Cookie";
-            fastcgi_hide_header "Set-Cookie";
         }
 
         location ~ [^/]\.php(/|$) {

+ 1 - 1
install/deb/templates/web/php-fpm/default.tpl

@@ -17,7 +17,7 @@ pm.status_path = /status
 
 php_admin_value[upload_tmp_dir] = /home/%user%/tmp
 php_admin_value[session.save_path] = /home/%user%/tmp
-php_admin_value[open_basedir] = /home/%user%/web/%domain%/public_html:/home/%user%/web/%domain%/public_shtml:/home/%user%/tmp:/var/www/html:/etc/phpmyadmin:/var/lib/phpmyadmin:/etc/roundcube:/var/lib/roundcube:/var/log/roundcube:/tmp:/bin:/usr/bin:/usr/local/bin:/usr/share:/opt
+php_admin_value[open_basedir] = /home/%user%/web/%domain%/public_html:/home/%user%/web/%domain%/public_shtml:/home/%user%/tmp:/var/www/html:/etc/phpmyadmin:/var/lib/phpmyadmin:/etc/roundcube:/var/lib/roundcube:/tmp:/bin:/usr/bin:/usr/local/bin:/usr/share:/opt
 php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f admin@%domain%
 
 env[HOSTNAME] = $HOSTNAME

+ 1 - 1
install/deb/templates/web/php-fpm/no-php.tpl

@@ -17,7 +17,7 @@
 
 ;php_admin_value[upload_tmp_dir] = /home/%user%/tmp
 ;php_admin_value[session.save_path] = /home/%user%/tmp
-;php_admin_value[open_basedir] = /home/%user%/web/%domain%/public_html:/home/%user%/web/%domain%/public_shtml:/home/%user%/tmp:/var/www/html:/etc/phpmyadmin:/var/lib/phpmyadmin:/etc/roundcube:/var/lib/roundcube:/var/log/roundcube:/tmp:/bin:/usr/bin:/usr/local/bin:/usr/share:/opt
+;php_admin_value[open_basedir] = /home/%user%/web/%domain%/public_html:/home/%user%/web/%domain%/public_shtml:/home/%user%/tmp:/var/www/html:/etc/phpmyadmin:/var/lib/phpmyadmin:/etc/roundcube:/var/lib/roundcube:/tmp:/bin:/usr/bin:/usr/local/bin:/usr/share:/opt
 ;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f admin@%domain%
 
 ;env[HOSTNAME] = $HOSTNAME

+ 1 - 1
install/deb/templates/web/php-fpm/socket.tpl

@@ -17,7 +17,7 @@ pm.status_path = /status
 
 php_admin_value[upload_tmp_dir] = /home/%user%/tmp
 php_admin_value[session.save_path] = /home/%user%/tmp
-php_admin_value[open_basedir] = /home/%user%/web/%domain%/public_html:/home/%user%/web/%domain%/public_shtml:/home/%user%/tmp:/var/www/html:/etc/phpmyadmin:/var/lib/phpmyadmin:/etc/roundcube:/var/lib/roundcube:/var/log/roundcube:/tmp:/bin:/usr/bin:/usr/local/bin:/usr/share:/opt
+php_admin_value[open_basedir] = /home/%user%/web/%domain%/public_html:/home/%user%/web/%domain%/public_shtml:/home/%user%/tmp:/var/www/html:/etc/phpmyadmin:/var/lib/phpmyadmin:/etc/roundcube:/var/lib/roundcube:/tmp:/bin:/usr/bin:/usr/local/bin:/usr/share:/opt
 php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f admin@%domain%
 
 env[HOSTNAME] = $HOSTNAME

+ 2376 - 0
install/deb/themes/dark.css

@@ -0,0 +1,2376 @@
+body {
+  background-color: #282828;
+}
+
+b,
+strong {
+  color: #cacaca;
+}
+
+button,
+select {
+  text-shadow: 0 0 0 #d4d4d4 !important;
+}
+
+body {
+  color: #cdcdcd;
+}
+
+.body-login, .body-reset {
+  background: #303030 !important;
+  background: radial-gradient(circle, rgba(77,77,77,1) 0%, rgba(31,31,31,1) 100%) !important;
+}
+
+a {
+  color: #cdcdcd;
+}
+
+.disabled {
+	
+}
+
+.clearfix:before,
+.clearfix:after {
+	
+}
+
+.clearfix:after {
+	
+}
+
+.text-right {
+	
+}
+
+.text-center {
+	
+}
+
+.text-small {
+	
+}
+
+.check-label {
+	
+}
+
+.check-label:before {
+	
+}
+
+.clicked-on.check-label:before,
+.selected .check-label:before {
+	
+}
+
+.l-center {
+	
+}
+
+.l-logo {
+	
+}
+
+.l-header {
+  background: #454545;
+  border-bottom: 1px solid #505050;
+  text-shadow: 1px 1px rgba(0,0,0,0.5);
+  box-shadow: 0px 8px 15px rgba(0,0,0,0.25);
+}
+
+.l-header a {
+	
+}
+
+.l-menu__item--active {
+	
+}
+
+.l-menu__item.l-menu__item--active a {
+  color: #dadada;
+  background: linear-gradient(to bottom, rgba(15,15,15,0.6) 0%,rgba(45,45,45,0.75) 30%,rgba(60,60,60,1) 95%);
+  text-shadow: 0px 1px rgba(0,0,0,0.5);
+  border-left-color: #353535;
+  border-right-color: #353535;
+}
+
+.l-menu {
+	
+
+}
+.l-menu__item {
+	
+}
+
+.l-menu__item a {
+  color: #e7e7e7;
+}
+
+.l-menu__item a:hover {
+  color: #dadada !important;
+  text-shadow: 1px 1px rgba(0,0,0,0.5) !important;
+  background: linear-gradient(to bottom, rgba(15,15,15,0.6) 0%,rgba(45,45,45,0.75) 30%,rgba(60,60,60,1) 95%) !important;
+  box-shadow: none !important;
+}
+.l-menu__item a:active {
+  background: linear-gradient(to bottom, rgba(15,15,15,0.7) 0%,rgba(45,45,45,0.85) 30%,rgba(50,50,50,1) 95%) !important;
+  color: #fff !important;
+  text-shadow: 0px -1px 1px rgba(0,0,0,0.5) !important;
+}
+
+.l-menu__item.l-menu__item--active:hover {
+  background: linear-gradient(to bottom, rgba(255,255,255,0.15) 0%,rgba(255,255,255,0.15) 30%,rgba(255,255,255,0.15) 95%) !important;
+}
+
+.l-menu.active .l-menu__item.focus a {
+	
+}
+.l-menu.active .l-menu__item.focus a:hover {
+	
+}
+
+
+.lang-ua .l-menu__item a,
+.lang-nl .l-menu__item a,
+.lang-fr .l-menu__item a,
+.lang-ru .l-menu__item a {
+	
+}
+.lang-el .l-menu__item a,
+.lang-tr .l-menu__item a {
+
+}
+.lang-ar .l-menu__item a {
+  padding: 11px 11px;
+}
+.lang-ar .l-menu__item a {
+  line-height: 35px;
+}
+
+.lang-de .l-menu__item a {
+  padding: 11px 12px;
+}
+
+.lang-tw .l-menu__item a {
+  padding: 13px 18px;
+}
+
+.l-profile {
+  overflow: hidden;
+  float: right;
+}
+
+.l-profile__username {
+  font-size: 1.2rem !important;
+}
+
+.l-profile__help {
+  font-size: 1.2rem !important;
+}
+
+.l-profile__logout {
+  color: #e7e7e7 !important;
+  font-size: 1.2rem !important;
+}
+
+.l-profile__server {
+  color: #ceefff;
+  margin-top: 10px;
+  float: left;
+}
+
+.l-profile__notifications {
+  color: #fff;
+  cursor: pointer;
+  font-weight: 600;
+  padding: 10px 5px 0;
+  font-size: 1.2rem !important;
+  line-height: 0.95rem;
+  border-left: 1px solid transparent !important;
+  border-right: 1px solid transparent !important;
+}
+
+.l-profile__notifications.active.l-profile__notifications.updates:active {
+  background: linear-gradient(to bottom, rgba(15,15,15,0.6) 0%,rgba(45,45,45,0.75) 30%,rgba(60,60,60,1) 95%) !important;
+  color: #046c98 !important;
+  text-shadow: 0px -1px 1px rgba(0,0,0,0.5) !important;
+  box-shadow: none !important;
+  transition: 0.2s;
+  border-left: 1px solid transparent !important;
+  border-right: 1px solid transparent !important;
+}
+.l-profile__notifications:hover,.l-profile__notifications.updates:hover {
+  text-shadow: 1px 1px rgba(0,0,0,0.5) !important;
+  background: linear-gradient(to bottom, rgba(15,15,15,0.6) 0%,rgba(45,45,45,0.75) 30%,rgba(60,60,60,1) 95%) !important;
+  border: none !important;
+  border-left: 1px solid transparent !important;
+  border-right: 1px solid transparent !important;
+  box-shadow: none !important;
+}
+
+.notification-container {
+  background-color: rgba(50,50,50,0.99);
+  text-shadow: 0px 1px rgba(0,0,0,0.5);
+  color: #dadada;
+  border: 1px solid #404040;
+}
+
+.notification-container .empty {
+
+}
+
+.notification-container .empty .status-icon {
+  color: #dadada;
+}
+
+.notification-container .unseen {
+  color: #dadada;
+}
+
+.notification-container li {
+  border-bottom: 1px solid #282828;
+}
+
+.notification-container  li:last-child {
+
+}
+
+.notification-container .mark-seen {
+  background-color: #ff3478;
+}
+.notification-container .mark-seen:hover {
+
+}
+.notification-container .mark-seen:active {
+
+}
+.notification-container .unseen .mark-seen{
+
+}
+.notification-container .title {
+
+}
+.notification-container .title a {
+
+}
+
+.notification-container .unseen .title a,
+.notification-container .unseen .title {
+  color: #fff !important;
+}
+.notification-container .unseen .title a:hover {
+
+}
+.notification-container .unseen .title a:active {
+
+}
+
+.notification-container a {
+  color: #4fabe9;
+}
+.notification-container a:hover {
+  color: #0099ff;
+}
+.notification-container a:active {
+  color: #0079cb;
+}
+
+.notification-container .icon {
+
+}
+.notification-container .icon.starred {
+
+}
+
+.notification-container .time {
+
+}
+
+.alert {
+  border: 1px solid #212121;
+}
+
+.alert i.fas {
+
+}
+
+.alert.alert-with-icon {
+
+}
+.alert.alert-info {
+
+}
+.alert.alert-info i.fas {
+
+}
+
+.alert.alert-danger {
+  background-color: #d13535;
+}
+.alert.alert-danger i.fas {
+  color: #d13535;
+}
+
+.alert.alert-success {
+
+}
+.alert.alert-success i.fas {
+
+}
+
+form#vstobjects .alert {
+
+}
+
+.app-list.cards {
+
+}
+
+.app-form {
+
+}
+
+.app-form label {
+
+}
+
+.card {
+  float: left;
+
+  background: #454545;
+  color: #fafafa;
+  text-shadow: 0px 1px rgba(0,0,0,0.95) !important;
+  border: 1px solid #606060;
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.2),
+              inset 0px 0px 60px rgba(0,0,0,0.25);
+}
+
+.card.disable {
+
+}
+
+.card.disable .card-thumb {
+
+}
+
+.card .card-details {
+
+}
+
+.card .card-details p {
+  color: #bdbdbd;
+}
+
+.card p.card-title {
+  color: #fafafa;
+}
+
+.card .card-thumb {
+
+}
+.card .card-thumb img {
+
+}
+
+.card button {
+
+}
+
+.l-stat {
+  background-color: #282828;
+}
+
+.l-stat__col {
+
+}
+
+.l-stat__col a {
+  border-bottom: 4px solid #282828;
+  background-color: #282828;
+}
+
+.l-stat__col a:hover {
+  border-bottom: 4px solid #d7d7d7;
+}
+.l-stat__col a:active, .l-stat__col a:focus {
+  border-bottom: 4px solid #d11755;
+}
+.l-stat__col--active a {
+  border-bottom: 4px solid #e93b76;
+}
+
+.l-stat.active .l-stat__col.focus a {
+  border-bottom: 4px solid #e93b76;
+}
+.l-stat.active .l-stat__col.focus a .l-stat__col-title {
+
+}
+
+
+.l-stat__col a:hover .l-stat__col-title {
+  color: #d7d7d7;
+}
+.l-stat__col a:active .l-stat__col-title {
+
+}
+
+
+.l-stat__col ul {
+
+}
+.l-stat__col li {
+
+}
+.l-stat__col span {
+
+}
+.l-stat__col-title {
+  font-weight: 500;
+  color: #bcbcbc;
+  text-shadow: 0px 1px rgba(0,0,0,0.4);
+}
+
+.l-stat__col--active .l-stat__col-title {
+  color: #ff558f;
+}
+
+.l-stat__col .fas {
+  color: #707070;
+  padding: 4px;
+}
+
+.l-stat__col--active .fas {
+  color: #aaaaaa;
+}
+
+.l-separator.selected,
+.l-separator {
+  border-top: 1px solid #454545;
+}
+
+div.l-content > div.l-separator:nth-of-type(2) {
+
+}
+
+div.l-content > div.l-separator:nth-of-type(4) {
+  border-bottom: 1px solid #454545;
+  background-color: #282828;
+  box-shadow: 0px 4px 6px rgba(0,0,0,0.25) !important;
+}
+
+.l-sort {
+  background-color: #282828;
+}
+
+.l-sort__create-btn {
+
+}
+.l-sort__create-btn:hover {
+
+}
+.l-sort__create-btn:active {
+
+}
+.l-sort__create-btn--active {
+
+}
+
+.l-sort__create-btn.restore {
+
+}
+.l-sort__create-btn.restore:hover {
+
+}
+.l-sort__create-btn.restore:active {
+
+}
+
+.l-sort__create-btn.edit {
+
+}
+.l-sort__create-btn.edit:hover {
+
+}
+.l-sort__create-btn.edit:active {
+
+}
+
+.context-menu.sort-order {
+  background-color: rgba(40,40,40,0.95);
+  box-shadow: 0 2px 16px 0 rgba(20, 20, 20, 0.65);
+  border-radius: 4px;
+  border: 1px solid rgba(90,90,90,1);
+}
+
+.context-menu.sort-order li {
+
+}
+.context-menu li {
+  border-bottom: 1px solid #454545;
+  color: #dadada;
+}
+.context-menu.sort-order span.name {
+
+}
+.context-menu.sort-order span.up {
+
+}
+.context-menu.sort-order span.active {
+  background-color: #454545 !important;
+  color: #fff;
+  background: linear-gradient(to bottom, rgba(15,15,15,0.6) 0%,rgba(45,45,45,0.75) 30%,rgba(60,60,60,1) 95%);
+  text-shadow: 0px 1px rgba(0,0,0,0.8);
+}
+.context-menu.sort-order span:hover {
+  color: #fff;
+  background:  linear-gradient(to bottom, rgba(25,25,25,0.6) 0%,rgba(55,55,55,0.75) 30%,rgba(70,70,70,1) 95%);
+  text-shadow: 0px -1px 1px rgba(0,0,0,0.5);
+  box-shadow: inset 0px 0px 1px rgba(0,0,0,0.4),
+              inset -1px -1px 4px rgba(40,40,40,0.4);
+}
+.context-menu.sort-order span:active,.context-menu.sort-order span:focus {
+  background: linear-gradient(to bottom, rgba(35,35,35,0.6) 0%,rgba(65,65,65,0.75) 30%,rgba(80,80,80,1) 95%);
+  color: #fff;
+  text-shadow: 0px -1px 1px rgba(0,0,0,0.5);
+  box-shadow: inset 0px 0px 1px rgba(0,0,0,0.4),
+              inset -1px -1px 4px rgba(40,40,40,0.4);
+}
+.context-menu.sort-order span.name i.fas.fa-sort-amount-down {
+
+}
+.context-menu.sort-order li:last-child {
+
+}
+.l-sort-toolbar {
+
+}
+
+.l-sort-toolbar table{
+
+}
+
+.l-sort-toolbar td.toggle-all {
+
+}
+
+.l-sort-toolbar .sort-by {
+
+}
+.l-sort-toolbar .sort-by:hover {
+  color: #d4d4d4;
+}
+.l-sort-toolbar .sort-by:hover b {
+  color: #d4d4d4;
+}
+.l-sort-toolbar .sort-by:active {
+
+}
+.l-sort-toolbar .sort-by:active b {
+
+}
+
+.l-sort-toolbar .sort-by b {
+
+}
+
+.l-sort-toolbar .toggle-all:hover {
+  color: #d4d4d4;
+}
+.l-sort-toolbar .toggle-all:active {
+
+}
+
+.l-sort-toolbar .l-select {
+
+}
+.l-sort-toolbar td {
+
+}
+
+.l-sort-toolbar.subtitle  {
+
+}
+
+.l-sort-toolbar td.step-right:first-of-type {
+
+}
+
+.l-sort-toolbar td:nth-of-type(2) {
+
+}
+.l-sort-toolbar td:last-of-type {
+
+}
+
+.l-sort-toolbar__filter-apply {
+  border: 1px solid #454545;
+  background-color: #424242;
+  text-shadow: 1px 1px rgba(0,0,0,0.9) !important;
+  box-shadow: 0px 1px 1px rgba(0,0,0,0.4) !important;
+  color: #cacaca;
+  font-size: 1em;
+}
+
+.l-sort-toolbar__filter-apply:hover {
+  color: #0099ff;
+  background-color: #454545;
+}
+
+.l-sort-toolbar__filter-apply:active {
+  color: #0074c2;
+  text-shadow: 0px -1px rgba(255,255,255,0.2);
+  box-shadow: inset 1px 1px 0px rgba(0,0,0,0.2);
+}
+
+.l-sort-toolbar__search {
+
+}
+.l-sort-toolbar__search:hover {
+
+}
+.l-sort-toolbar__search:active {
+
+}
+.l-sort-toolbar__search--active {
+
+}
+.l-sort-toolbar .vst {
+  color: #dadada;
+}
+.l-sort-toolbar .vst:hover {
+  color: #ff3478;
+}
+.l-sort-toolbar .vst:active {
+}
+.l-sort-toolbar .vst.selected {
+  color: #ff3478;
+}
+
+.l-unit-toolbar__buttonstrip {
+
+}
+
+.l-unit-toolbar__buttonstrip a {
+
+}
+
+.l-unit-toolbar__buttonstrip .fas {
+
+}
+
+
+.subtitle {
+  color: #ff3478;
+
+}
+
+.l-select {
+  border: 1px solid #454545;
+  box-shadow: 0px 1px 1px rgba(0,0,0,0.4) !important;
+}
+
+.lang-ru .l-select {
+
+}
+
+.l-select:after {
+
+}
+
+.l-select select {
+  background-color: #212121;
+  box-shadow: 0px 1px 1px rgba(0,0,0,0.4) !important;
+}
+
+.l-select select:focus {
+
+}
+.lang-ru .l-select select {
+
+}
+.l-select select option {
+
+}
+
+.l-sort-toolbar .l-select {
+  border: 1px solid #454545;
+  background-color: #454545;
+  text-shadow: 0px 1px rgba(0,0,0,0.65);
+  text-shadow: 1px 1px rgba(0,0,0,0.9);
+}
+
+.l-unit {
+  color: #dadada;
+}
+
+.table-header {
+  background: #404040 !important;
+  border-left: 1px solid #212121 !important;
+  border-right: 1px solid #212121 !important;
+  border-bottom: 1px solid #212121 !important;
+  border-top: 1px solid #454545 !important;
+  text-shadow: 0px 1px rgba(0,0,0,0.95);
+  border-bottom-left-radius: 0px !important;
+  border-bottom-right-radius: 0px !important;
+  color: #dadada;
+  box-shadow: inset 0px 1px 1px rgba(0,0,0,0.3) !important;
+}
+
+.table-header:hover {
+  background-color: #404040 !important;
+  border-left: 1px solid #212121 !important;
+  border-right: 1px solid #212121  !important;
+  box-shadow: inset 0px 1px 1px rgba(0,0,0,0.3) !important;
+}
+
+.table-header .fas {
+
+}
+
+.units .l-unit {
+  background-color: #303030;
+  border-bottom: 1px solid #282828;
+  border-left: 1px solid #212121;
+  border-right: 1px solid #212121;
+}
+
+.l-unit:hover, .units .l-unit:hover {
+  box-shadow: 0px 2px 10px rgba(20,20,20,0.20);
+  background-color: #353535;
+  text-shadow: 0px 1px rgba(0,0,0,0.5);
+  border-left: 1px solid #212121;
+  border-right: 1px solid #212121;
+}
+
+.units .l-unit.l-unit--starred {
+  border-left: 2px solid #ff3478;
+}
+.units.active .l-unit.focus {
+  background-color: #353535;
+}
+.units.active .l-unit.focus .l-unit__name {
+
+}
+.units.active .l-unit.focus .l-unit-toolbar__col--right {
+
+}
+
+.units > div:last-child {
+
+}
+
+.l-unit-ft {
+  color: #cdcdcd;
+
+}
+
+.l-unit:hover .l-unit-toolbar__col--right {
+
+}
+.l-unit--blue {
+
+}
+
+.l-unit--suspended {
+    background: #252525 !important;
+    color: #606060 !important;
+    text-shadow: 0px -1px rgba(0,0,0,0.4) !important;
+    box-shadow: inset 0px 0px 2px rgba(0,0,0,0.2);
+}
+
+.l-unit--suspended a {
+    color: #606060 !important;
+    text-shadow: 0px -1px rgba(0,0,0,0.4) !important;
+}
+
+.units .l-unit.l-unit--outdated {
+  color: #d4d4d4;
+}
+
+.l-unit--suspended .l-unit__name,
+.l-unit--suspended b,
+.l-unit--outdated .l-unit__name,
+.l-unit--outdated b {
+  color: #606060;
+}
+
+.l-unit--outdated .l-unit__name {
+
+}
+.l-unit--outdated b {
+  color: #d4d4d4;
+}
+
+.l-unit--suspended .l-percent {
+
+}
+.l-unit--suspended .l-percent__fill {
+
+}
+.l-unit--suspended .l-unit__name,
+.l-unit--suspended .l-unit__name span {
+
+}
+
+.l-unit--suspended.selected .l-unit__name,
+.l-unit--suspended.selected .l-unit__name span {
+  color: #707070;
+}
+
+.l-unit--suspended.selected {
+  background-color: #454545 !important;
+  color: #707070 !important;
+}
+
+.l-unit--outdated.selected {
+
+}
+
+
+
+.l-unit--suspended.selected .l-unit__name,
+.l-unit--suspended.selected b,
+.l-unit--outdated.selected .l-unit__name,
+.l-unit--outdated.selected b,
+.l-unit--suspended.selected .l-percent,
+.l-unit--suspended.selected .l-percent__fill,
+.l-unit--suspended.selected .l-unit__name,
+.l-unit--suspended.selected .l-unit__name span {
+
+}
+
+.l-unit.selected .l-percent {
+
+}
+
+
+.l-unit--selected {
+
+}
+.l-unit-toolbar{
+
+}
+
+.l-unit label {
+
+}
+.l-unit__columns {
+
+}
+.l-unit__col {
+
+}
+.l-unit__col--left {
+
+}
+
+.units.compact .l-unit__col--left {
+
+}
+
+.l-unit__col--left.step-left {
+
+}
+
+.l-unit__col--right.total {
+
+}
+
+.l-unit__col--right.back {
+
+}
+
+.l-sort-toolbar .step-left {
+
+}
+.step-right {
+
+}
+
+.l-unit__date {
+
+}
+
+.l-unit__suspended {
+
+}
+
+.units.compact .l-unit__suspended {
+
+}
+
+.l-unit--outdated .l-unit__suspended,
+.l-unit--suspended .l-unit__suspended {
+
+}
+
+.l-unit-ft .subtitle,
+.l-unit .subtitle {
+  color: #ff3478;
+
+}
+
+.l-unit.l-unit--outdated .l-unit__date {
+
+}
+
+.l-unit__name {
+  color: #dadada;
+}
+
+.l-unit__servername {
+
+}
+
+.l-unit__stats.separate,
+.l-unit__name.separate {
+
+}
+
+.l-unit__name.small {
+
+}
+
+.l-unit__name.small-2 {
+
+}
+
+.l-unit__name span {
+
+}
+.l-unit__name span:first-of-type {
+
+}
+.l-unit__name b {
+
+}
+
+.l-unit__ip {
+
+}
+.l-unit__ip span {
+
+}
+.display-ip {
+
+}
+.display-ip span {
+
+}
+
+.l-unit__stats {
+
+}
+
+.l-unit__stats:hover {
+  background: transparent !important;
+}
+
+.l-unit__stats table {
+
+}
+.l-unit__stats td {
+
+}
+.l-unit__stat-col--left a, .l-unit__stat-col--left a:visited {
+  color: #fafafa;
+}
+.l-unit__stat-col--left a:hover {
+  color: #fff;
+}
+
+.l-unit__stat-col--left {
+
+}
+
+.l-unit__stat-col--left.border {
+
+}
+.l-unit__stat-col--left.border-clear {
+
+}
+.l-unit__stat-col--left.super-compact {
+
+}
+.l-unit__stat-col--left.compact {
+
+}
+.l-unit__stat-col--left.compact-1 {
+
+}
+.l-unit__stat-col--left.compact-2 {
+
+}
+.l-unit__stat-col--left.compact-3 {
+
+}
+.l-unit__stat-col--left.compact-4 {
+
+}
+.l-unit__stat-col--left.compact-5 {
+
+}
+.l-unit__stat-col--left.wide {
+
+}
+.l-unit__stat-col--left.wide-2 {
+
+}
+.l-unit__stat-col--left.wide-3 {
+
+}
+.l-unit__stat-col--left.wide-4 {
+
+}
+.l-unit__stat-col--left.wide-5 {
+
+}
+.l-unit__stat-col--left.wide-6 {
+
+}
+.l-unit__stat-col--left.wide-7 {
+
+}
+
+.l-unit__stat-col--left.small-2 {
+
+}
+
+.l-unit__stat-col--left.tiny {
+
+}
+
+.l-unit__stat-col--left.tiny b {
+
+}
+
+
+.l-unit__stat-col--right {
+
+}
+
+.l-unit-toolbar__col--left {
+
+}
+
+.l-unit-toolbar__col--right {
+
+}
+
+body.mobile .l-unit-toolbar__col--right {
+
+}
+
+.l-unit-toolbar .shortcut {
+
+}
+
+.units.active .l-unit.focus .l-unit-toolbar .shortcut {
+
+}
+.units.active .l-unit.focus .l-unit-toolbar .shortcut.delete {
+
+}
+.units.active .l-unit.focus .l-unit-toolbar .shortcut.enter {
+
+}
+.units.active .l-unit.focus .l-unit-toolbar i {
+
+}
+
+.l-unit__stat-col.volume {
+
+}
+
+.actions-panel__col {
+
+}
+
+.actions-panel__col a {
+
+}
+
+.lang-ru .actions-panel__col a {
+
+}
+.lang-tw .actions-panel__col a {
+
+}
+.lang-ar .actions-panel__col a {
+
+}
+
+.icon-pad-right {
+
+}
+
+.l-icon-up-arrow, .l-icon-down-arrow, .l-icon-star, .l-icon-to-top, .l-icon-shortcuts, .l-icon-star-orange, .l-icon-star-blue {
+
+}
+
+.l-icon-down-arrow {
+
+}
+
+.l-icon-up-arrow {
+
+}
+
+
+.l-icon-star {
+
+}
+.l-unit--starred .l-icon-star {
+
+}
+.selected .l-icon-star {
+
+}
+
+.units.compact .l-icon-star {
+
+}
+
+.l-icon-star:hover {
+
+}
+
+.l-icon-star:active {
+
+}
+
+.l-unit:hover .l-icon-star {
+
+}
+
+
+.l-icon-to-top {
+
+}
+.l-icon-to-top:hover {
+
+}
+.l-icon-to-top:active {
+
+}
+
+.l-icon-shortcuts {
+
+}
+.l-icon-shortcuts:hover {
+
+}
+.l-icon-shortcuts:active {
+
+}
+
+body.mobile .l-icon-to-top,
+body.mobile .l-icon-shortcuts {
+
+}
+
+
+.l-icon-star-orange {
+
+}
+
+.l-icon-star-blue {
+
+}
+
+.media-top {
+
+}
+
+.l-unit__stat-cols {
+
+}
+.l-unit__stat-cols.last {
+
+}
+.l-unit__stat-cols.graph {
+
+}
+.l-unit__stat-cols.tiny {
+
+}
+
+.l-percent {
+
+}
+.l-percent__fill {
+
+}
+
+
+#vstobjects .l-center {
+
+}
+
+.timer-container {
+
+}
+
+.timer-container .refresh-timer {
+
+}
+.timer-container .refresh-timer.paused {
+
+}
+.timer-container .refresh-timer.paused .loader-half.right,
+.timer-container .refresh-timer.paused .loader-half.dark {
+
+}
+.timer-container .loader-half {
+
+}
+.timer-container .loader-half.left {
+
+}
+.timer-container .loader-half.right {
+
+}
+.timer-container .loader-half.dark {
+
+}
+.timer-container .movement {
+
+}
+.timer-container .movement.left {
+
+}
+.timer-container .movement.right {
+
+}
+.timer-container .timer-button {
+
+}
+.timer-container .timer-button.pause {
+
+}
+.timer-container .timer-button.play {
+
+}
+
+.uppercase {
+
+}
+
+.title b,
+.title {
+  color: #ff3478;
+
+}
+
+.title {
+
+}
+
+
+
+
+/* form styles */
+
+
+
+.vst-error {
+  color: #ff3333;
+
+}
+
+.vst-ok {
+  color: #53ba55;
+}
+
+.l-unit-toolbar__buttonstrip .vst-ok, .l-unit-toolbar__buttonstrip .vst-error {
+
+}
+
+.vst-ok a {
+
+}
+.vst-ok a:hover {
+  color: #ff3478;
+}
+.vst-ok a:active {
+
+}
+
+
+
+
+.data {
+
+}
+.data-col1 {
+
+}
+
+.data-col1 td {
+
+}
+
+.data-col1 tr:first-child td {
+
+}
+
+.login-box td,
+.data td {
+  color: #d4d4d4;
+}
+.input-label {
+
+}
+.data input[type="checkbox"] {
+
+}
+.step-top {
+
+}
+.step-top-small {
+
+}
+.jump-top {
+
+}
+.jump-small-top {
+
+}
+.float-right {
+
+}
+
+.data a {
+
+}
+label {
+
+}
+label:hover {
+  color: #d4d4d4 !important;
+}
+.vst-input {
+  background-color: #454545;
+  border: 1px solid #606060;
+  color: #d4d4d4;
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.35);
+}
+.vst-input:hover {
+  border-color: #0090ff;
+  background-color: #494949;
+}
+
+.vst-input:focus {
+  background-color: #222222;
+  border-color: #0080df;
+  color: #fff;
+  box-shadow: 0px 1px 6px rgba(0,52,91,0.75);
+}
+
+.vst-input:disabled,
+.vst-list:disabled {
+  background-color: #454545;
+  text-shadow: 1px 1px rgba(0,0,0,0.3);
+  color: #acacac;
+  border-color: #606060;
+}
+.vst-input:focus:disabled {
+
+}
+
+.vst-input:disabled:hover,
+.vst-list:disabled:hover {
+  border-color: #606060 !important;
+}
+
+.vst-input.long {
+
+}
+.vst-input.short {
+
+}
+.vst-input.vst-list-editor {
+
+}
+.vst-input.vst-list-editor:focus {
+  background-color: #222222;
+  box-shadow: none !important;
+}
+
+.vst-list {
+  background-color: #454545;
+  border: 1px solid #606060;
+  color: #d4d4d4;
+  text-shadow: 0 0 0 #d4d4d4;
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.35);
+}
+
+select.vst-list:-moz-focusring {
+
+}
+
+.vst-list.long-2 {
+
+}
+.vst-list option {
+
+}
+.vst-list:hover {
+  border-color: #0090ff;
+  background-color: #494949;
+}
+.vst-list:focus {
+  background-color: #222222;
+  border-color: #0080df;
+  color: #fff;
+  box-shadow: 0px 1px 6px rgba(0,52,91,0.75);
+}
+
+.vst-list.flat {
+  border: 1px solid #454545;
+  color: #fff;
+}
+.vst-list.flat:hover {
+  color: #ff3478;
+}
+.vst-list.flat option {
+  color: #d4d4d4;
+}
+
+a.vst-text,
+a.vst-text b{
+  color: #fff;
+}
+a.vst-text:hover,
+a.vst-text:hover b{
+  color: #ff3478;
+}
+a.vst-text:active,
+a.vst-text:active b{
+  color: #ff3478;
+}
+
+.advanced-options {
+  background: #454545 !important;
+  border: 1px solid #505050 !important;
+  text-shadow: 0px 1px rgba(0,0,0,0.4);
+  box-shadow: inset 0px 0px 2px rgba(0,0,0,0.5), 
+              0px 2px 6px rgba(0,0,0,0.4) !important;
+  color: #fff !important;
+  padding: 4px 0px 0px 18px;
+  overflow: hidden;
+  height: 28px;
+}
+
+.advanced-options a {
+  color: #fff !important;
+}
+
+.advanced-options .fas {
+
+}
+
+.vst-textinput {
+  background-color: #454545;
+  border: 1px solid #606060;
+  color: #d4d4d4;
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.35);
+}
+.vst-textinput:hover {
+  border: 1px solid #0090ff;
+  background-color: #494949;
+}
+.vst-textinput:focus {
+  background-color: #222222;
+  border-color: #0080df;
+  color: #fff !important;
+  box-shadow: 0px 1px 6px rgba(0,52,91,0.75);
+}
+.vst-textinput:disabled {
+  background-color: #454545;
+}
+.vst-textinput.console{
+
+}
+.vst-textinput.short {
+
+}
+#advanced-options .console{
+
+}
+
+.generate {
+  color: #29a9ff;
+  border-radius: 4px;
+  
+}
+.generate:hover {
+  background-color: #ff3478;
+  border-color: #ff3478;
+}
+.generate:active {
+  background-color: #be1f54;
+  border-color: #be1f54;
+}
+
+
+.vst-advanced {
+  border-bottom: 0px solid #326b9b;
+  color: #0094f7;
+  font-size: 0.8rem;
+  padding: 4px 12px;
+  text-decoration: none;
+  border-radius: 4px;
+  text-transform: none !important;
+}
+
+.login-box .vst-advanced:hover {
+  color: #ff3478 !important;
+  background-color: transparent;
+  border-color: transparent;
+  border: none !important;
+  background: none !important;
+  box-shadow: none !important;
+}
+
+.login-box .vst-advanced:active {
+  color: #be1f54 !important;
+  border: none !important;
+  background: none !important;
+  box-shadow: none !important;
+}
+
+.vst-advanced:hover {
+  color: #fff;
+  background-color: #ff3478;
+  border-color: #ff3478;
+  text-decoration: none;
+}
+
+.login-box .vst-advanced:active,
+.vst-advanced:active {
+  color: #fff;
+  background-color: #be1f54;
+  border-color: #be1f54;
+  text-decoration: none;
+}
+
+.login-box .vst-advanced {
+  border-bottom: none;
+  color: #326b9b;
+  font-size: 0.85em !important;
+  padding: 2px 2px 0;
+  text-decoration: none;
+  text-transform: uppercase;
+  border: none !important;
+  background: none !important;
+  box-shadow: none !important;
+}
+
+.vst-checkbox {
+
+}
+.lets-encrypt-note {
+
+}
+
+.additional-control {
+  color: #0099ff;
+}
+.additional-control:hover {
+  background-color: #ff3478;
+  border-color: #ff3478;
+}
+.additional-control:active {
+
+}
+
+.additional-control.ftp-remove-user {
+
+}
+
+.additional-control.delete:hover,
+.additional-control.ftp-remove-user:hover {
+
+}
+.additional-control.delete:active,
+.additional-control.ftp-remove-user:active {
+
+}
+.additional-control.add:hover {
+
+}
+.additional-control.add:active{
+
+}
+
+.additional-control.remove-ns {
+
+}
+
+.data .step-left {
+
+}
+.hide-password {
+
+}
+.toggle-psw-visibility-icon {
+
+}
+.show-passwords-enabled-action {
+
+}
+.ftp-path-value,
+.hint,
+td.hint {
+  color: #a2a2a2;
+  font-size: 0.8rem;
+}
+.ftp-path-prefix { padding-top: 12px; font-size: 0.8rem; color: #555; }
+
+.ui-dialog .ui-dialog-buttonpane button {
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.1),
+  inset 0px 0px 1px #000,
+  inset 0px 0px 3px rgba(0,0,0,0.5) !important;
+}
+
+.ui-button, .button, .ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit, .vst-advanced, .to-shortcuts, .to-top {
+  font-size: 0.85rem !important;
+  font-weight: 400 !important;
+  color: #eeeeee !important;
+  border: 1px solid #707070 !important;
+  background: rgb(48,48,48) !important;
+  background: linear-gradient(0deg, rgba(48,48,48,1) 0%, rgba(53,53,53,1) 35%, rgba(69,69,69,1) 100%) !important;
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.2),
+              inset 0px 0px 1px rgba(20,20,20,1),
+              inset 0px 0px 3px rgba(0,0,0, 0.5) !important;
+  text-shadow: 0px 1px 1px rgba(0,0,0,0.35) !important;
+}
+
+.ui-button:hover, .button:hover, .ui-button.cancel:hover, .button.cancel:hover,
+.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit:hover, .vst-advanced:hover, .to-shortcuts:hover, .to-top:hover  {
+  color: #fff !important;
+  text-shadow: 1px 1px rgba(0,0,0,0.25) !important;
+  border: 1px solid #0098ff !important;
+  background: linear-gradient(0deg, rgba(58,58,58,1) 0%, rgba(68,68,68,1) 35%, rgba(79,79,79,1) 100%) !important;
+  background-color: #454545;
+  box-shadow: 0px 1px 3px rgba(0,0,0,0.35),
+              inset 0px 0px 1px rgba(0,0,0,1),
+              inset 0px 0px 3px rgba(0,0,0,0.65) !important;
+  transition: 0.2s;
+}
+.ui-button:focus,.ui-button:active,
+.button:active,.button:focus,.ui-button.cancel:focus,.ui-button.cancel:active,
+.button.cancel:active,.button.cancel:focus,
+.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit:active, .vst-advanced:active, .to-shortcuts:active, .to-top:active,
+.to-shortcuts:focus, .to-top:focus   {
+  border: 1px solid #0066b4 !important;
+  background: linear-gradient(0deg, rgba(69,69,69,1) 0%, rgba(53,53,53,1) 35%, rgba(48,48,48,1) 100%) !important;
+  color: #d4d4d4 !important;
+  text-shadow: 0px -1px 1px rgba(0,0,0,0.55) !important;
+  box-shadow: 0px 1px 3px rgba(0,0,0,0.3),
+              inset 0px 0px 1px rgba(0,0,0,1),
+              inset -1px -1px 4px rgba(30,30,30,0.4) !important;
+}
+
+.ui-button-text-only {
+  text-shadow: 0px 1px rgba(0,0,0,0.5);
+}
+
+.ui-dialog .ui-dialog-buttonpane button span.ui-button-text {
+
+}
+
+.ui-dialog .ui-button:hover span {
+  color: #fafafa !important;
+}
+
+.ui-button-text-only .selected {
+
+}
+
+.ui-button.cancel,
+.button.cancel {
+  color: #eeeeee !important;
+  border: 1px solid #454545 !important;
+  background: rgb(48,48,48) !important;
+  background: linear-gradient(0deg, rgba(48,48,48,1) 0%, rgba(53,53,53,1) 35%, rgba(69,69,69,1) 100%) !important;
+}
+
+.ui-button-text {
+  color: #eeeeee !important;
+}
+
+.ui-button.cancel:active,
+.button.cancel:active {
+
+}
+a.button.cancel {
+
+}
+
+
+.ui-dialog button.cancel {
+  border: 1px solid #d4d4d4;
+  background-color: #d4d4d4;
+}
+
+.ui-button.danger:hover, .button.danger:hover {
+  background: rgb(133,0,0);
+  background: linear-gradient(0deg, rgba(133,0,0,1) 0%, rgba(203,0,0,1) 100%) !important;
+  color: #fff !important;
+  text-shadow: 0px 1px rgba(0,0,0,0.45) !important;
+  border: 1px solid rgb(170, 0, 0) !important;
+}
+
+.ui-button.danger:active, .button.danger:active, .ui-button.danger:focus, .button.danger:focus {
+  background: rgb(133,0,0);
+  background: linear-gradient(180deg, rgba(133,0,0,1) 0%, rgba(203,0,0,1) 100%) !important;
+  color: #4d0000 !important;
+  text-shadow: 0px -1px 1px rgba(255,255,255,0.3) !important;
+  border: 1px solid rgb(251, 71, 51) !important;
+}
+
+.ui-button span {
+
+}
+.ui-button:hover span {
+  color: #d4d4d4 !important;
+}
+.ui-button:active span {
+  color: #d4d4d4;
+}
+
+.ui-button.cancel span {
+
+}
+.ui-button:hover span {
+
+}
+.ui-button:active span {
+
+}
+
+.ui-dialog button.cancel span {
+  color: #fff !important;
+}
+
+.unlim-trigger {
+
+}
+.optional {
+
+}
+.data-active b {
+
+}
+.data-suspended b {
+
+}
+.data-date {
+
+}
+.data-dotted {
+
+}
+.mail-infoblock-td {
+
+}
+.mail-infoblock {
+  color: #fff;
+  border: 1px solid #606060;
+  margin-top: 87px;
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.35);
+  background-color: #454545;
+}
+
+.mail-infoblock:hover {
+
+}
+
+.mail-infoblock td {
+  color: #dadada;
+
+}
+.mail-infoblock td:first-child{
+
+}
+.mail-infoblock div {
+
+}
+.mail-infoblock a {
+  color: #52b9ff;
+}
+.mail-infoblock a:hover {
+  color: #ff3478;
+}
+
+.additional-info {
+
+}
+.additional-info td {
+
+}
+
+.additional-info td.details {
+
+}
+
+:focus {outline:none;}
+::-moz-focus-inner {border:0;}
+
+.login {
+  background-color: #282828;
+  box-shadow: 0px 8px 25px rgba(0,0,0, 0.3), inset 0px 0px 2px rgba(0,0,0,0.25) !important;
+}
+
+.login-welcome {
+  color: #fff !important;
+}
+
+.page-title {
+  color: #dbdbdb !important;
+}
+
+.qr-code {
+  border: 1px solid #3b3b3b;
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.35);
+}
+
+.password-option {
+
+}
+
+.login a.error {
+  color: #f864fa;
+
+}
+
+.hestiacp {
+
+}
+.hestiacp:hover {
+
+}
+.hestiacp:active {
+  color: #ff3478;
+}
+
+.login-bottom {
+
+}
+
+.l-unit.selected {
+  background-color: #454545;
+  color: #d4d4d4;
+  box-shadow: 0px 2px 10px rgba(30,30,30,0.35);
+  text-shadow: 0px 1px rgba(0,0,0,0.5);
+  border-left: 1px solid #212121;
+  border-right: 1px solid #212121;
+}
+
+.l-unit.selected:hover {
+  background-color: #555555;
+  color: #d4d4d4;
+  box-shadow: none !important;
+  text-shadow: 0px 1px rgba(0,0,0,0.4);
+}
+
+.l-unit.selected b,
+.l-unit.selected strong {
+  color: #d4d4d4;
+}
+
+
+/* MAIN MENU COLLAPSED */
+.collapsed .l-stat {
+
+}
+
+.collapsed .l-stat__col a {
+
+}
+
+.collapsed .l-stat__col-title {
+
+}
+
+div.l-content.collapsed > div.l-separator:nth-of-type(2) {
+
+}
+
+div.l-content.collapsed > div.l-separator:nth-of-type(4) {
+
+}
+
+div.l-content.collapsed .l-sort {
+
+}
+
+.l-content > .units.l-center::before {
+
+}
+
+.console-output {
+  color: #dadada !important;
+}
+
+form#vstobjects {
+
+}
+
+form#vstobjects.suspended {
+  background-color: #282828;
+}
+
+#add-icon {
+
+}
+.l-sort__create-btn.restore #add-icon {
+
+}
+.l-sort__create-btn.edit #add-icon {
+
+}
+#tooltip {
+
+}
+
+.l-sort__create-btn:active #add-icon {
+
+}
+.l-sort__create-btn.restore:active #add-icon {
+
+}
+
+.l-sort__create-btn.edit:active #add-icon {
+
+}
+
+.l-sort__create-btn.edit:hover #tooltip {
+
+}
+.l-sort__create-btn.edit:active #tooltip {
+
+}
+
+.l-sort__create-btn:active #tooltip {
+
+}
+
+.pill {
+
+}
+
+.pill.usage{
+  box-shadow: inset 0px 1px 1px rgba(0,0,0,0.85), 0px 1px 1px rgba(0,0,0,0.2);
+  background-color: rgba(15,15,15,0.5);
+  border: 1px solid rgba(120,120,120,0.95);
+  text-shadow: 0px 1px 1px rgba(0,0,0,0.5);
+  color: #909090;
+}
+
+.pill.usage b { color: #d8d8d8; }
+
+.badge {
+  box-shadow: 0px 1px 2px rgba(70,70,70,0.5), 
+              inset 0px 2px 2px rgba(0,0,0,0.65);
+  text-shadow: 0px 1px 2px rgba(0,0,0,0.5);
+  border: 1px solid #212121 !important;
+}
+
+.badge.large {
+
+}
+
+.badge.raised {
+  background: radial-gradient(ellipse at center, rgba(40,40,40,0.2) 0%,rgba(80,80,80,0.05) 100%);
+}
+
+.l-unit--suspended .badge {
+  background: #303030 !important;
+  color: #808080 !important;
+  text-shadow: 0px -1px rgba(0,0,0,0.4) !important;
+  box-shadow: 0px 1px 2px rgba(25,25,25,0.3) !important;
+}
+
+.pill.gray, .badge.gray {
+  border: 1px solid #181818;
+  background-color: #252525;
+  color: #dadada;
+  text-shadow: 0px 1px rgba(0,0,0,0.7) !important;
+}
+
+.pill.blue, .badge.blue {
+
+}
+
+.pill.purple, .badge.purple {
+
+}
+
+.pill.teal, .badge.teal {
+
+}
+
+.pill.maroon, .badge.maroon {
+  background-color: #ff3478;
+}
+
+.pill.red, .badge.red {
+
+}
+
+.pill.orange, .badge.orange {
+
+}
+
+.pill.green, .badge.green {
+
+}
+
+.pill.lightblue, .badge.lightblue {
+
+}
+
+.status-icon.large {
+
+}
+
+.status-icon.yellow, .status-icon.yellow:hover {
+  color: #f3e72c;
+}
+.status-icon.teal, .status-icon.teal:hover {
+  color: #33cccc;
+}
+.status-icon.purple, .status-icon.purple:hover {
+  color: #c364ff;
+}
+
+.status-icon.maroon, .status-icon.maroon:hover {
+  color: #ff3478;
+}
+
+.status-icon.red, .status-icon.red:hover {
+
+}
+
+.status-icon.green, .status-icon.green:hover {
+  color: #37cf39;
+}
+
+.status-icon.orange, .status-icon.orange:hover {
+
+}
+
+.status-icon.lightblue, .status-icon.lightblue:hover {
+
+}
+
+.status-icon.highlight, .status-icon.highlight:hover {
+  color: #dadada;
+}
+
+.status-icon.blue, .status-icon.blue:hover {
+  color: #0092f4;
+}
+
+.status-icon.dim {
+  color: #808080;
+  text-shadow: 1px 1px rgba(0,0,0,0.3);
+}
+
+.l-unit--suspended .status-icon.dim {
+  color: #808080 !important;
+  text-shadow: 0px !important;
+}
+
+.noselect {
+
+}
+
+.search-input {
+  background-color: #212121;
+  border: 1px solid #454545;
+  box-shadow: 0px 1px 1px rgba(0,0,0,0.4) !important;
+
+}
+.lang-ru .search-input{
+
+}
+.lang-ru .search-input.activated{
+
+}
+.search-input.activated{
+
+}
+.search-input:focus {
+
+}
+
+.float-left {
+
+}
+.float-right {
+
+}
+.display-inline-block {
+
+}
+.width-100p {
+
+}
+
+.l-sort-toolbar table td {
+
+}
+.l-sort-toolbar__search-box {
+
+}
+.ui-dialog .ui-dialog-buttonpane button:nth-of-type(2) {
+
+}
+
+.ui-dialog .ui-dialog-buttonpane {
+  border-color: #404040 !important;
+  background-color: #252525 !important;
+}
+
+.shortcuts {
+  background: rgba(30,30,30,0.95);
+  border: 1px solid rgba(255,255,255,0.25);
+  box-shadow: 0px 0px 20px rgba(0,0,0,0.5);
+  border-bottom: none !important;
+}
+
+.shortcuts .header {
+  border-bottom: 1px solid #353535;
+}
+
+.shortcuts .title {
+
+}
+.shortcuts .close {
+
+}
+.shortcuts .close:hover {
+
+}
+.shortcuts .close:active {
+
+}
+
+.shortcuts .close .fas {
+
+}
+.shortcuts ul {
+
+}
+.shortcuts ul li {
+
+}
+.shortcuts ul li.step-top {
+
+}
+.shortcuts ul li span {
+
+}
+.shortcuts ul li span.bigger {
+
+}
+
+.description {
+
+}
+.description ul{
+
+}
+
+.description li{
+
+}
+
+.description a {
+
+}
+.description a.purchase {
+
+}
+.description a.purchase:hover {
+  color: #d4d4d4;
+}
+.description a.purchase:active {
+  color: #d4d4d4;
+}
+
+.description a.cancel {
+
+}
+.description a.cancel:hover {
+
+}
+.description a.cancel:active {
+
+}
+
+.description.cancel-success {
+
+}
+
+.description .licence {
+
+}
+
+.description .licence input {
+
+}
+
+.description span {
+
+}
+
+.description .twoco {
+
+}
+
+.ui-dialog {
+  background-color: rgba(45,45,45,0.95) !important;
+  border: 1px solid rgba(80,80,80,0.97) !important;
+  box-shadow: inset 0px 1px 3px rgba(0,0,0,0.25), 
+              0px 8px 25px rgba(0,0,0,0.9) !important;
+}
+
+.ui-dialog .ui-dialog-content {
+  color: #dadada !important;
+}
+
+.ui-dialog .ui-dialog-title {
+  color: #f12569 !important;
+  font-weight: 600;
+}
+
+.ui-dialog-buttonpane {
+
+}
+
+.ui-widget {
+
+}
+
+.ui-widget-overlay {
+
+}
+
+.helper-container {
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.25);
+  border: 1px solid #606060;
+  background-color: #454545;
+}
+
+.context-helper {
+
+}
+.context-helper:hover {
+
+}
+.context-helper:active {
+  color: #ff3478;
+}
+
+
+.cron-helper-tabs {
+
+}
+
+.cron-helper-tabs a {
+  color: #cacaca;
+}
+
+.cron-helper-tabs a:hover {
+  color: #ff3478 !important;
+}
+.cron-helper-tabs a:active {
+  color: #3b9de8 !important;
+}
+.cron-helper-tabs .ui-tabs-selected a {
+  color: #ff3478 !important;
+}
+
+.cron-helper-tabs select.short {
+
+}
+
+.cron-helper-tabs p {
+  color: #dadada;
+
+}
+.cron-helper-tabs p span{
+
+}
+.cron-helper-tabs p span.first{
+
+}
+
+.cron-helper-tabs .button {
+
+}
+.cron-helper-tabs .button:hover {
+
+}
+.cron-helper-tabs .button:active {
+
+}
+
+.context-helper-close {
+
+}
+.context-helper-close:hover {
+
+}
+.context-helper-close:active {
+
+}
+
+.server-info {
+
+}
+
+.server-info-data {
+
+}
+.server-info-name {
+  color: #fafafa !important;
+
+}
+
+.server-info-output {
+  background: #282828;
+}
+
+.icon-server-info {
+  color: #707070;
+}
+
+.userlist-email {
+
+}
+
+.userlist-username {
+
+}
+
+.ui-widget-header a {
+  color: #cacaca !important; 
+}
+
+.body-rrd .units .l-unit {
+  background-color: #282828 !important;
+  border-left: 1px solid transparent !important;
+  border-right: 1px solid transparent !important;
+}
+
+@media screen and (max-width: 950px) {
+  .helper-container {
+    display: none;
+  }
+}

+ 56 - 7
install/deb/themes/flat.css

@@ -14,11 +14,24 @@ b, strong {
 
 .table-header {
     box-shadow: none !important;
+    background: #fafafa !important;
+}
+.advanced-options {
+    background: #fafafa !important;
 }
 
+.to-top, .to-shortcuts, 
+.to-top:hover, .to-shortcuts:hover,
+.to-top:active, .to-shortcuts:active {
+    box-shadow: none !important;
+    background: none !important;
+    background-color: #eee !important;
+} 
+
 .l-header {
     box-shadow: none;
     background: #5070a6;
+    text-shadow: none !important;
 }
 
 .l-menu__item--active {
@@ -27,6 +40,7 @@ b, strong {
 
 .l-menu__item.l-menu__item--active a {
     background: none;
+    box-shadow: none !important;
 }
 
 .l-menu__item a:hover {
@@ -36,7 +50,7 @@ b, strong {
 
 .l-menu__item a:active {
     background: none;
-    box-shadow: none;
+    box-shadow: none !important;
 }
 
 .l-profile__notifications:hover,
@@ -78,28 +92,55 @@ b, strong {
     box-shadow: none;
 }
 
-.ui-button, .button {
+.ui-button, .button, .ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit, .vst-advanced {
     box-shadow: none !important;
     background: linear-gradient(to bottom, rgba(235,243,249,1) 0%,rgba(223,235,245,1) 100%) !important;
 }
 
-.ui-button.cancel, .button.cancel {
+.ui-button.cancel,
+.button.cancel,
+.to-top, .to-shortcuts {
     box-shadow: none !important;
     background: linear-gradient(to bottom, rgba(250,250,250,1) 0%,rgba(241,241,241,1) 100%) !important;
 }
 
-.ui-button:hover, .button:hover, .ui-button.cancel:hover, .button.cancel:hover {
+.ui-button:hover, .button:hover, .ui-button.cancel:hover, .button.cancel:hover,
+.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit:hover,
+.vst-advanced:hover, .to-top:hover, .to-shortcuts:hover  {
+    color: #6986b7 !important;
     box-shadow: none !important;
     background: linear-gradient(to bottom, rgba(241,248,253,1) 0%,rgba(227,240,251,1) 100%) !important;
 }
 
 .ui-button:focus,.ui-button:active,
 .button:active,.button:focus,.ui-button.cancel:focus,.ui-button.cancel:active,
-.button.cancel:active,.button.cancel:focus {
+.button.cancel:active,.button.cancel:focus,
+.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit:active,
+.vst-advanced:active,.to-top:focus, .to-shortcuts:focus {
     box-shadow: none !important;
     background: linear-gradient(to bottom, rgba(210,232,250,1) 0%,rgba(194,224,248,1) 100%) !important;
 }
 
+.ui-button.danger:hover, .button.danger:hover {
+    background: #fcd3cf !important;
+    color: #F4301A !important;
+    border: 1px solid #F27E71 !important;
+}
+  
+.ui-button.danger:active, .button.danger:active, .ui-button.danger:focus, .button.danger:focus {
+    background: #a91200 !important; 
+    color: #fff !important;
+    border: 1px solid #F4301A !important;
+}
+
+.ui-dialog .ui-dialog-buttonpane button:nth-of-type(2) {
+    box-shadow: none !important;
+}
+
+.ui-dialog {
+    box-shadow: 0 2px 11px 0 rgba(0, 0, 0, 0.5) !important;
+}
+
 .alert {
     text-shadow: none !important;
     box-shadow: none !important;
@@ -115,10 +156,18 @@ b, strong {
 
 .notification-container {
     box-shadow: none;
-    border: 1px solid #dadada;
+    border: 1px solid #ccc;
+    background: #fff;
 }
 
 .context-menu.sort-order {
     box-shadow: none;
-    border: 1px solid #dadada;
+    border: 1px solid #ccc;
+    background: #fff !important;
+}
+
+.login {
+    background-color: rgba(255,255,255,0.8) !important;
+    box-shadow: 0px 2px 10px rgba(0,0,0, 0.3), 
+                inset 0px 0px 2px rgba(255,255,255,1) !important;
 }

+ 57 - 36
install/hst-install-debian.sh

@@ -22,9 +22,10 @@ codename="$(cat /etc/os-release |grep VERSION= |cut -f 2 -d \(|cut -f 1 -d \))"
 HESTIA_INSTALL_DIR="$HESTIA/install/deb"
 
 # Define software versions
-pma_v='4.9.4'
+pma_v='5.0.2'
 multiphp_v=("5.6" "7.0" "7.1" "7.2" "7.3" "7.4")
 fpm_v="7.3"
+mariadb_v="10.4"
 
 if [ "$release" -eq 8 ]; then
     software="nginx apache2 apache2-utils apache2.2-common
@@ -78,7 +79,7 @@ help() {
     echo "Usage: $0 [OPTIONS]
   -a, --apache            Install Apache        [yes|no]  default: yes
   -n, --nginx             Install Nginx         [yes|no]  default: yes
-  -w, --phpfpm            Install PHP-FPM       [yes|no]  default: no
+  -w, --phpfpm            Install PHP-FPM       [yes|no]  default: yes
   -o, --multiphp          Install Multi-PHP     [yes|no]  default: no
   -v, --vsftpd            Install Vsftpd        [yes|no]  default: yes
   -j, --proftpd           Install ProFTPD       [yes|no]  default: no
@@ -103,7 +104,7 @@ help() {
   -f, --force             Force installation
   -h, --help              Print this help
 
-  Example: bash $0 -e demo@hestiacp.com -p p4ssw0rd --apache no --phpfpm yes"
+  Example: bash $0 -e demo@hestiacp.com -p p4ssw0rd --multiphp yes"
     exit 1
 }
 
@@ -244,7 +245,7 @@ done
 # Defining default software stack
 set_default_value 'nginx' 'yes'
 set_default_value 'apache' 'yes'
-set_default_value 'phpfpm' 'no'
+set_default_value 'phpfpm' 'yes'
 set_default_value 'multiphp' 'no'
 set_default_value 'vsftpd' 'yes'
 set_default_value 'proftpd' 'no'
@@ -269,9 +270,6 @@ set_default_port '8083'
 set_default_lang 'en'
 
 # Checking software conflicts
-if [ "$multiphp" = 'yes' ]; then
-    phpfpm='yes'
-fi
 if [ "$proftpd" = 'yes' ]; then
     vsftpd='no'
 fi
@@ -440,7 +438,7 @@ echo ' |  _  |  __/\__ \ |_| | (_| | |___|  __/ '
 echo ' |_| |_|\___||___/\__|_|\__,_|\____|_|    '
 echo
 echo '                      Hestia Control Panel'
-echo '                                    v1.1.0'
+echo '                                    v1.1.2'
 echo -e "\n"
 echo "===================================================================="
 echo -e "\n"
@@ -597,40 +595,51 @@ apt=/etc/apt/sources.list.d
 # Updating system
 echo "Adding required repositories to proceed with installation:"
 echo
-# Installing nginx repo
-echo "(*) NGINX"
-echo "deb [arch=amd64] http://nginx.org/packages/mainline/$VERSION/ $codename nginx" > $apt/nginx.list
-wget --quiet http://nginx.org/keys/nginx_signing.key -O /tmp/nginx_signing.key
-APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/nginx_signing.key > /dev/null 2>&1
 
-# Installing sury php repo
+# Installing Nginx repo
+if [ "$nginx" = 'yes' ]; then
+    echo "(*) NGINX"
+    echo "deb [arch=amd64] http://nginx.org/packages/mainline/$VERSION/ $codename nginx" > $apt/nginx.list
+    wget --quiet http://nginx.org/keys/nginx_signing.key -O /tmp/nginx_signing.key
+    APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/nginx_signing.key > /dev/null 2>&1
+fi
+
+# Installing sury PHP repo
 echo "(*) PHP"
 echo "deb https://packages.sury.org/php/ $codename main" > $apt/php.list
 wget --quiet https://packages.sury.org/php/apt.gpg -O /tmp/php_signing.key
 APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/php_signing.key > /dev/null 2>&1
 
+# Installing sury Apache2 repo
+if [ "$apache" = 'yes' ]; then
+    echo "(*) Apache2"
+    echo "deb https://packages.sury.org/apache2/ $codename main" > $apt/apache2.list
+    wget --quiet https://packages.sury.org/apache2/apt.gpg -O /tmp/apache2_signing.key
+    APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/apache2_signing.key > /dev/null 2>&1
+fi
+
 # Installing MariaDB repo
-echo "(*) MariaDB"
-echo "deb [arch=amd64] http://ams2.mirrors.digitalocean.com/mariadb/repo/10.4/$VERSION $codename main" > $apt/mariadb.list
-if [ "$release" -eq 8 ]; then
-    APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key adv --recv-keys --keyserver keyserver.ubuntu.com CBCB082A1BB943DB > /dev/null 2>&1
-else
-    APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key adv --recv-keys --keyserver keyserver.ubuntu.com F1656F24C74CD1D8 > /dev/null 2>&1
+if [ "$mysql" = 'yes' ]; then
+    echo "(*) MariaDB"
+    echo "deb [arch=amd64] http://ams2.mirrors.digitalocean.com/mariadb/repo/$mariadb_v/$VERSION $codename main" > $apt/mariadb.list
+    if [ "$release" -eq 8 ]; then
+        APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key adv --recv-keys --keyserver keyserver.ubuntu.com CBCB082A1BB943DB > /dev/null 2>&1
+    else
+        APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key adv --recv-keys --keyserver keyserver.ubuntu.com F1656F24C74CD1D8 > /dev/null 2>&1
+    fi
 fi
 
-# Installing Backport repo for debian 8
+# Installing Backport repo for Debian 8
 if [ "$release" -eq 8 ]; then
     echo "deb [check-valid-until=no] http://archive.debian.org/debian jessie-backports main" >> /etc/apt/sources.list
 fi
 
-# Installing hestia repo
+# Installing HestiaCP repo
 echo "(*) Hestia Control Panel"
 echo "deb https://$RHOST/ $codename main" > $apt/hestia.list
-wget --quiet https://gpg.hestiacp.com/deb_signing.key -O /tmp/deb_signing.key
-APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/deb_signing.key > /dev/null 2>&1
-rm /tmp/deb_signing.key
+APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A189E93654F0B0E5 > /dev/null 2>&1
 
-# Installing postgresql repo
+# Installing PostgreSQL repo
 if [ "$postgresql" = 'yes' ]; then
     echo "(*) PostgreSQL"
     echo "deb http://apt.postgresql.org/pub/repos/apt/ $codename-pgdg main" > $apt/postgresql.list
@@ -1012,6 +1021,24 @@ else
     fi
 fi
 
+# Database stack
+if [ "$mysql" = 'yes' ]; then
+    installed_db_types='mysql'
+fi
+
+if [ "$pgsql" = 'yes' ]; then
+    installed_db_types="$installed_db_type,pgsql"
+fi
+
+if [ ! -z "$installed_db_types" ]; then
+    db=$(echo "$installed_db_types" |\
+        sed "s/,/\n/g"|\
+        sort -r -u |\
+        sed "/^$/d"|\
+        sed ':a;N;$!ba;s/\n/,/g')
+    echo "DB_SYSTEM='$db'" >> $HESTIA/conf/hestia.conf
+fi
+
 # FTP stack
 if [ "$vsftpd" = 'yes' ]; then
     echo "FTP_SYSTEM='vsftpd'" >> $HESTIA/conf/hestia.conf
@@ -1062,7 +1089,7 @@ echo "BACKUP_SYSTEM='local'" >> $HESTIA/conf/hestia.conf
 echo "LANGUAGE='$lang'" >> $HESTIA/conf/hestia.conf
 
 # Version & Release Branch
-echo "VERSION='1.1.0'" >> $HESTIA/conf/hestia.conf
+echo "VERSION='1.1.2'" >> $HESTIA/conf/hestia.conf
 echo "RELEASE_BRANCH='release'" >> $HESTIA/conf/hestia.conf
 
 # Installing hosting packages
@@ -1159,6 +1186,7 @@ if [ "$apache" = 'yes' ]; then
     a2enmod suexec > /dev/null 2>&1
     a2enmod ssl > /dev/null 2>&1
     a2enmod actions > /dev/null 2>&1
+    a2dismod status > /dev/null 2>&1
     if [ "$release" -eq 10 ]; then
         a2enmod mpm_itk > /dev/null 2>&1
     else
@@ -1330,8 +1358,8 @@ if [ "$mysql" = 'yes' ]; then
     cp -rf phpMyAdmin-$pma_v-all-languages/* /usr/share/phpmyadmin
 
     # Set config and log directory
-    sed -i "s|define('CONFIG_DIR', '');|define('CONFIG_DIR', '/etc/phpmyadmin/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
-    sed -i "s|define('TEMP_DIR', './tmp/');|define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
+    sed -i "s|define('CONFIG_DIR', ROOT_PATH);|define('CONFIG_DIR', '/etc/phpmyadmin/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
+    sed -i "s|define('TEMP_DIR', ROOT_PATH . 'tmp/');|define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
 
     # Create temporary folder and change permission
     mkdir /usr/share/phpmyadmin/tmp
@@ -1505,13 +1533,6 @@ fi
 
 if [ "$dovecot" = 'yes' ] && [ "$exim" = 'yes' ] && [ "$mysql" = 'yes' ]; then
     echo "(*) Configuring Roundcube webmail client..."
-    if [ "$apache" = 'yes' ]; then
-        cp -f $HESTIA_INSTALL_DIR/roundcube/apache.conf /etc/roundcube/
-        ln -s /etc/roundcube/apache.conf /etc/apache2/conf.d/roundcube.conf
-    fi
-    if [ "$nginx" = 'yes' ]; then
-        cp -f $HESTIA_INSTALL_DIR/nginx/webmail.inc /etc/nginx/conf.d/
-    fi
     cp -f $HESTIA_INSTALL_DIR/roundcube/main.inc.php /etc/roundcube/config.inc.php
     cp -f $HESTIA_INSTALL_DIR/roundcube/db.inc.php /etc/roundcube/debian-db-roundcube.php
     cp -f $HESTIA_INSTALL_DIR/roundcube/config.inc.php /etc/roundcube/plugins/password/

+ 59 - 36
install/hst-install-ubuntu.sh

@@ -22,9 +22,10 @@ codename="$(lsb_release -s -c)"
 HESTIA_INSTALL_DIR="$HESTIA/install/deb"
 
 # Define software versions
-pma_v='4.9.4'
+pma_v='5.0.2'
 multiphp_v=("5.6" "7.0" "7.1" "7.2" "7.3" "7.4")
 fpm_v="7.3"
+mariadb_v="10.4"
 
 # Defining software pack for all distros
 software="apache2 apache2.2-common apache2-suexec-custom apache2-utils
@@ -47,7 +48,7 @@ help() {
     echo "Usage: $0 [OPTIONS]
   -a, --apache            Install Apache        [yes|no]  default: yes
   -n, --nginx             Install Nginx         [yes|no]  default: yes
-  -w, --phpfpm            Install PHP-FPM       [yes|no]  default: no
+  -w, --phpfpm            Install PHP-FPM       [yes|no]  default: yes
   -o, --multiphp          Install Multi-PHP     [yes|no]  default: no
   -v, --vsftpd            Install Vsftpd        [yes|no]  default: yes
   -j, --proftpd           Install ProFTPD       [yes|no]  default: no
@@ -72,7 +73,7 @@ help() {
   -f, --force             Force installation
   -h, --help              Print this help
 
-  Example: bash $0 -e demo@hestiacp.com -p p4ssw0rd --apache no --phpfpm yes"
+  Example: bash $0 -e demo@hestiacp.com -p p4ssw0rd --multiphp yes"
     exit 1
 }
 
@@ -213,7 +214,7 @@ done
 # Defining default software stack
 set_default_value 'nginx' 'yes'
 set_default_value 'apache' 'yes'
-set_default_value 'phpfpm' 'no'
+set_default_value 'phpfpm' 'yes'
 set_default_value 'multiphp' 'no'
 set_default_value 'vsftpd' 'yes'
 set_default_value 'proftpd' 'no'
@@ -238,10 +239,6 @@ set_default_port '8083'
 set_default_lang 'en'
 
 # Checking software conflicts
-
-if [ "$multiphp" = 'yes' ]; then
-    phpfpm='yes'
-fi
 if [ "$proftpd" = 'yes' ]; then
     vsftpd='no'
 fi
@@ -403,7 +400,7 @@ echo ' |  _  |  __/\__ \ |_| | (_| | |___|  __/ '
 echo ' |_| |_|\___||___/\__|_|\__,_|\____|_|    '
 echo
 echo '                      Hestia Control Panel'
-echo '                                    v1.1.0'
+echo '                                    v1.1.2'
 echo -e "\n"
 echo "===================================================================="
 echo -e "\n"
@@ -561,33 +558,41 @@ apt=/etc/apt/sources.list.d
 echo "Adding required repositories to proceed with installation:"
 echo
 
-# Installing nginx repo
-echo "(*) NGINX"
-if [ -e $apt/nginx.list ]; then
-    rm $apt/nginx.list
-fi
-echo "deb [arch=amd64] http://nginx.org/packages/mainline/$VERSION/ $codename nginx" \
+# Installing Nginx repo
+if [ "$nginx" = 'yes' ]; then
+    echo "(*) NGINX"
+    if [ -e $apt/nginx.list ]; then
+        rm $apt/nginx.list
+    fi
+    echo "deb [arch=amd64] http://nginx.org/packages/mainline/$VERSION/ $codename nginx" \
     > $apt/nginx.list
-wget --quiet http://nginx.org/keys/nginx_signing.key -O /tmp/nginx_signing.key
-APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/nginx_signing.key > /dev/null 2>&1
+    wget --quiet http://nginx.org/keys/nginx_signing.key -O /tmp/nginx_signing.key
+    APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/nginx_signing.key > /dev/null 2>&1
+fi
 
-# Installing sury php repo
+# Installing sury PHP repo
 echo "(*) PHP"
 LC_ALL=C.UTF-8 add-apt-repository -y ppa:ondrej/php > /dev/null 2>&1
 
+# Installing sury Apache2 repo
+if [ "$apache" = 'yes' ]; then
+    echo "(*) Apache2"
+    echo "deb http://ppa.launchpad.net/ondrej/apache2/ubuntu $codename main" > $apt/apache2.list
+fi
+
 # Installing MariaDB repo
-echo "(*) MariaDB"
-echo "deb [arch=amd64] http://ams2.mirrors.digitalocean.com/mariadb/repo/10.4/$VERSION $codename main" > $apt/mariadb.list
-APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8 > /dev/null 2>&1
+if [ "$mysql" = 'yes' ]; then
+    echo "(*) MariaDB"
+    echo "deb [arch=amd64] http://ams2.mirrors.digitalocean.com/mariadb/repo/$mariadb_v/$VERSION $codename main" > $apt/mariadb.list
+    APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8 > /dev/null 2>&1
+fi
 
-# Installing hestia repo
+# Installing HestiaCP repo
 echo "(*) Hestia Control Panel"
 echo "deb https://$RHOST/ $codename main" > $apt/hestia.list
-wget --quiet https://gpg.hestiacp.com/deb_signing.key -O /tmp/deb_signing.key
-APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/deb_signing.key > /dev/null 2>&1
-rm /tmp/deb_signing.key
+APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key adv --keyserver keyserver.ubuntu.com --recv-keys A189E93654F0B0E5 > /dev/null 2>&1
 
-# Installing postgresql repo
+# Installing PostgreSQL repo
 if [ "$postgresql" = 'yes' ]; then
     echo "(*) PostgreSQL"
     echo "deb http://apt.postgresql.org/pub/repos/apt/ $codename-pgdg main" > $apt/postgresql.list
@@ -982,6 +987,24 @@ if [ "$phpfpm" = 'yes' ] || [ "$multiphp" = 'yes' ]; then
     echo "WEB_BACKEND='php-fpm'" >> $HESTIA/conf/hestia.conf
 fi
 
+# Database stack
+if [ "$mysql" = 'yes' ]; then
+    installed_db_types='mysql'
+fi
+
+if [ "$pgsql" = 'yes' ]; then
+    installed_db_types="$installed_db_type,pgsql"
+fi
+
+if [ ! -z "$installed_db_types" ]; then
+    db=$(echo "$installed_db_types" |\
+        sed "s/,/\n/g"|\
+        sort -r -u |\
+        sed "/^$/d"|\
+        sed ':a;N;$!ba;s/\n/,/g')
+    echo "DB_SYSTEM='$db'" >> $HESTIA/conf/hestia.conf
+fi
+
 # FTP stack
 if [ "$vsftpd" = 'yes' ]; then
     echo "FTP_SYSTEM='vsftpd'" >> $HESTIA/conf/hestia.conf
@@ -1032,7 +1055,7 @@ echo "BACKUP_SYSTEM='local'" >> $HESTIA/conf/hestia.conf
 echo "LANGUAGE='$lang'" >> $HESTIA/conf/hestia.conf
 
 # Version & Release Branch
-echo "VERSION='1.1.0'" >> $HESTIA/conf/hestia.conf
+echo "VERSION='1.1.2'" >> $HESTIA/conf/hestia.conf
 echo "RELEASE_BRANCH='release'" >> $HESTIA/conf/hestia.conf
 
 # Installing hosting packages
@@ -1135,6 +1158,7 @@ if [ "$apache" = 'yes' ]; then
     a2enmod ssl > /dev/null 2>&1
     a2enmod actions > /dev/null 2>&1
     a2enmod ruid2 > /dev/null 2>&1
+    a2dismod status > /dev/null 2>&1
     mkdir -p /etc/apache2/conf.d
     mkdir -p /etc/apache2/conf.d/domains
     echo "# Powered by hestia" > /etc/apache2/sites-available/default
@@ -1301,8 +1325,8 @@ if [ "$mysql" = 'yes' ]; then
     cp -rf phpMyAdmin-$pma_v-all-languages/* /usr/share/phpmyadmin
 
     # Set config and log directory
-    sed -i "s|define('CONFIG_DIR', '');|define('CONFIG_DIR', '/etc/phpmyadmin/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
-    sed -i "s|define('TEMP_DIR', './tmp/');|define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
+    sed -i "s|define('CONFIG_DIR', ROOT_PATH);|define('CONFIG_DIR', '/etc/phpmyadmin/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
+    sed -i "s|define('TEMP_DIR', ROOT_PATH . 'tmp/');|define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
 
     # Create temporary folder and change permission
     mkdir /usr/share/phpmyadmin/tmp
@@ -1466,13 +1490,6 @@ fi
 
 if [ "$dovecot" = 'yes' ] && [ "$exim" = 'yes' ] && [ "$mysql" = 'yes' ]; then
     echo "(*) Configuring Roundcube webmail client..."
-    if [ "$apache" = 'yes' ]; then
-        cp -f $HESTIA_INSTALL_DIR/roundcube/apache.conf /etc/roundcube/
-        ln -s /etc/roundcube/apache.conf /etc/apache2/conf.d/roundcube.conf
-    fi
-    if [ "$nginx" = 'yes' ]; then
-        cp -f $HESTIA_INSTALL_DIR/nginx/webmail.inc /etc/nginx/conf.d/
-    fi
     cp -f $HESTIA_INSTALL_DIR/roundcube/main.inc.php /etc/roundcube/config.inc.php
     cp -f $HESTIA_INSTALL_DIR/roundcube/db.inc.php /etc/roundcube/debian-db-roundcube.php
     cp -f $HESTIA_INSTALL_DIR/roundcube/config.inc.php /etc/roundcube/plugins/password/
@@ -1616,6 +1633,12 @@ if [ ! -z "$pub_ip" ] && [ "$pub_ip" != "$ip" ]; then
     if [ -e /etc/rc.local ]; then
         sed -i '/exit 0/d' /etc/rc.local
     fi
+
+    check_rclocal=$(cat /etc/rc.local | grep "#!")
+    if [ -z "$check_rclocal" ]; then
+        echo "#!/bin/sh" >> /etc/rc.local
+    fi
+
     echo "$HESTIA/bin/v-update-sys-ip" >> /etc/rc.local
     echo "exit 0" >> /etc/rc.local
     chmod +x /etc/rc.local

+ 2 - 2
install/hst-install.sh

@@ -74,7 +74,7 @@ fi
 check_wget_curl(){
     # Check wget
     if [ -e '/usr/bin/wget' ]; then
-        wget -q https://raw.githubusercontent.com/hestiacp/hestiacp/master/install/hst-install-$type.sh -O hst-install-$type.sh
+        wget -q https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install-$type.sh -O hst-install-$type.sh
         if [ "$?" -eq '0' ]; then
             bash hst-install-$type.sh $*
             exit
@@ -86,7 +86,7 @@ check_wget_curl(){
 
     # Check curl
     if [ -e '/usr/bin/curl' ]; then
-        curl -s -O https://raw.githubusercontent.com/hestiacp/hestiacp/master/install/hst-install-$type.sh
+        curl -s -O https://raw.githubusercontent.com/hestiacp/hestiacp/release/install/hst-install-$type.sh
         if [ "$?" -eq '0' ]; then
             bash hst-install-$type.sh $*
             exit

+ 18 - 203
install/upgrade/versions/latest.sh

@@ -1,215 +1,30 @@
 #!/bin/sh
 
-# Hestia Control Panel upgrade script for target version 1.1.0
+# Hestia Control Panel upgrade script for target version 1.1.2
 
 #######################################################################################
 #######                      Place additional commands below.                   #######
 #######################################################################################
 
-# Set default theme
-if [ -z $THEME ]; then
-    echo "(*) Enabling support for themes..."
-    $BIN/v-change-sys-theme 'default'
+if [ -e "/etc/apache2/mods-enabled/status.conf" ]; then
+    echo "(*) Disable Apache2 Server Status Module..."
+    a2dismod status > /dev/null 2>&1
 fi
 
-# Reduce SSH login grace time
-if [ -e /etc/ssh/sshd_config ]; then
-    echo "(*) Hardening SSH daemon configuration..."
-    sed -i "s/LoginGraceTime 2m/LoginGraceTime 1m/g" /etc/ssh/sshd_config
-    sed -i "s/#LoginGraceTime 2m/LoginGraceTime 1m/g" /etc/ssh/sshd_config
-fi
-
-# Implement recidive jail for fail2ban
-if [ ! -z "$FIREWALL_EXTENSION" ]; then
-    if ! cat /etc/fail2ban/jail.local | grep -q "\[recidive\]"; then
-        echo -e "\n\n[recidive]\nenabled  = true\nfilter   = recidive\naction   = hestia[name=HESTIA]\nlogpath  = /var/log/fail2ban.log\nmaxretry = 3\nfindtime = 86400\nbantime  = 864000" >> /etc/fail2ban/jail.local
-    fi
-fi
-
-# Enable OCSP SSL stapling and harden nginx configuration for roundcube
-if [ ! -z "$IMAP_SYSTEM" ]; then
-    echo "(*) Hardening security of Roundcube webmail..."
-    $BIN/v-update-mail-templates > /dev/null 2>&1
-    if [ -e /etc/nginx/conf.d/webmail.inc ]; then
-        cp -f /etc/nginx/conf.d/webmail.inc $HESTIA_BACKUP/conf/
-        sed -i "s/config|temp|logs/README.md|config|temp|logs|bin|SQL|INSTALL|LICENSE|CHANGELOG|UPGRADING/g" /etc/nginx/conf.d/webmail.inc
-    fi
-fi
-
-# Fix restart queue
-if [ -z "$($BIN/v-list-cron-jobs admin | grep 'v-update-sys-queue restart')" ]; then
-    command="sudo $BIN/v-update-sys-queue restart"
-    $BIN/v-add-cron-job 'admin' '*/2' '*' '*' '*' '*' "$command"
-fi
-
-# Remove deprecated line from ClamAV configuration file
-if [ -e "/etc/clamav/clamd.conf" ]; then
-    clamd_conf_update_check=$(grep DetectBrokenExecutables /etc/clamav/clamd.conf)
-    if [ ! -z "$clamd_conf_update_check" ]; then
-        echo "(*) Updating ClamAV configuration..."
-        sed -i '/DetectBrokenExecutables/d' /etc/clamav/clamd.conf
-    fi
-fi
-
-# Remove errornous history.log file created by certain builds due to bug in v-restart-system
-if [ -e $HESTIA/data/users/history.log ]; then
-    rm -f $HESTIA/data/users/history.log
-fi
-
-# Use exim4 server hostname instead of mail domain and remove hardcoded mail prefix
-if [ ! -z "$MAIL_SYSTEM" ]; then
-    echo "(*) Updating exim configuration..."
-    if cat /etc/exim4/exim4.conf.template | grep -q 'helo_data = mail.${sender_address_domain}'; then
-        sed -i 's/helo_data = mail.${sender_address_domain}/helo_data = ${primary_hostname}/g' /etc/exim4/exim4.conf.template
-    fi
-    if ! grep -q '^OUTGOING_IP = /' /etc/exim4/exim4.conf.template; then
-        sed -i '/^OUTGOING_IP/d' /etc/exim4/exim4.conf.template
-        sed -i 's|^begin acl|OUTGOING_IP = /etc/exim4/domains/$sender_address_domain/ip\nbegin acl|' /etc/exim4/exim4.conf.template
-    fi
-    if ! grep -q 'interface =' /etc/exim4/exim4.conf.template; then
-        sed -i '/interface =/d' /etc/exim4/exim4.conf.template
-        sed -i 's|dkim_strict = 0|dkim_strict = 0\n  interface = ${if exists{OUTGOING_IP}{${readfile{OUTGOING_IP}}}}|' /etc/exim4/exim4.conf.template
-    fi
-fi
-
-# Members of admin group should be permitted to enter admin folder
-if [ -d /home/admin ]; then
-    setfacl -m "g:admin:r-x" /home/admin
-fi
-
-# Fix sftp jail cronjob
-if [ -e "/etc/cron.d/hestia-sftp" ]; then
-    if ! cat /etc/cron.d/hestia-sftp | grep -q 'root'; then
-        echo "@reboot root /usr/local/hestia/bin/v-add-sys-sftp-jail" > /etc/cron.d/hestia-sftp
-    fi
-fi
-
-# Create default writeable folders for all users
-echo "(*) Updating default writable folders for all users..."
-for user in $($HESTIA/bin/v-list-sys-users plain); do
-    mkdir -p \
-        $HOMEDIR/$user/.cache \
-        $HOMEDIR/$user/.config \
-        $HOMEDIR/$user/.local \
-        $HOMEDIR/$user/.composer \
-        $HOMEDIR/$user/.ssh
-
-    chown $user:$user \
-        $HOMEDIR/$user/.cache \
-        $HOMEDIR/$user/.config \
-        $HOMEDIR/$user/.local \
-        $HOMEDIR/$user/.composer \
-        $HOMEDIR/$user/.ssh
-done
-
-# Remove redundant fail2ban jail
-if fail2ban-client status sshd > /dev/null 2>&1 ; then
-    fail2ban-client stop sshd >/dev/null 2>&1
-    if [ -f /etc/fail2ban/jail.d/defaults-debian.conf ]; then
-        mkdir -p $HESTIA_BACKUP/conf/fail2ban/jail.d
-        mv /etc/fail2ban/jail.d/defaults-debian.conf $HESTIA_BACKUP/conf/fail2ban/jail.d/
-    fi
-fi
-
-# Update Office 365/Microsoft 365 DNS template
-if [ -e "$HESTIA/data/templates/dns/office365.tpl" ]; then
-    echo "(*) Updating DNS template for Office 365..."
-    cp -f $HESTIA/install/deb/templates/dns/office365.tpl $HESTIA/data/templates/dns/office365.tpl
-fi
-
-# Ensure that backup compression level is correctly set
-GZIP_LVL_CHECK=$(cat $HESTIA/conf/hestia.conf | grep BACKUP_GZIP)
-if [ -z "$GZIP_LVL_CHECK" ]; then
-    echo "(*) Updating backup compression level variable..."
-    $BIN/v-change-sys-config-value "BACKUP_GZIP" '9'
-fi
-
-# Randomize Roundcube des_key for better security
-if [ -f "/etc/roundcube/config.inc.php" ]; then
-    rcDesKey="$(openssl rand -base64 30 | tr -d "/" | cut -c1-24)"
-    sed -i "s/vtIOjLZo9kffJoqzpSbm5r1r/$rcDesKey/g" /etc/roundcube/config.inc.php
-fi
-
-# Place robots.txt to prevent webmail crawling by search engine bots.
-if [ -e "/var/lib/roundcube/" ]; then
-    if [ ! -f "/var/lib/roundcube/robots.txt" ]; then
-        echo "User-agent: *" > /var/lib/roundcube/robots.txt
-        echo "Disallow: /" >> /var/lib/roundcube/robots.txt
-    fi
-fi
-
-# Installing postgresql repo
-if [ -e "/etc/postgresql" ]; then
-    osname="$(cat /etc/os-release | grep "^ID\=" | sed "s/ID\=//g")"
-    if [ "$osname" = "ubuntu" ]; then
-        codename="$(lsb_release -s -c)"
-    else
-        codename="$(cat /etc/os-release |grep VERSION= |cut -f 2 -d \(|cut -f 1 -d \))"
-    fi
-    echo "deb http://apt.postgresql.org/pub/repos/apt/ $codename-pgdg main" > /etc/apt/sources.list.d/postgresql.list
-    wget --quiet https://www.postgresql.org/media/keys/ACCC4CF8.asc -O /tmp/psql_signing.key
-    APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/psql_signing.key > /dev/null 2>&1
-    rm /tmp/psql_signing.key
-fi
-
-# Hardening MySQL configuration, prevent local infile.
-if [ -e "/etc/mysql/my.cnf" ]; then
-    mysql_local_infile_check=$(grep local-infile /etc/mysql/my.cnf)
-    if [ -z "$mysql_local_infile_check" ]; then
-        echo "(*) Hardening MySQL configuration..."
-        sed -i '/symbolic-links\=0/a\local-infile=0' /etc/mysql/my.cnf
-    fi
-fi
-
-# Hardening nginx configuration, drop TLSv1.1 support.
-if [ -e "/etc/nginx/nginx.conf" ]; then
-    nginx_tls_check=$(grep TLSv1.1 /etc/nginx/nginx.conf)
-    if [ ! -z "$nginx_tls_check" ]; then
-        echo "(*) Hardening nginx configuration, drop TLSv1.1 support..."
-        sed -i 's/TLSv1.1 //g' /etc/nginx/nginx.conf
-    fi
-fi
-
-# Fix logrotate permission bug for nginx
-if [ -e "/etc/logrotate/nginx" ]; then
-    sed -i "s/create 640 nginx adm/create 640/g" /etc/logrotate.d/nginx
-fi
+# Add sury apache2 repository
+if [ "$WEB_SYSTEM" = "apache2" ] && [ ! -e "/etc/apt/sources.list.d/apache2.list" ]; then
+    echo "(*) Install sury.org Apache2 repository..."
 
-# Fix logrotate permission bug for apache
-if [ -e "/etc/logrotate/apache2" ]; then
-    sed -i "s/create 640 root adm/create 640/g" /etc/logrotate.d/apache2
-fi
-
-# Repair messed up user log permissions from the logrotate bug. Ignoring errors
-for user in $($HESTIA/bin/v-list-users plain | cut -f1); do
-    for domain in $($HESTIA/bin/v-list-web-domains $user plain | cut -f1); do
-        chown root:$user /var/log/$WEB_SYSTEM/domains/$domain.* > /dev/null 2>&1
-        for sub_domain in $($HESTIA/bin/v-list-web-domain $user $domain plain | cut -f7 | tr ',' '\n'); do
-            chown root:$user /var/log/$WEB_SYSTEM/domains/$sub_domain.* > /dev/null 2>&1
-        done
-    done
-done
-
-chown root:root /var/log/$WEB_SYSTEM/domains/$WEBMAIL_ALIAS* > /dev/null 2>&1
-
-# Enable IMAP/POP3 quota information
-if [ -z "$IMAP_SYSTEM" ]; then
-    echo "(*) Enabling IMAP quota information reporting ..."
-    if [ -e /etc/dovecot/conf.d/20-pop3.conf ]; then
-        cp -f $HESTIA/install/deb/dovecot/conf.d/20-pop3.conf /etc/dovecot/conf.d/20-pop3.conf
-    fi
-    if [ -e /etc/dovecot/conf.d/20-imap.conf ]; then
-        cp -f $HESTIA/install/deb/dovecot/conf.d/20-imap.conf /etc/dovecot/conf.d/20-imap.conf
-    fi
-    if [ -e /etc/dovecot/conf.d/90-quota.conf ]; then
-        cp -f $HESTIA/install/deb/dovecot/conf.d/90-quota.conf /etc/dovecot/conf.d/90-quota.conf
+    # Check OS and install related repository
+    if [ -e "/etc/os-release" ]; then
+        type=$(grep "^ID=" /etc/os-release | cut -f 2 -d '=')
+        if [ "$type" = "ubuntu" ]; then
+            codename="$(lsb_release -s -c)"
+            echo "deb http://ppa.launchpad.net/ondrej/apache2/ubuntu $codename main" > /etc/apt/sources.list.d/apache2.list
+        elif [ "$type" = "debian" ]; then
+            echo "deb https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/apache2.list
+            wget --quiet https://packages.sury.org/apache2/apt.gpg -O /tmp/apache2_signing.key
+            APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/apache2_signing.key > /dev/null 2>&1
+        fi
     fi
 fi
-
-# Trigger multiphp legacy migration script
-num_php_versions=$(ls -d /etc/php/*/fpm/pool.d 2>/dev/null |wc -l)
-if [ "$num_php_versions" -gt 1 ] && [ -z "$WEB_BACKEND" ]; then
-    echo "(*) Migrate to new multiphp backend system..."
-    cp -rf $HESTIA/data/templates/web $HESTIA_BACKUP/templates/web
-    bash $HESTIA/install/upgrade/manual/migrate_multiphp.sh > /dev/null 2>&1
-fi

+ 224 - 0
install/upgrade/versions/previous/1.1.0.sh

@@ -0,0 +1,224 @@
+#!/bin/sh
+
+# Hestia Control Panel upgrade script for target version 1.1.0
+
+#######################################################################################
+#######                      Place additional commands below.                   #######
+#######################################################################################
+
+# Set default theme
+if [ -z $THEME ]; then
+    echo "(*) Enabling support for themes..."
+    $BIN/v-change-sys-theme 'default'
+fi
+
+# Reduce SSH login grace time
+if [ -e /etc/ssh/sshd_config ]; then
+    echo "(*) Hardening SSH daemon configuration..."
+    sed -i "s/LoginGraceTime 2m/LoginGraceTime 1m/g" /etc/ssh/sshd_config
+    sed -i "s/#LoginGraceTime 2m/LoginGraceTime 1m/g" /etc/ssh/sshd_config
+fi
+
+# Implement recidive jail for fail2ban
+if [ ! -z "$FIREWALL_EXTENSION" ]; then
+    if ! cat /etc/fail2ban/jail.local | grep -q "\[recidive\]"; then
+        echo -e "\n\n[recidive]\nenabled  = true\nfilter   = recidive\naction   = hestia[name=HESTIA]\nlogpath  = /var/log/fail2ban.log\nmaxretry = 3\nfindtime = 86400\nbantime  = 864000" >> /etc/fail2ban/jail.local
+    fi
+fi
+
+# Enable OCSP SSL stapling and harden nginx configuration for roundcube
+if [ ! -z "$IMAP_SYSTEM" ]; then
+    echo "(*) Hardening security of Roundcube webmail..."
+    $BIN/v-update-mail-templates > /dev/null 2>&1
+    if [ -e /etc/nginx/conf.d/webmail.inc ]; then
+        cp -f /etc/nginx/conf.d/webmail.inc $HESTIA_BACKUP/conf/
+        sed -i "s/config|temp|logs/README.md|config|temp|logs|bin|SQL|INSTALL|LICENSE|CHANGELOG|UPGRADING/g" /etc/nginx/conf.d/webmail.inc
+    fi
+fi
+
+# Fix restart queue
+if [ -z "$($BIN/v-list-cron-jobs admin | grep 'v-update-sys-queue restart')" ]; then
+    command="sudo $BIN/v-update-sys-queue restart"
+    $BIN/v-add-cron-job 'admin' '*/2' '*' '*' '*' '*' "$command"
+fi
+
+# Remove deprecated line from ClamAV configuration file
+if [ -e "/etc/clamav/clamd.conf" ]; then
+    clamd_conf_update_check=$(grep DetectBrokenExecutables /etc/clamav/clamd.conf)
+    if [ ! -z "$clamd_conf_update_check" ]; then
+        echo "(*) Updating ClamAV configuration..."
+        sed -i '/DetectBrokenExecutables/d' /etc/clamav/clamd.conf
+    fi
+fi
+
+# Remove errornous history.log file created by certain builds due to bug in v-restart-system
+if [ -e $HESTIA/data/users/history.log ]; then
+    rm -f $HESTIA/data/users/history.log
+fi
+
+# Use exim4 server hostname instead of mail domain and remove hardcoded mail prefix
+if [ ! -z "$MAIL_SYSTEM" ]; then
+    echo "(*) Updating exim configuration..."
+    if cat /etc/exim4/exim4.conf.template | grep -q 'helo_data = mail.${sender_address_domain}'; then
+        sed -i 's/helo_data = mail.${sender_address_domain}/helo_data = ${primary_hostname}/g' /etc/exim4/exim4.conf.template
+    fi
+    if ! grep -q '^OUTGOING_IP = /' /etc/exim4/exim4.conf.template; then
+        sed -i '/^OUTGOING_IP/d' /etc/exim4/exim4.conf.template
+        sed -i 's|^begin acl|OUTGOING_IP = /etc/exim4/domains/$sender_address_domain/ip\nbegin acl|' /etc/exim4/exim4.conf.template
+    fi
+    if ! grep -q 'interface =' /etc/exim4/exim4.conf.template; then
+        sed -i '/interface =/d' /etc/exim4/exim4.conf.template
+        sed -i 's|dkim_strict = 0|dkim_strict = 0\n  interface = ${if exists{OUTGOING_IP}{${readfile{OUTGOING_IP}}}}|' /etc/exim4/exim4.conf.template
+    fi
+fi
+
+# Members of admin group should be permitted to enter admin folder
+if [ -d /home/admin ]; then
+    setfacl -m "g:admin:r-x" /home/admin
+fi
+
+# Fix sftp jail cronjob
+if [ -e "/etc/cron.d/hestia-sftp" ]; then
+    if ! cat /etc/cron.d/hestia-sftp | grep -q 'root'; then
+        echo "@reboot root /usr/local/hestia/bin/v-add-sys-sftp-jail" > /etc/cron.d/hestia-sftp
+    fi
+fi
+
+# Create default writeable folders for all users
+echo "(*) Updating default writable folders for all users..."
+for user in $($HESTIA/bin/v-list-sys-users plain); do
+    mkdir -p \
+        $HOMEDIR/$user/.cache \
+        $HOMEDIR/$user/.config \
+        $HOMEDIR/$user/.local \
+        $HOMEDIR/$user/.composer \
+        $HOMEDIR/$user/.ssh
+
+    chown $user:$user \
+        $HOMEDIR/$user/.cache \
+        $HOMEDIR/$user/.config \
+        $HOMEDIR/$user/.local \
+        $HOMEDIR/$user/.composer \
+        $HOMEDIR/$user/.ssh
+done
+
+# Remove redundant fail2ban jail
+if fail2ban-client status sshd > /dev/null 2>&1 ; then
+    fail2ban-client stop sshd >/dev/null 2>&1
+    if [ -f /etc/fail2ban/jail.d/defaults-debian.conf ]; then
+        mkdir -p $HESTIA_BACKUP/conf/fail2ban/jail.d
+        mv /etc/fail2ban/jail.d/defaults-debian.conf $HESTIA_BACKUP/conf/fail2ban/jail.d/
+    fi
+fi
+
+# Update Office 365/Microsoft 365 DNS template
+if [ -e "$HESTIA/data/templates/dns/office365.tpl" ]; then
+    echo "(*) Updating DNS template for Office 365..."
+    cp -f $HESTIA/install/deb/templates/dns/office365.tpl $HESTIA/data/templates/dns/office365.tpl
+fi
+
+# Ensure that backup compression level is correctly set
+GZIP_LVL_CHECK=$(cat $HESTIA/conf/hestia.conf | grep BACKUP_GZIP)
+if [ -z "$GZIP_LVL_CHECK" ]; then
+    echo "(*) Updating backup compression level variable..."
+    $BIN/v-change-sys-config-value "BACKUP_GZIP" '9'
+fi
+
+# Randomize Roundcube des_key for better security
+if [ -f "/etc/roundcube/config.inc.php" ]; then
+    rcDesKey="$(openssl rand -base64 30 | tr -d "/" | cut -c1-24)"
+    sed -i "s/vtIOjLZo9kffJoqzpSbm5r1r/$rcDesKey/g" /etc/roundcube/config.inc.php
+fi
+
+# Place robots.txt to prevent webmail crawling by search engine bots.
+if [ -e "/var/lib/roundcube/" ]; then
+    if [ ! -f "/var/lib/roundcube/robots.txt" ]; then
+        echo "User-agent: *" > /var/lib/roundcube/robots.txt
+        echo "Disallow: /" >> /var/lib/roundcube/robots.txt
+    fi
+fi
+
+# Installing postgresql repo
+if [ -e "/etc/postgresql" ]; then
+    echo "(*) Enabling native PostgreSQL APT repository..."
+    osname="$(cat /etc/os-release | grep "^ID\=" | sed "s/ID\=//g")"
+    if [ "$osname" = "ubuntu" ]; then
+        codename="$(lsb_release -s -c)"
+    else
+        codename="$(cat /etc/os-release |grep VERSION= |cut -f 2 -d \(|cut -f 1 -d \))"
+    fi
+    echo "deb http://apt.postgresql.org/pub/repos/apt/ $codename-pgdg main" > /etc/apt/sources.list.d/postgresql.list
+    wget --quiet https://www.postgresql.org/media/keys/ACCC4CF8.asc -O /tmp/psql_signing.key
+    APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 apt-key add /tmp/psql_signing.key > /dev/null 2>&1
+    rm /tmp/psql_signing.key
+fi
+
+# Hardening MySQL configuration, prevent local infile.
+if [ -e "/etc/mysql/my.cnf" ]; then
+    mysql_local_infile_check=$(grep local-infile /etc/mysql/my.cnf)
+    if [ -z "$mysql_local_infile_check" ]; then
+        echo "(*) Hardening MySQL configuration..."
+        sed -i '/symbolic-links\=0/a\local-infile=0' /etc/mysql/my.cnf
+    fi
+fi
+
+# Hardening nginx configuration, drop TLSv1.1 support.
+if [ -e "/etc/nginx/nginx.conf" ]; then
+    nginx_tls_check=$(grep TLSv1.1 /etc/nginx/nginx.conf)
+    if [ ! -z "$nginx_tls_check" ]; then
+        echo "(*) Updating nginx security settings - disabling TLS v1.1..."
+        sed -i 's/TLSv1.1 //g' /etc/nginx/nginx.conf
+    fi
+fi
+
+# Fix logrotate permission bug for nginx
+if [ -e "/etc/logrotate/nginx" ]; then
+    sed -i "s/create 640 nginx adm/create 640/g" /etc/logrotate.d/nginx
+fi
+
+# Fix logrotate permission bug for apache
+if [ -e "/etc/logrotate/apache2" ]; then
+    sed -i "s/create 640 root adm/create 640/g" /etc/logrotate.d/apache2
+fi
+
+# Repair messed up user log permissions from the logrotate bug. Ignoring errors
+for user in $($HESTIA/bin/v-list-users plain | cut -f1); do
+    for domain in $($HESTIA/bin/v-list-web-domains $user plain | cut -f1); do
+        chown root:$user /var/log/$WEB_SYSTEM/domains/$domain.* > /dev/null 2>&1
+        for sub_domain in $($HESTIA/bin/v-list-web-domain $user $domain plain | cut -f7 | tr ',' '\n'); do
+            chown root:$user /var/log/$WEB_SYSTEM/domains/$sub_domain.* > /dev/null 2>&1
+        done
+    done
+done
+
+chown root:root /var/log/$WEB_SYSTEM/domains/$WEBMAIL_ALIAS* > /dev/null 2>&1
+
+# Enable IMAP/POP3 quota information
+if [ "$IMAP_SYSTEM" = "dovecot" ]; then
+    echo "(*) Enabling IMAP quota information reporting..."
+    if [ -e /etc/dovecot/conf.d/20-pop3.conf ]; then
+        cp -f $HESTIA/install/deb/dovecot/conf.d/20-pop3.conf /etc/dovecot/conf.d/20-pop3.conf
+    fi
+    if [ -e /etc/dovecot/conf.d/20-imap.conf ]; then
+        cp -f $HESTIA/install/deb/dovecot/conf.d/20-imap.conf /etc/dovecot/conf.d/20-imap.conf
+    fi
+    if [ -e /etc/dovecot/conf.d/90-quota.conf ]; then
+        cp -f $HESTIA/install/deb/dovecot/conf.d/90-quota.conf /etc/dovecot/conf.d/90-quota.conf
+    fi
+fi
+
+# Trigger multiphp legacy migration script
+num_php_versions=$(ls -d /etc/php/*/fpm/pool.d 2>/dev/null |wc -l)
+if [ "$num_php_versions" -gt 1 ] && [ -z "$WEB_BACKEND" ]; then
+    echo "(*) Enabling modular Multi-PHP backend..."
+    cp -rf $HESTIA/data/templates/web $HESTIA_BACKUP/templates/web
+    bash $HESTIA/install/upgrade/manual/migrate_multiphp.sh > /dev/null 2>&1
+fi
+
+# Disable global subfolder alias for webmail in favor of subdomain
+if [ -e /etc/nginx/conf.d/webmail.inc ]; then
+    rm -f /etc/nginx/conf.d/webmail.inc
+fi
+if [ -e /etc/apache2/conf.d/roundcube.conf ]; then
+    rm -f /etc/apache2/conf.d/roundcube.conf
+fi

+ 20 - 0
install/upgrade/versions/previous/1.1.1.sh

@@ -0,0 +1,20 @@
+#!/bin/sh
+
+# Hestia Control Panel upgrade script for target version 1.1.1
+
+#######################################################################################
+#######                      Place additional commands below.                   #######
+#######################################################################################
+
+# Remove 5s delay when sending mail through exim4
+if [ -e "/etc/exim4/exim4.conf.template" ]; then
+    echo "(*) Updating exim4 configuration..."
+    sed -i "s|rfc1413_query_timeout = 5s|rfc1413_query_timeout = 0s|g" /etc/exim4/exim4.conf.template
+fi
+
+# Fix phpMyAdmin blowfish and tmp directory issues
+if [ -e "/usr/share/phpmyadmin/libraries/vendor_config.php" ]; then
+    echo "(*) Updating phpMyAdmin configuration..."
+    sed -i "s|define('CONFIG_DIR', ROOT_PATH);|define('CONFIG_DIR', '/etc/phpmyadmin/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
+    sed -i "s|define('TEMP_DIR', ROOT_PATH . 'tmp/');|define('TEMP_DIR', '/var/lib/phpmyadmin/tmp/');|" /usr/share/phpmyadmin/libraries/vendor_config.php
+fi

+ 1 - 1
src/deb/hestia/control

@@ -1,7 +1,7 @@
 Source: hestia
 Package: hestia
 Priority: optional
-Version: 1.1.0
+Version: 1.1.2
 Section: admin
 Maintainer: HestiaCP <info@hestiacp.com>
 Homepage: https://www.hestiacp.com

+ 1 - 1
src/deb/hestia/postinst

@@ -19,7 +19,7 @@ upgrade_refresh_config
 new_version=$(dpkg -l | awk '$2=="hestia" { print $3 }')
 
 # phpMyAdmin
-pma_v='4.9.4'
+pma_v='5.0.2'
 
 ###############################################################
 #               Begin standard upgrade routines               #

+ 1 - 1
src/deb/nginx/control

@@ -1,7 +1,7 @@
 Source: hestia-nginx
 Package: hestia-nginx
 Priority: optional
-Version: 1.17.8
+Version: 1.17.10
 Section: admin
 Maintainer: HestiaCP <info@hestiacp.com>
 Homepage: https://www.hestiacp.com

+ 1 - 1
src/deb/php/control

@@ -1,7 +1,7 @@
 Source: hestia-php
 Package: hestia-php
 Priority: optional
-Version: 7.4.2
+Version: 7.4.5
 Section: admin
 Maintainer: HestaCP <info@hestiacp.com>
 Homepage: https://www.hestiacp.com

+ 71 - 68
src/deb/php/php.ini

@@ -108,11 +108,6 @@
 ;   Development Value: E_ALL
 ;   Production Value: E_ALL & ~E_DEPRECATED & ~E_STRICT
 
-; html_errors
-;   Default Value: On
-;   Development Value: On
-;   Production value: On
-
 ; log_errors
 ;   Default Value: Off
 ;   Development Value: On
@@ -289,6 +284,13 @@ implicit_flush = Off
 ; callback-function.
 unserialize_callback_func =
 
+; The unserialize_max_depth specifies the default depth limit for unserialized
+; structures. Setting the depth limit too high may result in stack overflows
+; during unserialization. The unserialize_max_depth ini setting can be
+; overridden by the max_depth option on individual unserialize() calls.
+; A value of 0 disables the depth limit.
+;unserialize_max_depth = 4096
+
 ; When floats & doubles are serialized, store serialize_precision significant
 ; digits after the floating point. The default value ensures that when floats
 ; are decoded with unserialize, the data will remain the same.
@@ -304,12 +306,12 @@ serialize_precision = -1
 ; http://php.net/open-basedir
 ;open_basedir =
 
-; This directive allows you to disable certain functions for security reasons.
+; This directive allows you to disable certain functions.
 ; It receives a comma-delimited list of function names.
 ; http://php.net/disable-functions
-disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,passthru,system,proc_open,popen,show_source,
+disable_functions = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,passthru,system,proc_open,popen,show_source,
 
-; This directive allows you to disable certain classes for security reasons.
+; This directive allows you to disable certain classes.
 ; It receives a comma-delimited list of class names.
 ; http://php.net/disable-classes
 disable_classes =
@@ -359,6 +361,12 @@ zend.enable_gc = On
 ; Default: ""
 ;zend.script_encoding =
 
+; Allows to include or exclude arguments from stack traces generated for exceptions
+; Default: Off
+; In production, it is recommended to turn this setting on to prohibit the output
+; of sensitive information in stack traces
+zend.exception_ignore_args = On
+
 ;;;;;;;;;;;;;;;;;
 ; Miscellaneous ;
 ;;;;;;;;;;;;;;;;;
@@ -396,7 +404,7 @@ max_input_time = 120
 ; How many GET/POST/COOKIE input variables may be accepted
 ;max_input_vars = 1000
 
-; Maximum amount of memory a script may consume (128MB)
+; Maximum amount of memory a script may consume
 ; http://php.net/memory-limit
 memory_limit = 128M
 
@@ -511,7 +519,7 @@ ignore_repeated_errors = Off
 ignore_repeated_source = Off
 
 ; If this parameter is set to Off, then memory leaks will not be shown (on
-; stdout or in the log). This has only effect in a debug compile, and if
+; stdout or in the log). This is only effective in a debug compile, and if
 ; error reporting includes E_WARNING in the allowed list
 ; http://php.net/report-memleaks
 report_memleaks = On
@@ -540,11 +548,8 @@ report_memleaks = On
 ; error message as HTML for easier reading. This directive controls whether
 ; the error message is formatted as HTML or not.
 ; Note: This directive is hardcoded to Off for the CLI SAPI
-; Default Value: On
-; Development Value: On
-; Production value: On
 ; http://php.net/html-errors
-;html_errors = On
+html_errors = On
 
 ; If html_errors is set to On *and* docref_root is not empty, then PHP
 ; produces clickable error messages that direct to a page describing the error
@@ -598,6 +603,7 @@ syslog.ident = hestia-php
 ;   ascii (all printable ASCII characters and NL)
 ;   no-ctrl (all characters except control characters)
 ;   all (all characters)
+;   raw (like "all", but messages are not split at newlines)
 ; http://php.net/syslog.filter
 ;syslog.filter = ascii
 
@@ -668,7 +674,7 @@ register_argc_argv = Off
 ; first used (Just In Time) instead of when the script starts. If these
 ; variables are not used within a script, having this directive on will result
 ; in a performance gain. The PHP directive register_argc_argv must be disabled
-; for this directive to have any affect.
+; for this directive to have any effect.
 ; http://php.net/auto-globals-jit
 auto_globals_jit = On
 
@@ -906,13 +912,14 @@ default_socket_timeout = 60
 ;
 ;extension=bz2
 ;extension=curl
+;extension=ffi
+;extension=ftp
 ;extension=fileinfo
 ;extension=gd2
 ;extension=gettext
 ;extension=gmp
 ;extension=intl
 ;extension=imap
-;extension=interbase
 ;extension=ldap
 ;extension=mbstring
 ;extension=exif      ; Must be after mbstring as it depends on it
@@ -1127,37 +1134,6 @@ odbc.defaultlrl = 4096
 ; http://php.net/odbc.defaultbinmode
 odbc.defaultbinmode = 1
 
-[Interbase]
-; Allow or prevent persistent links.
-ibase.allow_persistent = 1
-
-; Maximum number of persistent links.  -1 means no limit.
-ibase.max_persistent = -1
-
-; Maximum number of links (persistent + non-persistent).  -1 means no limit.
-ibase.max_links = -1
-
-; Default database name for ibase_connect().
-;ibase.default_db =
-
-; Default username for ibase_connect().
-;ibase.default_user =
-
-; Default password for ibase_connect().
-;ibase.default_password =
-
-; Default charset for ibase_connect().
-;ibase.default_charset =
-
-; Default timestamp format.
-ibase.timestampformat = "%Y-%m-%d %H:%M:%S"
-
-; Default date format.
-ibase.dateformat = "%Y-%m-%d"
-
-; Default time format.
-ibase.timeformat = "%H:%M:%S"
-
 [MySQLi]
 
 ; Maximum number of persistent links.  -1 means no limit.
@@ -1188,11 +1164,11 @@ mysqli.default_port = 3306
 ; http://php.net/mysqli.default-socket
 mysqli.default_socket =
 
-; Default host for mysql_connect() (doesn't apply in safe mode).
+; Default host for mysqli_connect() (doesn't apply in safe mode).
 ; http://php.net/mysqli.default-host
 mysqli.default_host =
 
-; Default user for mysql_connect() (doesn't apply in safe mode).
+; Default user for mysqli_connect() (doesn't apply in safe mode).
 ; http://php.net/mysqli.default-user
 mysqli.default_user =
 
@@ -1414,7 +1390,8 @@ session.cookie_domain =
 session.cookie_httponly =
 
 ; Add SameSite attribute to cookie to help mitigate Cross-Site Request Forgery (CSRF/XSRF)
-; Current valid values are "Lax" or "Strict"
+; Current valid values are "Strict", "Lax" or "None". When using "None",
+; make sure to include the quotes, as `none` is interpreted like `false` in ini files.
 ; https://tools.ietf.org/html/draft-west-first-party-cookies-07
 session.cookie_samesite =
 
@@ -1422,12 +1399,9 @@ session.cookie_samesite =
 ; http://php.net/session.serialize-handler
 session.serialize_handler = php
 
-; Defines the probability that the 'garbage collection' process is started
-; on every session initialization. The probability is calculated by using
-; gc_probability/gc_divisor. Where session.gc_probability is the numerator
-; and gc_divisor is the denominator in the equation. Setting this value to 1
-; when the session.gc_divisor value is 100 will give you approximately a 1% chance
-; the gc will run on any given request.
+; Defines the probability that the 'garbage collection' process is started on every
+; session initialization. The probability is calculated by using gc_probability/gc_divisor,
+; e.g. 1/100 means there is a 1% chance that the GC process starts on each request.
 ; Default Value: 1
 ; Development Value: 1
 ; Production Value: 1
@@ -1435,13 +1409,9 @@ session.serialize_handler = php
 session.gc_probability = 0
 
 ; Defines the probability that the 'garbage collection' process is started on every
-; session initialization. The probability is calculated by using the following equation:
-; gc_probability/gc_divisor. Where session.gc_probability is the numerator and
-; session.gc_divisor is the denominator in the equation. Setting this value to 100
-; when the session.gc_probability value is 1 will give you approximately a 1% chance
-; the gc will run on any given request. Increasing this value to 1000 will give you
-; a 0.1% chance the gc will run on any given request. For high volume production servers,
-; this is a more efficient approach.
+; session initialization. The probability is calculated by using gc_probability/gc_divisor,
+; e.g. 1/100 means there is a 1% chance that the GC process starts on each request.
+; For high volume production servers, using a value of 1000 is a more efficient approach.
 ; Default Value: 100
 ; Development Value: 1000
 ; Production Value: 1000
@@ -1457,8 +1427,8 @@ session.gc_maxlifetime = 1440
 ;       (see session.save_path above), then garbage collection does *not*
 ;       happen automatically.  You will need to do your own garbage
 ;       collection through a shell script, cron entry, or some other method.
-;       For example, the following script would is the equivalent of
-;       setting session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes):
+;       For example, the following script is the equivalent of setting
+;       session.gc_maxlifetime to 1440 (1440 seconds = 24 minutes):
 ;          find /path/to/sessions -cmin +24 -type f | xargs rm
 
 ; Check HTTP Referer to invalidate externally stored URLs containing ids.
@@ -1719,6 +1689,11 @@ zend.assertions = -1
 ; Default: 100000
 ;mbstring.regex_stack_limit=100000
 
+; This directive specifies maximum retry count for mbstring regular expressions. It is similar
+; to the pcre.backtrack_limit for PCRE.
+; Default: 1000000
+;mbstring.regex_retry_limit=1000000
+
 [gd]
 ; Tell the jpeg decode to ignore warnings and try to create
 ; a gd image. The warning will then be displayed as notices
@@ -1886,6 +1861,10 @@ ldap.max_links = -1
 ; errors.
 ;opcache.mmap_base=
 
+; Facilitates multiple OPcache instances per user (for Windows only). All PHP
+; processes with the same cache ID and user share an OPcache instance.
+;opcache.cache_id=
+
 ; Enables and sets the second level cache directory.
 ; It should improve performance when SHM memory is full, at server restart or
 ; SHM reset. The default "" disables file based caching.
@@ -1916,6 +1895,24 @@ opcache.validate_root=1
 ; optimizations.
 ;opcache.opt_debug_level=0
 
+; Specifies a PHP script that is going to be compiled and executed at server
+; start-up.
+; http://php.net/opcache.preload
+;opcache.preload=
+
+; Preloading code as root is not allowed for security reasons. This directive
+; facilitates to let the preloading to be run as another user.
+; http://php.net/opcache.preload_user
+;opcache.preload_user=
+
+; Prevents caching files that are less than this number of seconds old. It
+; protects from caching of incompletely updated files. In case all file updates
+; on your site are atomic, you may increase performance by setting it to "0".
+;opcache.file_update_protection=2
+
+; Absolute path used to store shared lockfiles (for *nix only).
+;opcache.lockfile_path=/tmp
+
 [curl]
 ; A default value for the CURLOPT_CAINFO option. This is required to be an
 ; absolute path.
@@ -1939,6 +1936,12 @@ opcache.validate_root=1
 ; SSL stream context option.
 ;openssl.capath=
 
-; Local Variables:
-; tab-width: 4
-; End:
+[ffi]
+; FFI API restriction. Possible values:
+; "preload" - enabled in CLI scripts and preloaded files (default)
+; "false"   - always disabled
+; "true"    - always enabled
+;ffi.enable=preload
+
+; List of headers files to preload, wildcard patterns allowed.
+;ffi.preload=

+ 1 - 1
src/hst_autocompile.sh

@@ -88,7 +88,7 @@ BUILD_ARCH='amd64'
 HESTIA_V="${BUILD_VER}_${BUILD_ARCH}"
 NGINX_V=$(curl -s https://raw.githubusercontent.com/hestiacp/hestiacp/$branch/src/deb/nginx/control |grep "Version:" |cut -d' ' -f2)
 OPENSSL_V='1.1.1d'
-PCRE_V='8.43'
+PCRE_V='8.44'
 ZLIB_V='1.2.11'
 PHP_V=$(curl -s https://raw.githubusercontent.com/hestiacp/hestiacp/$branch/src/deb/php/control |grep "Version:" |cut -d' ' -f2)
 

+ 2 - 1
web/add/dns/index.php

@@ -122,10 +122,11 @@ if (!empty($_POST['ok_rec'])) {
     $v_type = escapeshellarg($_POST['v_type']);
     $v_val = escapeshellarg($_POST['v_val']);
     $v_priority = escapeshellarg($_POST['v_priority']);
+    $v_ttl = escapeshellarg($_POST['v_ttl']);
 
     // Add dns record
     if (empty($_SESSION['error_msg'])) {
-        exec (HESTIA_CMD."v-add-dns-record ".$user." ".$v_domain." ".$v_rec." ".$v_type." ".$v_val." ".$v_priority, $output, $return_var);
+        exec (HESTIA_CMD."v-add-dns-record ".$user." ".$v_domain." ".$v_rec." ".$v_type." ".$v_val." ".$v_priority." '' false ".$v_ttl, $output, $return_var);
         check_return_code($return_var,$output);
         unset($output);
         $v_type = $_POST['v_type'];

+ 6 - 0
web/add/web/index.php

@@ -197,6 +197,12 @@ if (!empty($_POST['ok'])) {
              exec (HESTIA_CMD."v-add-web-domain-ssl ".$user." ".escapeshellarg($v_domain)." ".$tmpdir." ".$v_ssl_home." 'no'", $output, $return_var);
              check_return_code($return_var,$output);
              unset($output);
+
+            // Cleanup certificate tempfiles
+            if (!empty($_POST['v_ssl_crt'])) unlink($tmpdir."/".$v_domain.".crt");
+            if (!empty($_POST['v_ssl_key'])) unlink($tmpdir."/".$v_domain.".key");
+            if (!empty($_POST['v_ssl_ca']))  unlink($tmpdir."/".$v_domain.".ca");
+            rmdir($tmpdir);
          }
      }
 

+ 1 - 1
web/add/webapp/index.php

@@ -95,7 +95,7 @@ if (!empty($_POST['ok']) && !empty($app) ) {
 if(!empty($installer)) {
     render_page($user, $TAB, 'setup_webapp');
 } else {
-    render_page($user, $TAB, 'add_webapp');
+    render_page($user, $TAB, 'list_webapps');
 }
 
 

+ 1 - 1
web/css/jquery-custom-dialogs.css

@@ -53,7 +53,7 @@
 
 /* Component containers
 ----------------------------------*/
-.ui-widget { font-family: 'Exo'; font-size: 0.9rem; }
+.ui-widget { font-family: 'Exo'; font-size: 0.85rem; }
 .ui-widget .ui-widget { font-size: 10pt; }
 .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: 'Exo'; }
 .ui-widget-content { border: 1px solid #aaaaaa; color: #ccc; }

+ 209 - 137
web/css/styles.min.css

@@ -784,8 +784,8 @@ a {
   width: 100%;
   z-index: 900;
   height: 38px;
-  text-shadow: 1px 1px rgba(0,0,0,0.5);
-  box-shadow: 0px 8px 20px rgba(120,120,120,0.35);
+  text-shadow: 1px 1px rgba(0,0,0,0.25);
+  box-shadow: 0px 4px 10px rgba(100,100,100,0.4);
   border-bottom: 1px solid #fff;
 }
 
@@ -802,6 +802,12 @@ a {
   font-size: 0.8rem;
   background: linear-gradient(to bottom, rgba(255,255,255,0.6) 0%,rgba(255,255,255,0.75) 30%,rgba(255,255,255,1) 95%);
   text-shadow: 0px 1px rgba(255,255,255,0.8);
+  border-left: 1px solid rgba(255,255,255,0.98);
+  border-right: 1px solid rgba(255,255,255,0.98);
+}
+
+.l-menu__item.l-menu__item--active:hover {
+  box-shadow: none;
 }
 
 .l-menu {
@@ -824,18 +830,19 @@ a {
 
 .l-menu__item a:hover {
   color: #3b9de8 !important;
-  text-shadow: 1px 1px rgba(255,255,255,0.5) !important;
   border: 0;
-  background: linear-gradient(to bottom, rgba(241,248,253,1) 0%,rgba(218,236,250,1) 50%,rgba(190,221,246,1) 51%,rgba(227,240,251,1) 100%) !important;
-  box-shadow: inset 0px 0px 1px #fff,
-              inset 0px 0px 6px rgba(255,255,255,0.6) !important;
+  box-shadow: inset 0px 0px 6px rgba(255,255,255,0.6) !important;
   transition: 0.2s;
   border-left: 1px solid rgba(0,0,0,0.1);
   border-right: 1px solid rgba(0,0,0,0.1);
+  color: #4686b8 !important;
+  background: linear-gradient(to bottom, rgba(255,255,255,0.6) 0%,rgba(255,255,255,0.75) 30%,rgba(255,255,255,1) 95%);
+  text-shadow: 0px 1px rgba(255,255,255,0.8);
 }
+
 .l-menu__item a:active {
   border: 0;
-  background: linear-gradient(to bottom, rgba(210,232,250,1) 0%,rgba(187,220,247,1) 50%,rgba(162,207,244,1) 51%,rgba(194,224,248,1) 100%) !important;
+  background: linear-gradient(to bottom, rgba(255,255,255,0.5) 0%,rgba(255,255,255,0.6) 30%,rgba(255,255,255,0.95) 95%);
   color: #046c98 !important;
   text-shadow: 0px -1px 1px rgba(255,255,255,0.5) !important;
   box-shadow: inset 0px 0px 1px #fff,
@@ -854,32 +861,6 @@ a {
   color: #fff;
 }
 
-
-.lang-ua .l-menu__item a,
-.lang-nl .l-menu__item a,
-.lang-fr .l-menu__item a,
-.lang-ru .l-menu__item a {
-  padding: 11px 18px;
-}
-.lang-el .l-menu__item a,
-.lang-tr .l-menu__item a {
-  padding: 11px 15px;
-}
-.lang-ar .l-menu__item a {
-  padding: 11px 11px;
-}
-.lang-ar .l-menu__item a {
-  line-height: 35px;
-}
-
-.lang-de .l-menu__item a {
-  padding: 11px 12px;
-}
-
-.lang-tw .l-menu__item a {
-  padding: 13px 18px;
-}
-
 .l-profile {
   overflow: hidden;
   float: right;
@@ -914,8 +895,7 @@ a {
 }
 
 .l-profile__notifications.active.l-profile__notifications.updates:active {
-  border: 1px solid #378ccd !important;
-  background: linear-gradient(to bottom, rgba(210,232,250,1) 0%,rgba(187,220,247,1) 50%,rgba(162,207,244,1) 51%,rgba(194,224,248,1) 100%) !important;
+  background: linear-gradient(to bottom, rgba(255,255,255,0.6) 0%,rgba(255,255,255,0.75) 30%,rgba(255,255,255,1) 95%) !important;
   color: #046c98 !important;
   text-shadow: 0px -1px 1px rgba(255,255,255,0.5) !important;
   box-shadow: 0px 1px 3px rgba(0,0,0,0.15),
@@ -926,17 +906,13 @@ a {
 .l-profile__notifications:hover,.l-profile__notifications.updates:hover {
   color: #3b9de8 !important;
   text-shadow: 1px 1px rgba(255,255,255,0.5) !important;
-  border: 1px solid #54a6e5 !important;
-  background: linear-gradient(to bottom, rgba(241,248,253,1) 0%,rgba(218,236,250,1) 50%,rgba(190,221,246,1) 51%,rgba(227,240,251,1) 100%) !important;
-  box-shadow: 0px 1px 3px rgba(0,0,0,0.15),
-              inset 0px 0px 1px #fff,
-              inset 0px 0px 6px rgba(255,255,255,0.6) !important;
+  background: linear-gradient(to bottom, rgba(255,255,255,0.75) 0%,rgba(255,255,255,0.87) 30%,rgba(255,255,255,1) 95%) !important;
   transition: 0.2s;
 }
 
 .notification-container {
   background-color: rgba(255,255,255,0.95);
-  box-shadow: 0 3px 30px 0 rgba(0, 0, 0, 0.5);
+  box-shadow: 0 3px 20px 0 rgba(0, 0, 0, 0.4);
   list-style-type: none;
   margin: 0 18px;
   max-height: 90%;
@@ -1057,13 +1033,14 @@ a {
   border-radius: 4px;
   box-sizing: border-box;
   display: block;
-  font-size: 0.75rem;
+  font-size: 0.8rem;
   font-weight: 400;
   margin-top: 1rem;
   padding: 0.8rem;
   position: relative;
   text-align: left;
   box-shadow: 0px 2px 4px rgba(0,0,0,0.2);
+  text-shadow: 0px 1px rgba(0,0,0,0.45);
   border: 1px solid #fff;
 }
 
@@ -1086,7 +1063,6 @@ a {
 }
 .alert.alert-info {
   color: #fff;
-  text-shadow: 0px 1px rgba(0,0,0,0.45);
   background-color: #618ecc;
 }
 .alert.alert-info i.fas {
@@ -1123,7 +1099,14 @@ form#vstobjects .alert {
 }
 
 .app-form {
-  padding:2em 1em 2em 1em;
+  padding: 2em 1em 2em 9rem;
+}
+
+.app-form label {
+  font-size: 0.85rem;
+  padding-bottom: 3px;
+  font-weight: 600;
+  cursor: default;
 }
 
 .card {
@@ -1265,14 +1248,12 @@ form#vstobjects .alert {
   font-weight: 600;
   color: #5b5b5b;
   min-height: 21px;
+  font-size: 16px;
 }
 
 .l-stat__col--active .l-stat__col-title {
   color: #cc3366;
-  font-size: 22px;
-  margin-top: -7px;
-  letter-spacing: -1px;
-  margin-right: -4px;
+  font-size: 16px;
 }
 
 .l-stat__col .fas {
@@ -1280,6 +1261,10 @@ form#vstobjects .alert {
   padding: 4px;
 }
 
+.l-stat__col--active .fas {
+  color: #cc3366;
+}
+
 .l-separator.selected,
 .l-separator {
   height: 1px;
@@ -1365,8 +1350,8 @@ div.l-content > div.l-separator:nth-of-type(4) {
   top: 42px;
   background-color: rgba(255,255,255,0.95);
   list-style-type: none;
-  box-shadow: 0 2px 12px 0 rgba(20, 20, 20, 0.45);
-  border-radius: 8px;
+  box-shadow: 0 2px 14px 0 rgba(20, 20, 20, 0.35);
+  border-radius: 4px;
   border: 1px solid rgba(255,255,255,1);
   padding: 0px;
 }
@@ -1657,12 +1642,12 @@ div.l-content > div.l-separator:nth-of-type(4) {
 .table-header {
   font-size: 0.95em !important;
   background: linear-gradient(to bottom, rgba(247,247,247,1) 0%,rgba(255,255,255,1) 100%) !important;
-  border-left: 1px solid #ddd !important;
-  border-right: 1px solid #ddd !important;
-  border-bottom: 1px solid #ddd !important;
-  border-top: 1px solid #ddd !important;
-  text-shadow: 0px 1px rgba(255,255,255,0.95);
-  box-shadow: inset 0px 0px 1px rgba(255,255,255,1), inset 0px 0px 4px rgba(255,255,255,0.8), 0px 4px 6px rgba(190,190,190,0.3) !important;
+  border-left: 1px solid #d0d0d0 !important;
+  border-right: 1px solid #d0d0d0 !important;
+  border-bottom: 1px solid #d0d0d0 !important;
+  border-top: 1px solid #d0d0d0 !important;
+  text-shadow: 0px 1px rgba(255,255,255,1);
+  box-shadow: inset 0px 1px 1px rgba(255,255,255,1), inset 0px 0px 1px rgba(255,255,255,1), inset 0px 0px 4px rgba(255,255,255,0.8), 0px 2px 6px rgba(140,140,140,0.35) !important;
   border-top-left-radius: 0px;
   border-top-right-radius: 0px;
   border-bottom-left-radius: 6px;
@@ -1677,8 +1662,8 @@ div.l-content > div.l-separator:nth-of-type(4) {
 
 .table-header:hover {
   background-color: linear-gradient(to bottom, rgba(247,247,247,1) 0%,rgba(255,255,255,1) 100%) !important;
-  border-left: 1px solid #ddd !important;
-  border-right: 1px solid #ddd !important;
+  border-left: 1px solid #d0d0d0 !important;
+  border-right: 1px solid #d0d0d0 !important;
 }
 
 .table-header .fas {
@@ -1823,7 +1808,9 @@ div.l-content > div.l-separator:nth-of-type(4) {
   padding-top: 15px;
   vertical-align: top;
   padding-bottom: 15px;
+  cursor: default;
 }
+
 .l-unit__col--left {
   width: 100px;
   padding-right: 10px;
@@ -1895,7 +1882,8 @@ div.l-content > div.l-separator:nth-of-type(4) {
 
 .l-unit__name {
   color: #414141;
-  font-size: 28px;
+  font-size: 22px;
+  margin-top: 10px;
   margin-bottom: 10px;
   font-weight: 500;
   letter-spacing: -0.02em;
@@ -2412,7 +2400,7 @@ body.mobile .l-icon-shortcuts {
 
 
 .vst-error {
-  color: #BE5ABF;
+  color: #ff3333;
   font-weight: 600;
   overflow: hidden;
   max-width: 500px;
@@ -2421,11 +2409,12 @@ body.mobile .l-icon-shortcuts {
 }
 
 .vst-ok {
-  color: #3b9de8;
+  color: #53ba55;
   overflow: hidden;
   max-width: 500px;
   text-overflow: ellipsis;
   white-space: nowrap;
+  font-size: 0.8rem;
 }
 
 .l-unit-toolbar__buttonstrip .vst-ok, .l-unit-toolbar__buttonstrip .vst-error {
@@ -2517,10 +2506,10 @@ label:hover {
   box-shadow: 0px 1px 4px rgba(0,0,0,0.15);
 }
 .vst-input:hover {
-  border: 1px solid #909090;
+  border: 1px solid #94c8f0;
 }
 .vst-input:focus {
-  border: 1px solid #3b9de8;
+  border: 1px solid #008fee;
   background-color: #D7F9FF;
   color: #333;
 }
@@ -2535,6 +2524,12 @@ label:hover {
   border-color: #f1f1f1;
   background-color: #f1f1f1;
 }
+
+.vst-input:disabled:hover,
+.vst-list:disabled:hover {
+  border-color: #cfcfcf;
+}
+
 .vst-input.long {
   width: 832px;
 }
@@ -2591,10 +2586,10 @@ select.vst-list:-moz-focusring {
   padding: 6px 1px 6px 15px;
 }
 .vst-list:hover {
-  border: 1px solid #909090;
+  border: 1px solid #94c8f0;
 }
 .vst-list:focus {
-  border: 1px solid #3b9de8;
+  border: 1px solid #008fee;
   color: #333;
 }
 
@@ -2615,6 +2610,10 @@ select.vst-list:-moz-focusring {
   color: #4e4e4e;
 }
 
+.vst-text {
+  cursor: default;
+}
+
 a.vst-text,
 a.vst-text b{
   color: #326b9b;
@@ -2663,10 +2662,10 @@ a.vst-text:active b{
   box-shadow: 0px 1px 4px rgba(0,0,0,0.15);
 }
 .vst-textinput:hover {
-  border: 1px solid #909090;
+  border: 1px solid #94c8f0;
 }
 .vst-textinput:focus {
-  border: 1px solid #3b9de8;
+  border: 1px solid #008fee;
   background-color: #D7F9FF;
   color: #333;
 }
@@ -2710,12 +2709,16 @@ a.vst-text:active b{
   font-size: 0.8rem;
   padding: 2px 2px 0;
   text-decoration: none;
-  text-transform: uppercase;
+  text-transform: none;
 }
 .login-box .vst-advanced:hover {
   color: #cc3366;
   background-color: transparent;
   border-color: transparent;
+  font-size: 0.85em !important;
+  box-shadow: none !important;
+  background: none !important;
+  border: none !important
 }
 
 .vst-advanced:hover {
@@ -2725,12 +2728,19 @@ a.vst-text:active b{
   text-decoration: none;
 }
 
-.login-box .vst-advanced:active,
-.vst-advanced:active {
+.login-box .vst-advanced:active {
   color: #fff;
   background-color: #F7D616;
   border-color: #F7D616;
   text-decoration: none;
+  font-size: 0.85em !important;
+  box-shadow: none !important;
+  background: none !important;
+  border: none !important
+}
+
+.vst-advanced:active {
+  font-size: unset;
 }
 
 .login-box .vst-advanced {
@@ -2740,6 +2750,10 @@ a.vst-text:active b{
   padding: 2px 2px 0;
   text-decoration: none;
   text-transform: uppercase;
+  font-size: 0.85em !important;
+  box-shadow: none !important;
+  background: none !important;
+  border: none !important
 }
 .vst-checkbox {
   font-size: 0.85rem;
@@ -2830,45 +2844,57 @@ td.hint {
 }
 .ftp-path-prefix { padding-top: 12px; font-size: 0.8rem; color: #555; }
 
+.ui-dialog .ui-dialog-buttonpane button {
+  box-shadow: 0px 1px 4px rgba(0,0,0,0.2),
+  inset 0px 0px 1px #fff,
+  inset 0px 0px 3px rgba(255,255,255,0.5) !important;
+}
 
-.ui-button, .button {
+.ui-dialog .ui-dialog-buttonpane {
+  margin-bottom: -6px !important;
+  padding: 0 !important;
+}
+
+.ui-button, .button, .ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit, .vst-advanced {
   filter:chroma(color=#000);
   cursor: pointer;
   border-radius: 3px 3px 3px 3px !important;
-  font-size: 1.0em !important;
+  font-size: 1.05em !important;
   font-weight: 500 !important;
   padding: 2px 16px 3px 20px !important;
   min-width: 100px !important;
   height: 28px !important;
   color: #30659d !important;
-  border: 1px solid #3b9de8 !important;
+  border: 1px solid #0083db !important;
   background-color: #3b9de8 !important;
   background: linear-gradient(to bottom, rgba(235,243,249,1) 0%,rgba(215,230,243,1) 50%,rgba(192,216,236,1) 51%,rgba(223,235,245,1) 100%) !important;
-  box-shadow: 0px 1px 4px rgba(0,0,0,0.2),
+  box-shadow: 0px 1px 3px rgba(0,0,0,0.25),
               inset 0px 0px 1px #fff,
               inset 0px 0px 3px rgba(255,255,255,0.5) !important;
-  text-shadow: 0px 1px 1px rgba(255,255,255,0.6) !important;
+  text-shadow: 0px 1px 1px rgba(255,255,255,0.85) !important;
 }
 .ui-button:hover, .button:hover, .ui-button.cancel:hover, .button.cancel:hover,
-.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit:hover {
-  color: #3b9de8 !important;
+.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit:hover,
+.vst-advanced:hover, .to-top:hover, .to-shortcuts:hover {
+  color: #0077c6 !important;
   text-shadow: 1px 1px rgba(255,255,255,0.5) !important;
   border: 1px solid #54a6e5 !important;
   background: linear-gradient(to bottom, rgba(241,248,253,1) 0%,rgba(218,236,250,1) 50%,rgba(190,221,246,1) 51%,rgba(227,240,251,1) 100%) !important;
-  box-shadow: 0px 1px 3px rgba(0,0,0,0.15),
+  box-shadow: 0px 1px 3px rgba(0,0,0,0.25),
               inset 0px 0px 1px #fff,
               inset 0px 0px 6px rgba(255,255,255,0.6) !important;
   transition: 0.2s;
 }
 .ui-button:focus,.ui-button:active,
 .button:active,.button:focus,.ui-button.cancel:focus,.ui-button.cancel:active,
-.button.cancel:active,.button.cancel:focus, .ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit,
-.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit:active {
-  border: 1px solid #378ccd !important;
-  background: linear-gradient(to bottom, rgba(210,232,250,1) 0%,rgba(187,220,247,1) 50%,rgba(162,207,244,1) 51%,rgba(194,224,248,1) 100%) !important;
-  color: #046c98 !important;
-  text-shadow: 0px -1px 1px rgba(255,255,255,0.5) !important;
-  box-shadow: 0px 1px 3px rgba(0,0,0,0.15),
+.button.cancel:active,.button.cancel:focus,
+.ui-button.ui-widget.ui-state-default.ui-corner-all.ui-button-text-only.submit:active,
+.vst-advanced:active,.to-top:focus, .to-shortcuts:focus {
+  border: 1px solid #0066b4 !important;
+  background: linear-gradient(to bottom, rgba(194,224,248,1) 0%,  rgba(162,207,244,1) 51%, rgba(210,232,250,1) 100%) !important;
+  color: #517bab !important;
+  text-shadow: 0px -1px 2px rgba(255,255,255,0.85) !important;
+  box-shadow: 0px 1px 2px rgba(0,0,0,0.2),
               inset 0px 0px 1px #fff,
               inset -1px -1px 4px rgba(220,220,220,0.4) !important;
 }
@@ -2882,6 +2908,11 @@ td.hint {
 
 .ui-dialog .ui-dialog-buttonpane button span.ui-button-text {
   padding: 2px !important;
+  font-size: 0.85rem !important;
+}
+
+.ui-dialog .ui-button:hover span {
+  color: #046c98 !important;
 }
 
 .ui-button-text-only .selected {
@@ -2889,7 +2920,8 @@ td.hint {
 }
 
 .ui-button.cancel,
-.button.cancel {
+.button.cancel,
+.to-top, .to-shortcuts {
   color: #717171 !important;
   border: 1px solid #aaaaaa !important;
   background: linear-gradient(to bottom, rgba(250,250,250,1) 0%,rgba(236,236,236,1) 50%,rgba(221,221,221,1) 51%,rgba(241,241,241,1) 100%) !important;
@@ -2900,7 +2932,8 @@ td.hint {
   color: #30659d !important;
 }
 .ui-button.cancel:active,
-.button.cancel:active {
+.button.cancel:active,
+.to-top:active, .to-shortcuts:active {
   border: 1px solid #378ccd;
   background-color: #378ccd;
 }
@@ -2915,26 +2948,6 @@ a.button.cancel {
   border: 1px solid #4b4b4b;
   background-color: #4b4b4b;
 }
-/*
-.ui-dialog button.cancel:hover {
-  color: #fff;
-  border: 1px solid #999;
-  background-color: #999;
-}
-.ui-dialog button.cancel:active {
-  border: 1px solid #54a6e5;
-  background-color: #54a6e5;
-}
-*/
-
-/*
-.ui-button.danger, .button.danger {
-  background: linear-gradient(to bottom, #fbf1ef 0%,#f7c5bf 50%,#f5ada5 51%,#fde2df 100%) !important;
-  color: #F4301A !important;
-  text-shadow: 0px 1px rgba(255,255,255,0.5) !important;
-  border: 1px solid #F4968B !important;
-}
-*/
 
 .ui-button.danger:hover, .button.danger:hover {
   background: linear-gradient(to bottom, #fbf2f1 0%,#f7cac5 50%,#f6b4ac 51%,#fde6e3 100%) !important;
@@ -2944,9 +2957,10 @@ a.button.cancel {
 }
 
 .ui-button.danger:active, .button.danger:active, .ui-button.danger:focus, .button.danger:focus {
-  background: linear-gradient(to bottom, #f9e3df 0%,#f5a69d 50%,#f48578 51%,#fcd0ca 100%) !important; 
-  color: #fff !important;
-  text-shadow: 0px -1px 1px rgba(0,0,0,0.3) !important;
+  background: linear-gradient(to bottom, #fcd0ca 0%,#f5a69d 50%,#f9e3df 100%) !important;
+  color: #ce1500 !important;
+  text-shadow: 0px 1px 1px rgba(255,255,255,0.2),
+               0px -1px 1px rgba(255,255,255,0.6) !important;
   border: 1px solid #F4301A !important;
 }
 
@@ -2959,6 +2973,7 @@ a.button.cancel {
 .ui-button:active span {
   color: #4b4b4b;
 }
+
 .ui-button.cancel span {
   color: #777;
 }
@@ -2970,10 +2985,9 @@ a.button.cancel {
 }
 
 .ui-dialog button.cancel span {
-  color: #ccc;
+  color: #777 !important;
 }
 
-
 .unlim-trigger {
   cursor: pointer;
   padding-left: 4px;
@@ -3062,8 +3076,9 @@ a.button.cancel {
 ::-moz-focus-inner {border:0;}
 
 .login {
-  background-color: #fff;
-  box-shadow: 0px 8px 25px rgba(0,0,0, 0.3);
+  background-color: rgba(255,255,255,0.7);
+  box-shadow: 0px 8px 25px rgba(0,0,0, 0.3),
+              inset 0px 0px 2px rgba(255,255,255,1);
   font-family: 'Exo', Tahoma, Arial, Helvetica, sans-serif;
   margin: 0;
   padding: 0;
@@ -3071,12 +3086,30 @@ a.button.cancel {
   vertical-align: top;
   width: 500px;
   border-radius: 6px;
+  cursor: default;
+}
+
+.login .vst-input {
+  border-color: #5787c8;
+}
+
+.login .button {
+  font-size: 0.8rem !important;
 }
 
 .login-welcome {
   font-size: 1.05rem !important;
+  font-weight: 500 !important;
+  padding-bottom: 30px !important;
+  font-weight: 600;
+}
+
+.page-title {
+  font-size: 1.3rem !important;
   font-weight: 400 !important;
   padding-bottom: 30px !important;
+  letter-spacing: -0.01em;
+  cursor: default;
 }
 
 .qr-code {
@@ -3113,9 +3146,8 @@ a.button.cancel {
 }
 
 .l-unit.selected {
-  background-color: #fefba7;
+  background-color: #f8f8f8;
   color: #4b4b4b;
-  border-bottom: 1px solid #c0b990;
   box-shadow: 0px 2px 10px rgba(150,150,150,0.20);
   text-shadow: 0px 1px rgba(255,255,255,0.5);
   border-left: 1px solid #ddd;
@@ -3123,7 +3155,7 @@ a.button.cancel {
 }
 
 .l-unit.selected:hover {
-  background-color: #fefccd;
+  background-color: #fff5ce;
   color: #4b4b4b;
   box-shadow: 0px 2px 14px rgba(150,150,150,0.25);
   text-shadow: 0px 1px rgba(255,255,255,0.6);
@@ -3172,9 +3204,8 @@ div.l-content.collapsed .l-sort {
 
 .console-output {
   font-family: "Inconsolata", "Lucida Console", Monaco, monospace;
-  font-size: 0.9rem;
+  font-size: 0.92rem;
   color: #202020;
-  letter-spacing: -0.02em;
 }
 
 form#vstobjects {
@@ -3182,7 +3213,7 @@ form#vstobjects {
 }
 
 form#vstobjects.suspended {
-  background-color: #EAEAEA;
+  background-color: #fff;
   padding-bottom: 30px;
 }
 
@@ -3255,11 +3286,11 @@ form#vstobjects.suspended {
   padding-right: 8px;
   margin-right: 10px;
   line-height: 0.75rem;
-  box-shadow: 0px 1px 1px rgba(0,0,0,0.25), inset 0px 0px 1px rgba(0,0,0,0.15);
+  box-shadow: 0px 1px 1px rgba(0,0,0,0.35), inset 0px 1px 0px rgba(0,0,0,0.1);
   background-color: rgba(255,255,255,0.75);
   font-weight: 500;
-  border: 1px solid rgba(255,255,255,0.9);
-  text-shadow: 0px 1px 1px rgba(255,255,255,0.5);
+  border: 1px solid rgba(255,255,255,0.75);
+  text-shadow: 0px 1px 1px rgba(255,255,255,0.6);
   color: #30659d;
 }
 
@@ -3271,9 +3302,12 @@ form#vstobjects.suspended {
   min-height: 24px;
   line-height: 24px;
   border-radius: 50%;
-  font-weight: 600;
-  box-shadow: 0px 0px 3px rgba(120,120,120,0.6);
+  font-weight: 700;
+  font-size: 0.75rem;
+  box-shadow: 0px 1px 2px rgba(70,70,70,0.5), 
+              inset 0px 2px 2px #fff;
   text-shadow: 0px 1px 2px rgba(0,0,0,0.5);
+  border: 1px solid #b8b8b8 !important;
 }
 
 .badge.large {
@@ -3476,7 +3510,7 @@ form#vstobjects.suspended {
 }
 
 .shortcuts {
-  background: rgba(20, 20, 20, 0.92);
+  background: rgba(50,50,50,0.93);
   display: inline-block;
   position: fixed;
   left: 50%;
@@ -3490,16 +3524,19 @@ form#vstobjects.suspended {
   transform: translate(-50%, 0);
   border-top-left-radius: 6px;
   border-top-right-radius: 6px;
-  box-shadow: 0px 3px 40px rgba(0,0,0,0.6);
+  box-shadow: 0px 4px 30px rgba(0,0,0,0.5);
+  line-height: 0.9rem;
+  cursor: default;
 }
+
 .shortcuts .header {
-  border-bottom: 1px solid #333;
+  border-bottom: 1px solid #606060;
   height: 43px;
 }
 
 .shortcuts .title {
   text-transform: uppercase;
-  color: #ffcc00;
+  color: #ff3478;
   padding: 7px 0 7px 14px;
   display: inline-block;
   float: left;
@@ -3516,13 +3553,14 @@ form#vstobjects.suspended {
   width: 46px;
 }
 .shortcuts .close:hover {
-  background-color: #000;
+  color: #db0000;
 }
 .shortcuts .close:active {
-  background-color: #3b9de8;
+  color: #a60000;
 }
 .shortcuts .close .fas {
-  font-size: 1.3rem;
+  font-size: 0.8rem;
+  line-height: 1.4rem;
 }
 .shortcuts ul {
   list-style-type: none;
@@ -3538,13 +3576,14 @@ form#vstobjects.suspended {
   padding-top: 30px;
 }
 .shortcuts ul li span {
-  color: #48F4EF;
+  color: #ff3478;
   display: inline-block;
   font-weight: 600;
   padding: 0 20px 0 0;
   text-align: right;
 /*  width: 140px;*/
 }
+
 .shortcuts ul li span.bigger {
   font-size: 18px;
 }
@@ -3639,14 +3678,15 @@ form#vstobjects.suspended {
   font-family: 'Exo', Arial, Helvetica, sans-serif !important;
   font-weight: 500 !important;
   background-color: rgba(255,255,255,0.9) !important;
-  box-shadow: 0 8px 40px 0 rgba(0, 0, 0, 0.35) !important;
+  box-shadow: inset 0px 1px 3px rgba(0,0,0,0.25), 
+              0 8px 40px 0 rgba(0, 0, 0, 0.35) !important;
   border-radius: 6px !important;
-  border: 2px solid rgba(255,255,255,0.95) !important;
+  border: 1px solid rgba(255,255,255,0.98) !important;
   text-align: center !important;
 }
 
 .ui-dialog .ui-dialog-content {
-  color: #121212 !important;
+  color: #535353 !important;
   padding: 10px 26px 30px !important;
 }
 
@@ -3658,10 +3698,20 @@ form#vstobjects.suspended {
   letter-spacing: -0.01em !important;
   text-align: center !important;
   float: none !important;
+  font-weight: 500;
 }
 
 .ui-dialog-buttonpane {
-  border-color: #aaaaaa !important;
+  border-color: #fff!important;
+  box-shadow: inset 0px 0px 2px rgba(0,0,0,0.25);
+  border-bottom: 1px solid #fff !important;
+  background: #e0e0e0;
+  margin-top: 0px !important;
+  padding-top: 0px !important;
+}
+
+.ui-widget {
+  font-size: 0.85rem !important;
 }
 
 .ui-widget-overlay {
@@ -3781,20 +3831,42 @@ form#vstobjects.suspended {
 
 }
 
+.server-info-output {
+  color: #cc3366; 
+  padding: 10px 0 20px 20px; 
+  background: #fff;
+}
+
 .server-info-data {
   margin-left: 100px; 
   margin-top: -20px;
 }
+
 .server-info-name {
   margin-top: 5px;
   margin-bottom: 30px;
 }
+
+.server-info-output {
+  color: #cc3366; 
+  padding: 10px 0 20px 20px; 
+  background: #fff;
+}
+
 .icon-server-info {
   font-size: 5.2em;
   float: left;
   margin-right: 32px;
 }
 
+.userlist-email {
+  font-size: 0.75rem;
+}
+
+.userlist-username {
+  font-size: 1.05em;
+}
+
 @media screen and (max-width: 950px) {
   .helper-container {
     display: none;

+ 4 - 2
web/edit/dns/index.php

@@ -78,6 +78,7 @@ if ((!empty($_GET['domain'])) && (!empty($_GET['record_id'])))  {
     }
     $v_date = $data[$v_record_id]['DATE'];
     $v_time = $data[$v_record_id]['TIME'];
+    $v_ttl = $data[$v_record_id]['TTL'];
 }
 
 // Check POST request for dns domain
@@ -161,12 +162,13 @@ if ((!empty($_POST['save'])) && (!empty($_GET['domain'])) && (!empty($_GET['reco
     $v_record_id = escapeshellarg($_POST['v_record_id']);
 
     // Change dns record
-    if (($v_rec != $_POST['v_rec']) || ($v_type != $_POST['v_type']) || ($v_val != $_POST['v_val']) || ($v_priority != $_POST['v_priority']) && (empty($_SESSION['error_msg']))) {
+    if (($v_rec != $_POST['v_rec']) || ($v_type != $_POST['v_type']) || ($v_val != $_POST['v_val']) || ($v_priority != $_POST['v_priority']) || ($v_ttl != $_POST['v_ttl']) && (empty($_SESSION['error_msg']))) {
         $v_rec = escapeshellarg($_POST['v_rec']);
         $v_type = escapeshellarg($_POST['v_type']);
         $v_val = escapeshellarg($_POST['v_val']);
         $v_priority = escapeshellarg($_POST['v_priority']);
-        exec (HESTIA_CMD."v-change-dns-record ".$v_username." ".$v_domain." ".$v_record_id." ".$v_rec." ".$v_type." ".$v_val." ".$v_priority, $output, $return_var);
+        $v_ttl = escapeshellarg($_POST['v_ttl']);
+        exec (HESTIA_CMD."v-change-dns-record ".$v_username." ".$v_domain." ".$v_record_id." ".$v_rec." ".$v_type." ".$v_val." ".$v_priority." false ".$v_ttl, $output, $return_var);
         check_return_code($return_var,$output);
         $v_rec = $_POST['v_rec'];
         $v_type = $_POST['v_type'];

+ 5 - 0
web/edit/server/index.php

@@ -509,6 +509,11 @@ if (!empty($_POST['save'])) {
             $v_ssl_signature = $ssl_str['HESTIA']['SIGNATURE'];
             $v_ssl_pub_key = $ssl_str['HESTIA']['PUB_KEY'];
             $v_ssl_issuer = $ssl_str['HESTIA']['ISSUER'];
+
+            // Cleanup certificate tempfiles
+            if (file_exists($tmpdir . '/certificate.crt')) unlink($tmpdir . '/certificate.crt');
+            if (file_exists($tmpdir . '/certificate.key')) unlink($tmpdir . '/certificate.key');
+            rmdir($tmpdir);
         }
     }
 

+ 352 - 348
web/inc/i18n/cn.php

@@ -10,104 +10,104 @@
  */
 
 $LANG['cn'] = array(
-    'Packages'  => '预设方案',
-    'IP'  => 'IP 地址',
-    'Graphs'  => '资源图表',
-    'Statistics'  => '统计信息',
-    'Log'  => '系统日志',
-    'Server'  => '服务器',
-    'Services'  => '系统服务',
+    'Packages' => '用户方案',
+    'IP' => 'IP 地址',
+    'Graphs' => '资源图表',
+    'Statistics' => '统计信息',
+    'Log' => '系统日志',
+    'Server' => '服务器',
+    'Services' => '系统服务',
     'Firewall' => '防火墙',
-    'Updates'  => '系统更新',
-    'Log in'  => '登录',
-    'Log out'  => '登出',
-
-    'USER'  => '用户账户',
-    'WEB'  => 'Web 服务',
-    'DNS'  => 'DNS 服务',
-    'MAIL'  => '邮箱服务',
-    'DB'  => '数据库',
-    'CRON'  => '定时任务',
-    'BACKUP'  => '数据备份',
-
-    'LOGIN'  => '登录',
-    'RESET PASSWORD'  => '重置密码',
-    'SEARCH'  => '搜索',
-    'PACKAGE'  => '预设方案',
-    'RRD'  => '资源图表',
-    'STATS'  => '统计信息',
-    'LOG'  => '系统日志',
-    'UPDATES'  => '系统更新',
-    'FIREWALL'  => '防火墙',
-    'SERVER'  => '服务器',
-    'MEMORY'  => '内存',
-    'DISK'  => '磁盘',
-    'NETWORK'  => '网络',
-    'Web Log Manager'  => 'Web 日志管理',
-
-    'no notifications'  => '没有通知',
-
-    'Add User'  => '添加用户',
-    'Add Domain'  => '添加域名',
+    'Updates' => '系统更新',
+    'Log in' => '登录',
+    'Log out' => '登出',
+
+    'USER' => '用户账户',
+    'WEB' => 'Web 服务',
+    'DNS' => 'DNS 服务',
+    'MAIL' => '邮箱服务',
+    'DB' => '数据库',
+    'CRON' => '定时任务',
+    'BACKUP' => '数据备份',
+
+    'LOGIN' => '登录',
+    'RESET PASSWORD' => '重置密码',
+    'SEARCH' => '搜索',
+    'PACKAGE' => '用户方案',
+    'RRD' => '资源图表',
+    'STATS' => '统计信息',
+    'LOG' => '系统日志',
+    'UPDATES' => '系统更新',
+    'FIREWALL' => '防火墙',
+    'SERVER' => '服务器',
+    'MEMORY' => '内存',
+    'DISK' => '磁盘',
+    'NETWORK' => '网络',
+    'Web Log Manager' => 'Web 日志管理',
+
+    'no notifications' => '没有通知',
+
+    'Add User' => '添加用户',
+    'Add Domain' => '添加域名',
     'Add Web Domain' => '添加网站域名',
-    'Add DNS Domain'  => '添加DNS域名',
-    'Add DNS Record'  => '添加DNS记录',
-    'Add Mail Domain'  => '添加邮箱域名',
-    'Add Mail Account'  => '添加邮箱账户',
-    'Add Database'  => '添加数据库',
-    'Add Cron Job'  => '添加定时任务',
-    'Create Backup'  => '创建备份',
-    'Configure'  => '配置',
-    'Restore All'  => '全部恢复',
-    'Add Package'  => '添加方案',
-    'Add IP'  => '添加IP地址',
+    'Add DNS Domain' => '添加DNS域名',
+    'Add DNS Record' => '添加DNS记录',
+    'Add Mail Domain' => '添加邮箱域名',
+    'Add Mail Account' => '添加邮箱账户',
+    'Add Database' => '添加数据库',
+    'Add Cron Job' => '添加定时任务',
+    'Create Backup' => '创建备份',
+    'Configure' => '配置',
+    'Restore All' => '全部恢复',
+    'Add Package' => '添加方案',
+    'Add IP' => '添加IP地址',
     'Add Rule' => '添加规则',
     'Ban IP Address' => '封锁IP地址',
-    'Search'  => '搜索',
+    'Search' => '搜索',
     'Add one more FTP Account' => '增加一个FTP账户',
-    'Overall Statistics'  => '整体统计信息',
-    'Daily'  => '按天',
-    'Weekly'  => '按周',
-    'Monthly'  => '按月',
-    'Yearly'  => '按年',
-    'Add'  => '添加',
-    'Back'  => '返回',
-    'Save'  => '保存',
-    'Submit'  => '提交',
-
-    'toggle all'  => '批量操作',
-    'apply to selected'  => '应用于选中项的操作',
-    'rebuild'  => '重建',
-    'rebuild web'  => '重建网站',
-    'rebuild dns'  => '重建DNS',
-    'rebuild mail'  => '重建邮箱',
-    'rebuild db'  => '重建数据库',
-    'rebuild cron'  => '重建定时任务',
-    'update counters'  => '更新计数器',
-    'suspend'  => '暂停',
-    'unsuspend'  => '解除暂停',
-    'delete'  => '删除',
-    'show per user'  => '按用户显示',
-    'login as'  => '登录至账户',
-    'logout'  => '登出',
-    'edit'  => '编辑',
-    'open webstats'  => '打开网站统计',
-    'view logs'  => '查看日志',
-    'list records'  => '列出 %s 条记录',
-    'add record'  => '添加记录',
-    'list accounts'  => '列出 %s 个账户',
-    'add account'  => '添加账户',
-    'open webmail'  => '打开网页邮箱',
-    'list fail2ban' => 'Fail2ban 封锁名单',
-    'open %s'  => '打开 %s',
-    'download'  => '下载',
-    'restore'  => '恢复',
-    'configure restore settings'  => '配置恢复选项',
-    'stop'  => '停止',
-    'start'  => '启动',
-    'restart'  => '重新启动',
-    'update'  => '更新',
-    'generate'  => '生成',
+    'Overall Statistics' => '整体统计信息',
+    'Daily' => '按天',
+    'Weekly' => '按周',
+    'Monthly' => '按月',
+    'Yearly' => '按年',
+    'Add' => '添加',
+    'Back' => '返回',
+    'Save' => '保存',
+    'Submit' => '提交',
+
+    'toggle all' => '批量操作',
+    'apply to selected' => '应用于选中项的操作',
+    'rebuild' => '重建',
+    'rebuild web' => '重建网站',
+    'rebuild dns' => '重建DNS',
+    'rebuild mail' => '重建邮箱',
+    'rebuild db' => '重建数据库',
+    'rebuild cron' => '重建定时任务',
+    'update counters' => '更新计数器',
+    'suspend' => '暂停',
+    'unsuspend' => '解除暂停',
+    'delete' => '删除',
+    'show per user' => '按用户显示',
+    'login as' => '登录至账户',
+    'logout' => '登出',
+    'edit' => '编辑',
+    'open webstats' => '打开网站统计',
+    'view logs' => '查看日志',
+    'list records' => '列出 %s 条记录',
+    'add record' => '添加记录',
+    'list accounts' => '列出 %s 个账户',
+    'add account' => '添加账户',
+    'open webmail' => '打开网页邮箱',
+    'list fail2ban' => 'Fail2ban 封锁列表',
+    'open %s' => '打开 %s',
+    'download' => '下载',
+    'restore' => '恢复',
+    'configure restore settings' => '配置恢复',
+    'stop' => '停止',
+    'start' => '启动',
+    'restart' => '重新启动',
+    'update' => '更新',
+    'generate' => '生成',
     'Generate CSR' => '生成CSR',
     'reread IP' => '重新读取IP',
     'enable autoupdate' => '启用自动更新',
@@ -116,41 +116,41 @@ $LANG['cn'] = array(
     'turn off notifications' => '停用通知',
     'configure' => '配置',
 
-    'Adding User'  => '添加用户',
-    'Editing User'  => '编辑用户',
-    'Adding Domain'  => '添加域名',
-    'Editing Domain'  => '编辑域名',
-    'Adding DNS Domain'  => '添加DNS域名',
-    'Editing DNS Domain'  => '编辑DNS域名',
-    'Adding DNS Record'  => '添加DNS记录',
-    'Editing DNS Record'  => '编辑DNS记录',
-    'Adding Mail Domain'  => '添加邮箱域名',
-    'Editing Mail Domain'  => '编辑邮箱域名',
-    'Adding Mail Account'  => '添加邮箱账户',
-    'Editing Mail Account'  => '编辑邮箱账户',
-    'Adding database'  => '添加数据库',
-    'Editing Cron Job'  => '编辑定时任务',
-    'Adding Cron Job'  => '添加定时任务',
-    'Editing Database'  => '编辑数据库',
-    'Adding Package'  => '添加方案',
-    'Editing Package'  => '编辑方案',
-    'Adding IP address'  => '添加IP地址',
-    'Editing IP Address'  => '编辑IP地址',
-    'Editing Backup Exclusions' => '配置排除备份项目',
+    'Adding User' => '添加用户',
+    'Editing User' => '编辑用户',
+    'Adding Domain' => '添加域名',
+    'Editing Domain' => '编辑域名',
+    'Adding DNS Domain' => '添加DNS域名',
+    'Editing DNS Domain' => '编辑DNS域名',
+    'Adding DNS Record' => '添加DNS记录',
+    'Editing DNS Record' => '编辑DNS记录',
+    'Adding Mail Domain' => '添加邮箱域名',
+    'Editing Mail Domain' => '编辑邮箱域名',
+    'Adding Mail Account' => '添加邮箱账户',
+    'Editing Mail Account' => '编辑邮箱账户',
+    'Adding database' => '添加数据库',
+    'Editing Cron Job' => '编辑定时任务',
+    'Adding Cron Job' => '添加定时任务',
+    'Editing Database' => '编辑数据库',
+    'Adding Package' => '添加方案',
+    'Editing Package' => '编辑方案',
+    'Adding IP address' => '添加IP地址',
+    'Editing IP Address' => '编辑IP地址',
+    'Editing Backup Exclusions' => '配置排除备份项目',
     'Generating CSR' => '生成CSR',
-    'Listing'  => '列出',
-    'Search Results'  => '搜索结果',
+    'Listing' => '列出',
+    'Search Results' => '搜索结果',
     'Adding Firewall Rule' => '添加防火墙规则',
     'Editing Firewall Rule' => '编辑防火墙规则',
-    'Adding IP Address to Banlist' => '添加IP至封锁名单',
+    'Adding IP Address to Banlist' => '添加IP至封锁列表',
 
-    'active'  => '正常',
-    'spnd'  => '暂停',
-    'suspended'  => '已暂停',
-    'running'  => '运行中',
-    'stopped'  => '已停止',
-    'outdated'  => '可升级新版本',
-    'updated'  => '已是最新版本',
+    'active' => '正常',
+    'spnd' => '暂停',
+    'suspended' => '已暂停',
+    'running' => '运行中',
+    'stopped' => '已停止',
+    'outdated' => '可升级新版本',
+    'updated' => '已是最新版本',
 
     'yes' => '是',
     'no' => '否',
@@ -185,33 +185,33 @@ $LANG['cn'] = array(
     'per domain' => '每域名',
     'DNS Domains' => 'DNS域名',
     'DNS domains' => 'DNS域名',
-    'DNS records'  => 'DNS记录',
+    'DNS records' => 'DNS记录',
     'Name Servers' => 'DNS服务器',
     'Mail Domains' => '邮箱域名',
     'Mail Accounts' => '邮箱账户',
     'Cron Jobs' => '定时任务',
     'SSH Access' => 'SSH权限',
-    'IP Address'  => 'IP地址',
+    'IP Address' => 'IP地址',
     'IP Addresses' => 'IP地址',
     'Backups' => '备份',
     'Backup System' => '备份系统',
-    'backup exclusions' => '排除备份项目',
+    'backup exclusions' => '排除备份项目',
     'template' => '模板',
     'SSL Support' => '启用SSL',
     'SSL Home Directory' => 'SSL站点主目录',
-    'Lets Encrypt Support'  => '采用 Let&#39s Encrypt',
-    'Lets Encrypt'  => 'Let&#39s Encrypt',
+    'Lets Encrypt Support' => '采用 Let&#39s Encrypt',
+    'Lets Encrypt' => 'Let&#39s Encrypt',
     'Your certificate will be automatically issued in 5 minutes' => '证书将在5分钟内自动完成签发',
     'Proxy Support' => '反向代理',
     'Proxy Extensions' => '需代理的文件扩展名',
     'Web Statistics' => '网站统计',
     'Additional FTP Account' => '额外的FTP账户',
-    'Path'  => '路径',
+    'Path' => '路径',
     'SOA' => 'SOA',
     'TTL' => 'TTL',
     'Expire' => '过期',
     'Records' => '记录',
-    'Serial'  => 'Serial',
+    'Serial' => '序号',
     'Catchall email' => '未知收件人聚合邮箱',
     'AntiVirus Support' => '防病毒支持',
     'AntiSpam Support' => '防垃圾邮件支持',
@@ -221,16 +221,16 @@ $LANG['cn'] = array(
     'Autoreply' => '自动回复',
     'Forward to' => '转发到',
     'Do not store forwarded mail' => '不保留已转发的邮件',
-    'IMAP hostname'  => 'IMAP 服务器',
-    'IMAP port'  => 'IMAP 端口',
-    'IMAP security'  => 'IMAP 安全性',
-    'IMAP auth method'  => 'IMAP 身份验证',
-    'SMTP hostname'  => 'SMTP 服务器',
-    'SMTP port'  => 'SMTP 端口',
-    'SMTP security'  => 'SMTP 安全性',
-    'SMTP auth method'  => 'SMTP 身份验证',
-    'STARTTLS'  => 'STARTTLS',
-    'Normal password'  => '普通密码',
+    'IMAP hostname' => 'IMAP 服务器',
+    'IMAP port' => 'IMAP 端口',
+    'IMAP security' => 'IMAP 安全类型',
+    'IMAP auth method' => 'IMAP 身份验证',
+    'SMTP hostname' => 'SMTP 服务器',
+    'SMTP port' => 'SMTP 端口',
+    'SMTP security' => 'SMTP 安全类型',
+    'SMTP auth method' => 'SMTP 身份验证',
+    'STARTTLS' => 'STARTTLS',
+    'Normal password' => '普通密码',
     'database' => '数据库',
     'User' => '用户名称',
     'Host' => '主机',
@@ -249,144 +249,146 @@ $LANG['cn'] = array(
     'shared' => '共享',
     'dedicated' => '独立',
     'Owner' => '归属',
-    'Users'  => '用户',
-    'Load Average'  => '平均负载',
-    'Memory Usage'  => '内存用量',
-    'APACHE2 Usage'  => 'Apache2 用量',
-    'HTTPD Usage'  => 'HTTPD 用量',
-    'NGINX Usage'  => 'NGINX 用量',
-    'MySQL Usage on localhost'  => 'MySQL用量 (localhost)',
-    'PostgreSQL Usage on localhost'  => 'PostgreSQL用量 (localhost)',
-    'Bandwidth Usage eth0'  => '网络流量 (eth0)',
-    'Bandwidth Usage eth1'  => '网络流量 (eth1)',
-    'Bandwidth Usage venet0'  => '网络流量 (venet0)',
-    'Bandwidth Usage venet1'  => '网络流量 (venet1)',
-    'Exim Usage'  => 'Exim 用量',
-    'FTP Usage'  => 'FTP 用量',
-    'SSH Usage'  => 'SSH 用量',
-    'reverse proxy'  => '反向代理',
-    'web server'  => 'Web服务',
+    'Users' => '用户',
+    'Load Average' => '平均负载',
+    'Memory Usage' => '内存使用情况',
+    'APACHE2 Usage' => 'Apache2 使用情况',
+    'HTTPD Usage' => 'HTTPD 使用情况',
+    'NGINX Usage' => 'NGINX 使用情况',
+    'MySQL Usage on localhost' => 'MySQL 使用情况 (localhost)',
+    'PostgreSQL Usage on localhost' => 'PostgreSQL 使用情况 (localhost)',
+    'Bandwidth Usage eth0' => '网络使用情况 (eth0)',
+    'Bandwidth Usage eth1' => '网络使用情况 (eth1)',
+    'Bandwidth Usage venet0' => '网络使用情况 (venet0)',
+    'Bandwidth Usage venet1' => '网络使用情况 (venet1)',
+    'Bandwidth Usage docker0' => '网络使用情况 (docker0)',
+    'Bandwidth Usage docker1' => '网络使用情况 (docker1)',
+    'Exim Usage' => 'Exim 使用情况',
+    'FTP Usage' => 'FTP 使用情况',
+    'SSH Usage' => 'SSH 使用情况',
+    'reverse proxy' => '反向代理',
+    'web server' => 'Web服务',
     'backend server' => '后端服务', //New Keyword for PHP-FPM in SERVER page.
-    'dns server'  => 'DNS服务',
-    'mail server'  => '邮箱服务',
-    'pop/imap server'  => 'POP/IMAP服务',
-    'email antivirus'  => '邮箱防病毒',
-    'email antispam'  => '防垃圾邮件',
-    'database server'  => '数据库服务',
-    'ftp server'  => 'FTP服务',
-    'job scheduler'  => '执行定时任务',
-    'firewall'  => '防火墙服务',
-    'brute-force monitor'  => '防范暴力攻击',
-    'CPU'  => 'CPU',
-    'Memory'  => '内存',
-    'Uptime'  => '已运行时间',
-    'core package'  => '核心系统',
-    'php interpreter'  => 'PHP解释器',
-    'internal web server'  => '内部Web服务',
-    'Version'  => '版本',
-    'Release'  => '发布号',
-    'Architecture'  => '架构',
-    'Object'  => '对象',
-    'Username'  => '用户名称',
-    'Password'  => '密码',
-    'Email'  => '电子邮箱',
-    'Package'  => '方案',
-    'Language'  => '语言',
-    'First Name'  => '名字',
-    'Last Name'  => '姓氏',
-    'Send login credentials to email address'  => '将登录信息发送到邮箱',
-    'Default Template'  => '默认模板',
-    'Default Name Servers'  => '默认DNS服务器',
-    'Domain'  => '域名',
-    'DNS Support'  => 'DNS支持',
-    'Mail Support'  => '邮箱支持',
-    'Advanced options'  => '高级选项',
-    'Basic options'  => '基本选项',
-    'Aliases'  => '别名',
-    'SSL Certificate'  => 'SSL证书',
-    'SSL Key'  => 'SSL密钥',
-    'SSL Certificate Authority / Intermediate'  => 'CA证书或中级证书',
+    'dns server' => 'DNS服务',
+    'mail server' => '邮箱服务',
+    'pop/imap server' => 'POP/IMAP服务',
+    'email antivirus' => '邮箱防病毒',
+    'email antispam' => '防垃圾邮件',
+    'database server' => '数据库服务',
+    'ftp server' => 'FTP服务',
+    'job scheduler' => '执行定时任务',
+    'firewall' => '防火墙服务',
+    'brute-force monitor' => '防范暴力攻击',
+    'CPU' => 'CPU',
+    'Memory' => '内存',
+    'Uptime' => '已运行时间',
+    'core package' => '核心系统',
+    'php interpreter' => 'PHP解释器',
+    'internal web server' => '内部Web服务',
+    'Version' => '版本',
+    'Release' => '发布号',
+    'Architecture' => '架构',
+    'Object' => '对象',
+    'Username' => '用户名称',
+    'Password' => '密码',
+    'Email' => '电子邮箱',
+    'Package' => '方案',
+    'Language' => '语言',
+    'First Name' => '名字',
+    'Last Name' => '姓氏',
+    'Send login credentials to email address' => '将登录信息发送到邮箱',
+    'Default Template' => '默认模板',
+    'Default Name Servers' => '默认DNS服务器',
+    'Domain' => '域名',
+    'DNS Support' => 'DNS支持',
+    'Mail Support' => '邮箱支持',
+    'Advanced options' => '高级选项',
+    'Basic options' => '基本选项',
+    'Aliases' => '别名',
+    'SSL Certificate' => 'SSL证书',
+    'SSL Key' => 'SSL密钥',
+    'SSL Certificate Authority / Intermediate' => 'SSL CA证书 / 中级证书',
     'SSL CSR' => 'SSL CSR',
-    'optional'  => '可选',
+    'optional' => '可选',
     'internal' => '内部',
-    'Statistics Authorization'  => '统计授权',
-    'Statistics Auth'  => '统计验证',
-    'Account'  => '账户',
-    'Prefix will be automaticaly added to username'  => '用户名称将会自动添加 %s 前缀',
-    'Send FTP credentials to email'  => '将FTP登录信息发送到邮箱',
-    'Expiration Date'  => '到期日期',
-    'YYYY-MM-DD'  => 'YYYY-MM-DD',
-    'Name servers'  => 'DNS服务器',
-    'Record'  => '记录',
-    'IP or Value'  => 'IP或值',
-    'Priority'  => '优先级',
+    'Statistics Authorization' => '统计授权',
+    'Statistics Auth' => '统计验证',
+    'Account' => '账户',
+    'Prefix will be automaticaly added to username' => '用户名称将会自动添加 %s 前缀',
+    'Send FTP credentials to email' => '将FTP登录信息发送到邮箱',
+    'Expiration Date' => '到期日期',
+    'YYYY-MM-DD' => 'YYYY-MM-DD',
+    'Name servers' => 'DNS服务器',
+    'Record' => '记录',
+    'IP or Value' => 'IP或值',
+    'Priority' => '优先级',
     'Record Number' => '记录编号',
-    'in megabytes'  => '以MB为单位',
-    'Message'  => '信息',
-    'use local-part'  => '采用 local-part',
-    'one or more email addresses'  => '一个或更多邮箱地址',
-    'Prefix will be automaticaly added to database name and database user'  => '数据库名及用户名将会自动添加 %s 前缀',
-    'Database'  => '数据库名称',
-    'Type'  => '类型',
-    'Minute'  => '分',
-    'Command'  => '指令',
-    'Package Name'  => '方案名称',
-    'Netmask'  => '子网掩码',
-    'Interface'  => '网络接口',
-    'Shared'  => '共享',
-    'Assigned user'  => '指定用户',
-    'Assigned domain'  => '指定域名',
+    'in megabytes' => '以MB为单位',
+    'Message' => '信息',
+    'use local-part' => '使用域内部分',
+    'one or more email addresses' => '一个或更多邮箱地址',
+    'Prefix will be automaticaly added to database name and database user' => '数据库名及用户名将会自动添加 %s 前缀',
+    'Database' => '数据库名称',
+    'Type' => '类型',
+    'Minute' => '分',
+    'Command' => '指令',
+    'Package Name' => '方案名称',
+    'Netmask' => '子网掩码',
+    'Interface' => '网络接口',
+    'Shared' => '共享',
+    'Assigned user' => '指定用户',
+    'Assigned domain' => '指定域名',
     'NAT IP association' => 'NAT IP 关联',
-    'shell'  => 'shell',
-    'web domains'  => '网站域名',
-    'web aliases'  => '网站别名',
-    'dns records'  => 'DNS记录',
-    'mail domains'  => '邮箱域名',
-    'mail accounts'  => '邮箱账户',
-    'accounts'  => '账户',
-    'databases'  => '数据库',
-    'cron jobs'  => '定时任务',
-    'backups'  => '备份',
-    'quota'  => '配额',
-    'day of week'  => '星期几',
-    'cmd'  => '指令',
-    'users'  => '用户',
-    'domains'  => '域名',
-    'aliases'  => '别名',
-    'records'  => '记录',
-    'jobs'  => '任务',
-    'username'  => '用户名称',
-    'password'  => '密码',
-    'type'  => '类型',
-    'charset'  => '编码',
-    'domain'  => '域名',
-    'ip'  => 'IP',
-    'ip address'  => 'IP地址',
-    'IP address'  => 'IP地址',
-    'netmask'  => '子网掩码',
-    'interface'  => '网络接口',
-    'assigned user'  => '指定用户',
-    'ns1'  => 'ns1',
-    'ns2'  => 'ns2',
-    'user'  => '用户',
-    'email'  => '邮箱',
-    'first name'  => '名字',
-    'last name'  => '姓氏',
-    'account'  => '账户',
-    'ssl certificate'  => 'SSL证书',
-    'ssl key'  => 'SSL密钥',
-    'stats user password'  => '统计用户账户密码',
-    'stats username'  => '统计用户名称',
-    'stats password'  => '统计密码',
-    'ftp user password'  => 'FTP用户账户密码',
-    'ftp user'  => 'FTP用户',
+    'shell' => 'shell',
+    'web domains' => '网站域名',
+    'web aliases' => '网站别名',
+    'dns records' => 'DNS记录',
+    'mail domains' => '邮箱域名',
+    'mail accounts' => '邮箱账户',
+    'accounts' => '账户',
+    'databases' => '数据库',
+    'cron jobs' => '定时任务',
+    'backups' => '备份',
+    'quota' => '配额',
+    'day of week' => '星期几',
+    'cmd' => '指令',
+    'users' => '用户',
+    'domains' => '域名',
+    'aliases' => '别名',
+    'records' => '记录',
+    'jobs' => '任务',
+    'username' => '用户名称',
+    'password' => '密码',
+    'type' => '类型',
+    'charset' => '编码',
+    'domain' => '域名',
+    'ip' => 'IP',
+    'ip address' => 'IP地址',
+    'IP address' => 'IP地址',
+    'netmask' => '子网掩码',
+    'interface' => '网络接口',
+    'assigned user' => '指定用户',
+    'ns1' => 'ns1',
+    'ns2' => 'ns2',
+    'user' => '用户',
+    'email' => '邮箱',
+    'first name' => '名字',
+    'last name' => '姓氏',
+    'account' => '账户',
+    'ssl certificate' => 'SSL证书',
+    'ssl key' => 'SSL密钥',
+    'stats user password' => '统计用户账户密码',
+    'stats username' => '统计用户名称',
+    'stats password' => '统计密码',
+    'ftp user password' => 'FTP用户账户密码',
+    'ftp user' => 'FTP用户',
     'Last 70 lines of %s.%s.log' => '%s.%s.log 的最后 70 行',
     'AccessLog' => '访问日志',
     'ErrorLog' => '错误日志',
     'Download AccessLog' => '下载访问日志',
     'Download ErrorLog' => '下载错误日志',
     'Country' => '国家地区',
-    '2 letter code' => '采用 ISO 3166-1 二位代码 如: 中国CN / 美国US',
+    '2 letter code' => '采用 ISO 3166-1 α-2 二位代码 如: 中国CN / 美国US',
     'State / Province' => '州 / 省级',
     'City / Locality' => '市 / 地区',
     'Organization' => '组织名称',
@@ -417,48 +419,48 @@ $LANG['cn'] = array(
     'cron' => '任务',
     'user dir' => '用户目录',
 
-    'unlimited'  => '无限',
-    '1 account'  => '1 个账户',
-    '%s accounts'  => '%s 个账户',
-    '1 domain'  => '1 个域名',
-    '%s domains'  => '%s 个域名',
-    '1 record'  => '1 条记录',
-    '%s records'  => '%s 条记录',
-    '1 mail account'  => '1 个邮箱账户',
-    '%s mail accounts'  => '%s 个邮箱账户',
-    '1 database'  => '1 个数据库',
-    '%s databases'  => '%s 个数据库',
-    '1 cron job'  => '1 个任务',
-    '%s cron jobs'  => '%s 个任务',
-    '1 archive'  => '1 个存档',
-    '%s archives'  => '%s 个存档',
-    '1 item'  => '1 个项目',
-    '%s items'  => '%s 个项目',
-    '1 package'  => '1 个方案',
-    '%s packages'  => '%s 个方案',
-    '1 IP address'  => '1 个IP地址',
-    '%s IP addresses'  => '%s 个IP地址',
-    '1 month'  => '1 个月',
-    '%s months'  => '%s 个月',
-    '1 log record'  => '1 条日志记录',
-    '%s log records'  => '%s 条日志记录',
-    '1 object'  => '1 个对象',
-    '%s objects'  => '%s 个对象',
+    'unlimited' => '无限',
+    '1 account' => '1 个账户',
+    '%s accounts' => '%s 个账户',
+    '1 domain' => '1 个域名',
+    '%s domains' => '%s 个域名',
+    '1 record' => '1 条记录',
+    '%s records' => '%s 条记录',
+    '1 mail account' => '1 个邮箱账户',
+    '%s mail accounts' => '%s 个邮箱账户',
+    '1 database' => '1 个数据库',
+    '%s databases' => '%s 个数据库',
+    '1 cron job' => '1 个任务',
+    '%s cron jobs' => '%s 个任务',
+    '1 archive' => '1 个存档',
+    '%s archives' => '%s 个存档',
+    '1 item' => '1 个项目',
+    '%s items' => '%s 个项目',
+    '1 package' => '1 个方案',
+    '%s packages' => '%s 个方案',
+    '1 IP address' => '1 个IP地址',
+    '%s IP addresses' => '%s 个IP地址',
+    '1 month' => '1 个月',
+    '%s months' => '%s 个月',
+    '1 log record' => '1 条日志记录',
+    '%s log records' => '%s 条日志记录',
+    '1 object' => '1 个对象',
+    '%s objects' => '%s 个对象',
     'no exclusions' => '没有被排除的项目',
     '1 rule' => '1 条规则',
     '%s rules' => '%s 条规则',
     'There are no currently banned IP' => '目前没有被封锁的IP地址',
 
-    'USER_CREATED_OK'  => '用户 <a href="/edit/user/?user=%s"><b>%s</b></a> 已添加成功',
-    'WEB_DOMAIN_CREATED_OK'  => '网站域名 <a href="/edit/web/?domain=%s"><b>%s</b></a> 已添加成功',
-    'DNS_DOMAIN_CREATED_OK'  => 'DNS域名 <a href="/list/dns/?domain=%s"><b>%s</b></a> 已添加成功',
-    'DNS_RECORD_CREATED_OK'  => '记录 <b>%s.%s</b> 已添加成功',
-    'MAIL_DOMAIN_CREATED_OK'  => '邮箱域名 <a href="/list/mail/?domain=%s"><b>%s</b></a> 已添加成功',
-    'MAIL_ACCOUNT_CREATED_OK'  => '邮箱账户 <a href="/edit/mail/?account=%s&domain=%s"><b>%s@%s</b></a> 已添加成功',
-    'DATABASE_CREATED_OK'  => '数据库 <a href="/edit/db/?database=%s"><b>%s</b></a> 已添加成功',
-    'CRON_CREATED_OK'  => '定时任务已添加成功',
-    'IP_CREATED_OK'  => 'IP地址 <a href="/edit/ip/?ip=%s"><b>%s</b></a> 已添加成功',
-    'PACKAGE_CREATED_OK'  => '方案 <a href="/edit/package/?package=%s"><b>%s</b></a> 已添加成功',
+    'USER_CREATED_OK' => '用户 <a href="/edit/user/?user=%s"><b>%s</b></a> 已添加成功',
+    'WEB_DOMAIN_CREATED_OK' => '网站域名 <a href="/edit/web/?domain=%s"><b>%s</b></a> 已添加成功',
+    'DNS_DOMAIN_CREATED_OK' => 'DNS域名 <a href="/list/dns/?domain=%s"><b>%s</b></a> 已添加成功',
+    'DNS_RECORD_CREATED_OK' => '记录 <b>%s.%s</b> 已添加成功',
+    'MAIL_DOMAIN_CREATED_OK' => '邮箱域名 <a href="/list/mail/?domain=%s"><b>%s</b></a> 已添加成功',
+    'MAIL_ACCOUNT_CREATED_OK' => '邮箱账户 <a href="/edit/mail/?account=%s&domain=%s"><b>%s@%s</b></a> 已添加成功',
+    'DATABASE_CREATED_OK' => '数据库 <a href="/edit/db/?database=%s"><b>%s</b></a> 已添加成功',
+    'CRON_CREATED_OK' => '定时任务已添加成功',
+    'IP_CREATED_OK' => 'IP地址 <a href="/edit/ip/?ip=%s"><b>%s</b></a> 已添加成功',
+    'PACKAGE_CREATED_OK' => '方案 <a href="/edit/package/?package=%s"><b>%s</b></a> 已添加成功',
     'SSL_GENERATED_OK' => 'SSL证书已生成成功',
     'RULE_CREATED_OK' => '规则已创建成功',
     'BANLIST_CREATED_OK' => 'IP地址已封锁成功',
@@ -466,8 +468,8 @@ $LANG['cn'] = array(
     'Autoupdate has been successfully disabled' => '自动更新已成功关闭',
     'Cronjob email reporting has been successfully enabled' => '定时任务的电子邮件报告已成功启用',
     'Cronjob email reporting has been successfully disabled' => '定时任务的电子邮件报告已成功关闭',
-    'Changes has been saved.'  => '已保存更改',
-    'Confirmation'  => '确认',
+    'Changes has been saved.' => '已保存更改',
+    'Confirmation' => '确认',
     'DELETE_USER_CONFIRMATION' => '确定要删除用户 %s 吗?',
     'SUSPEND_USER_CONFIRMATION' => '确定要暂停用户 %s 吗?',
     'UNSUSPEND_USER_CONFIRMATION' => '确定要解除暂停用户 %s 吗?',
@@ -486,31 +488,31 @@ $LANG['cn'] = array(
     'DELETE_CRON_CONFIRMATION' => '确定要删除定时任务吗?',
     'SUSPEND_CRON_CONFIRMATION' => '确定要暂停定时任务吗?',
     'UNSUSPEND_CRON_CONFIRMATION' => '确定要解除暂停定时任务吗?',
-    'DELETE_BACKUP_CONFIRMATION'  => '确定要删除 %s 备份吗?',
+    'DELETE_BACKUP_CONFIRMATION' => '确定要删除 %s 备份吗?',
     'DELETE_EXCLUSION_CONFIRMATION' => '确定要删除 %s 例外吗?',
-    'DELETE_PACKAGE_CONFIRMATION'  => '确定要删除方案 %s 吗?',
-    'DELETE_IP_CONFIRMATION'  => '确定要删除IP地址 %s 吗?',
+    'DELETE_PACKAGE_CONFIRMATION' => '确定要删除方案 %s 吗?',
+    'DELETE_IP_CONFIRMATION' => '确定要删除IP地址 %s 吗?',
     'DELETE_RULE_CONFIRMATION' => '确定要删除规则 #%s 吗?',
     'SUSPEND_RULE_CONFIRMATION' => '确定要暂停规则 #%s 吗?',
     'UNSUSPEND_RULE_CONFIRMATION' => '确定要解除暂停规则 #%s 吗?',
     'LEAVE_PAGE_CONFIRMATION' => '确定要离开当前页吗?',
     'RESTART_CONFIRMATION' => '确定要重新启动 %s 吗?',
-    'Welcome'  => '欢迎',
-    'LOGGED_IN_AS'  => '以 %s 的身份登录',
-    'Error'  => '错误',
-    'Invalid username or password'  => '无效的用户名称或密码',
-    'Invalid username or code'  => '无效的用户名称或验证码.',
-    'Passwords not match'  => '密码错误',
-    'Please enter valid email address.'  => '请输入正确的邮箱',
-    'Field "%s" can not be blank.'  => '"%s" 不能为空',
-    'Password is too short.'  => '密码太短 (至少为6个数字+字母)',
-    'Error code:'  => '错误代码: %s',
-    'SERVICE_ACTION_FAILED'  => '"%s" "%s" 失败',
+    'Welcome' => '欢迎',
+    'LOGGED_IN_AS' => '以 %s 的身份登录',
+    'Error' => '错误',
+    'Invalid username or password' => '无效的用户名称或密码',
+    'Invalid username or code' => '无效的用户名称或验证码.',
+    'Passwords not match' => '密码错误',
+    'Please enter valid email address.' => '请输入正确的邮箱',
+    'Field "%s" can not be blank.' => '"%s" 不能为空',
+    'Password is too short.' => '密码太短 (至少为6个数字+字母)',
+    'Error code:' => '错误代码: %s',
+    'SERVICE_ACTION_FAILED' => '"%s" "%s" 失败',
     'IP address is in use' => 'IP地址在使用中',
-    'BACKUP_SCHEDULED'  => '您的要求已加入队列中,备份完成后会以电子邮件通知您 ',
-    'BACKUP_EXISTS'  => '已经有一个备份正在执行,请等待备份完成后再操作',
-    'RESTORE_SCHEDULED'  => '您的要求已加入队列中,恢复完成后会以电子邮件通知您',
-    'RESTORE_EXISTS'  => '已经有一个恢复正在执行,请等待恢复完成后再操作',
+    'BACKUP_SCHEDULED' => '您的要求已加入队列中,备份完成后会以电子邮件通知您 ',
+    'BACKUP_EXISTS' => '已经有一个备份正在执行,请等待备份完成后再操作',
+    'RESTORE_SCHEDULED' => '您的要求已加入队列中,恢复完成后会以电子邮件通知您',
+    'RESTORE_EXISTS' => '已经有一个恢复正在执行,请等待恢复完成后再操作',
 
     'WEB_EXCLUSIONS' => '输入域名,每行一个。要排除所有域名请使用 *。要排除特定目录使用以下格式: domain.com:public_html/cache:public_html/tmp',
     'DNS_EXCLUSIONS' => '输入域名,每行一个。要排除所有域名请使用 *',
@@ -519,27 +521,27 @@ $LANG['cn'] = array(
     'CRON_EXCLUSIONS' => '要排除所有任务请使用 *',
     'USER_EXCLUSIONS' => '输入目录名称,每行一个。要排除所有目录请使用 *',
 
-    'Welcome to Hestia Control Panel'  => '欢迎来到 Hestia 管理系统',
-    'MAIL_FROM'  => 'Hestia 管理系统 <noreply@%s>',
+    'Welcome to Hestia Control Panel' => '欢迎来到 Hestia 管理系统',
+    'MAIL_FROM' => 'Hestia 管理系统 <noreply@%s>',
     'GREETINGS_GORDON_FREEMAN' => "您好, %s %s,\n",
     'GREETINGS' => "您好,\n",
     'ACCOUNT_READY' => "您的账户已创建成功,并可以开始使用了!\n\nhttps://%s/login/\n用户名称: %s\n密码: %s\n\n--\nHestia Control Panel\n",
 
-    'FTP login credentials'  => 'FTP 登录信息',
+    'FTP login credentials' => 'FTP 登录信息',
     'FTP_ACCOUNT_READY' => "FTP账户已创建成功,并可以开始使用了!\n\n主机名称: %s\n用户名称: %s_%s\n密码: %s\n\n--\nHestia Control Panel\n",
 
-    'Database Credentials'  => '数据库登录信息',
+    'Database Credentials' => '数据库登录信息',
     'DATABASE_READY' => "数据库已添加成功!\n\n数据库名称: %s\n用户名称: %s\n密码: %s\n%s\n\n--\nHestia Control Panel\n",
 
-    'forgot password'  => '忘记密码',
-    'Confirm'  => '确认',
-    'New Password'  => '新密码',
-    'Confirm Password'  => '确认密码',
-    'Reset'  => '重置',
-    'Reset Code'  => '重置代码',
-    'RESET_NOTICE'  => '',
-    'RESET_CODE_SENT'  => '密码重置代码已发送到您的邮箱<br>',
-    'MAIL_RESET_SUBJECT'  => '密码重置在 %s',
+    'forgot password' => '忘记密码',
+    'Confirm' => '确认',
+    'New Password' => '新密码',
+    'Confirm Password' => '确认密码',
+    'Reset' => '重置',
+    'Reset Code' => '重置代码',
+    'RESET_NOTICE' => '',
+    'RESET_CODE_SENT' => '密码重置代码已发送到您的邮箱<br>',
+    'MAIL_RESET_SUBJECT' => '密码重置在 %s',
     'PASSWORD_RESET_REQUEST' => '重置密码请点击链接:\nhttps://%s/reset/?action=confirm&user=%s&code=%s\n\n或者您可以到 https://%s/reset/?action=code&user=%s 输入密码重置代码:\n%s\n\n如果您没有要求重置密码,请忽略此邮件\n\n--\nHestia Control Panel\n',
 
     'Jan' => '01月',
@@ -568,6 +570,7 @@ $LANG['cn'] = array(
     'MAIL Server' => '邮箱服务器',
     'Antivirus' => '防病毒引擎',
     'AntiSpam' => '防垃圾邮件',
+    'Use Web Domain SSL Certificate' => '采用网站域名SSL证书',
     'Webmail URL' => '网页邮箱网址',
     'MySQL Support' => 'MySQL 支持',
     'phpMyAdmin URL' => '设置 phpMyAdmin 网址',
@@ -703,7 +706,7 @@ $LANG['cn'] = array(
     'Add File to the Current Selection' => '将文件添加到当前选中区内',
     'Select All Files' => '选择所有文件',
     'shortcuts are inspired by magnificent GNU <a href="https://www.midnight-commander.org/">Midnight Commander</a> file manager' =>
-        '快捷键的灵感来自旖旎的 GNU <a href="https://www.midnight-commander.org/">Midnight Commander</a> 文件管理器',
+    '快捷键的灵感来自华丽的 GNU <a href="https://www.midnight-commander.org/">Midnight Commander</a> 文件管理器',
 
     'Licence Key' => '许可密匙',
     'Enter License Key' => '输入许可密匙',
@@ -712,7 +715,7 @@ $LANG['cn'] = array(
     'Disable and Cancel Licence' => '停用并取消许可',
     'Licence Activated' => '许可已激活',
     'Licence Deactivated' => '许可已停用',
-    'Restrict users so that they cannot use SSH and access only their home directory.' => '限制用户,使他们通过 SSH 只能访问自己的主目录。',
+    'Restrict users so that they cannot use SSH and access only their home directory.' => '限制用户,对他们禁用 SSH 且只能访问自己的主目录。',
     'Browse, copy, edit, view, and retrieve all of your web domain files using fully featured File Manager.' => '功能全面的文件管理器,浏览,复制,编辑,查看和检索你的 Web 文件。',
     'This is a commercial module, you would need to purchace license key to enable it.' => '这是商业模块,请购买许可密匙来启用它。',
 
@@ -741,19 +744,20 @@ $LANG['cn'] = array(
     'every' => '每隔',
     'Generate' => '生成',
 
+    'webalizer' => 'Webalizer',
     'awstats' => 'AWStats',
 
-    'Hestia SSL' => 'SSL',
-    'SUBJECT' => '颁发给',
+    'Hestia SSL' => 'Hestia SSL',
+    'SUBJECT' => '使用者',
     'ALIASES' => '可选名称',
-    'NOT_BEFORE' => '有效期',
+    'NOT_BEFORE' => '有效期',
     'NOT_AFTER' => '有效期至',
     'SIGNATURE' => '签名算法',
-    'PUB_KEY' => '公钥长度',
+    'PUB_KEY' => '密钥大小',
     'ISSUER' => '颁发者',
 
     'Use server hostname' => '采用服务器主机名',
-    'Use domain hostname' => '采用域名',
+    'Use domain hostname' => '采用账户所在域名',
     'Use STARTTLS' => '采用 STARTTLS 加密',
     'Use SSL / TLS' => '采用 SSL / TLS 加密',
     'No encryption' => '不加密',
@@ -761,8 +765,8 @@ $LANG['cn'] = array(
 
     'maximum characters length, including prefix' => '包含前缀最多 %s 个字符',
 
-    'Email Credentials' => '电子邮件证书',
+    'Email Credentials' => '电子邮件凭据',
 
-    'Theme' => '外觀',
-    'Operating System' => '作業系統',
+    'Theme' => '主题',
+    'Operating System' => '操作系统',
 );

+ 1 - 1
web/inc/i18n/en.php

@@ -132,7 +132,7 @@ $LANG['en'] = array(
     'Adding IP address'  => 'Add IP Address',
     'Editing IP Address'  => 'Edit IP Address',
     'Editing Backup Exclusions' => 'Edit Backup Exclusions',
-    'Generating CSR' => 'Generate New Self-Signed SSL Certificate',
+    'Generating CSR' => 'New Self-Signed SSL Certificate',
     'Listing'  => 'Listing',
     'Search Results'  => 'Search Results',
     'Adding Firewall Rule' => 'Add Firewall Rule',

+ 2 - 2
web/inc/i18n/es.php

@@ -232,7 +232,7 @@ $LANG['es'] = array(
     'SMTP security'  => 'Seguridad STMP',
     'SMTP auth method'  => 'Método de Autentificación STMP',
     'STARTTLS'  => 'STARTTLS',
-    'Normal password'  => 'Normal password',
+    'Normal password'  => 'Contraseña normal',
     'database'  => 'base de datos',
     'User'  => 'Usuario',
     'Host'  => 'Host',
@@ -763,5 +763,5 @@ $LANG['es'] = array(
     'Email Credentials' => 'Datos de acceso a la cuenta de correo',
 
     'Theme' => 'Aspecto',
-    'Operating System' => 'Operatsioonisüsteemi',
+    'Operating System' => 'Sistema operativo',
 );

+ 773 - 0
web/inc/i18n/hr.php

@@ -0,0 +1,773 @@
+<?php
+/**
+ * Hestia Croatian hr_HR language file
+ * VINS DIGITAL (info@vins.hr)
+ */
+
+$LANG['hr'] = array(
+    'Packages'  => 'Paketi',
+    'IP'  => 'Mreža',
+    'Graphs'  => 'Nadzor',
+    'Statistics'  => 'Statistika',
+    'Log'  => 'Bilješke',
+    'Server'  => 'Poslužitelj',
+    'Services'  => 'Servisi',
+    'Firewall' => 'Vatrozid',
+    'Updates'  => 'Ažuriranja',
+    'Log in'  => 'Prijava',
+    'Log out'  => 'Odjava',
+
+    'USER'  => 'KORISNICI',
+    'WEB'  => 'WEB',
+    'DNS'  => 'DNS',
+    'MAIL'  => 'E-POŠTA',
+    'DB'  => 'BAZE',
+    'CRON'  => 'CRON',
+    'BACKUP'  => 'SIG. KOPIJE',
+
+    'LOGIN'  => 'PRIJAVA',
+    'RESET PASSWORD'  => 'POSTAVLJANJE ZAPORKE',
+    'SEARCH'  => 'PRETRAGA',
+    'PACKAGE'  => 'PAKET',
+    'RRD'  => 'NADZOR ZADATAKA',
+    'STATS'  => 'STATISTIKA',
+    'LOG'  => 'BILJEŠKE',
+    'UPDATES'  => 'AŽURIRANJA',
+    'FIREWALL'  => 'VATROZID',
+    'SERVER'  => 'POSLUŽITELJ',
+    'MEMORY'  => 'MEMORIJA',
+    'DISK'  => 'DISK',
+    'NETWORK'  => 'MREŽA',
+    'Web Log Manager'  => 'Upravitelj web bilješki',
+
+    'no notifications'  => 'nema obavijesti',
+
+    'Add User'  => 'Dodavanje korisnika',
+    'Add Domain'  => 'Dodavanje domene',
+    'Add Web Domain'  => 'Dodavanje web domene',
+    'Add DNS Domain'  => 'Dodavanje DNS zone',
+    'Add DNS Record'  => 'Dodavanje DNS zapisa',
+    'Add Mail Domain'  => 'Dodavanje domene e-pošte',
+    'Add Mail Account'  => 'Dodavanje e-pošte',
+    'Add Database'  => 'Dodavanje baze podataka',
+    'Add Cron Job'  => 'Dodavanje zadataka',
+    'Create Backup'  => 'Izrada sigurnosne kopije',
+    'Configure'  => 'Postavke',
+    'Restore All'  => 'Vratite sve',
+    'Add Package'  => 'Dodavanje paketa',
+    'Add IP'  => 'Dodavanje IP adrese',
+    'Add Rule' => 'Dodavanje pravila',
+    'Ban IP Address' => 'Blokirajte IP adresu',
+    'Search'  => 'Pretraga',
+    'Add one more FTP Account' => 'Dodavanje FTP računa',
+    'Overall Statistics'  => 'Pogledajte svu statistiku',
+    'Daily'  => 'Dnevno',
+    'Weekly'  => 'Tjedno',
+    'Monthly'  => 'Mjesečno',
+    'Yearly'  => 'Godišnje',
+    'Add'  => 'Dodavanje',
+    'Back'  => 'Povratak',
+    'Save'  => 'Spremanje',
+    'Submit'  => 'Slanje',
+
+    'toggle all'  => 'Promijenite sve',
+    'apply to selected'  => 'Primijente na odabrane',
+    'rebuild'  => 'Obnavljanje',
+    'rebuild web'  => 'Obnavljanje web Domene',
+    'rebuild dns'  => 'Obnavljanje DNS Zone',
+    'rebuild mail'  => 'Obnavljanje domene e-pošte',
+    'rebuild db'  => 'Obnavljanje baze',
+    'rebuild cron'  => 'Obnavljanje Cron zadataka',
+    'update counters'  => 'Ažurirajte brojače prometa',
+    'suspend'  => 'Zabrana',
+    'unsuspend'  => 'Reaktivacija',
+    'delete'  => 'Brisanje',
+    'show per user'  => 'Prikaz po korisniku',
+    'login as'  => 'Prijavite se kao',
+    'logout'  => 'Odjava',
+    'edit'  => 'Uredite',
+    'open webstats'  => 'Pogledajte statistiku web-a',
+    'view logs'  => 'Pogledajte bilješke',
+    'list records'  => 'Popis %s zapisa',
+    'add record'  => 'Dodavanje zapisa',
+    'list accounts'  => 'Popis %s računa',
+    'add account'  => 'Dodavanje računa',
+    'open webmail'  => 'Otvorite Web poštu',
+    'list fail2ban' => 'Upravljajte blokiranim IP adresama',
+    'open %s'  => 'Otvorite %s',
+    'download'  => 'Preuzimanje',
+    'restore'  => 'Vraćanje',
+    'configure restore settings'  => 'Postavke vraćanja sigurnosne kopije',
+    'stop'  => 'Zaustavljanje',
+    'start'  => 'Pokretanje',
+    'restart'  => 'Ponovo pokretanje',
+    'update'  => 'Ažuriranje',
+    'generate'  => 'Stvaranje',
+    'Generate CSR' => 'Stvorite vlastito potpisanu SSL vjerodajnicu',
+    'reread IP' => 'Provjerite IP adresu',
+    'enable autoupdate' => 'Automatska ažuriranja: isključena',
+    'disable autoupdate' => 'Automatska ažuriranja: uključena',
+    'turn on notifications' => 'Uključivanje obavijesti',
+    'turn off notifications' => 'Isključivanje obavijesti',
+    'configure' => 'Postavljanje',
+
+    'Adding User'  => 'Dodavanje korisnika',
+    'Editing User'  => 'Uređenje korinsnika',
+    'Adding Domain'  => 'Dodavanje web domene',
+    'Editing Domain'  => 'Uređenje web domene',
+    'Adding DNS Domain'  => 'Dodavanje DNS zone',
+    'Editing DNS Domain'  => 'Uređenje DNS zone',
+    'Adding DNS Record'  => 'Dodavanje DNS zapia',
+    'Editing DNS Record'  => 'Uređenje DNS zapia',
+    'Adding Mail Domain'  => 'Dodavanje domene e-pošte',
+    'Editing Mail Domain'  => 'Uređenje domene e-pošte',
+    'Adding Mail Account'  => 'Dodavanje e-pošte',
+    'Editing Mail Account'  => 'Uređenje e-pošte',
+    'Adding database'  => 'Dodavanje baze podataka',
+    'Editing Cron Job'  => 'Uređenje zadataka',
+    'Adding Cron Job'  => 'Dodavanje zadataka',
+    'Editing Database'  => 'Uređenje baze podataka',
+    'Adding Package'  => 'Dodavanje paketa',
+    'Editing Package'  => 'Uređenje paketa',
+    'Adding IP address'  => 'Dodavanje IP adrese',
+    'Editing IP Address'  => 'Uređenje IP adrese',
+    'Editing Backup Exclusions' => 'Uređenje iznimke iz sigurnosne kopije',
+    'Generating CSR' => 'Stvaranje vlastito potpisane SSL vjerodajnice',
+    'Listing'  => 'Popis',
+    'Search Results'  => 'Rezultati pretraživanja',
+    'Adding Firewall Rule' => 'Dodavanje pravila vatrozida',
+    'Editing Firewall Rule' => 'Uređenje pravila vatrozida',
+    'Adding IP Address to Banlist' => 'Blokiranje IP adresu',
+
+    'active'  => 'Aktivan',
+    'spnd'  => 'Pod zabranom',
+    'suspended'  => 'Pod zabranom',
+    'running'  => 'Izvršava se',
+    'stopped'  => 'Zaustavljen',
+    'outdated'  => 'Zastario',
+    'updated'  => 'Ažuriran',
+
+    'yes'  => 'Da',
+    'no'  => 'Ne',
+    'none'  => 'Ništa',
+    'pb'  => 'PB',
+    'tb'  => 'TB',
+    'gb'  => 'GB',
+    'mb'  => 'MB',
+    'minute'  => 'minuta',
+    'hour'  => 'sat',
+    'day'  => 'dan',
+    'days'  => 'dana',
+    'hours'  => 'sati',
+    'minutes'  => 'minute',
+    'month'  => 'mjesec',
+    'package'  => 'paket',
+    'Bandwidth'  => 'Propusnost',
+    'Disk'  => 'Disk',
+    'Web'  => 'Web',
+    'Mail'  => 'e-pošta',
+    'Databases'  => 'Baze podataka',
+    'User Directories'  => 'Korisnički imenici',
+    'Template'  => 'Predložak',
+    'Web Template'  => 'Predložak za web',
+    'Backend Template'  => 'Predložak za pozadnski sustav',
+    'Proxy Template' =>'Predložak za proxy',
+    'DNS Template'  => 'Predložak za DNS',
+    'Web Domains'  => 'Web domene',
+    'SSL Domains'  => 'SSL web domene',
+    'Web Aliases'  => 'Web Pseudonim',
+    'per domain'  => 'Po domeni',
+    'DNS Domains'  => 'DNS zone',
+    'DNS domains'  => 'DNS zone',
+    'DNS records'   => 'DNS zapisi',
+    'Name Servers'  => 'Imenski poslužitelji',
+    'Mail Domains'  => 'Domene e-pošte',
+    'Mail Accounts'  => 'Računi e-pošte',
+    'Cron Jobs'  => 'Cron zadaci',
+    'SSH Access'  => 'SSH pristup',
+    'IP Address'  => 'IP adresa',
+    'IP Addresses'  => 'IP adrese',
+    'Backups'  => 'Sigurnosne kopije',
+    'Backup System'  => 'Sigurnosna kopija sustava',
+    'backup exclusions' => 'Iznimke iz sigurnosne kopije',
+    'template'  => 'Predložak',
+    'SSL Support'  => 'Omogućite SSL na ovoj domeni',
+    'SSL Home Directory'  => 'Početna mapa za SSL',
+    'Force SSL/HTTPS' => 'Prisilite automatsko usmjeravanje HTTP-a na HTTPS',
+    'Enable SSL HSTS' => 'Uključite strogu sigurnost HTTP prometa (HSTS) <a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security" target="_blank"><i class="fas fa-question-circle"></i></a>',
+    'Lets Encrypt Support'  => 'Koristite Lets Encrypt da bi dobili SSL vjerodajnice',
+    'Lets Encrypt'  => 'Lets Encrypt',
+    'Your certificate will be automatically issued in 5 minutes' => 'Vaša vjerodajnica će biti automatski izdana unutar 5 minuta.',
+    'Proxy Support'  => 'Proxy podrška',
+    'Proxy Extensions'  => 'Proxy dodaci',
+    'Web Statistics'  => 'Web statistika',
+    'Additional FTP Account'  => 'Dodatni FTP račun(i)',
+    'Path'  => 'Putanja',
+    'SOA'  => 'SOA',
+    'TTL'  => 'TTL',
+    'Expire'  => 'Istek',
+    'Records'  => 'Zapisi',
+    'Serial'  => 'Serijski broj',
+    'Catchall email'  => 'Uhvati-sve pošta',
+    'AntiVirus Support'  => 'Protuvirusna zaštita',
+    'AntiSpam Support'  => 'Ograničenje neželjene pošte',
+    'DKIM Support'  => 'DKIM',
+    'Accounts'  => 'Računi',
+    'Quota'  => 'Ograničenje prostora',
+    'Autoreply'  => 'Automatski odgovor',
+    'Forward to'  => 'Proslijedite na',
+    'Do not store forwarded mail'  => 'Ne želim spremati proslijeđenu poštu',
+    'IMAP hostname'  => 'IMAP poslužitelj',
+    'IMAP port'  => 'IMAP priključak',
+    'IMAP security'  => 'IMAP sigurnost',
+    'IMAP auth method'  => 'IMAP način prijave',
+    'SMTP hostname'  => 'SMTP poslužitelj',
+    'SMTP port'  => 'SMTP priključak',
+    'SMTP security'  => 'SMTP sigurnost',
+    'SMTP auth method'  => 'SMTP način prijave',
+    'STARTTLS'  => 'STARTTLS',
+    'Normal password'  => 'Normalna zaporka',
+    'database'  => 'Baza podataka',
+    'User'  => 'Korisnik',
+    'Host'  => 'Poslužitelj',
+    'Charset'  => 'Kodna stranica',
+    'Min'  => 'Minuta',
+    'Hour'  => 'Sat',
+    'Day'  => 'Dan',
+    'Month'  => 'Mjesec',
+    'Day of week'  => 'Dan u tjednu',
+    'local'  => 'Lokalizacija',
+    'Run Time'  => 'Vrijeme izvršavanja',
+    'Backup Size'  => 'Veličina sigurnosne kopije',
+    'SYS'  => 'SYS',
+    'Domains'  => 'Domene',
+    'Status'  => 'Status',
+    'shared'  => 'Dijeljena',
+    'dedicated'  => 'Posvećena',
+    'Owner' => 'Vlasnik',
+    'Users'  => 'Korisnici',
+    'Load Average'  => 'Prosječno opterećenje',
+    'Memory Usage'  => 'Korištenje memorije',
+    'APACHE2 Usage'  => 'Korištenje Apache poslužitelja',
+    'HTTPD Usage'  => 'Korištenje Apache poslužitelja',
+    'NGINX Usage'  => 'Korištenje NGINX poslužitelja',
+    'MySQL Usage on localhost'  => 'Korištenje MySQL baze',
+    'PostgreSQL Usage on localhost'  => 'Korištenje PostgreSQL baze',
+    'Bandwidth Usage eth0'  => 'Promet kroz eth0',
+    'Bandwidth Usage eth1'  => 'Promet kroz eth1',
+    'Exim Usage'  => 'SMTP promet',
+    'FTP Usage'  => 'FTP promet',
+    'SSH Usage'  => 'SSH promet',
+    'reverse proxy'  => 'Obrnuti Proxy',
+    'web server'  => 'Web poslužitelj',
+    'dns server'  => 'DNS poslužitelj',
+    'mail server'  => 'Mail poslužitelj',
+    'pop/imap server'  => 'POP/IMAP poslužitelj',
+    'email antivirus'  => 'Protuvirusna zaštita',
+    'email antispam'  => 'Zaštita od neželjene pošte',
+    'database server'  => 'Poslužitelj baze podataka',
+    'backend server' => 'Poslužitelj pozadinskog sustava',
+    'ftp server'  => 'FTP poslužitelj',
+    'job scheduler'  => 'Planer zadataka',
+    'firewall'  => 'Vatrozid',
+    'brute-force monitor'  => 'Nadzor pristupa',
+    'CPU'  => 'Procesor',
+    'Memory'  => 'Memorija',
+    'Uptime'  => 'Neprekinuti rad',
+    'core package'  => 'Hestia upravljačka ploča',
+    'php interpreter'  => 'Hestia PHP',
+    'internal web server'  => 'Hestia web poslužitelj',
+    'Version'  => 'Inačica',
+    'Release'  => 'Distribucija',
+    'Architecture'  => 'Arhitektura',
+    'Object'  => 'Objekt',
+    'Username'  => 'Korisničko ime',
+    'Password'  => 'Zaporka',
+    'Email'  => 'E-pošta',
+    'Package'  => 'Paket',
+    'Language'  => 'Jezik',
+    'First Name'  => 'Ime',
+    'Last Name'  => 'Prezime',
+    'Send login credentials to email address'  => 'Slanje pristupnih podataka na adresu e-pošte:',
+    'Default Template'  => 'Zadani predložak',
+    'Default Name Servers'  => 'Zadani imenski poslužitelji',
+    'Domain'  => 'Domena',
+    'DNS Support'  => 'Napravite DNS zonu',
+    'Mail Support'  => 'Omogućite e-poštu na ovoj domeni',
+    'Advanced options'  => 'Napredne značajke',
+    'Basic options'  => 'Osnovne značajke',
+    'Aliases'  => 'Pseudonimi',
+    'SSL Certificate'  => 'SSL Certifikati',
+    'SSL Key'  => 'SSL Ključ',
+    'SSL Certificate Authority / Intermediate'  => 'SSL Autoritet vjerodajnice / Posrednik',
+    'SSL CSR' => 'Zahtjev za SSL vjerodajnicom',
+    'optional'  => 'Neobavezan',
+    'internal' => 'Interni',
+    'Statistics Authorization'  => 'Ovlaštenje za pregled statistike',
+    'Statistics Auth'  => 'Ovlaštenje statistike',
+    'Account'  => 'Račun',
+    'Prefix will be automaticaly added to username'  => 'Prefiks %s će automatski biti dodan korisničkom imenu',
+    'Send FTP credentials to email'  => 'Slanje pristupnih podataka za FTP e-poštom na:',
+    'Expiration Date'  => 'Datum isteka',
+    'YYYY-MM-DD'  => 'GGGG-MM-DD',
+    'Name servers'  => 'Imenski poslužitelji',
+    'Record'  => 'Zapis',
+    'IP or Value'  => 'IP ili vrijednost',
+    'Priority'  => 'Prioritet',
+    'Record Number' => 'Broj zapisa',
+    'in megabytes'  => 'u MB',
+    'Message'  => 'Poruka',
+    'use local-part'  => 'Koristite lokalni dio, bez naziva domene',
+    'one or more email addresses'  => 'Jednu ili više adresa e-pošte',
+    'Prefix will be automaticaly added to database name and database user'  => 'Prefiks <b>%s</b> će biti dodan imenima baza i korisničkim imenima',
+    'Database'  => 'Baza podataka',
+    'Type'  => 'Tip',
+    'Minute'  => 'Minuta',
+    'Command'  => 'Naredba',
+    'Package Name'  => 'Naziv paketa',
+    'Netmask'  => 'Mrežna maska',
+    'Interface'  => 'Sučelje',
+    'Shared'  => 'Dijeljena',
+    'Assigned user'  => 'Pridruženi korisnik',
+    'Assigned domain'  => 'Pridružena domena',
+    'NAT IP association' => 'NAT-IP pridruživanje',
+    'shell'  => 'Ljuska',
+    'web domains'  => 'Web domene',
+    'web aliases'  => 'Web pseudonimi',
+    'dns records'  => 'DNS zapisi',
+    'mail domains'  => 'Domene e-pošte',
+    'mail accounts'  => 'Računi e-pošte',
+    'accounts'  => 'Računa',
+    'databases'  => 'Baza',
+    'cron jobs'  => 'Cron zadataka',
+    'backups'  => 'Sigurnsnih kopija',
+    'quota'  => 'Ograničenje',
+    'day of week'  => 'Dan u tjednu',
+    'cmd'  => 'Komanda',
+    'users'  => 'korisnika',
+    'domains'  => 'domena',
+    'zones' => 'zona',
+    'aliases'  => 'pseudonima',
+    'records'  => 'zapisa',
+    'jobs'  => 'zadataka',
+    'username'  => 'korisničko ime',
+    'password'  => 'zaporka',
+    'type'  => 'tip',
+    'charset'  => 'kodna stranica',
+    'domain'  => 'domena',
+    'ip'  => 'IP',
+    'ip address'  => 'IP adresa',
+    'IP address'  => 'IP adresa',
+    'netmask'  => 'mrežna maska',
+    'interface'  => 'sučelje',
+    'assigned user'  => 'pridruženi korisnik',
+    'ns1'  => 'ns1',
+    'ns2'  => 'ns2',
+    'user'  => 'korisnik',
+    'email'  => 'e-pošta',
+    'first name'  => 'ime',
+    'last name'  => 'prezime',
+    'account'  => 'račun',
+    'ssl certificate'  => 'SSL vjerodajnica',
+    'ssl key'  => 'SSL ključ',
+    'stats user password'  => 'Pristupni podaci statistike',
+    'stats username'  => 'Korisničko ime',
+    'stats password'  => 'Zaporka',
+    'ftp user password'  => 'Pristupni podaci za FTP',
+    'ftp user'  => 'Korisničko ime',
+    'Last 70 lines of %s.%s.log' => 'Zadnjh 70 linija of %s.%s.log',
+    'AccessLog' => 'Bilješke pristupa',
+    'ErrorLog' => 'Bilješke grešaka',
+    'Download AccessLog' => 'Bilješke pristupa preuzimanju',
+    'Download ErrorLog' => 'Bilješke grešaka preuzimanja',
+    'Country' => 'Država',
+    '2 letter code' => 'Dvoslovna oznaka',
+    'State / Province' => 'Županija',
+    'City / Locality' => 'Grad',
+    'Organization' => 'Tvrtka',
+    'Action' => 'Radnja',
+    'Protocol' => 'Protokol',
+    'Port' => 'Priključak',
+    'Comment' => 'Usluga',
+    'Banlist' => 'Usluga',
+    'ranges are acceptable' => 'Rasponi se prihvaćaju',
+    'CIDR format is supported' => 'CIDR oblik se prihvaća',
+    'ACCEPT' => 'Dozvolite',
+    'DROP' => 'Blokirajte',
+    'TCP' => 'TCP',
+    'UDP' => 'UDP',
+    'ICMP' => 'ICMP',
+    'SSH' => 'SSH',
+    'FTP' => 'FTP',
+    'HESTIA' => 'Hestia',
+    'Add one more Name Server' => 'Dodajte imenski poslužitelj',
+
+    'web domain' => 'Web domena',
+    'dns domain' => 'DNS zona',
+    'dns record' => 'DNS zapis',
+    'mail domain' => 'Domena e-pošte',
+    'mail account' => 'Račun e-pošte',
+    'cron job' => 'Cron zadatak',
+
+    'cron' => 'Cron',
+    'user dir' => 'Korisnički imenik',
+
+    'unlimited'  => '∞',
+    '1 account'  => '1 račun',
+    '%s accounts'  => '%s računa',
+    '1 domain'  => '1 domena',
+    '%s domains'  => '%s domena',
+    '1 record'  => '1 zapis',
+    '%s records'  => '%s zapisa',
+    '1 mail account'  => '1 račun',
+    '%s mail accounts'  => '%s računa e-pošte',
+    '1 database'  => '1 baza',
+    '%s databases'  => '%s baza',
+    '1 cron job'  => '1 cron zadatak',
+    '%s cron jobs'  => '%s cron zadataka',
+    '1 archive'  => '1 arhiva',
+    '%s archives'  => '%s arhiva',
+    '1 item'  => '1 predmet',
+    '%s items'  => '%s predmet',
+    '1 package'  => '1 paket',
+    '%s packages'  => '%s paketa',
+    '1 IP address'  => '1 IP adresa',
+    '%s IP addresses'  => '%s IP adresa',
+    '1 month'  => '1 mjesec',
+    '%s months'  => '%s mjeseci',
+    '1 log record'  => '1 bilješka',
+    '%s log records'  => '%s bilješki',
+    '1 object'  => '1 predmet',
+    '%s objects'  => '%s predmeta',
+    'no exclusions' => 'Bez iznimki',
+    '1 rule' => '1 pravlo',
+    '%s rules' => '%s pravilo',
+    'There are no currently banned IP' => 'Trenutno nema blokiranih IP adresa',
+
+    'USER_CREATED_OK'  => 'Korisnik <a href="/edit/user/?user=%s"><b>%s</b></a> Je uspješno dodan.',
+    'WEB_DOMAIN_CREATED_OK'  => 'Domena <a href="/edit/web/?domain=%s"><b>%s</b></a> je uspješno dodana.',
+    'DNS_DOMAIN_CREATED_OK'  => 'DNS domena <a href="/list/dns/?domain=%s"><b>%s</b></a> je uspješno dodana.',
+    'DNS_RECORD_CREATED_OK'  => 'Zapis <b>%s.%s</b> je uspješno dodan.',
+    'MAIL_DOMAIN_CREATED_OK'  => 'Domena e-pošte <a href="/list/mail/?domain=%s"><b>%s</b></a> je uspješno dodana.',
+    'MAIL_ACCOUNT_CREATED_OK'  => 'Račun e-pošte <a href="/edit/mail/?account=%s&domain=%s"><b>%s@%s</b></a> je uspješno dodana.',
+    'DATABASE_CREATED_OK'  => 'Baza <a href="/edit/db/?database=%s"><b>%s</b></a> je uspješno dodana.',
+    'CRON_CREATED_OK'  => 'Cron zadatak je uspješno dodan.',
+    'IP_CREATED_OK'  => 'IP adresa <a href="/edit/ip/?ip=%s"><b>%s</b></a> je uspješno dodana.',
+    'PACKAGE_CREATED_OK'  => 'Paket <a href="/edit/package/?package=%s"><b>%s</b></a> je uspješno dodan.',
+    'SSL_GENERATED_OK' => 'Vjerodajnica je uspješno dodana.',
+    'RULE_CREATED_OK' => 'Prailo je uspješno dodano.',
+    'BANLIST_CREATED_OK' => 'IP adresa je uspješno blokirana.',
+    'Autoupdate has been successfully enabled' => 'Automatsko ažuriranje je uspješno aktivirano.',
+    'Autoupdate has been successfully disabled' => 'Automatsko ažuriranje je uspješno deaktivirano.',
+    'Cronjob email reporting has been successfully enabled' => 'Izvještaj o Cron zadatcima e-poštom je uspješno aktiviran.',
+    'Cronjob email reporting has been successfully disabled' => 'Izvještaj o Cron zadatcima e-poštom je uspješno deaktiviran.',
+    'Changes has been saved.'  => 'Promjene su uspješno spremljene.',
+    'Confirmation'  => 'Potvrda',
+    'DELETE_USER_CONFIRMATION' => 'Jeste li sigurni da želite obrisati korisnika %s?',
+    'SUSPEND_USER_CONFIRMATION' => 'Jeste li sigurni da želite staviti zabrane korisniku %s?',
+    'UNSUSPEND_USER_CONFIRMATION' => 'Jeste li sigurni da želite reaktivirati korisnika %s?',
+    'DELETE_DOMAIN_CONFIRMATION' => 'Jeste li sigurni da želite obrisati domenu %s?',
+    'SUSPEND_DOMAIN_CONFIRMATION' => 'Jeste li sigurni da želite staviti zabranu na domenu %s?',
+    'UNSUSPEND_DOMAIN_CONFIRMATION' => 'Jeste li sigurni da želite reaktivirati na domenu %s?',
+    'DELETE_RECORD_CONFIRMATION' => 'Jeste li sigurni da želite obrisati zapis %s?',
+    'SUSPEND_RECORD_CONFIRMATION' => 'Jeste li sigurni da želite staviti zabranu na zapis %s?',
+    'UNSUSPEND_RECORD_CONFIRMATION' => 'Jeste li sigurni da želite reaktivirati zapis %s?',
+    'DELETE_MAIL_ACCOUNT_CONFIRMATION' => 'Jeste li sigurni da želite obrisati račun e-pošte %s?',
+    'SUSPEND_MAIL_ACCOUNT_CONFIRMATION' => 'Jeste li sigurni da želite staviti zabranu na račun e-pošte %s?',
+    'UNSUSPEND_MAIL_ACCOUNT_CONFIRMATION' => 'Jeste li sigurni da želite reaktivirati račun e-pošte %s?',
+    'DELETE_DATABASE_CONFIRMATION' => 'Jeste li sigurni da želite obrisati bazu podataka %s?',
+    'SUSPEND_DATABASE_CONFIRMATION' => 'Jeste li sigurni da želite staviti zabranu na bazu %s?',
+    'UNSUSPEND_DATABASE_CONFIRMATION' => 'Jeste li sigurni da želite reaktivirati bazu %s?',
+    'DELETE_CRON_CONFIRMATION' => 'Jeste li sigurni da želite obrisati cron zadatak?',
+    'SUSPEND_CRON_CONFIRMATION' => 'Jeste li sigurni da želite zabraniti cron zadatak?',
+    'UNSUSPEND_CRON_CONFIRMATION' => 'Jeste li sigurni da želite reaktivirati cron zadatak?',
+    'DELETE_BACKUP_CONFIRMATION'  => 'Jeste li sigurni da želite obrisati sigurnosnu kopiju %s?',
+    'DELETE_EXCLUSION_CONFIRMATION' => 'Jeste li sigurni da želite obrisati izuzetak %s?',
+    'DELETE_PACKAGE_CONFIRMATION'  => 'Jeste li sigurni da želite obrisati paket %s?',
+    'DELETE_IP_CONFIRMATION'  => 'Jeste li sigurni da želite obrisati IP adresu %s?',
+    'DELETE_RULE_CONFIRMATION' => 'Jeste li sigurni da želite obrisati pravilo #%s?',
+    'DELETE_LOGS_CONFIRMATION'  => 'Jeste li sigurni da želite obrisati bilješke?',
+    'SUSPEND_RULE_CONFIRMATION' => 'Jeste li sigurni da želite zabraniti pravilo #%s?',
+    'UNSUSPEND_RULE_CONFIRMATION' => 'Jeste li sigurni da želite reaktivirati pravilo #%s?',
+    'Are you sure you want to stop service' => 'Jeste li sigurni da želite zaustaviti servis %s?',
+    'LEAVE_PAGE_CONFIRMATION' => 'Napustiti stranicu?',
+    'RESTART_CONFIRMATION' => 'Jeste li sigurni da želite ponovno pokrenuti %s?',
+    'Welcome'  => 'Dobrodošli',
+    'LOGGED_IN_AS'  => 'Prijavljeni ste kao korisnik %s',
+    'Error'  => 'Greška',
+    'Invalid username or password'  => 'Neispravno korisničko ime ili zaporka.',
+    'Invalid username or code'  => 'Neispravno korisničko ime ili šifra.',
+    'Passwords not match'  => 'Zaporke nisu identične.',
+    'Please enter valid email address.'  => 'Molimo unesite valjanu adresu e-pošte.',
+    'Field "%s" can not be blank.'  => 'Polje "%s" ne smije ostati prazno.',
+    'Password is too short.'  => 'Zaporka je pre kratka (treba imati minimalno 6 znakova)',
+    'Error code:'  => 'Šifra greške: %s',
+    'SERVICE_ACTION_FAILED'  => '"%s" "%s" nije uspjela',
+    'IP address is in use' => 'IP adresa se već koristi',
+    'BACKUP_SCHEDULED'  => 'Zadatak je u stavljen u red za izvršenje. Primit ćete poruku e-poštom kad Vaša sigurnosna kopija bude spremna za preuzimanje.',
+    'BACKUP_EXISTS'  => 'Sigurnosno kopiranje se izvršava. Molimo pričekajte da se kopiranje završi.',
+    'RESTORE_SCHEDULED'  => 'Zadatak je u stavljen u red za izvršenje. Primit ćete poruku e-poštom kad Vaša sigurnosna kopija bude vraćena.',
+    'RESTORE_EXISTS'  => 'Sigurnosno vraćanje podataka se izvršava. Molimo pričekajte da se vraćanje završi.',
+
+    'WEB_EXCLUSIONS' => 'Upišite ime domene, jedno po liniji. Ako želite izuzeti sve domene, koristite *. Ako želite izuzeti pojedinu mapu, koristite sljedeći format: domain.com:public_html/cache:public_html/tmp',
+    'DNS_EXCLUSIONS' => 'Upišite ime domene, jedno po liniji. Ako želite izuzeti sve domene, koristite *',
+    'MAIL_EXCLUSIONS' => 'Upišite ime domene, jedno po liniji. Ako želite izuzeti sve domene, koristite *. Ako želite izuzete pojedini račun, koristite sljedeći format: domain.com:info:support:postmaster',
+    'DB_EXCLUSIONS' => 'Upišite cijelo ime baze, jedno po liniji. Ako želite izuzeti sve baze, koristite *',
+    'CRON_EXCLUSIONS' => 'Ako želite izuzeti sve zadatke, koristite *',
+    'USER_EXCLUSIONS' => 'Upišite ime mape, jedno po liniji. Ako želite izuzeti sve mape, koristite *',
+
+    'Welcome to Hestia Control Panel'  => 'Dobrodošli u Hestia upravljačku ploču',
+    'MAIL_FROM'  => 'Hestia upravljačka ploča <noreply@%s>',
+    'GREETINGS_GORDON_FREEMAN' => "Pozdrav, %s %s,\n",
+    'GREETINGS' => "Pozdrav,\n",
+    'ACCOUNT_READY' => "Vaš račun je aktiviran i spreman za korištenje.\n\nhttps://%s/login/\nKorisničko ime: %s\nZaporka: %s\n\n--\nHestia upravljačka ploča\n",
+
+    'FTP login credentials'  => 'Pristupni podaci za FTP',
+    'FTP_ACCOUNT_READY' => "Vaš FTP račun je aktiviran i spraman za korištenje.\n\nPoslužitelj: %s\nKorisničko ime: %s_%s\nZaporka: %s\n\n--\nHestia upravljačka ploča\n",
+
+    'Database Credentials'  => 'Pristupni podaci za bazu podataka',
+    'DATABASE_READY' => "Vaša baza je uspješno aktivirana.\n\nBaza: %s\nKorisnik: %s\nZaporka: %s\n%s\n\n--\nHestia upravljačka ploča\n",
+
+    'forgot password'  => 'Zaboravljena zaporka',
+    'Confirm'  => 'Potvrdite',
+    'New Password'  => 'Nova zaporka',
+    'Confirm Password'  => 'Potvrdite zaporku',
+    'Reset'  => 'Ponovno postavljanje',
+    'Reset Code'  => 'Šifra za ponovno postavljanje',
+    'RESET_NOTICE'  => '',
+    'RESET_CODE_SENT'  => 'Šifra za ponovno postavljanje zaporke je poslana na Vašu adresu e-pošte.<br>',
+    'MAIL_RESET_SUBJECT'  => 'Zaporka je ponovno postavljena %s',
+    'PASSWORD_RESET_REQUEST' => "Za ponovo postavljanje Vaše zaporke, molimo posjetite poveznicu:\nhttps://%s/reset/?action=confirm&user=%s&code=%s\n\nAlternatively, možete posjetiti https://%s/reset/?action=code&user=%s i unesti sljedeću šifru za ponovno postavljanje:\n%s\n\nAko niste zatražili ponovno postavljanje zaporke, molimo ignorirajte ovu poruku i primite naše isprike.\n\n--\nHestia kontrolna ploča\n",
+
+    'Jan' => 'Sij',
+    'Feb' => 'Velj',
+    'Mar' => 'Ožu',
+    'Apr' => 'Tra',
+    'May' => 'Svi',
+    'Jun' => 'Lip',
+    'Jul' => 'Srp',
+    'Aug' => 'Kol',
+    'Sep' => 'Ruj',
+    'Oct' => 'Lis',
+    'Nov' => 'Stu',
+    'Dec' => 'Pro',
+
+    'Configuring Server' => 'Postavke poslužitelja',
+    'Hostname' => 'Ime poslužitelja',
+    'Time Zone' => 'Vremenska zona',
+    'Default Language' => 'Zadani jezik',
+    'Proxy Server' => 'Proxy poslužitelj',
+    'Web Server' => 'Web poslužitelj',
+    'Backend Server' => 'Poslužitelj pozadinskog sustava',
+    'Backend Pool Mode' => 'Pool način pozadinskog sustava',
+    'DNS Server' => 'DNS poslužitelj',
+    'DNS Cluster' => 'DNS grupa',
+    'MAIL Server' => 'Poslužitelj e-pošte',
+    'Antivirus' => 'Protuvirusni program',
+    'AntiSpam' => 'Ograničavanje neželjene pošte',
+    'Webmail URL' => 'Pseudonim za webmail',
+    'MySQL Support' => 'Podrška za MySQL',
+    'phpMyAdmin URL' => 'Poveznica za phpMyAdmin',
+    'PostgreSQL Support' => 'Podrška za PostgreSQL',
+    'phpPgAdmin URL' => 'Poveznica za phpPgAdmin',
+    'Maximum Number Of Databases' => 'Maksimalni broj baza podataka',
+    'Current Number Of Databases' => 'Trenutni broj baza podataka',
+    'Local backup' => 'Lokalna sigurnosna kopija',
+    'Compression level' => 'Nivo sažimanja',
+    'Directory' => 'Mapa',
+    'Remote backup' => 'Udaljena sigurnosna kopija',
+    'ftp' => 'FTP',
+    'sftp' => 'SFTP',
+    'SFTP Chroot' => 'SFTP Chroot',
+    'FileSystem Disk Quota' => 'Ograničenje diskovnog prostora',
+    'Hestia Control Panel Plugins' => 'Dodaci',
+    'preview' => 'predpregled',
+    'Reseller Role' => 'Uloga preprodavača',
+    'Web Config Editor' => 'Uređivanje postavki za web',
+    'Template Manager' => 'Upravljanje predlošcima',
+    'Backup Migration Manager' => 'Upravljanje migracijom sigurnosne kopije',
+    'FileManager' => 'Upravitelj datoteka',
+    'show: CPU / MEM / NET / DISK' => 'Pregled naprednih detalja',
+
+    'sort by' => 'redosljed',
+    'Date' => 'Datum',
+    'Starred' => 'Sa zvjezdicom',
+    'Name' => 'Ime',
+
+    'save to favorites' => 'spremanje u favorite',
+
+    'File Manager' => 'Upravitelj datoteka',
+    'size' => 'veličina',
+    'date' => 'datum',
+    'name' => 'ime',
+    'Initializing' => 'Pokretanje',
+    'UPLOAD' => 'UČITAJTE',
+    'NEW FILE' => 'NOVA DATOTEKA',
+    'NEW DIR' => 'NOVA MAPA',
+    'DELETE' => 'OBRIŠITE',
+    'RENAME' => 'PREIMENUJTE',
+    'MOVE' => 'PRESELITE',
+    'RIGHTS' => 'PRAVA',
+    'COPY' => 'KOPIRAJTE',
+    'ARCHIVE' => 'ARHIVA',
+    'EXTRACT' => 'RASPAKIRAJTE',
+    'DOWNLOAD' => 'PREUZMITE',
+    'Are you sure?' => 'Jeste li sigurni?',
+    'Hit' => 'Posjeta',
+    'to reload the page' => 'da bi ponovno učitali',
+    'Directory name cannot be empty' => 'Naziv mape ne može biti prazan',
+    'File name cannot be empty' => 'Naziv datoteke ne može biti prazan',
+    'No file selected' => 'Nije odabrana ni jedna datoteka',
+    'No file or folder selected' => 'Nije odabrana ni jedna mapa ili datoteka',
+    'File type not supported' => 'Ovaj tip datoteke nije podržan',
+    'Directory download not available in current version' => 'Preuzimanje mape nije moguće u ovoj inačici',
+    'Directory not available' => 'Mapa nije dostupna',
+    'Done' => 'Završeno',
+    'Close' => 'Zatvorite',
+    'Copy' => 'Kopirajte',
+    'Cancel' => 'Otkažite',
+    'Rename' => 'Preimenujte',
+    'Move' => 'Preselite',
+    'Change Rights' => 'Promijenite prava',
+    'Delete' => 'Brisanje',
+    'Extract' => 'Raspakirajte',
+    'Create' => 'Napravite novu',
+    'Compress' => 'Sažmite',
+    'OK' => 'OK',
+    'YOU ARE COPYING' => 'KOPIRATE',
+    'YOU ARE REMOVING' => 'BRIŠETE',
+    'Delete items' => 'Brisanje stavki',
+    'Copy files' => 'Kopiranje datoteka',
+    'Move files' => 'Preseljenje datoteka',
+    'Are you sure you want to copy' => 'Jeste li sigurni da želite kopirati',
+    'Are you sure you want to move' => 'Jeste li sigurni da želite preseliti',
+    'Are you sure you want to delete' => 'Jeste li sigurni da želite izbrisati',
+    'into' => 'u',
+    'existing files will be replaced' => 'postojeće datoteke će biti zamijenjene',
+    'Original name' => 'Izvorno ime',
+    'File' => 'Datoteka',
+    'already exists' => 'već postoji',
+    'Create file' => 'Napravite datoteku',
+    'Create directory' => 'Napravite mapu',
+    'read by owner' => 'čitanje za vlasnika',
+    'write by owner' => 'pisanje za vlasnika',
+    'execute/search by owner' => 'izvršavanje za vlasnika',
+    'read by group' => 'čitanje za grupu',
+    'write by group' => 'pisanje za grupu',
+    'execute/search by group' => 'izvršavanje za grupu',
+    'read by others' => 'čitanje za sve',
+    'write by others' => 'pisanje za sve',
+    'execute/search by others' => 'izvršavanje za sve',
+
+    'Shortcuts' => 'Prečaci',
+    'Add New object' => 'Dodajte novi objekt',
+    'Save Form' => 'Spremanje obrasca',
+    'Cancel saving form' => 'Otkažite spremanje obrasca',
+    'Go to USER list' => 'Idite na popis korisnika',
+    'Go to WEB list' => 'Idite na popis web-ova',
+    'Go to DNS list' => 'Idite na popis DNS-ova',
+    'Go to MAIL list' => 'Idite na popie e-pošte',
+    'Go to DB list' => 'Idite na popis baza podataka',
+    'Go to CRON list' => 'Idite na popis cron zadataka',
+    'Go to BACKUP list' => 'Idite na popis sigurnosnih kopija',
+    'Focus on search' => 'Fokus na pretragu',
+    'Display/Close shortcuts' => 'Prikažite/Zatvorite prečace',
+    'Move backward through top menu' => 'Pomaknite nazad u vršnom izborniku',
+    'Move forward through top menu' => 'Pomaknite naprijed u vršnom izborniku',
+    'Enter focused element' => 'Pređite na element u fokusu',
+    'Move up through elements list' => 'Pomaknite gore na popisu elemenata',
+    'Move down through elements list' => 'Pomaknite dolje na popisu elemenata',
+
+    'Upload' => 'Učitavanje',
+    'New File' => 'Nova datoteka',
+    'New Folder' => 'Nova mapa',
+    'Download' => 'Preuzimanje',
+    'Archive' => 'Arhiva',
+    'Save File (in text editor)' => 'Spremi datoteku (u uređivaću teksta)',
+    'Close Popup / Cancel' => 'Zatvorite skočni prozor / Otkažite',
+    'Move Cursor Up' => 'Pomaknite pokazivač gore',
+    'Move Cursor Down' => 'Pomaknite pokazivač dolje',
+    'Switch to Left Tab' => 'Prebacite na lijevu karticu',
+    'Switch to Right Tab' => 'Prebacite na desnu karticu',
+    'Switch Tab' => 'Prebacite karticu',
+    'Go to the Top of the File List' => 'Skočite na vrh popisa datoteka',
+    'Go to the Last File' => 'Skočite na dno popisa datoteka',
+    'Open File / Enter Directory' => 'Otvorite datoteku / Uđite u mapu',
+    'Edit File' => 'Uredite datoteku',
+    'Go to Parent Directory' => 'Idite u prethodnu mapu',
+    'Select Current File' => 'Odaberite trenutnu datoteku',
+    'Select Bunch of Files' => 'Odaberite više datoteka',
+    'Add File to the Current Selection' => 'Dodajte datoteku u trenutni odabir',
+    'Select All Files' => 'Odaberite sve datoteke',
+    'shortcuts are inspired by magnificent GNU <a href="https://www.midnight-commander.org/">Midnight Commander</a> file manager' =>
+    'prečaci su inspirirani veličanstvenim GNU upraviteljem datoteka <a href="https://www.midnight-commander.org/">Midnight Commander-om</a>',
+
+    'Licence Key' => 'Licenčni ključ',
+    'Enter License Key' => 'Unesite licenčni ključ',
+    'Buy Licence' => 'Kupite licencu',
+    'Buy Lifetime License' => 'Kupite doživotnu licencu',
+    'Disable and Cancel Licence' => 'Onemogučite i otkažite licencu',
+    'Licence Activated' => 'Licenca aktivirana',
+    'Licence Deactivated' => 'Licenca deaktivirana',
+    'Restrict users so that they cannot use SSH and access only their home directory.' => 'Ograničite prava korisnika tako da ne mogu koristiti SSH, odnosno da mogu koristiti samo svoju osobnu mapu.',
+    'Browse, copy, edit, view, and retrieve all of your web domain files using fully featured File Manager.' => 'Pretražujte, kopirajte, uređujte, pregledavajte i preuzimajte sve vaše datoteke s web domene koriteći se cjelovitim upraviteljem datoteka.',
+    'This is a commercial module, you would need to purchace license key to enable it.' => 'Ovo je komercijalni modul, trebate kupiti licenčni ključ da bi ga omogućili.',
+
+    'Minutes' => 'Minute',
+    'Hourly' => 'Svaki sat',
+    'Run Command' => 'Izvršite komandu',
+    'every month' => 'svaki mjesec',
+    'every odd month' => 'svaki neparni mjesec',
+    'every even month' => 'svaki parni mjesec',
+    'every day' => 'svaki dan',
+    'every odd day' => 'svaki neparni dan',
+    'every even day' => 'svaki parni dan',
+    'weekdays (5 days)' => 'radnim danima (5 dana)',
+    'weekend (2 days)' => 'vikendima (2 dana)',
+    'Monday' => 'ponedjeljak',
+    'Tuesday' => 'utorak',
+    'Wednesday' => 'srijeda',
+    'Thursday' => 'četvrtak',
+    'Friday' => 'petak',
+    'Saturday' => 'subota',
+    'Sunday' => 'nedjelja',
+    'every hour' => 'svaki sat',
+    'every two hours' => 'svaka dva sata',
+    'every minute' => 'svake minute',
+    'every two minutes' => 'svake dvije minute',
+    'every' => 'svakih',
+    'Generate' => 'Napravite',
+
+    'awstats' => 'AWStats',
+
+    'Hestia SSL' => 'SSL',
+    'SUBJECT' => 'PREDMET',
+    'ALIASES' => 'PSEUDONIM',
+    'NOT_BEFORE' => 'NE_PRIJE',
+    'NOT_AFTER' => 'NE_POSLIJE',
+    'SIGNATURE' => 'POTPIS',
+    'PUB_KEY' => 'JAVNI_KLJUČ',
+    'ISSUER' => 'IZDAVATELJ',
+
+    'Use server hostname' => 'Koristite ime poslužitelja',
+    'Use domain hostname' => 'Koristite ime domene',
+    'Use STARTTLS' => 'Koristite STARTTLS',
+    'Use SSL / TLS' => 'Koristite SSL / TLS',
+    'No encryption' => 'Bez šifriranja',
+    'Do not use encryption' => 'Nemojte koristiti šifriranje',
+    'maximum characters length, including prefix' => 'maksimalna dužina %s znakova (uključujući prefiks)',
+
+    'Email Credentials' => 'Slanje pristupnih podataka na adresu e-pošte',
+
+    '2 Factor Authentication' => 'Dvofaktorska provjera autentičnosti',
+    'Enable 2FA' => 'Omogućite dvofaktorsku provjeru autentičnosti',
+    'Please scan the code below in your 2FA application:' => 'Da bi završili postavljanje dvofaktorske provjera autentičnosti, očitajte QR kod<br />koristeći aplikaciju za potvrdu autentičnosti (poput <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2">Google Authenticator-a</a>):',
+    '2FA Reset Code:' => 'Šifra za oporavku računa:',
+
+    'Theme' => 'Izgled',
+
+    'Operating System' => 'Operacijski sustav',
+    'Please wait while php is installed or removed' => 'Dodavanje ili uklanjanje neke od inačica PHP-a trajat će oko 1 minute po inačici. Molimo pričekajte dok proces ne završi i nemojte osvježavati stanicu.',
+    'Avoid adding web domains on admin account' => 'Toplo preporučamo da napravite standarnog korisnika prije dodavanja web domena na poslužitelj zbog visokih privilegija koje ima admin račun te potencijalne sigurnosne rizike koji proizlaze iz toga.',
+    
+);

+ 8 - 5
web/reset/index.php

@@ -30,13 +30,16 @@ if ((!empty($_POST['user'])) && (empty($_POST['code']))) {
         } else {
             $mailtext = __('GREETINGS');
         }
-        $mailtext .= __('PASSWORD_RESET_REQUEST',$_SERVER['HTTP_HOST'],$user,$rkey,$_SERVER['HTTP_HOST'],$user,$rkey);
-        if (!empty($rkey)) send_email($to, $subject, $mailtext, $from);
+        if (in_array(str_replace(':'.$_SERVER['SERVER_PORT'],'.conf',$_SERVER['HTTP_HOST']), array_merge(scandir('/etc/nginx/conf.d'),scandir('/etc/nginx/conf.d/domains'),scandir('/etc/apache2/conf.d/domains'),scandir('/etc/apache2/conf.d')))){
+            $mailtext .= __('PASSWORD_RESET_REQUEST',$_SERVER['HTTP_HOST'],$user,$rkey,$_SERVER['HTTP_HOST'],$user,$rkey);
+            if (!empty($rkey)) send_email($to, $subject, $mailtext, $from);
+            header("Location: /reset/?action=code&user=".$_POST['user']);
+            exit;
+        } else {
+            $ERROR = "<a class=\"error\">".__('Invalid host domain')."</a>";
+        }
         unset($output);
     }
-
-    header("Location: /reset/?action=code&user=".$_POST['user']);
-    exit;
 }
 
 if ((!empty($_POST['user'])) && (!empty($_POST['code'])) && (!empty($_POST['password'])) ) {

+ 21 - 6
web/restart/system/index.php

@@ -11,13 +11,28 @@ if ((!isset($_GET['token'])) || ($_SESSION['token'] != $_GET['token'])) {
     exit();
 }
 
-if ($_SESSION['user'] == 'admin') {
-    if (!empty($_GET['hostname'])) {
-        exec (HESTIA_CMD."v-restart-system yes", $output, $return_var);
-        $_SESSION['error_msg'] = 'The system is going down for reboot NOW!';
+// If the stored reset token matches the current request one it means that we need 
+// to prevent the action because the browser automatically reloaded the page when 
+// the server turned on. This will prevent duplicate restarts.
+$reset_token_dir = '/var/tmp/';
+if (isset($_GET['system_reset_token']) && is_numeric($_GET['system_reset_token'])) {
+    clearstatcache();
+    $reset_token_file = $reset_token_dir . 'hst_reset_' . $_GET['system_reset_token'];
+    if (file_exists($reset_token_file)) {
+        unlink($reset_token_file);
+        sleep(5);
+        header('location: /list/server/');
+        exit();
+    }
+    if ($_SESSION['user'] == 'admin') {
+        if (!empty($_GET['hostname'])) {
+            touch($reset_token_file);
+            $_SESSION['error_msg'] = 'The system is going down for reboot NOW!';
+            exec(HESTIA_CMD . "v-restart-system yes", $output, $return_var);
+        }
+        unset($output);
     }
-    unset($output);
 }
 
 header("Location: /list/server/");
-exit;
+exit();

+ 0 - 4
web/src/app/WebApp/Installers/LaravelSetup.php

@@ -8,10 +8,6 @@ class LaravelSetup extends BaseSetup {
 
     protected $config = [
         'form' => [
-            'protocol' => [
-                'type' => 'select',
-                'options' => ['http','https'],
-            ],
         ],
         'database' => true,
         'resources' => [

+ 0 - 4
web/src/app/WebApp/Installers/SymfonySetup.php

@@ -8,10 +8,6 @@ class SymfonySetup extends BaseSetup {
 
     protected $config = [
         'form' => [
-            'protocol' => [
-                'type' => 'select',
-                'options' => ['http','https'],
-            ],
         ],
         'database' => true,
         'resources' => [

+ 22 - 10
web/templates/admin/add_cron.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/cron/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -357,13 +348,34 @@
             <input type="hidden" name="ok" value="Add" />
             <table class="data mode-add">
                 <tr class="data-add">
+                <td class="data-dotted">
+                        <table class="data-col1">
+                            <tr>
+                                <td>
+                                </td>
+                            </tr>
+                        </table>
+                    </td>
                     <td class="data-dotted">
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding Cron Job')?></span>
+                                    <span class="page-title"><?=__('Adding Cron Job')?></span>
                                  </td>
                             </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                          echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                          if (!empty($_SESSION['ok_msg'])) {
+                                            echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                          }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text input-label">
                                     <?php print __('Command');?>

+ 15 - 11
web/templates/admin/add_db.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/db/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -44,11 +35,24 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding database')?></span>
+                                    <span class="page-title"><?=__('Adding database')?></span>
                                 </td>
                             </tr>
                             <tr>
-                                <td class="step-top hint" style="color:#777;" >
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                            echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td class="step-top hint">
                                     <?php print __('Prefix will be automaticaly added to database name and database user',"<b>".$user."_</b>");?>
                                 </td>
                             </tr>

+ 14 - 10
web/templates/admin/add_dns.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/dns/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -45,7 +36,20 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding DNS Domain')?></span>
+                                    <span class="page-title"><?=__('Adding DNS Domain')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 24 - 10
web/templates/admin/add_dns_rec.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="javascript:window.history.back();"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -37,7 +28,20 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding DNS Record')?></span>
+                                    <span class="page-title"><?=__('Adding DNS Record')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                            echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>
@@ -116,6 +120,16 @@
                                     <input type="text" size="20" class="vst-input" name="v_priority" value="<?=htmlentities(trim($v_priority, "'"))?>">
                                 </td>
                             </tr>
+                            <tr>
+                                <td class="vst-text input-label">
+                                    <?php print __('TTL');?> <span class="optional">(<?php print __('optional');?>)</span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <input type="text" size="20" class="vst-input" name="v_ttl" value="<?=htmlentities(trim($v_ttl, "'"))?>">
+                                </td>
+                            </tr>                            
                         </table>
                         <table class="data-col2">
                         </table>

+ 14 - 10
web/templates/admin/add_firewall.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/firewall/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -45,7 +36,20 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding Firewall Rule')?></span>
+                                    <span class="page-title"><?=__('Adding Firewall Rule')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 24 - 20
web/templates/admin/add_firewall_banlist.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/firewall/banlist/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -45,7 +36,30 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding IP Address to Banlist')?></span>
+                                    <span class="page-title"><?=__('Adding IP Address to Banlist')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                          echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                          if (!empty($_SESSION['ok_msg'])) {
+                                            echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                          }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td class="vst-text input-label">
+                                    <?=__('IP address')?> <span class="optional">(<?=__('CIDR format is supported')?>)</span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <input type="text" size="20" class="vst-input" name="v_ip" value="<?=htmlentities(trim($v_ip, "'"))?>">
                                 </td>
                             </tr>
                             <tr>
@@ -66,16 +80,6 @@
                                     </select>
                                 </td>
                             </tr>
-                            <tr>
-                                <td class="vst-text input-label">
-                                    <?=__('IP address')?> <span class="optional">(<?=__('CIDR format is supported')?>)</span>
-                                </td>
-                            </tr>
-                            <tr>
-                                <td>
-                                    <input type="text" size="20" class="vst-input" name="v_ip" value="<?=htmlentities(trim($v_ip, "'"))?>">
-                                </td>
-                            </tr>
                         </table>
                         <table class="data-col2">
                             <tr>

+ 14 - 10
web/templates/admin/add_ip.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/ip/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -45,7 +36,20 @@
                         <table class="data-col2" width="600px">
                         <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding IP address')?></span>
+                                    <span class="page-title"><?=__('Adding IP address')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/add_mail.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/mail/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -44,7 +35,20 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding Mail Domain')?></span>
+                                    <span class="page-title"><?=__('Adding Mail Domain')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/add_mail_acc.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="javascript:window.history.back();"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -38,7 +29,20 @@
                     <table class="data-col2" width="440px">
                         <tr>
                             <td class="step-top">
-                                <span class="login-welcome"><?=__('Adding Mail Account')?></span>
+                                <span class="page-title"><?=__('Adding Mail Account')?></span>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td>
+                                <?php
+                                    if (!empty($_SESSION['error_msg'])) {
+                                        echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                    } else {
+                                        if (!empty($_SESSION['ok_msg'])) {
+                                            echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                        }
+                                    }
+                                ?>
                             </td>
                         </tr>
                         <tr>

+ 14 - 10
web/templates/admin/add_package.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/package/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -44,7 +35,20 @@
                         <table class="data-col2">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding Package')?></span>
+                                    <span class="page-title"><?=__('Adding Package')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/add_user.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/user/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -45,7 +36,20 @@
                         <table class="data-col2">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Adding User')?></span>
+                                    <span class="page-title"><?=__('Adding User')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 11
web/templates/admin/add_web.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/web/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -48,9 +39,21 @@
                     <table class="data-col2">
                         <tr>
                             <td class="step-top">
-                                <span class="login-welcome"><?=__('Add Web Domain')?></span>
+                                <span class="page-title"><?=__('Add Web Domain')?></span>
+                                <br>
+                                <span>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </span>
                                 <?php if ($user == 'admin') { ?>
-                                <span class="alert alert-info alert-with-icon">
+                                <span class="alert alert-danger alert-with-icon">
                                     <i class="fas fa-exclamation"></i>
                                     <?=__('Avoid adding web domains on admin account')?>
                                 </span>

+ 15 - 11
web/templates/admin/edit_backup_exclusions.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/backup/exclusions/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -47,9 +38,22 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing Backup Exclusions')?></span>
+                                    <span class="page-title"><?=__('Editing Backup Exclusions')?></span>
                                 </td>
-                            </tr>  
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text step-top">
                                     <?php print __('Web Domains');?>

+ 14 - 10
web/templates/admin/edit_cron.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/cron/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -367,7 +358,20 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing Cron Job')?></span>
+                                    <span class="page-title"><?=__('Editing Cron Job')?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 15 - 11
web/templates/admin/edit_db.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/db/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -49,9 +40,22 @@
                         <table class="data-col2" width="600px">
                              <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing Database')?></span>
+                                    <span class="page-title"><?=__('Editing Database')?></span>
                                 </td>
-                            </tr>  
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text step-top">
                                     <?php print __('Database');?>

+ 15 - 11
web/templates/admin/edit_dns.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/dns/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -47,9 +38,22 @@
                         <table class="data-col2">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing DNS Domain')?></span>
+                                    <span class="page-title"><?=__('Editing DNS Domain')?></span>
                                 </td>
-                            </tr>  
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text step-top">
                                     <?php print __('Domain');?>

+ 25 - 11
web/templates/admin/edit_dns_rec.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/dns/?domain=<?=htmlentities(trim($v_domain, "'"))?>&token=<?=$_SESSION['token']?>"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -47,9 +38,22 @@
                         <table class="data-col2">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing DNS Record')?></span>
+                                    <span class="page-title"><?=__('Editing DNS Record')?></span>
                                 </td>
-                            </tr>  
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text step-top">
                                     <?=__('Domain');?>
@@ -126,6 +130,16 @@
                                     <input type="text" size="20" class="vst-input" name="v_priority" value="<?=htmlentities(trim($v_priority, "'"))?>">
                                 </td>
                             </tr>
+                            <tr>
+                                <td class="vst-text input-label">
+                                    <?php print __('TTL');?> <span class="optional">(<?=__('optional');?>)</span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <input type="text" size="20" class="vst-input" name="v_ttl" value="<?=htmlentities(trim($v_ttl, "'"))?>">
+                                </td>
+                            </tr>                            
                             <tr>
                                 <td class="vst-text input-label">
                                     <?php print __('Record Number');?> <span class="optional">(<?=__('internal');?>)</span>

+ 15 - 11
web/templates/admin/edit_firewall.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/firewall/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -48,9 +39,22 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing Firewall Rule')?></span>
+                                    <span class="page-title"><?=__('Editing Firewall Rule')?></span>
                                 </td>
-                            </tr>  
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text step-top">
                                     <?php print __('Action'); ?>

+ 15 - 11
web/templates/admin/edit_ip.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/ip/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -48,9 +39,22 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing IP Address')?></span>
+                                    <span class="page-title"><?=__('Editing IP Address')?></span>
                                 </td>
-                            </tr>  
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text step-top">
                                     <?php print __('IP address'); ?>

+ 21 - 14
web/templates/admin/edit_mail.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/mail/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -47,9 +38,22 @@
                         <table class="data-col2">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing Mail Domain')?></span>
+                                    <span class="page-title"><?=__('Editing Mail Domain')?></span>
                                 </td>
-                            </tr>  
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text step-top">
                                     <?php print __('Domain');?>
@@ -96,14 +100,17 @@
                                     <table style="display:<?php if ($v_ssl == 'no' ) { echo 'none';} else {echo 'block';}?> ;" id="ssltable">
                                         <tr>
                                             <td class="input-label vst-text">
+                                                <label><input type="checkbox" size="20" class="vst-checkbox" name="v_letsencrypt" <?php if($v_letsencrypt == 'yes' || $v_letencrypt == 'on') echo "checked=yes" ?> onclick="App.Actions.MAIL.toggle_letsencrypt(this)"> <?php print __('Lets Encrypt Support');?></label>
+                                            </td>
+                                        </tr>
+                                        <tr>
+                                            <td>
                                                 <span class="alert alert-info alert-with-icon">
                                                     <i class="fas fa-exclamation"></i>
-                                                    <?=__("Let's Encrypt for mail needs a dns record for mail.$v_domain and $v_webmail_alias!")?><br/>
+                                                    <?=__("To enable Let's Encrypt SSL, ensure that DNS records exist for mail.$v_domain and $v_webmail_alias!")?><br/>
                                                 </span>
-                                                <label><input type="checkbox" size="20" class="vst-checkbox" name="v_letsencrypt" <?php if($v_letsencrypt == 'yes' || $v_letencrypt == 'on') echo "checked=yes" ?> onclick="App.Actions.MAIL.toggle_letsencrypt(this)"> <?php print __('Lets Encrypt Support');?></label>
                                             </td>
                                         </tr>
-                                      
                                         <tr>
                                             <td class="vst-text input-label">
                                                 <?php print __('SSL Certificate');?>

+ 15 - 11
web/templates/admin/edit_mail_acc.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/mail/?domain=<?=htmlentities(trim($v_domain, "'"))?>&token=<?=$_SESSION['token']?>"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -48,9 +39,22 @@
                       <table class="data-col2" width="440px">
                         <tr>
                             <td class="step-top">
-                                <span class="login-welcome"><?=__('Editing Mail Account')?></span>
+                                <span class="page-title"><?=__('Editing Mail Account')?></span>
                             </td>
-                        </tr>  
+                        </tr>
+                        <tr>
+                            <td>
+                                <?php
+                                    if (!empty($_SESSION['error_msg'])) {
+                                        echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                    } else {
+                                        if (!empty($_SESSION['ok_msg'])) {
+                                            echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                        }
+                                    }
+                                ?>
+                            </td>
+                        </tr>
                         <tr>
                             <td class="vst-text step-top input-label">
                                 <?php print __('Account');?>

+ 15 - 11
web/templates/admin/edit_package.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/package/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -42,9 +33,22 @@
                         <table class="data-col2">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Editing Package')?></span>
+                                    <span class="page-title"><?=__('Editing Package')?></span>
                                 </td>
-                            </tr>  
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
+                                </td>
+                            </tr>
                             <tr>
                                 <td class="vst-text step-top">
                                     <?php print __('Package Name');?>

+ 15 - 11
web/templates/admin/edit_server.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/server/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
           </div>
           <div class="l-unit-toolbar__buttonstrip float-right">
-              <?php
-              if (!empty($_SESSION['error_msg'])) {
-                echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-              } else {
-                if (!empty($_SESSION['ok_msg'])) {
-                  echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                }
-              }
-            ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
         </div>
@@ -46,10 +37,23 @@
                         <table class="data-col2" width="600px">
                           <tr>
                             <td class="step-top">
-                                <span class="login-welcome"><?=__('Configuring Server')?></span>
-                                <br /><br />
+                                <span class="page-title"><?=__('Configuring Server')?></span>
                             </td>
                           </tr>
+                        <tr>
+                            <td>
+                                <?php
+                                    if (!empty($_SESSION['error_msg'])) {
+                                        echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                    } else {
+                                        if (!empty($_SESSION['ok_msg'])) {
+                                            echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                        }
+                                    }
+                                ?>
+                                <br /><br />
+                            </td>
+                        </tr>
                           <tr>
                                 <td class="vst-text input-label step-top advanced-options">
                                     <a href="javascript:elementHideShow('basic');" class="vst-text">

+ 14 - 10
web/templates/admin/edit_server_bind9.html

@@ -4,15 +4,6 @@
           <a class="ui-button cancel" id="btn-back" href="/list/server/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
         </div>
         <div class="l-unit-toolbar__buttonstrip float-right">
-            <?php
-            if (!empty($_SESSION['error_msg'])) {
-              echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-            } else {
-              if (!empty($_SESSION['ok_msg'])) {
-                echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-              }
-            }
-          ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
       </div>
@@ -47,7 +38,20 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                    <span class="page-title"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/edit_server_dovecot.html

@@ -4,15 +4,6 @@
           <a class="ui-button cancel" id="btn-back" href="/list/server/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
         </div>
         <div class="l-unit-toolbar__buttonstrip float-right">
-                <?php
-                if (!empty($_SESSION['error_msg'])) {
-                  echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-                } else {
-                  if (!empty($_SESSION['ok_msg'])) {
-                    echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                  }
-                }
-              ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
         </div>
       </div>
@@ -47,7 +38,20 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                    <span class="page-title"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/edit_server_httpd.html

@@ -5,15 +5,6 @@
           <a href="/edit/server/php/" class="ui-button cancel" title="<?=__('Configure')?> PHP"><i class="fas fa-pencil-alt status-icon orange"></i> <?=__('Configure')?> PHP</a>
         </div>
         <div class="l-unit-toolbar__buttonstrip float-right">
-            <?php
-            if (!empty($_SESSION['error_msg'])) {
-              echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-            } else {
-              if (!empty($_SESSION['ok_msg'])) {
-                echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-              }
-            }
-          ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
           </div>
       </div>
@@ -48,8 +39,21 @@
                         <table class="data-col2" width="600px">
                           <tr class="step-top">
                             <td class="step-top">
-                              <span class="login-welcome"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                              <span class="page-title"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
                             </td>
+                          </tr>
+                          <tr>
+                              <td>
+                                  <?php
+                                      if (!empty($_SESSION['error_msg'])) {
+                                          echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                      } else {
+                                          if (!empty($_SESSION['ok_msg'])) {
+                                              echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                          }
+                                      }
+                                  ?>
+                              </td>
                           </tr>
                             <tr>
                                 <td class="vst-text step-top">

+ 14 - 10
web/templates/admin/edit_server_mysql.html

@@ -4,15 +4,6 @@
           <a class="ui-button cancel" id="btn-back" href="/list/server/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
         </div>
         <div class="l-unit-toolbar__buttonstrip float-right">
-                <?php
-                if (!empty($_SESSION['error_msg'])) {
-                  echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-                } else {
-                  if (!empty($_SESSION['ok_msg'])) {
-                    echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                  }
-                }
-              ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
         </div>
       </div>
@@ -47,7 +38,20 @@
                         <table class="data-col2" width="600px"  id="basic-options">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                    <span class="page-title"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/edit_server_nginx.html

@@ -5,15 +5,6 @@
             <a href="/edit/server/php/" class="ui-button cancel" title="<?=__('Configure')?> PHP"><i class="fas fa-pencil-alt status-icon orange"></i> <?=__('Configure')?> PHP</a>
         </div>
         <div class="l-unit-toolbar__buttonstrip float-right">
-                <?php
-                if (!empty($_SESSION['error_msg'])) {
-                  echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-                } else {
-                  if (!empty($_SESSION['ok_msg'])) {
-                    echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                  }
-                }
-              ?>
                 <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
         </div>
       </div>
@@ -48,7 +39,20 @@
                         <table class="data-col2" width="600px"  id="basic-options">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                    <span class="page-title"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/edit_server_pgsql.html

@@ -4,15 +4,6 @@
           <a class="ui-button cancel" id="btn-back" href="/list/server/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
         </div>
         <div class="l-unit-toolbar__buttonstrip float-right">
-            <?php
-            if (!empty($_SESSION['error_msg'])) {
-              echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-            } else {
-              if (!empty($_SESSION['ok_msg'])) {
-                echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-              }
-            }
-          ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
         </div>
       </div>
@@ -47,7 +38,20 @@
                         <table class="data-col2" width="600px">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                    <span class="page-title"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/edit_server_php.html

@@ -4,15 +4,6 @@
             <a class="ui-button cancel" id="btn-back" href="/list/server/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
         </div>
         <div class="l-unit-toolbar__buttonstrip float-right">
-                <?php
-                if (!empty($_SESSION['error_msg'])) {
-                  echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-                } else {
-                  if (!empty($_SESSION['ok_msg'])) {
-                    echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-                  }
-                }
-              ?>
             <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
         </div>
       </div>
@@ -47,7 +38,20 @@
                         <table class="data-col2" width="600px"  id="basic-options">
                             <tr>
                                 <td class="step-top">
-                                    <span class="login-welcome"><?=__('Configuring Server')?>: PHP</span>
+                                    <span class="page-title"><?=__('Configuring Server')?>: PHP</span>
+                                </td>
+                            </tr>
+                            <tr>
+                                <td>
+                                    <?php
+                                        if (!empty($_SESSION['error_msg'])) {
+                                            echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                        } else {
+                                            if (!empty($_SESSION['ok_msg'])) {
+                                                echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                            }
+                                        }
+                                    ?>
                                 </td>
                             </tr>
                             <tr>

+ 14 - 10
web/templates/admin/edit_server_service.html

@@ -4,15 +4,6 @@
           <a class="ui-button cancel" id="btn-back" href="/list/server/"><i class="fas fa-arrow-left status-icon blue"></i> <?=__('Back')?></a>
         </div>
         <div class="l-unit-toolbar__buttonstrip float-right">
-            <?php
-            if (!empty($_SESSION['error_msg'])) {
-              echo "<span class=\"vst-error\"> → ".htmlentities($_SESSION['error_msg'])."</span>";
-            } else {
-              if (!empty($_SESSION['ok_msg'])) {
-                echo "<span class=\"vst-ok\"> → ".$_SESSION['ok_msg']."</span>";
-              }
-            }
-          ?>
           <a href="#" class="ui-button" title="<?=__('Save')?>" data-action="submit" data-id="vstobjects"><i class="fas fa-save status-icon purple"></i> <?=__('Save')?></a>
         </div>
       </div>
@@ -47,8 +38,21 @@
                         <table class="data-col2" width="600px">
                           <tr>
                             <td class="step-top">
-                                <span class="login-welcome"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
+                                <span class="page-title"><?=__('Configuring Server')?>: <?php print $v_service_name ?></span>
                             </td>
+                          </tr>
+                          <tr>
+                              <td>
+                                  <?php
+                                      if (!empty($_SESSION['error_msg'])) {
+                                          echo "<span class=\"vst-error\"> <i class=\"fas fa-exclamation-circle status-icon red\"></i> ".htmlentities($_SESSION['error_msg'])."</span>";
+                                      } else {
+                                          if (!empty($_SESSION['ok_msg'])) {
+                                              echo "<span class=\"vst-ok\"> <i class=\"fas fa-check-circle status-icon green\"></i> ".$_SESSION['ok_msg']."</span>";
+                                          }
+                                      }
+                                  ?>
+                              </td>
                           </tr>
                             <tr>
                                 <td class="vst-text step-top">

Некоторые файлы не были показаны из-за большого количества измененных файлов