Category Archives: Apache

Debian Install SSL Certificates for Apache OpenSSL

Something else that I do not do often and have never documented is the install of an SSL certificate on Debian servers for use with Apache / OpenSSL. For this post I am assuming that an existing SSL certificate has been purchased. I use a lot of wildcard certificates for multiple servers rather than a certificate per site / server.

Go to this directory

# cd /etc/ssl/private/

By default there is a self-signed certificate key ssl-cert-snakeoil.key in the directory

This directory is restricted to root user and ssl-cert group.

Using an existing certificate, key, and intermediate certificate, create a file for each in the same directory.

Change the relevant ownership

# chown root:ssl-cert *

and change the access

#chmod 640 *

This should provide something like:

/etc/ssl/private# ls -la
drwx--x--- 2 root ssl-cert 4096 Apr 14 12:12 .
drwxr-xr-x 4 root root     4096 Mar 28 08:41 ..
-rw-r----- 1 root ssl-cert 1589 Apr 14 12:11 mydomain-intermediate.crt
-rw-r----- 1 root ssl-cert 1704 Mar 20 23:25 ssl-cert-snakeoil.key
-rw-r----- 1 root ssl-cert 2049 Apr 14 12:10 mydomain-cert.crt
-rw-r----- 1 root ssl-cert 1678 Apr 14 12:13 mydomain-key.key

Ok, now off to the Apache config

# cd /etc/apache2/sites-available/

and edit the site file that is relevant so that the Virtual Host *:443 section includes the correct paths to the above certificate files

  # Example SSL configuration
  SSLEngine on
  SSLProtocol all -SSLv2
  SSLCertificateChainFile "/etc/ssl/private/mydomain-intermediate.crt"
  SSLCertificateFile "/etc/ssl/private/mydomain-cert.crt"
  SSLCertificateKeyFile "/etc/ssl/private/mydomain-key.key"

If there is no Virtual Host *:443 section then there should be an existing VirtualHost *:80 for the website and this can be copied / duplicated in the same file, just change the port in the copy from 80 to 443 and insert the above Example SSL lines at the bottom of the new section above the closing tag.

If Apache is a fresh install it may not have SSL enabled

#a2enmod ssl 

Test Apache syntax

#apachectl -t 

Restart Apache

#apachectl graceful 


#service apache2 restart 

depending on what you need for existing sites on the server.


Turning off WordPress redirects index.php to index.html on Cpanel Apache

I spent a bit of time today trying to research why Apache on Cpanel insisted on redirecting from index.php when it was entered as an explicit URL to the default index.html page in the website home directory.

As it turned out, while I am searching for “cpanel apache redirects” I should have been asking “Why does WordPress redirect…” and that change of question led me to this WordPress forum thread that addressed the actual issue.

Now normally I would not repeat the information here, but just in case that link disappears, I do want to be able to get to it again, so here it is.

The issue actually is not Apache or Cpanel driven, but is an issue with WordPress and the way that it redirects all requests to the home page for the site. Hence despite me trying to access index.php, WordPress was redirecting to index.html, and that prevented me from seeing the new WP site.

Ultimately the purpose of this was to allow for WordPress to be installed alongside an existing page based site and deploy for final user acceptance before switching off the old site and moving to WordPress as the new site.

The trick is simply a manually installed plugin that can be removed after final commissioning to production.

1. Open your site with an FTP program or SSH depending on you preference

2. Navigate to yoursite_folder/wp-content/plugins/

3. Create a new folder for the plugin – call it disable-canonical-redirects – or dcr for short

4. Change to that folder

5. Create a new index.php file and include (copy and paste or re-type) this PHP code into that file:

Plugin Name: Disable Canonical URL Redirection
Description: Disables the "Canonical URL Redirect" features of WordPress 2.3 and above.
Version: 1.0
Author: Mark Jaquith
Author URI:

remove_filter('template_redirect', 'redirect_canonical');

5. Visit your WordPress Admin backend and activate this new plugin

6. All is now good to go and access index.html by default or index.php for WordPress explicitly.

Many thanks to Mark and others in that discussion thread.


Awstats for many users from a single server Debian Squeeze

There are a number of websites and servers that I want to track stats for.

Each individual CPanel includes Awstats by default, but I have a number of dedicated servers that don’t  have cpanel, and clients that want stats access who I don’t want to give access to the CPanel too (yep, I don’t trust them!)

So this is about installing a stand-alone Awstats with all features and a login process for the various clients to view the relevant areas or servers and domains that will be monitored.

This will include:

  • a mix of Windows and Linux based systems
  • transfer of logs from the source servers to the Awstats server

First up the Awstats server is a Linux Debian Squeeze (6.0.6) setup and installing Awstats is the starting point.

I referenced a number of sites including:

and all of them have helpful information but not quite aligned to what I found on my server.

The simple command for getting Awstats is:

apt-get install awstats

Next there are some fix ups and notes:

To start with the apt-get does not unzip the model file or create the appropriate directories. (Considering that this has been documented for around 5 years I am wondering why someone has not fixed it. I might even give it a try myself, but the tweaks are minor)

So create the correct directories in /usr/share/doc/awstats/examples#

/usr/share/doc/awstats/examples# mkdir -p wwwroot/cgi-bin

Next copy the .gz file to the new directory

/usr/share/doc/awstats/examples# cp awstats.model.conf.gz wwwroot/cgi-bin

Next unzip the .gz file

/usr/share/doc/awstats/examples# cd  wwwroot/cgi-bin

/usr/share/doc/awstats/examples/wwwroot/cgi-bin/#gunzip  awstats.model.conf.gz

Running the configure script for Awstats is next but check that we have appropriate answers for the questions:

The Apache default config file path is /etc/apache2/httpd.conf but, I prefer to use the sites-available construct and have a distinct config for the sites on the server, so.. /etc/apache2/sites-available/001-awstats will be the config file that I use

The site name is whatever your site is and I’ll use the default web site for this server just to get it going

/usr/share/doc/awstats/examples# perl
----- AWStats awstats_configure 1.0 (build 1.8) (c) Laurent Destailleur
----- This tool will help you to configure AWStats to analyze statistics for one web server.
You can try to use it to let it do all that is possible in AWStats setup, however following
the step by step manual setup documentation (docs/index.html) is often a better idea.
Above all if:
- You are not an administrator user,
- You want to analyze downloaded log files without web server,
- You want to analyze mail or ftp log files instead of web log files,
- You need to analyze load balanced servers log files,
- You want to 'understand' all possible ways to use AWStats...
Read the AWStats documentation (docs/index.html).

-----> Running OS detected: Linux, BSD or Unix Warning: AWStats standard
directory on Linux OS is '/usr/local/awstats'.
If you want to use standard directory, you should first move all content
 of AWStats distribution from current directory:
/usr/share/doc/awstats/examples to standard directory: /usr/local/awstats
And then, run from this location.
Do you want to continue setup from this NON standard directory [yN] ?

-----> Check for web server install
Enter full config file path of your Web server. Example: /etc/httpd/httpd.conf
Example: /usr/local/apache2/conf/httpd.conf
Example: c:\Program files\apache group\apache\conf\httpd.conf
Config file path ('none' to skip web server setup): >
ANSWER = /etc/apache2/sites-available/001-awstats

-----> Check and complete web server config file '/etc/apache2/sites-available/001-awstats'
   All AWStats directives are already present.

-----> Update model config file '/usr/share/doc/awstats/examples/wwwroot/cgi-bin/awstats.model.conf'
File awstats.model.conf updated.

-----> Need to create a new config file ?
Do you want me to build a new AWStats config/profile file (required if first install) [y/N] ?

-----> Define config file name to create What is the name of your web site or profile analysis ?
Example: <a href=""></a>
Example: demo Your web site, virtual server or profile name: >
ANSWER = default-web-site.your-domain.tld.somewhere

-----> Define config file path In which directory do you plan to store your config file(s) ?
Default: /etc/awstats Directory path to store config file(s) (Enter for default): >
ANSWER = [Enter for Default]

-----> Create config file '/etc/awstats/awstats.default-web-site.your-domain.tld.somewhere.conf'
Config file /etc/awstats/awstats.default-web-site.your-domain.tld.somewhere.conf created.

-----> Add update process inside a scheduler
Sorry, does not support automatic add to cron yet.
You can do it manually by adding the following command to your cron:
 /usr/share/doc/awstats/examples/wwwroot/cgi-bin/ -update -config=default-web-site.your-domain.tld.somewhere
Or if you have several config files and prefer having only one command:
/usr/share/doc/awstats/examples/tools/ now
Press ENTER to continue...

A SIMPLE config file has been created:
You should have a look inside to check and change manually main parameters.
You can then manually update your statistics for 'default-web-site.your-domain.tld.somewhere' with command:
 > perl -update -config=default-web-site.your-domain.tld.somewhere
 You can also read your statistics for 'default-web-site.your-domain.tld.somewhere' with URL:
 > <a href="http://localhost/awstats/">http://localhost/awstats/</a>

Press ENTER to finish...

Next edit the apache config file that was created by the script, in my example it is /etc/apache2/sites-available/001-awstats
Add this section for the awstats-icon alias. I suggest near the top of the file after the CGI script directives rather than the bottom.

Alias /awstatsicons/ /usr/share/awstats/icon/
<Directory /usr/share/awstats/icon>
   Options None
   AllowOverride None
   Order allow,deny
   Allow from all

There may be a pointer in the file already for Alias

Alias /awstatsicon "/usr/share/awstats/examples/wwwroot/icon/"

If there is then it is incorrect. Just use a # at the start of the line to disable it.

To complete the Apache config enable the new 001-awstats site and restart apache2

/etc/apache2/sites-enabled# a2ensite
/etc/apache2/sites-enabled# apachectl graceful

You can also use “service apache2 graceful” with same outcome
Next in the /etc/awstats/ directory find the awstats.your-domain-name.conf file that was created earlier.
Edit the file around line 51 MAIN SETUP SECTION and change the log file location for the default web site




everything else should be ok as a default.

So now we have a configured Awstats for a basic test. Try running this command

/etc/awstats# /usr/lib/cgi-bin/ -config=default-web-site.your-domain.tld.somewhere

Remember that the -config option here must match the awstats.default-web-site.your-domain.tld.somewhere.conf of the file created earlier. Except do not include the awstats. or the .conf as this prefix and suffix are automatically assumed by the application.

The response should look something like this:

Create/Update database for config "/etc/awstats/awstats.default-web-site.your-domain.tld.somewhere.conf" by AWStats version 6.95 (build 1.943)
From data in log file "/var/log/apache2/access.log"...
Phase 1 : First bypass old records, searching new record...
Searching new records from beginning of log file...
Phase 2 : Now process new records (Flush history on disk after 20000 hosts)...
Jumped lines in file: 0
Parsed lines in file: 28
Found 0 dropped records,
Found 0 corrupted records,
Found 0 old records,
Found 28 new qualified records.

Finally the test is to check that it is alive ! In a web browser try the following substituting the example domain in the URL and as the config to check.


Ok, so that works.

Now to configure a process to update the stats from the logs  is the perl script that will do this, but it is sitting in an odd place under examples. I moved it just to have it in a more logical place alongside the script.  This is not essential.

#cd /usr/share/doc/awstats/examples/
/usr/share/doc/awstats/examples# cp /usr/lib/cgi-bin/

There is a whole commentary on the sequencing of rotating logs and stats updates at

For what I need using the Apache Logrotate process will suit.  Modify the /etc/logrotate.d/apache2 file

# cd /etc/logrotate.d/
/etc/logrotate.d/# mcedit apache2

Insert the following 3 new lines just after the sharedscripts line and before the postrotate line.

/usr/lib/cgi-bin/ -awstatsprog=/usr/lib/cgi-bin/ now

I did not include the config option “-configdir=/etc/awstats/” as that is the default and it is redundant
The command “/usr/lib/cgi-bin/ -awstatsprog=/usr/lib/cgi-bin/ now” can be run from the command line to confirm that it is correct.

So now the awstats is running and the logrotate will update the stats every morning

Security of access to the files is the next topic and I’ve recorded that as a separate post.

Next add another site with logs. Adding another site is simply a case of identifying the log files and adding a conf file for them.

Secure access with .htacess

Awstats Configuration Files awstats.conf, awstats.model.conf

The default setup for awstats is really aimed at a minimal number of web site or other logs and the ability to setup specific config files for each site is good but seems a little top heavy.

The awstats.conf and awstats.conf.local files provide for the single site type setup. Configure the main .conf settings or alternatively add the specific overrides of the defaults into the awstats.conf.local file and all is good.

Using the awstats.model.conf for multiple web sites and copying it to a site specific file also is a good plan for a nominal number of sites.

But once we get to having 37 sites it is getting a bit out of hand.

So how to improve the process and automate it?


  • Have a standard config file for all the standard settings
  • Have a standard log file format for the specific type of log being stat’d
  • Have a header type config file that is specific to the site or URL being stat’d
  • Combine them all on-the-fly by using the Includes option in the awstats config files

I think the order should be:

awstats looks in /etc/awstats when the updateall process is executed

in the /etc/awstats directory are the header files which look like:

#include main config file from somewhere else (it cannot be in this directory as it would be read as a conf file directly)
#include the required log file format – parsing both apache and windows logs
#have only the site specific instructions in the file so that the file size and chance of overriding config standards is reduced

I’ll experiment with the above and update this with the result.

Moving Moodle to a Plesk environment

I am migrating a moodle install from an older system into a new hosted environment with Plesk in the background.

The setup of the Plesk account is straight forward. While the transfer was simple enough using SFTP via FileZilla out of one Linux system to my workstation and off to the new server.

The first obvious task was to modify the config.php file for moodle with its new information.

The less obvious task was the error accessing the moodledata directory which for preference sits outside the Plesk default httpdocs directory.

If you are getting an error about the $CFG->dataroot being invalid or similar it will be the open_basedir setting.

Check the logs for Apache errors


to modify the default Apache settings in a Plesk world create a file called vhost.conf in the conf directory I use mcedit as my favourite Linux command line editor (apt-get install mc) (Midnight Commander tools)

#mcedit /var/www/vhosts/your_domain_name/conf/vhost.conf

and create an entry like

<Directory /var/www/vhosts/your_domain_name/httpdocs/>
php_admin_value open_basedir "/var/www/vhosts/your_domain_name/httpdocs:/var/www/vhosts/your_domain_name/moodledata"

I referenced Aaron Gadberry’s blog for the above but stumbled when it came to restarting the Apache service

#/usr/local/psa/admin/bin/websrvmng -a

is no longer valid. Given that Aaron wrote his info in 2006  and 5 years later Plesk is version 10 for my server it is not surprising there is a change. The correct command for restarting / reconfiguring a single vhost is

#/usr/local/psa/admin/bin/httpdmng --reconfigure-domain your_domain_name

The final part of this conversion was to modify the Moodle MySQL database to a UTF8 format.

I have used phpmyadmin for years and most Linux servers including Plesk offer it for mySQL admin.

It’s a simple thing to change the database. Just select the database in phpmyadmin and select the Operations tab. Down the bottom is the current collation in a select list. Change the selection to utf8_unicode_ci which is at the very bottom of the list and click on Go.

Plesk 10.2.0 and SSL Certificates

One of the servers I manage has a Plesk control panel. I am not familiar with it having used cpanel/whm for the last 11 years since I first got a hosted server.

I was setting up what I thought would be an easy SSL certificate install. I’ve started this post because I am now delving into the core of the server <supposition>as the damn GUI hates me.</supposition>

Before you even start, if you want to have an SSL certificate on a sub-domain site, forget it unless you a) make it a wildcard certificate or b) are prepared to have the only ip address attached to that certificate.

Plesk 10.x only allows one IP address per subscription and that is set for all the sub-domains as well as the domain attached to the subscription.

So to apply a certificate that works for the subscription it must be a wildcard certificate. i.e.


sub-domains exist for


certificate is for


it will be applied to all the domains




While the option to have a specific SSL for


as it is not possible to split the IP addresses to isolate the SSL per IP address.

MySQL & PHP Upgrade CentOS server

I now appear to have a new Linux VPS running with CentOS and Plesk. I wont go into the stupid details of why this has taken 2 weeks to provision, or another 2 days for me to ‘fix’ the ip addresses etc, only to find that CentOS has an older version of PHP at 5.1 and MySQL needing to be upgraded to match with PHP 5.3 when I tried to upgrade.

I referenced Christian Montoya’s blog for the update for PHP but found that I had a couple of issues.

The first was that when I ran the yum command for the PHP upgrade it complained about the MySQL support / version.

yum update php

was changed to include MySQL

yum update php mysql

Which did what I needed.

Running the

php -v

Advised that the updated 5.3 version was installed but I then found that MySQL was not running.

A quick wade around discovered that /var/log/mysqld.log that there was another error preventing MySQL from starting. This was the message:

[ERROR] /usr/libexec/mysqld: unknown option '--skip-bdb'

Editing the /etc/my.cnf file to comment out this option in both the main section and the mysql_safe section of the file fixed this issue and allowed MySQL to start.

Next I had in the mysql log messages like:

[ERROR] Column count of mysql.proc is wrong. Expected 20, found 16. 
Created with MySQL 50077, now running 50156. 
Please use mysql_upgrade to fix this error.

So trying to use mysql_upgrade as a command by itself fails for user root@local host

]# mysql_upgrade
Looking for 'mysql' as: mysql
Looking for 'mysqlcheck' as: mysqlcheck
Running 'mysqlcheck with default connection arguments
mysqlcheck: Got error: 1045: Access denied for user 'root'@'localhost' (using password: NO) when 
trying to connect
FATAL ERROR: Upgrade failed

Using the correct username is as simple as

#mysqlupgrade -u username -p  [Enter]

Which will prompt you for the password and then run the upgrade with the authenticated username.

And that, I hope, completes the backend upgrade so I can run SugarCRM on this server.

SME Server and open_basedir restriction affects cURL

This is another little item that I wanted to document before I forget what was done and why.

Using SME Server 8.0beta6 for my web development server. I like the ibay options for quickly setting up new sites for testing and knowing that it will be consistent with any other ibay and therefore comparison of software app versions is easy.

That said I had an issue with using / linking Gallery 3 and WordPress 3 on my server.

I posted to the forums for each of the applications but figured I’d note the details here as well.

The title of this blog entry is relating to cURL and the open_basedir restriction in Apache on SME Server and this is one of the issues I came across. It may equally apply for anyone using a piece of software that uses cURL features.

In the server or php log (/var/log/messages on SME Server) I kept getting this message:

PHP Warning:  curl_setopt() [function.curl-setopt]: CURLOPT_FOLLOWLOCATION cannot be activated when in safe_mode or an open_basedir is set in /home/e-smith/files/ibays/mysite/html/wp-content/plugins/g3client/client.php on line 72

On SME Server for a permanent adjustment you will need to modify one of the httpd.conf template files.
I documented the basic format for this file in another entry ‘SME Server httpd.conf open_basedir path to include /tmp‘. If you have not done this before you’ll need to start with that part of the process then do the following.

On your SME Server go to

# cd /etc/e-smith/templates-custom/etc/httpd/conf/httpd.conf/

Edit the existing template snippet file 95AddType00PHP2ibays (with your preferred editor)
Find the line with the php_admin_value setting

$OUT .= ” php_admin_value open_basedir $basedir:/tmp:/usr/share/pear:/usr/share/pear-addons\n”;

and insert the if statement immediately above the line with the php_admin_value as shown

if ($ibay->key eq ‘insert_your_ibay_name_here‘) {
$OUT .= “#openbase_dir disabled for this ibay\n”;
$OUT .= “#”;
$OUT .= ”    php_admin_value open_basedir $basedir:/tmp:/usr/share/pear:/usr/share/pear-addons\n”;

This will comment out ‘#’ the open_basedir line for the specified ibay and cURL will now work as required.

If your SME Server is public facing then this may introduce a security risk so use with caution.

In my case the server is private and only risks being messed up by me.

.htaccess useful options

This is a post that I started to remind me of what the correct syntax is for the .htaccess file. But given that it has kind of grown to include a heap of .htaccess info I thought it wise to highlight the Apache official .htaccess tutorial pages. Given the information in that tutorial only use .htaccess if you really need to and preferably use the correct httpd.conf (apache2.conf or similar depending on your distro) for the commands as it will help with system performance. That said, there are a number of things that I use .htaccess for, here are some of them.

Edit: Have not read this as yet, but it seems to contain a heap more detail.

The following came from

Redirecting to
If search engines find both www and non-www links from other sites to your site, they may treat and as two different websites with the same content. This means that your site can be penalized for duplicate content. Many experts recommend to set up a 301 redirect (permanent redirect) from to…

The code for this would be:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^YourSite\.com [nc]
RewriteRule (.*)$1 [R=301,L]

Of course, using the .htaccess file and having all the correct paths enabled will help.

My default SME Server uses Apache2 and I have found that in order to use .htaccess and htpasswd effectively I had to add / enable some modules in the /etc/httpd/conf/httpd.conf file.

Setting aside the fact that SME Server needs to have specific templates updated, the Centos distro that it is based on will be similar to this (I expect).

I did enable a number of auth type modules to address a number of errors.  In each case the /var/log/httpd/error.log was where the errors were recorded.

.htaccess: Invalid command ‘AuthUserFile’, perhaps misspelled or defined by a module not included in the server configuration

was fixed by enabling

LoadModule authn_file_mod modules/

While the error

configuration error: couldn’t check user. No user file?

needed to have the Basic Authentication module enabled in the LoadModules section of the httpd.conf

LoadModule auth_basic_mod modules/

needed to have Basic Authentication enabled. Note that by default Digest is enabled but given that Digest provides little security above Basic I am ok with using Basic with SSL. Note that the SSL is essential for Basic Authentication to be of use. Read the info from Apache on Basic v Digest as I think it makes it clear.

…and another error

configuration error: couldn’t check access. No groups file?:

needed to have this module added.

LoadModule authz_user_mod modules/

at this point I could login from the browser and got a prompt to access the directory. However there was still an error in the log which stated:

/.htaccess: order not allowed here

This was because I had not completed the AllowOverride construct in the httpd.conf file.

In my httpd.conf I have sections for each virtual site / directory on the server.

Options None
Options +Indexes
Options +Includes
AllowOverride None
order deny,allow
deny from all
allow from all

in which the ‘AllowOverride None ‘ directive will ignore .htacess, while setting it to AllowOverride AuthConfig will allow it to check for a username/password it also needs the AllowOverride Limit to avoid the error about Order.

So to summarise the httpd.conf change I added a specific directory directive for the directory I am securing with htaccess/ htpasswd with the following:

AllowOverride AuthConfig Limit
order deny,allow
deny from all
allow from all