Cheap VPS & Xen Server

Residential Proxy Network - Hourly & Monthly Packages

Extending Perfect Server – Debian Squeeze [ISPConfig 3]


The following tutorial will extend the “Perfect Server…. ” for ISPConfig 3 with BIND & Courier installed in Debian Squeeze. It explains how to change default ports (ssh, ispconfig, webmin), how to install some useful applications (webmin, roundcube, atop, htop, multitail, tiger etc), how to update awstats periodically (more than once a day) or whenever you want, how to create clients’ data backups (periodically) accessible under their folder and finally it explains how to tweak your system for performance (mysqltuner, tuning-primer) or security (custom firewall rules, (D)Dos Deflate, fail2ban modified).

This tutorial works for me, I corrected the mistakes mentioned in comments but I can not guarantee that it will work for you.

In specific this tutorial explains how to:

  1. install Webmin and change it’s port to 50000
  2. change the default port for ISPConfig from 8080 to 50443
  3. install Roundcube so as all users can access it over SSL (port 50443 — as ISPConfig ) under /webmail
  4. extend fail2ban (for webmin, roundcube, ssh) and  apply a small patch
  5. install multitail and use a simple command to see all useful logs
  6. change the port 22 for SSH to 50022
  7. access phpmyadmin over SSL (port 50443 — as ISPConfig ) under a different url than the default (e.g. /mydomaindb)
  8. install some useful apps/extensions to you server (htop, php-apc, iptraf, logwatch etc)
  9. update awstats manually or automatic whenever you want
  10. impove mysql settings using scripts like mysqltuner or tuning-primer that suggest which settings to tweak in your mysql installation
  11. harden you system (simple steps), by blocking specific –insistent– IPs or networks, or/and by using custom rules to protect your server against simple ddos attacks, in companion with (D)Dos Deflate.
  12. create daily backup of clients’ web folders and their databases in their folders, so as they will be able to download them

To follow this tutorial you have to read and apply the following:

– The Perfect Server – Debian Squeeze (Debian 6.0) With BIND & Courier [ISPConfig 3]

– If you want to access ISPconfig Panel and webmail through SSL I also assume that you followed the chapter 6.2 Enabling SSL For The ISPConfig Web Interface of The ISPConfig 3 manual or this post (This is only needed if you want to access the control panel AND the webmail interface through ssl on port 8080).

A note here: To NOT have problems after a future update do:

cp /etc/apache2/ssl/ispserver.crt /usr/local/ispconfig/interface/ssl/ispserver.crt
cp /etc/apache2/ssl/ispserver.key  /usr/local/ispconfig/interface/ssl/ispserver.key

and edit /etc/apache2/sites-enabled/000-ispconfig.vhost, removing the lines that you pasted following the manual, and uncommenting the default lines for SSL.

nano /etc/apache2/sites-enabled/000-ispconfig.vhost

The contents must look like:

[...]

  # SSL Configuration

  SSLEngine On

  SSLCertificateFile /usr/local/ispconfig/interface/ssl/ispserver.crt
  SSLCertificateKeyFile /usr/local/ispconfig/interface/ssl/ispserver.key
[...]

– If you followed the above, then I finally assume that you read the workaround about suExec and ISPConfig 3 in this post.

This how to, is a (major) updated version of  Easy RoundCube (Over SSL) And Webmin With fail2ban For ISPConfig 3 On Debian Squeeze with a lot more additions.

Before you proceed make sure that your server is functional, and you are satisfied with it.  If you follow this tutorial you will make a lot of changes, and this (by it’s own) needs a lot of debugging in case of errors!

 

1. WEBMIN

Please have in mind that if you install webmin you MUST be very careful in using it. You should not use webmin for editing settings of critical parts of ISPConfig (apache, postfix, imap, pop3, dns). Use it only in emergency cases or when you need to do things that DON’T interfere with ISPConfig (e.g. firewall, bootscripts, cron e.t.c)

To install webmin we must first install some dependencies:

apt-get install libapt-pkg-perl libauthen-pam-perl libio-pty-perl apt-show-versions

Download the latest webmin from http://www.webmin.com/download.html:

cd /tmp
wget http://prdownloads.sourceforge.net/webadmin/webmin_1.530_all.deb

and install it:

dpkg -i webmin_1.530_all.deb

Before changing a port to something else than the default, DON’T forget to add the port to your firewall. If you are using the defaults of ISPConfig, go to System -> Firewall and add the port you want (In this manual we will use 50000 for Webmin, 50443 for ISPConfig, 50022 for ssh). Save and DON’T remove old ports (8080, 10000, 22) until you are absolutely sure that the new ports are working.

To change the default port of webmin, edit the file /etc/webmin/miniserv.conf:

nano /etc/webmin/miniserv.conf

and change the Port=10000 and listen=10000 to Port=50000 and listen=50000. Restart webmin:

/etc/init.d/webmin restart

Visit https://www.example.com:50000 to install updates through webmin interface. You will have to accept the security warning, as the certificate of webmin is custom signed.

 

2. Set a different port for ISPConfig Control Panel

Before changing a port to something else than the default, DON’T forget to add the port to your firewall. If you are using the defaults of ISPConfig, go to System -> Firewall and add the port you want (In this manual we will use 50000 for Webmin, 50443 for ISPConfig, 50022 for ssh). Save and DON’T remove old ports (8080, 10000, 22) until you are absolutely sure that the new ports are working.

To change the default port of ISPConfig Control Panel (8080), to a different one (e.g. 50443):

nano /etc/apache2/sites-enabled/000-ispconfig.vhost

and make sure that all references to 8080 are changed to 50443. Mine looks like this (ONLY the first lines are showing):

[...]
Listen 50443
NameVirtualHost *:50443

<VirtualHost _default_:50443>
[...]

Restart apache and access the control panel at https://www.example.com:50443:

/etc/init.d/apache2 restart

3. ROUNDCUBE

Following the above instructions you can install roundcube via apt-get. However following another logic (if you have the time and the courage) you can install roundcube in it’s own subdomain, manually.

In “Perfect Server ….” you usually install Squirrelmai. However if you don’t want it you can remove it:

apt-get remove squirrelmail

and delete the /etc/apache2/conf.d/squirrelmail.conf:

rm /etc/apache2/conf.d/squirrelmail.conf

OR if you want it edit the /etc/apache2/conf.d/squirrelmail.conf and change the alias to something like ‘webmail1’.

Install roundcube. (You MUST have the mysql administrator’s password before you proceed — Let dbconfig-common configure the database. You will be asked some questions about the password of the db administrator and the password of the new user that will be created for roundcube. Answer those questions and continue:

apt-get install roundcube roundcube-mysql

Examle answers:
“Configure database for roundcube with dbconfig-common?” …. Answer Yes
“Database type to be used by roundcube: …Answer mysql
“Password of the database’s administrative user:” … Answer your-admin-DB-password
“MySQL application password for roundcube:” … Answer the-password-you-want-to-give-to-the-roundcube-user
“Password confirmation:”… Answer the-password-you-want-to-give-to-the-roundcube-user

If something goes wrong you can always run:

dpkg-reconfigure roundcube-core

For more information, please see this post.

For everyone to be able to access his webmail (under his domain name) you have to create or edit the file /etc/apache2/conf.d/roundcube so as to set the alias to ‘webmail’. If you want SSL you should include the last two directives (IfModule mod_rewrite.c) to have apache ALWAYS redirect to your SSL installation of ISPConfig.

nano /etc/apache2/conf.d/roundcube

# Those aliases do not work properly with several hosts on your apache server
# Uncomment them to use it or adapt them to your configuration
#    Alias /roundcube/program/js/tiny_mce/ /usr/share/tinymce/www/
    Alias /roundcube /var/lib/roundcube
    Alias /webmail /var/lib/roundcube

# Access to tinymce files
<Directory "/usr/share/tinymce/www/">
      Options Indexes MultiViews FollowSymLinks
      AllowOverride None
      Order allow,deny
      allow from all
</Directory>

<Directory /var/lib/roundcube/>
  Options +FollowSymLinks
  # This is needed to parse /var/lib/roundcube/.htaccess. See its
  # content before setting AllowOverride to None.
  AllowOverride All
  order allow,deny
  allow from all
</Directory>

# Protecting basic directories:
<Directory /var/lib/roundcube/config>
        Options -FollowSymLinks
        AllowOverride None
</Directory>

<Directory /var/lib/roundcube/temp>
        Options -FollowSymLinks
        AllowOverride None
        Order allow,deny
        Deny from all
</Directory>

<Directory /var/lib/roundcube/logs>
        Options -FollowSymLinks
        AllowOverride None
        Order allow,deny
        Deny from all
</Directory>

<IfModule mod_rewrite.c>
  <IfModule mod_ssl.c>
    <Location /webmail>
      RewriteEngine on
      RewriteCond %{HTTPS} !^on$ [NC]
      RewriteRule . https://%{HTTP_HOST}:50443%{REQUEST_URI}  [L]
    </Location>
  </IfModule>
</IfModule>

<IfModule mod_rewrite.c>
  <IfModule mod_ssl.c>
    <Location /roundcube>
      RewriteEngine on
      RewriteCond %{HTTPS} !^on$ [NC]
      RewriteRule . https://%{HTTP_HOST}:50443%{REQUEST_URI}  [L]
    </Location>
  </IfModule>
</IfModule>


# For ISPConfig 3.0.5.1 and above, also, add the following

<IfModule mod_php5.c>
AddType application/x-httpd-php .php
php_flag magic_quotes_gpc Off
php_flag track_vars On
php_admin_flag allow_url_fopen Off
php_value include_path .:/usr/share/php:/usr/share/pear
php_admin_value upload_tmp_dir /var/lib/roundcube/temp
php_admin_value open_basedir /usr/share/php:/usr/lib/roundcube:/etc/roundcube:/usr/share/roundcube:/var/lib/roundcube:/var/log/roundcube
php_flag register_globals off
</IfModule>

Edit /var/lib/roundcube/config/main.inc.php:

nano /var/lib/roundcube/config/main.inc.php

and SET some variables in the file (if this is the first time you edit the file the lines are 60 and 66):

auto_create_user = TRUE;
$rcmail_config['default_host'] = 'localhost';

If you will install the following plugin (the logger that helps fail2ban) you have to extend the list of plugins in the same file. If the only plugin is the one that will be istalled right afterward you have to edit the line (42) as below:

$rcmail_config['plugins'] = array('fail2ban');

Install the roundcube logger plugin from http://mattrude.com/projects/roundcube-fail2ban-plugin/.

Basically you have to download the file (fail2ban.php) and paste it in the fail2ban folder in the plugins folder of roundcube. Finally you must have this file:  /usr/share/roundcube/plugins/fail2ban/fail2ban.php. Execute:

cd /usr/share/roundcube/plugins/
wget –no-check-certificate http://github.com/downloads/mattrude/rc-plugin-fail2ban/roundcube-fail2ban-plugin.1.0.tgz
tar -xvzf roundcube-fail2ban-plugin.1.0.tgz
touch /var/log/roundcube/userlogins
chown www-data:www-data /var/log/roundcube/userlogins

This plugin will update the log file with each failed login attempt: /var/log/roundcube/userlogins

Don’t forget to edit the link for the webmail in ISPConfig (System -> Interface Config -> (tab) Mail) and set it to /webmail. Lastly, restart apache.

/etc/init.d/apache2 restart

You can now access webmail at http://www.example.com/webmail

 

4. FAIL2BAN

Extend the jail.local file that falko suggests in The Perfect Server – Debian Squeeze (Debian 6.0) With BIND & Courier [ISPConfig 3]: /etc/fail2ban/jail.local

nano /etc/fail2ban/jail.local

You have to append or edit the following:

[roundcube]
enabled  = true
port     = http,50443
filter   = roundcube
logpath  = /var/log/roundcube/userlogins
maxretry = 5

[webmin-auth]
enabled = true
port    = 50000
filter  = webmin-auth
logpath  = /var/log/auth.log
maxretry = 3 

[ssh]
enabled = true
port    = 50022
filter  = sshd
logpath  = /var/log/auth.log
maxretry = 6

The 50443 port in roundcube is only needed if you enabled the redirection to https (look in the beggining of this tutorial).
The 50000 port in webmin-auth is the changed port (look in the beggining of this tutorial).
The 50022 port in ssh is the changed port (look in the following sections of this tutorial).

Last (and very important) don’t forget to create the roundcube.conf file /etc/fail2ban/filter.d/roundcube.conf.

nano /etc/fail2ban/filter.d/roundcube.conf

with the following contents:

[Definition]
failregex = FAILED login for .*. from <host>
ignoreregex =

Lucky us the webmin-auth and the ssh filters are already done for us by the fail2ban itself. Restart fail2ban:

/etc/init.d/fail2ban restart

If someone adds a lot of jails in fail2ban, then some of them may not start (errors in /var/log/fail2ban.log but not in the output !!!). See it by yourself by executing:

iptables -L -n

Unfortunately the solution is a bit of a hack… but at least it is a solution:

In the file /usr/bin/fail2ban-client at line 145 you have to insert time.sleep(0.1) or time.sleep(0.05):

nano /usr/bin/fail2ban-client

So before the change the file looks like this:

[...]
 def __processCmd(self, cmd, showRet = True):
                beautifier = Beautifier()
                for c in cmd:
                        beautifier.setInputCmd(c)
                        try:
[...]

And afterward the file looks like this:

[...]
 def __processCmd(self, cmd, showRet = True):
                beautifier = Beautifier()
                for c in cmd:
                        time.sleep(0.05)
                        beautifier.setInputCmd(c)
                        try:
[...]

Restart again fail2ban:

/etc/init.d/fail2ban restart

You can check that all jails are active with the command:

iptables -L -n

5. multitail

In Debian install multitail via apt:

apt-get install multitail

Create the folder /root/scripts (if you didn’t do it before) and insert the command that will allow you to see multiple file simultaneously:

mkdir /root/scripts
cd /root/scripts
nano mytail

Paste the lines:

#!/bin/bash
multitail -ci yellow -e "ailed" -n 1000 /var/log/auth.log  \
-ci red -e "Ban" -n 1000 -I /var/log/fail2ban.log \
-ci red -e "fw" -n 1000 -I /var/log/messages \
-ci green -e "Unban" -n 1000 -I /var/log/messages \
-ci blue -e "fail" -n 1000 -I /var/log/syslog

Save, exit and make it executable for root:

chmod 700 /root/scripts/mytail

Execute it (to see the output) with the command (press “q” for exit):

/root/scripts/mytail

 

6. SSH over 50022 port

Before changing a port to something else than the default, DON’T forget to add the port to your firewall. If you are using the defaults of ISPConfig, go to System -> Firewall and add the port you want (In this manual we will use 50000 for Webmin, 50443 for ISPConfig, 50022 for ssh). Save and DON’T remove old ports (8080, 10000, 22) until you are absolutely sure that the new ports are working.

In debian you install ssh server (if you don’t have it already) with apt-get. After that edit the config file (/etc/ssh/sshd_config)

apt-get install ssh openssh-server openssh-client
nano /etc/ssh/sshd_config

Leave “Port 22” and ADD “Port 50022” right after “Port 22”. Save, exit and restart ssh:

/etc/init.d/ssh restart

CAUTION: You have to relogin over ssh to port 50022. After the above modification even sftp will be accessible over the port 50022. If you remove the port 22, then you can access ssh AND sftp ONLY over the port 50022.

If you succeed to login in using the port 50022 (with the following command) you can remove the line “Port 22” from /etc/ssh/sshd_config:

ssh -p 50022 root@server1.example.com

If you did the above then you have to override ssh jail and change the port of the fail2ban SSH jail (from ssh to 50022) in /etc/fail2ban/jail.local.

(If you followed the tutorial from the beginning, you have already done this in the Fail2ban section.)

 

7. phpmyadmin under different url (+ ssl tip)

To access phpmyadmin over ssl under mydomaindb, (or another unique name) you can apply the same tip as with roundcube (for the ssl part). As for the new url you have to edit the /etc/apache2/conf.d/phpmyadmin.conf , change the Alias from “/phpmyadmin” to “/mydomaindb” and ensure that you have the following lines in it (Notice the last lines from <IfModule mod_rewrite.c> to…. </IfModule> which are used to redirect to SSL):

# phpMyAdmin default Apache configuration

Alias /mydomaindb /usr/share/phpmyadmin

<Directory /usr/share/phpmyadmin>
        Options FollowSymLinks
        DirectoryIndex index.php

        <IfModule mod_php5.c>
                AddType application/x-httpd-php .php

                php_flag magic_quotes_gpc Off
                php_flag track_vars On
                php_flag register_globals Off
                php_value include_path .
        </IfModule>

</Directory>

# Authorize for setup
<Directory /usr/share/phpmyadmin/setup>
    <IfModule mod_authn_file.c>
    AuthType Basic
    AuthName "phpMyAdmin Setup"
    AuthUserFile /etc/phpmyadmin/htpasswd.setup
    </IfModule>
    Require valid-user
</Directory>

# Disallow web access to directories that don't need it
<Directory /usr/share/phpmyadmin/libraries>
    Order Deny,Allow
    Deny from All
</Directory>
<Directory /usr/share/phpmyadmin/setup/lib>
    Order Deny,Allow
    Deny from All
</Directory>

<IfModule mod_rewrite.c>
  <IfModule mod_ssl.c>
    <Location /mydomaindb>
      RewriteEngine on
      RewriteCond %{HTTPS} !^on$ [NC]
      RewriteRule . https://%{HTTP_HOST}:50443%{REQUEST_URI}  [L]
    </Location>
  </IfModule>
</IfModule>

After this, restart Apache

/etc/init.d/apache2 restart

Don’t forget to change the link of phpmyadmin in ISPConfig 3 GUI (Interface Config -> Sites (tab).

 

8. Install a php accelarator (apc) and other useful apps.

In this section we will install apc (php accelarator), which is developed by the guys who develop php and some apps (htop, iptraf, logwatch, tiger).

apt-get install php-apc htop iptraf logwatch tiger

Edit /etc/php5/conf.d/apc.ini, so as to increase the memory cache:

nano /etc/php5/conf.d/apc.ini

And append the following line:

apc.shm_size=128

Finally restart Apache:

/etc/init.d/apache2 restart

With htop you can see system info in a better way than top, with iptraf you can see real time statistics for your connection, with logwatch you can have your system mail you a summary of log files and with tiger you can have yourself mailed with a periodically report of your system’s security vulnerabilities (if any exists).

As a lot of scripts/apps send a lot of mails to user root, you can alias root’s mail, to a more ‘real’ email address. So, after you set up a ‘real’ mail for your example.com domain, you can edit the aliases and add an alias to root user:

nano /etc/aliases

and change the line

root:root

to something like

root:server1@example.com

After this execute:

newaliases

If you want to install Drupal (or other cms) you will propably need uploadprogress and json. To accomplish their installation, do:

apt-get install php5-dev php-services-json
pecl install uploadprogress
touch /etc/php5/apache2/conf.d/uploadprogress.ini
nano /etc/php5/apache2/conf.d/uploadprogress.ini

And append the following line:

extension=uploadprogress.so

Finally restart Apache:

/etc/init.d/apache2 restart

9. Anytime stats with awstats

In this section, you can apply a modification that will allow you to update the awstats anytime you want, or (by using cron) in more frequent time intervals. Before we proceed we must change the default log format for awstats. In Debian Squeeze the default format is 4, but we need the 1. So either you edit the file /etc/awstats/awstats.conf or the file /etc/awstats/awstats.conf.local . I prefer the second one, because it will let me keep up with updates:

nano /etc/awstats/awstats.conf.local

and append the line: LogFormat=1

After that, the file should look like:

# You can overrides config directives here.
# This is particularly useful for users with several configs for
# different virtual servers, who want to reuse common parameters.
# Also, this file is not updated with each new upstream release.
LogFormat=1

Now we have to copy the default daily cron of ISPConfig and edit it … actually we have to edit it A LOT (new file name : mycron.php ). Basically we have to cutoff a lot of lines and only keep some of them. Do:

cp /usr/local/ispconfig/server/cron_daily.php /root/scripts/mycron.php
chmod 700 /root/scripts/mycron.php
nano /root/scripts/mycron.php

and paste all the following lines:

<?php

/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


require('/usr/local/ispconfig/server/lib/config.inc.php');
require('/usr/local/ispconfig/server/lib/app.inc.php');
set_time_limit(0);

// make sure server_id is always an int
$conf['server_id'] = intval($conf['server_id']);
// Load required base-classes
$app->uses('ini_parser,file,services,getconf');

#######################################################################################################
// Create awstats statistics
#######################################################################################################

$sql = "SELECT domain_id, domain, document_root FROM web_domain WHERE stats_type = 'awstats' AND server_id = ".$conf['server_id'];
$records = $app->db->queryAllRecords($sql);
$web_config = $app->getconf->get_server_config($conf['server_id'], 'web');
foreach($records as $rec) {
        $logfile = escapeshellcmd($rec['document_root'].'/log/access.log');
        $domain = escapeshellcmd($rec['domain']);
        $statsdir = escapeshellcmd($rec['document_root'].'/web/stats');
        $awstats_pl = $web_config['awstats_pl'];
        $awstats_buildstaticpages_pl = $web_config['awstats_buildstaticpages_pl'];
        $awstats_conf_dir = $web_config['awstats_conf_dir'];
        $awstats_website_conf_file = $web_config['awstats_conf_dir'].'/awstats.'.$domain.'.conf';
        if(is_file($awstats_website_conf_file)) unlink($awstats_website_conf_file);
        if(!is_file($awstats_website_conf_file)) {
                $awstats_conf_file_content = 'Include "'.$awstats_conf_dir.'/awstats.conf"
                LogFile="/var/log/ispconfig/httpd/'.$domain.'/access.log"
                SiteDomain="'.$domain.'"
                HostAliases="www.'.$domain.' localhost 127.0.0.1"';
                file_put_contents($awstats_website_conf_file,$awstats_conf_file_content);
        }
 if(!@is_dir($statsdir)) mkdir($statsdir);

        // awstats_buildstaticpages.pl -update -config=mydomain.com -lang=en -dir=/var/www/domain.com/web/stats -awstatsprog=/path/to/awstats.pl
        $command = "$awstats_buildstaticpages_pl -update -config='$domain' -lang=en -dir='$statsdir' -awstatsprog='$awstats_pl'";

        if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) {
                exec($command);
                rename($rec['document_root'].'/web/stats/awstats.'.$domain.'.html',$rec['document_root'].'/web/stats/index.html');
                $app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG);
        } else {
                $app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN);
        }

}


die("finished.\n");
?>

This script is a cutoff  of the ISPConfig’s default cron file and applies up to ISPConfi 3.0.3. It’s made by Till Brehm , and we edited it, so as the update procedure DOES NOT modify any system (or log) file whenever we call it. In simple words, the script reads the access.log file of each domain and DOES NOT do any rotation or any modification, except that it reproduces the html files for awstats. Keep in mind that the default ISPConfig cron job, will run as usual at 00:30 and it will simply append to the stats db and recreate the html files.

In the above script you can change the language produced by awstats if you simply change the letters after “lang=” with those that represent your country.

For ISPConfig 3.0.4 please use the following code:

<?php

/*
Copyright (c) 2007, Till Brehm, projektfarm Gmbh
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of ISPConfig nor the names of its contributors
      may be used to endorse or promote products derived from this software without
      specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

require('/usr/local/ispconfig/server/lib/config.inc.php');
require('/usr/local/ispconfig/server/lib/app.inc.php');

set_time_limit(0);

// make sure server_id is always an int
$conf['server_id'] = intval($conf['server_id']);


// Load required base-classes
$app->uses('ini_parser,file,services,getconf');


#######################################################################################################
// Create awstats statistics
#######################################################################################################

$sql = "SELECT domain_id, domain, document_root FROM web_domain WHERE stats_type = 'awstats' AND server_id = ".$conf['server_id'];
$records = $app->db->queryAllRecords($sql);

$web_config = $app->getconf->get_server_config($conf['server_id'], 'web');


foreach($records as $rec) {
        $logfile = escapeshellcmd($rec['document_root'].'/log/access.log');
        $domain = escapeshellcmd($rec['domain']);
        $statsdir = escapeshellcmd($rec['document_root'].'/web/stats');
        $awstats_pl = $web_config['awstats_pl'];
        $awstats_buildstaticpages_pl = $web_config['awstats_buildstaticpages_pl'];

        $awstats_conf_dir = $web_config['awstats_conf_dir'];
        $awstats_website_conf_file = $web_config['awstats_conf_dir'].'/awstats.'.$domain.'.conf';

        if(is_file($awstats_website_conf_file)) unlink($awstats_website_conf_file);

        $sql = "SELECT domain FROM web_domain WHERE (type = 'alias' OR AND type = 'subdomain') server_id = ".$conf['server_id'];
        $aliases = $app->db->queryAllRecords($sql);
        $aliasdomain = '';

        if(is_array($aliases)) {
                foreach ($aliases as $alias) {
                        $aliasdomain.= ' '.$alias['domain']. ' www.'.$alias['domain'];
                }
        }

        if(!is_file($awstats_website_conf_file)) {
                $awstats_conf_file_content = 'Include "'.$awstats_conf_dir.'/awstats.conf"
LogFile="/var/log/ispconfig/httpd/'.$domain.'/access.log"
SiteDomain="'.$domain.'"
HostAliases="www.'.$domain.' localhost 127.0.0.1"'.$aliasdomain;
                file_put_contents($awstats_website_conf_file,$awstats_conf_file_content);
        }

if(!@is_dir($statsdir)) mkdir($statsdir);


####################################################################################
######################### RECREATE STATS ###########################################
$redo = 0; // set this to 1 if you want to recreate statistics for a specific month
$REMONTH = 11; // select the month
$REYEAR = 2011; //select the year
$LANG = 'gr'; // set your language
// After setting the above rerun this script 
// e.g
// php /path/to
####################################################################################
####################################################################################
if ( $redo == 1 ) {

$awmonth = $REMONTH;
$awyear = $REYEAR;
        $statsdirold = $statsdir."/".$awyear."-".$awmonth."/";
        if (!is_dir($statsdirold)) {
                mkdir($statsdirold);
        }
        $command = "$awstats_buildstaticpages_pl -month='$awmonth' -year='$awyear' -update -config='$domain' -lang='$LANG' -dir='$statsdirold' -awstatsprog='$awstats_pl'";

        if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) {
               exec($command);
               rename($statsdirold.'awstats.'.$domain.'.html',$statsdirold.'awsindex.html');
               $app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG);
        } else {
               $app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN);
        }
}
else {
  if (date("d") == 1) {

      $awmonth = date("n")-1;
      $awyear = date("Y");


        if (date("n") == 0) {
                $awyear = date("Y")-1;
               $awmonth = "12";
        }

        $statsdirold = $statsdir."/".$awyear."-".$awmonth."/";

        if (!is_dir($statsdirold)) {
                mkdir($statsdirold);
                $command = "$awstats_buildstaticpages_pl -month='$awmonth' -year='$awyear' -update -config='$domain' -lang='$LANG' -dir='$statsdirold' -awstatsprog='$awstats_pl'";

                if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) {
                        exec($command);
                        rename($statsdirold.'awstats.'.$domain.'.html',$statsdirold.'awsindex.html');
                        $app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG);
                } else {
                        $app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN);
                }

        }
  }

// ispconfig, on the second day of month, overwrites the stats created before by this script
// to overwrite ispconfig default execution on 2nd day of month we must execute the below code
  if (date("d") == 2) {
      $awmonth = date("n")-1;
      $awyear = date("Y");
        if (date("n") == 0) {
                $awyear = date("Y")-1;
               $awmonth = "12";
        } 
        $statsdirold = $statsdir."/".$awyear."-".$awmonth."/";
                $command = "$awstats_buildstaticpages_pl -month='$awmonth' -year='$awyear' -update -config='$domain' -lang='$LANG' -dir='$statsdirold' -awstatsprog='$awstats_pl'";
                if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) {
                        exec($command);
                        rename($statsdirold.'awstats.'.$domain.'.html',$statsdirold.'awsindex.html');
                        $app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG);
                } else {
                        $app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN);
                }

  }
// end of overwrite
// unfortunately the above will execute many times (as many as you run this script by cron)


       $awmonth = date("n");
       $awyear = date("Y");
       $command = "$awstats_buildstaticpages_pl -month='$awmonth' -year='$awyear' -update -config='$domain' -lang='$LANG' -dir='$statsdir' -awstatsprog='$awstats_pl'";

       if($awstats_pl != '' && $awstats_buildstaticpages_pl != '' && fileowner($awstats_pl) == 0 && fileowner($awstats_buildstaticpages_pl) == 0) {
                exec($command);
                if(is_file($rec['document_root'].'/web/stats/index.html')) unlink($rec['document_root'].'/web/stats/index.html');
                rename($rec['document_root'].'/web/stats/awstats.'.$domain.'.html',$rec['document_root'].'/web/stats/awsindex.html');
                if(!is_file($rec['document_root']."/web/stats/index.php")) copy("/usr/local/ispconfig/server/conf/awstats_index.php.master",$rec['document_root']."/web/stats/index.php");

                $app->log('Created awstats statistics with command: '.$command,LOGLEVEL_DEBUG);
        } else {
                $app->log("No awstats statistics created. Either $awstats_pl or $awstats_buildstaticpages_pl is not owned by root user.",LOGLEVEL_WARN);
        }

} //end redo
} // end foreach


die("finished.\n");
?>

Keep in mind (in version > =3.0.4) that you will not see any stats the first day of every month (as with the normal script). If you want to see the udated stats after the first execution the first day of the month you have to read this post :  http://www.Kreationnext.com/forums/showthread.php?p=270816#post270816

To execute the script every 4 hours, first create the file /root/scripts/mycron.sh, make it executable and then add it to the cronjob list:

touch /root/scripts/mycron.sh
chmod 700 /root/scripts/mycron.sh
nano /root/scripts/mycron.sh

and paste the following:

#!/bin/sh
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/X11R6/bin
/usr/bin/php /root/scripts/mycron.php

Add the cronjob:

crontab -e

Append the following line, save and exit:

45 0,4,8,12,16,20 * * * /root/scripts/mycron.sh

You can also initiate the stats creation anytime by:

/root/scripts/mycron.sh

You can recreate stats of previously months (as long as there are data in /var/lib/awstats or /var/cache/awstats). Read the comments in the script, set redo=1 and execute the script. More at http://www.Kreationnext.com/forums/showthread.php?t=51731

10. mysql tuning

Download tuning-primer.sh and mysqltuner.pl. These will help you to improve mysql’s configuration file.

cd /root/scripts
wget http://www.day32.com/MySQL/tuning-primer.sh
wget http://mysqltuner.com/mysqltuner.pl
chmod 700 tuning-primer.sh mysqltuner.pl

To execute them:

perl /root/scripts/mysqltuner.pl
/root/scripts/tuning-primer.sh

The scripts will ask some simple questions (user/pass) and will display in red colour, their suggestions for critical settings. You can use their suggestions to boost the performance of mysql-server.

11. Hardening you system

First of all, make sure that you have set the security level to High, in Server Config – Web (tab) of ISPConfig3 panel.

The following instructions are just a demostration. Please fully understand them (by reading documentation over the Internet), before you apply and use them.

In general, if you follow them, you can rate limit traffic on specific ports, reduce syn connections and prevent intrusions that use known bad packets. To apply them create the folder /root/scripts (if it doesn’t exist) and the following 5 files. (loadfw, unloadfw, IPs, fwrules and reloadfail2ban). The first will contain the script to load the rules, the second the script to unload the rules, the third will contain the “BAD” IPs and the “BAD” networks, the fourth the custom rules and the fifth some commands to reload eveything (including fail2ban).

mkdir /root/scripts
touch /root/scripts/loadfw
touch /root/scripts/unloadfw
touch /root/scripts/IPs
touch /root/scripts/fwrules
touch /root/scripts/reloadfail2ban
cd /root/scripts
nano loadfw

Paste the following:

#!/bin/bash
# Simple iptables IP/subnet load script
# ----------------------------------------------------------

cd /root/scripts/

IPT=/sbin/iptables
DROPMSG="fwBLOCKED "
BADIPS=$(egrep -v -E "^#|^$" /root/scripts/IPs)

while read fwrule
do
  $IPT -I INPUT $fwrule

done < /root/scripts/fwrules

for ipblock in $BADIPS
do
   $IPT -I INPUT -s $ipblock -j DROP
   $IPT -I INPUT -s $ipblock -j LOG --log-prefix "$DROPMSG"
done

Edit unloadfw:

nano unloadfw

Paste the following:

#!/bin/bash
# Simple iptables IP/subnet unload script
# ---------------------------------------------------------


cd /root/scripts/

IPT=/sbin/iptables
DROPMSG="fwBLOCKED "
BADIPS=$(egrep -v -E "^#|^$" /root/scripts/IPs)

while read fwrule
do
  $IPT -D INPUT $fwrule

done < /root/scripts/fwrules
for ipblock in $BADIPS
do
   $IPT -D INPUT -s $ipblock -j DROP
   $IPT -D INPUT -s $ipblock -j LOG --log-prefix "$DROPMSG"done

Edit IPs:

nano IPs

Paste the annoying IPs (e.g. IPs banned multiple times by fail2ban) or whole networks. You can add here IPs or netwroks at any time, but before you make any modification (especially if you remove sth) you have to run “/root/scripts/unloadfw”. Afterward you can edit the file, inserting IPs or networks and finally you have to run “/root/scripts/loadfw” (see below)

#IP
x.y.z.w
x.q.a.r

#netwroks
d.r.t.h/24

#mailservers
a.g.h.j

(You can use http://www.countryipblocks.net to see the networks that are assosiated with each country). Edit fwrules:

nano fwrules

Paste the following (and anything else that can be inserted (-I) or deleted (-D) in/from INPUT chain. The rules are for servers with a single network interface (eth0). Please change them to fit your needs (e.g. change eth0 if your network interface is different).

-p tcp --dport 50022 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw50022 -j DROP
-p tcp --dport 50022 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw50022 -j LOG --log-prefix "LMfwport50022"
-p tcp --dport 50022 -i eth0 -m state --state NEW -m recent --set --name fw50022
-p tcp --dport 50000 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw50000 -j DROP
-p tcp --dport 50000 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw50000 -j LOG --log-prefix "LMfwport50000"
-p tcp --dport 50000 -i eth0 -m state --state NEW -m recent --set --name fw50000
-p tcp --dport 10000 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw10000 -j DROP
-p tcp --dport 10000 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw10000 -j LOG --log-prefix "LMfwport10000"
-p tcp --dport 10000 -i eth0 -m state --state NEW -m recent --set --name fw10000
-p tcp --dport 25 -i eth0 -m state --state NEW -m recent --rcheck --seconds 60 --hitcount 20 --name fw25 -j DROP
-p tcp --dport 25 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 20 --name fw25 -j LOG --log-prefix "LMfwport25"
-p tcp --dport 25 -i eth0 -m state --state NEW -m recent --set --name fw25
-p tcp --dport 110 -i eth0 -m state --state NEW -m recent --rcheck --seconds 60 --hitcount 20 --name fw110 -j DROP
-p tcp --dport 110 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 20 --name fw110 -j LOG --log-prefix "LMfwport110"
-p tcp --dport 110 -i eth0 -m state --state NEW -m recent --set --name fw110
-p tcp --dport 50443 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw50443 -j DROP
-p tcp --dport 50443 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw50443 -j LOG --log-prefix "LMfwport50443"
-p tcp --dport 50443 -i eth0 -m state --state NEW -m recent --set --name fw7443
-p tcp --dport 22 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw22 -j DROP
-p tcp --dport 22 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw22 -j LOG --log-prefix "LMfwport22"
-p tcp --dport 22 -i eth0 -m state --state NEW -m recent --set --name fw22
-p tcp --dport 20 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw20 -j DROP
-p tcp --dport 20 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw20 -j LOG --log-prefix "LMfwport20"
-p tcp --dport 20 -i eth0 -m state --state NEW -m recent --set --name fw20
-p tcp --dport 21 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw21 -j DROP
-p tcp --dport 21 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw21 -j LOG --log-prefix "LMfwport21"
-p tcp --dport 21 -i eth0 -m state --state NEW -m recent --set --name fw21
-p tcp --dport 143 -i eth0 -m state --state NEW -m recent --rcheck --seconds 60 --hitcount 20 --name fw143 -j DROP
-p tcp --dport 143 -i eth0 -m state --state NEW -m recent --update --seconds 60 --hitcount 20 --name fw143 -j LOG --log-prefix "LMfwport143"
-p tcp --dport 143 -i eth0 -m state --state NEW -m recent --set --name fw143
-p tcp --dport 53 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw53 -j DROP
-p tcp --dport 53 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw53 -j LOG --log-prefix "LMfwport53"
-p tcp --dport 53 -i eth0 -m state --state NEW -m recent --set --name fw53
-p tcp --dport 443 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw443 -j DROP
-p tcp --dport 443 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw443 -j LOG --log-prefix "LMfwport443"
-p tcp --dport 443 -i eth0 -m state --state NEW -m recent --set --name fw443
-p tcp --dport 8081 -i eth0 -m state --state NEW -m recent --rcheck --seconds 30 --hitcount 20 --name fw8081 -j DROP
-p tcp --dport 8081 -i eth0 -m state --state NEW -m recent --update --seconds 30 --hitcount 20 --name fw8081 -j LOG --log-prefix "LMfwport8081"
-p tcp --dport 8081 -i eth0 -m state --state NEW -m recent --set --name fw8081
-p icmp -j DROP
-p icmp -m limit --limit 2/s -j ACCEPT
-p tcp --syn --dport 80 -m connlimit --connlimit-above 25 -j DROP
-p tcp --syn --dport 80 -m connlimit --connlimit-above 25 -j LOG --log-prefix "BLfwsyn80"
-p tcp --syn --dport 443 -m connlimit --connlimit-above 25 -j DROP
-p tcp --syn --dport 443 -m connlimit --connlimit-above 25 -j LOG --log-prefix "BLfwsyn443"
-p tcp --syn --dport 50443 -m connlimit --connlimit-above 25 -j DROP
-p tcp --syn --dport 50443 -m connlimit --connlimit-above 25 -j  LOG --log-prefix "BLfwsyn50443"
-p tcp --syn --dport 50022 -m connlimit --connlimit-above 10 -j DROP
-p tcp --syn --dport 50022 -m connlimit --connlimit-above 10 -j LOG --log-prefix "BLfwsyn50022"
-p tcp --syn --dport 22 -m connlimit --connlimit-above 10 -j DROP
-p tcp --syn --dport 22 -m connlimit --connlimit-above 10 -j LOG --log-prefix "BLfwsyn22"
-p tcp --syn --dport 50000 -m connlimit --connlimit-above 15 -j DROP
-p tcp --syn --dport 50000 -m connlimit --connlimit-above 15 -j LOG --log-prefix "BLfwsyn50000"
-p tcp --syn --dport 10000 -m connlimit --connlimit-above 15 -j DROP
-p tcp --syn --dport 10000 -m connlimit --connlimit-above 15 -j LOG --log-prefix "BLfwsyn10000"
-p tcp --syn --dport 25 -m connlimit --connlimit-above 10 -j DROP
-p tcp --syn --dport 25 -m connlimit --connlimit-above 10 -j LOG --log-prefix "BLfwsyn25"
-p tcp --syn --dport 20 -m connlimit --connlimit-above 10 -j DROP
-p tcp --syn --dport 20 -m connlimit --connlimit-above 10 -j LOG --log-prefix "BLfwsyn20"
-p tcp --syn --dport 21 -m connlimit --connlimit-above 10 -j DROP
-p tcp --syn --dport 21 -m connlimit --connlimit-above 10 -j LOG --log-prefix "BLfwsyn21"
-p tcp --syn --dport 110 -m connlimit --connlimit-above 10 -j DROP
-p tcp --syn --dport 110 -m connlimit --connlimit-above 10 -j LOG --log-prefix "BLfwsyn110"
-p tcp --syn --dport 143 -m connlimit --connlimit-above 10 -j DROP
-p tcp --syn --dport 143 -m connlimit --connlimit-above 10 -j LOG --log-prefix "BLfwsyn143"
-p tcp --syn --dport 53 -m connlimit --connlimit-above 10 -j DROP
-p tcp --syn --dport 53 -m connlimit --connlimit-above 10 -j LOG --log-prefix "BLfwsyn53"
-i eth0 -p tcp --tcp-flags ALL ALL -j DROP
-i eth0 -p tcp --tcp-flags ALL ALL -j LOG --log-level 4 --log-prefix "FLAAfw"
-i eth0 -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
-i eth0 -p tcp --tcp-flags ALL FIN,URG,PSH -j LOG --log-level 4 --log-prefix "FINGfw"
-i eth0 -f -j DROP
-i eth0 -f  -m limit --limit 6/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "FRAGfw"
-i eth0 -p tcp --tcp-flags ALL NONE -j DROP
-i eth0 -p tcp --tcp-flags ALL NONE -m limit --limit 5/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "NULLfw"
-i eth0 -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
-i eth0 -p tcp --tcp-flags SYN,FIN SYN,FIN -m limit --limit 5/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "XMASfw"
-i eth0 -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
-i eth0 -p tcp --tcp-flags SYN,RST SYN,RST -j LOG --log-level 4 --log-prefix "SYNRTSfw"
-i eth0 -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
-i eth0 -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j LOG --log-level 4 --log-prefix "SYNRTSACKfw"
-i eth0 -p tcp --tcp-flags ALL ACK,RST,SYN,FIN -j DROP
-i eth0 -p tcp --tcp-flags ALL ACK,RST,SYN,FIN -j LOG --log-level 4 --log-prefix "SYNRTSYNSfw"
-i eth0 -p tcp ! --syn -m state --state NEW -j DROP
-i eth0 -p tcp ! --syn -m state --state NEW  -m limit --limit 5/m --limit-burst 7 -j LOG --log-level 4 --log-prefix "DROSYNCfw"

Edit reloadfail2ban:

nano reloadfail2ban

Paste the following:

#!/bin/bash

/etc/init.d/fail2ban restart
sleep 2
/root/scripts/unloadfw
sleep 2
/root/scripts/loadfw

Keep in mind that the reloadfail2ban script just unloads the custom rules in fwrules, restarts fail2ban and loads the rules in fwrules again. It doesn’t do a full firewall restart. So before you edit the rules in this file (or IPs file), unload them with unloadfw. The role of reloadfail2ban is to test the functionality of fail2ban

Finally execute:

chmod 700 reloadfail2ban
chmod 700 unloadfw
chmod 700 loadfw
/root/scripts/reloadfail2ban

If you want the custom rules to load after every reboot paste the line: /root/scripts/loadfw in the end of /etc/init.d/rc.local:

nano /etc/init.d/rc.local

and append:

[...]
/root/scripts/loadfw

(D)DoS Deflate is a lightweight bash shell script designed to assist in the process of blocking a denial of service attack. It creates a list of IP addresses connected to the server, along with their total number of connections. It is one of the simplest and easiest to install solutions at the software level.

IP addresses with over a pre-configured number of connections are automatically blocked in the server’s firewall, which can be direct iptables or Advanced Policy Firewall (APF). To install (D)DoS Deflate:

cd /tmp
wget http://www.inetbase.com/scripts/ddos/install.sh
chmod 0700 install.sh
./install.sh

Edit /usr/local/ddos/ddos.conf and apply the follow changes that will disable APF firewall and use plain iptables, email events to root and block IP with more than 100 connections per minute.

[...]
APF_BAN=0
EMAIL_TO="root"
NO_OF_CONNECTIONS=100
[...]

The above are just a bunch of suggestions. You can extend them as you like.

The implementation is just one approach of many. You can use a firewall solution like APF, Shorewall etc. I would be gland to include more different approaches in companion with this one.

10. Clients’ BackUps

The contents of the script changed on 29-03-2011. Please update

This script WILL NOT work correctly for ISPConfig v. 3.0.5 and above. You have to do a lot of changes and is not recommended. Please use the ISPConfig new way of backing up.

The following script, is an easy way to backup your clients data and your clients databases in their website folder. As you may know, in ISPConfig3 each client has a folder in the form /var/www/clients/clientXY, in which there are all his web sites. The script will back up all his websites in each web folder, in companion with his databases and the client will be able to download them. In case, a client has more than one database, then all the databases will be backed up in his first (based on webID) site. The script will also keep the last 3 days of those files and the last 3 Sundays for admin usage in a directory of your choice (the default is /var/backup/sites).

This is a very simple script. For a more advanced solution look at this post.

Create the script, make it executable and edit it:

cd /root/scripts/
touch mybackup.sh
chmod 0700 mybackup.sh
nano mybackup.sh

The contents must be the following:(Change the variables ispUSER, ispPASS, ispHOST, DEST and SITES to fit your needs):

#!/bin/bash
# Shell script to backup MySql database and clients websites
# 
# Last updated: March - 2011
# --------------------------------------------------------------------
# This is a free shell script under GNU GPL version 2.0 or above
# Copyright (C) 2011 iopen.gr
# Feedback/comment/suggestions : http://iopen.gr
# --------------------------------------------------------------------
#
#           INTENDED for the  ISPConfig 3.0.x and above
#
# This script will back up every web folder (web, stats, cgi e.t.c 
# of every client in companion with all the client's DBs
# The backups will be placed in the website client's folder 
# The scipt will keep the current and the 2 previous backup
# It will also keep the last 3 sundays
# --------------------------------------------------------------------

# Database credentials. Use a DB user with full read access or use the root user 
ispUSER="root"                  # DB user
ispPASS="---yourpass---"        # user's password
ispHOST="localhost"             # Hostname

CURDIR="$(pwd)" 
# Variables with full path to binaries
MYSQL="$(which mysql)"
MYSQLDUMP="$(which mysqldump)"
CHOWN="$(which chown)"
CHMOD="$(which chmod)"
GZIP="$(which gzip)"
TAR="$(which tar)" 

# Your Server's  Main  Backup Directory
DEST="/var/backup"
 
# Sites (ONLY) backup directory in your  Main Backup Directory
SITES="$DEST/sites"
  
 
# Variables for Dates in yymmdd format
TODAY=`date +%Y%0m%0d`
YESTERDAY=`date -d '1 day ago' +%Y%0m%0d`
BACK2=`date -d '2 day ago' +%Y%0m%0d`
BACK3=`date -d '3 day ago' +%Y%0m%0d`
BACK22=`date -d '22 day ago' +%Y%0m%0d`
 
[ ! -d $SITES ] && mkdir -p $SITES || :
 
# Give Only root access to backups in this scripts folders
$CHOWN 0.0 -R $SITES
$CHMOD 0600 $SITES

# -------------------------------------------------------------------------- 
# Remove previous (current) backups of the client directory
# The backups are in the form :
# *BU*gz
# -------- CAUTION ---------
# Do not store any other file in this form in the clients directory
# -------------------------------------------------------------------------- 
echo "-------------------------------------------------------------"

QRY="use dbispconfig; SELECT web_domain.system_user, web_domain.system_group, \
web_domain.document_root, web_domain.domain FROM web_domain WHERE  \
web_domain.type!='alias' AND web_domain.system_user IS NOT NULL AND (LENGTH(web_domain.redirect_path)<5 OR web_domain.redirect_path IS NULL) ;"

echo $QRY | mysql -u $ispUSER -h $ispHOST -p$ispPASS | while read -r line
do  # ${col[0]}=domain user / folder name / system user, ${col[1]}=clientID / system group ,
        while read -a col  # ${col[2]}=path to website, ${col[3]}= domain name
        do
                echo "    CLEANING OLD BACKUPS in ${col[2]} folder "
                for delfile in ${col[2]}/*BU*gz ; 
                do [ -f $delfile ] && rm $delfile; 
                done
        done
done

# -------------------------------------------------------------------------- 
# Remove anything that is 22 days old and have the form :
# *[date 22 days old]*gz
# from server's $SITES directory
# -------------------------------------------------------------------------- 
                echo "-------------------------------------------------------------"
                echo "    CLEANING OLD BACKUPS in SITES folder "
                for delfile in $SITES/*$BACK22*gz ; 
                do [ -f $delfile ] && rm $delfile;  
                done
                echo "-------------------------------------------------------------"
                echo "                                                             "
                echo "                                                             "

# -------------------------------------------------------------------------- 
# For each client, backup his database in his website folder 
# For client with multiple sites backup all dbs in his first site
# Furthermore copy today's backup in the server's  $SITES directory 
# Remove the backup that is older than 3 days from server's $SITES directory
# Keep the last 3 Sundays
# -------------------------------------------------------------------------- 

QRY="use dbispconfig; SELECT web_database.database_name , web_database.database_user ,\
 min(web_domain.system_user) as muser, web_domain.system_group, min(web_domain.document_root) as mpath, \
web_domain.domain FROM web_database, web_domain WHERE web_database.sys_userid=web_domain.sys_userid \
AND web_database.sys_groupid=web_domain.sys_groupid AND web_domain.type='vhost' \
AND web_domain.system_user IS NOT NULL AND (LENGTH(web_domain.redirect_path)<5 OR web_domain.redirect_path IS NULL) \
 GROUP BY web_database.database_name , web_database.database_user,  web_domain.system_group;"

echo $QRY | mysql -u $ispUSER -h $ispHOST -p$ispPASS | while read -r line
do  # ${col[0]} = dbname, ${col[1]}=dbuser , ${col[2]}=domain user / folder name / system user,
        while read -a col   #${col[3]}=clientID / system group , ${col[4]}=path to website
        do
                echo "          DB: "${col[0]} 
                echo "-------------------------------------------------------------"
                echo "Backing Up DB:" ${col[0]}  "in :"  ${col[4]}/${col[0]}BU.gz
                $MYSQLDUMP -u $ispUSER -h $ispHOST -p$ispPASS -c --add-drop-table --add-locks \
		 --quick --lock-tables ${col[0]} | $GZIP -9 > ${col[4]}/${col[0]}BU.gz
                cp ${col[4]}/${col[0]}BU.gz $SITES/${col[0]}.$TODAY.gz
                        if [ `date -d '3 day ago' +%u` -ne 7 ] # if 3 days ago is not Sunday
                        then    #remove the  backup
                                [ -f $SITES/${col[0]}.$BACK3.gz ] && rm $SITES/${col[0]}.$BACK3.gz
                        fi
                $CHOWN ${col[2]}:${col[3]} ${col[4]}/${col[0]}BU.gz
                $CHMOD 0660 ${col[4]}/${col[0]}BU.gz
                echo "-------------------------------------------------------------"
                echo "                                                             "

        done
done

# -------------------------------------------------------------------------- 
# For each client, backup his sites in his website folder 
# Furthermore copy today's backup in the server's  $SITES directory 
# Remove the backup that is older than 3 days from server's $SITES diriectory
# Keep the last 3 Sundays
# -------------------------------------------------------------------------- 



QRY="use dbispconfig; SELECT web_domain.system_user, web_domain.system_group,\
 web_domain.document_root, web_domain.domain FROM web_domain WHERE  \
web_domain.type!='alias' AND web_domain.system_user \
IS NOT NULL AND (LENGTH(web_domain.redirect_path)<5 OR web_domain.redirect_path IS NULL) ;"

echo $QRY | mysql -u $ispUSER -h $ispHOST -p$ispPASS | while read -r line
do     # ${col[0]}=domain user / folder name / system user, ${col[1]}=clientID / system group ,
        while read -a col   # ${col[2]}=path to website, ${col[3]}= domain name
        do
                echo "                                                             "
                echo "         Site:" ${col[3]}
                echo "-------------------------------------------------------------"
                echo "Backing Up site: " ${col[2]}/  "in :"  ${col[2]}/${col[3]}BU.tar.gz
                cd ${col[2]}
                sudo -u ${col[0]} $TAR -czf ${col[2]}/${col[3]}BU.tar.gz .
                cp ${col[2]}/${col[3]}BU.tar.gz $SITES/${col[3]}.$TODAY.tar.gz
                        if [ `date -d '3 day ago' +%u` -ne 7 ] # if 3 days ago is not Sunday
                        then    #remove the backup
                                [ -f $SITES/${col[3]}.$BACK3.tar.gz ] && rm $SITES/${col[3]}.$BACK3.tar.gz
                        fi
                $CHOWN ${col[0]}:${col[1]} ${col[2]}/${col[3]}BU.tar.gz
                $CHMOD 0660 ${col[2]}/${col[3]}BU.tar.gz

                echo "-------------------------------------------------------------"
                echo "                                                             "
        done
done
cd $CURDIR

You can run the backup script by executing:

/root/scripts/mybackup.sh

or you can add it as a cron job (e.g. every day at 22:30):

crontab -e

and append the following line:

30 22 * * * /root/scripts/mybackup.sh > /dev/null 2>> /var/log/backup.log

 

Final Notes

Please, feel free to comment anything for this tutorial in an appropriate threat in Kreationnext forums. Useful comments will be included in a future updated version.

This is the first version and as careful as I was, the tutorial may contain errors. Please let me know of them, so as to correct them, as soon as possible.

Comments

comments