I get a lot of questions about how do we turn on ‘display_errors’ in PHP for debugging purposes. Although there are unlimited resources on the Internet which describes the process but I always see that there is some incomplete information regarding this. The clients get confused about this particular parameter because apparently there are two instances/locations of ‘display_errors’ in the configuration file of PHP.

In this small tutorial, I will show you how you make changes at the correct place so that you can turn ‘display_errors‘ on without any confusion. As mentioned, there are two locations of this parameter:


First instance is at line number 96 (might be different for you depending upon the PHP version and OS used).


Second instance is at line number 469, which again might be different for your installation.

In order to enable ‘display_errors’, you need to edit ‘Off’ to ‘On’ at line number 479, that is second instance and not the first one.

Once you make this change, you will need to reload/restart the web service in order to make the changes effective. If you are using FPM process to manage PHP, then reload/restart ‘php-fpm‘ process to make this change effective. You can confirm if the value has been changed from ‘Off’ to ‘On’ by accessing the phpinfo() page and searching for ‘display_errors‘ which should show that it is set to ‘On.

Feel free to write a comment if you have any doubt or suggestions.

In this tutorial, I will walk you through the configuration of creating and installing the client certificates in the nginx web server and the browser so that we can achieve the restrtiction based on client certificates.

So, what are client certificates? Heck, I also did not knew this until today when one of our client’s mentioned them. Before diving into the configuration, I would like to mentioned the difference between server certificates and client certificates:

Server certificates: are used on the server side to check the authenticity of the website that a user is visiting along with the encryption. When using server certificates, the user has to decide weather to trust the website for it’s authenticity or not.

Client certificates: are used by the server to check if the client is authenticated to view certain parts of the website. For example, you have a wordpress installation which is accessible to general public, along with that, if you try to access the wordpress admin page, it will also be visible to the end users. This opens up a security hole to brute force the wordpress admin page and a malicious user can gain access by brute forcing the admin page. If no other measures are taken, your wordpress, or in fact, any other app’s admin page is in jeopardy. Administrators issue client certificates so that the authenticated user can install them in their browsers so that when the admin page is accessed from the very same browser, the client certificates are sent over to the server so that the server can authenticate the user and allow access to specific parts of a web application, in this case, the admin page for wordpress.

Now that we are clear about the difference between server and client certificates, let’s dive in the configuration.

Generate the certificates:

First step is to generate the required certificates on the server. I will simply quote the steps here as there are much more advanced tutorials on the web about generating self signed certificates with explanation. If you want to dig deep about the certificates, then I would recommend you to search a bit on any seach engine for “generating self signed certificates” etc. Follow the steps mentioned below:

1. We will first create the CA key file and CA Certificate in order to self sign the certificate. These certificates can also be used as server certificates, so I will not generate extra server certificates.

openssl genrsa -des3 -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt

2. Next, we will create client key and certificate signing request (CSR) and use it again to self sign this client certificate. NOTE: We are signing the certificates here ourselves but in production environment it is not recommended at all and highly discouraged.

openssl genrsa -des3 -out client.key 1024
openssl req -new -key client.key -out client.csr

3. Now we will self sign this certificate as:

openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

Converting client key to .P12 format:

Next thing is to convert the client.key to .p12 format so that it can be converted into browser compatible format. PKCS (.p12) format is a binary format for storing the server certificates (or any intermediate certificate as a matter of fact) in a single file. For more information on various certificates and their encryption types, you can refer to this article.

openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12

Now we have a client.p12 which can be imported into any compatible browser. This has been tested by me on firefox for Windows OS (Windows 8.1) and Linux (arch linux) system architectures.

Nginx configuration:

In this part, we will configure our nginx configuration to check the client certificates when a request is recevied at the server and decide if the user should be given the privilege to access the ‘admin’ page of our test wordpress installation. We have all our certificates for this purpose saved at one location that is: /root/certs. Open up the nginx configuration file for your blog (in my case, it is: /etc/nginx/conf.d/wordpress.conf). We will also incorporate a setting such that any request received at plain “http://” will be forwarded to “https://” automatically. After installing the certificates, we will add a specific rule that if the client certificate is passed by the browser (that will initially be requested by web server) and is valid, he will be allowed to access the admin page. Otherwise, a 403 Forbidden error will be returned. Let’s get to the configuration.

1. First of all, I will redirect all traffic from http:// to https:// in wordpress.conf:

server {
listen  80;
server_name     example.com;
return 301 https://$host$request_uri;

The above server block will redirect the traffic coming on port 80 to port 443 (https://). 301 here stands for permanent redirect.

2. Next, we will define another server block for https:// requests, this server block will also have all the required configuration for server and client certificates.

server {
   listen       443;
   server_name  example.com;
   root   /usr/share/nginx/html;
   index  index.php index.html index.htm;

   access_log  /var/log/nginx/blog.acc.log;
   error_log  /var/log/nginx/blog.err.log error;

   ssl                  on;
   ssl_certificate      /root/certs/ca.crt;
   ssl_certificate_key  /root/certs/ca.key;
   ssl_client_certificate      /root/certs/client.crt;
   ssl_verify_client   optional;
   ssl_session_timeout  5m;

   location ~ .php$ {
      root           /usr/share/nginx/html;
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param   VERIFIED $ssl_client_verify;
      fastcgi_param   DN $ssl_client_s_dn;
      include        fastcgi_params;


ssl_certificate: This is the server side certificate that we have generated above.

ssl_certificate_key: This is the key used with the above certificate.

ssl_client_certificate: This is the client side certificate that the web server expects from the web browser.

ssl_verify_client: Here, the server will act accordingly, for example, if we define ‘optional’ (as I did in the above configuration), the web server expects the client certificate to be returned by the browser but it is not mandatory. Second option that we can define here is: ‘on’ which mean that the web server will strictly look for the client certificate, if it is received, the access is granted otherwise 400 error is returned in the browser. The values returned are stored in a variable called: ssl_client_verify and can have values as: “SUCCESS“, if the client certificate is received and verified; “FAILED“, if the client certificate is received but failed the authenticity and “NONE“, if no certificate is received.

 fastcgi_param   VERIFIED $ssl_client_verify: This variable is passed to PHP-FPM location block and we have passed ‘VERIFIED’ to this parameter. This means that any value that will be stored in this variable (SUCCESS, FAILED or NONE) will be verified against our CA cert and further processing will be done on this basis.

fastcgi_param   DN $ssl_client_s_dn: This will be useful if you want to check the DN of client certificate received and the part we might be interested in is the Common Name (CN). An example could be of following type:


Next, we will tell the browser about what to do with the requests for /admin, /login or /wp-login.php requests. We will make use of simple if-else statements, yes, it is possible to use this syntax with nginx 😉 Configuration is as follows:

location ~^/(admin|login|wp-admin)(.*)$ {
   index   index.php index.html;
   if ($ssl_client_verify = "NONE") {
      return 403;
location ~ .php$ {
   fastcgi_index  index.php;
   fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
   fastcgi_param   VERIFIED $ssl_client_verify;
   fastcgi_param   DN $ssl_client_s_dn;
   include        fastcgi_params;


location ~^/(admin|login|wp-admin)(.*)$: This line here starts the location block for /admin* , /login* and /wp-admin* followed by the type of page you want to serve (index.php or index.html or index.htm).

if ($ssl_client_verify = “NONE”): This starts the if statement within the location block which checks a condition that what value is stored in $ssl_client_verify variable. The value stored in this variable is governed by ssl_verify_client parameter in the configuration (see above).

return 403: This is self explanatory, if the value is NONE, means no certificate is returned by the browser or the certificate returned does not match the one defined above, then the server will return 403 Forbidden error to the user. If not, the request will be forwarded to php-fpm location block for processing PHP requests. If you just want to forward plain html requests after the client verification, then this php-fpm block is not needed here.

Full configuration file will look like the following:

server {
   listen  80;
   server_name     example.com;
   return 301 https://$host$request_uri;
server {
   listen       443;
   server_name  example.com;
   root   /usr/share/nginx/html;
   index  index.php index.html index.htm;

   access_log  /var/log/nginx/blog.acc.log;
   error_log  /var/log/nginx/blog.err.log error;

   ssl                  on;
   ssl_certificate      /root/certs/ca.crt;
   ssl_certificate_key  /root/certs/ca.key;
   ssl_client_certificate      /root/certs/client.crt;
   ssl_verify_client   optional;
   ssl_session_timeout  5m;

   location ~^/(admin|login|wp-admin)(.*)$ {
      index   index.php index.html;
      if ($ssl_client_verify = "NONE") {
         return 403;
   location ~ .php$ {
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param   VERIFIED $ssl_client_verify;
      fastcgi_param   DN $ssl_client_s_dn;
      include        fastcgi_params;
   location ~ .php$ {
      root           /usr/share/nginx/html;
      fastcgi_index  index.php;
      fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param   VERIFIED $ssl_client_verify;
      fastcgi_param   DN $ssl_client_s_dn;
      include        fastcgi_params;

This finishes our server configuration part and next, we will head over to the client in order to install the client certificate.

Installing client certificates in a browser:

Now that we have our server configured for client certificates, it’s time to install the client certificate in a browser. I have tested this firefox browser on Windows 8.1 and Arch Linux as mentioned above. You can install the same certificate in any browser such as Google Chrome (or Chromium in Linux world), Safari for iOS etc. The instructions for installing certificates manually depends on different browsers, for which you may consult your browsers documentation on how to install certificates manually.

Before we install the certificate, let’s first try to access the admin page of wordpress. If you do so, you will receive a 403 Forbidden error as per the configuration above. If you receive this error, then pat yourself on your back because you have configured the server correctly.

Steps to install the client certificates on firefox browser:

1. Download the client.p12 file that we have created in the starting along with other certificates. I would recommend you to first create a tar archive which have this file and then download that one to maintain the integrity of the file. Once you have it downloaded at your client machine, extract it and open firefox.

Goto: Options/Preferences >> Advanced >> Certificates >> View Certificates >> Your Certificates >> Import >> Browse to the location where client.p12 is located >> select file >> Open

This will import the certificate and you should see your certificate under Your Certificates heading. Once this is done, you have your certificate installed. Try to access your wordpress admin page again and voila! you can access it without any issues. Now try another browser (in which you have not imported the certificate yet) to check if you can access the admin page. I bet you cannot if you have all the instructions followed mentioned here.

Pretty neat stuff, ain’t it!

Varnish, as most of Linux administrators are already known to, is an HTTP accelerator and it does it’s job pretty well. So well, that most of the high traffic websites uses it for easing up load on the web server. Basically what it does is, it sits in front of a web server looking out for requests from end users, when a request is received, it looks up for any cached version of same page and if found, it serves it from there without even consulting the web server at the backend.

Port 80 basically is the port number reserved for the web server, but as we are using HTTP accelerator, Varnish sits on port 80 intercepting all the incoming traffic. It caches the pages and serves them from itself reducing load on the web server, which also increases the speed to an unbelievable level. Settings Varnish is quite easy (we will look into the configuration shortly) which requires novice to medium level of expertise. The more you want to explore Varnish, the more it gets complicated. That is the beauty of Varnish, even new server administrators can set it up in few minutes and the way it is built up, basic setup should suffice for most needs. Let’s dive into the basic setup, I am going to illustrate it on a Linux box (CentOS) but you can us any other flavor as per your choice:

1. Install Varnish 4.0

# rpm --nosignature -i https://repo.varnish-cache.org/redhat/varnish-4.0.el6.rpm
# yum install varnish

2. Make changes in configuration file to make Varnish run on port number 80 along with some other changes:

# vim /etc/sysconfig/varnish


-p thread_pool_min=${VARNISH_MIN_THREADS} 
-p thread_pool_max=${VARNISH_MAX_THREADS} 
-p thread_pool_timeout=${VARNISH_THREAD_TIMEOUT} 
-u varnish -g varnish 


1. VARNISH_VCL_CONF= Defines the location of varnish configuration file which will be loaded at starting the service.

2. VARNISH_LISTEN_PORT= Varnish will start listening on this port after a service restart. Make sure you do not have any web service running on that port because two services trying to run on the same port will clash. For now, make your web service to run on port 8080 instead.

3. VARNISH_STORAGE_SIZE= Define the size of storage that will be used by Varnish to store the cached content.

4. VARNISH_STORAGE= This option defines what type of storage you want to use, here I have selected to use RAM instead of a file to store the cached contents because reading from RAM is pretty fast as compared to a file on hard disk. For more information, have a look here.

5. DAEMON_OPTS= Here all the above will be used, make sure there is only one instance of “Daemon Opts” in the varnish file.

VCL file:

Varnish’s default configuration file is well documented (if you want to perform some advanced tasks using varnish) but at this basic level, we should simply tell varnish where to look for backend web server. This is where VCL’s come in handy. Open up the configuration file and uncomment/make changes as mentioned below:

# vim /etc/varnish/default.vcl

backend default {
.host = "";
.port = "8080";

That is it! now restart the Varnish service (/etc/init.d/varnish start), Once done, you have a basic setup of varnish that is listening connections on port 80 and forwarding non cached content to backend web server which is listening on 8080.

Varnish Examples:

1. You have a specific file that you do not want to cache and that request should goto the web server everytime a user requests it. Default ‘VCL’ file makes it pretty easy if you know regex. I am going to bypass a file called “xmlrpc.php” such that every time there is request for this file, it will be sent to the web server, no questions asked 😉

# vim /etc/varnish/default.vcl

sub vcl_recv {
if ( req.method == "POST" && req.url ~ "^/xmlrpc.php$" ) {
return (pass);

2. You want to restrict access to some login page on your website only to a single IP address. Well, let’s see how to achieve this. Here I will be blocking access to my blog’s admin page such that it can only be accessed from a single IP address that I will define in /etc/varnish/default.vcl:

vim /etc/varnish/default.vcl

acl admin_whitelist {

sub vcl_recv {
if ((( req.url ~ "^/wp-admin/$" ) || ( req.url ~ "^/login$" ) || ( req.url ~ "^/wp-login.php$" )) && !( client.ip ~ admin_whitelist )) {
return (synth(403," "));

Above code in default.vcl will make sure that when ever a request is made to admin page, it will return a 403 Forbidden error message if the IP address is not mentioned in acl admin_whitelist { block. “X.X.X.X” and “XX.XX.XX.XX” are the external IP addresses from where you want to allow access. Now if you impletement it, you will see the error messge but you will also see another contents such as Guru Meditation, Varnish server, XID etc. which makes the page kind of look ugly. We want a simple, clean page displaying the error only and nothing else.

Well, default.vcl is here to rescue again. Let’s edit the same file again:

# vim /etc/varnish/default.vcl

sub vcl_synth {
set resp.http.Content-Type = "text/html; charset=utf-8";
if (resp.status == 403) {
synthetic( {"
<h2>Access denied!</h2>
"} );
else {
synthetic( {"
<h3>Something went wrong, please contact administrator at: <a href="mailto:admin@example.com">admin@example.com</a></h3>
"} );
return (deliver);

Restart the Varnish service and bingo! you have custom error page for varnish. You can add any code there to execute when a 403 error is encountered or any other error. Just make sure to add another block, for example, you want to show a custom page for “500 Internal Server” error, varnish is the way to go.

There are much more advanced implementations regarding varnish which you can create simply by using one configuration file, default.vcl. Google is an awsome place to start and if you want to get your hands really dirty with varnish, then head to the official varnish guide. It has ample amount of samples which you can use/implement. Official varnish guide can be found here. Just make sure to choose the guide which matches your version of varnish. There are a lot of changes in the syntax for Varnish 3 and Varnish 4.

I hope this has been informative for you. Adios till next time!

I had a lot of issue with php-fpm and nginx services being run on this very server, they goes in to dead state with the error: service dead but pid file exists. And sometimes it happens that some service gets exited without any valid error or anything, and if you are running a small blog like me, then you do not goto the extent to have another server and configure nagios which will keep track of your server services and files. Hence, the idea of a script came to my mind. What this simple script does is, check the status of three services (which are mentioned in the script and you may add more), if the service  is running, no action is taken, if the service is not running for any reason, this script will try to start that particular service. Moreover, if there are issues while starting a particular service, the script will shoot an email to the user (also mentioned in the script) with the status.

After that, I added a cron to run this script every 5 minutes. So basically these three services (php-fpm, mysql and nginx) are checked every 5 minutes. This serves the purpose until you find the root cause of the error mentioned above. Feel free to use this script at your discretion and make changes to it.

#!/usr/bin/env bash
# Date: 20 November, 2014
# Author: Aman Hanjrah
# License: GPL
# About: This is a minimal script that will check the status of services (php-fpm, mysql and nginx), if some problem is found, it will try to restart the service automatically, if not successful, it will shoot an email as defined in "$EMAIL" variable
# Start
# Define administrator email address
# Check php-fpm service
function chkPhpFpm() {
CHK_FPM=$(/etc/init.d/php-fpm status)
if [[ $(echo $?) != 0 ]]; then

# Try to restart the php-fpm service if issues are encountered
function strtPhpFpm() {
STRT_FPM=$(/etc/init.d/php-fpm restart)
if [[ $(echo $?) != 0 ]]; then
# Shoot an email to administartor in case restart fails
echo -e "An attempt to restart php-fpm service FAILED!" | mutt -s "MANUAL INTERVENTION REQUIRED - php-fpm" -- $EMAIL

# Check nginx service
function chkNginx() {
CHK_NGINX=$(/etc/init.d/nginx status)
if [[ $(echo $?) != 0 ]]; then

# Try to restart the php-fpm service if issues are encountered
function strtNginx() {
STRT_NGINX=$(/etc/init.d/nginx restart)
if [[ $(echo $?) != 0 ]]; then
# Shoot an email to administartor in case restart fails
echo -e "An attempt to restart nginx service FAILED!" | mutt -s "MANUAL INTERVENTION REQUIRED - nginx" -- $EMAIL

# Check MySQL service
function chkMysql() {
CHK_MYSQL=$(/etc/init.d/mysqld status)
if [[ $(echo $?) != 0 ]]; then

# Try to restart the php-fpm service if issues are encountered
function strtMysql() {
STRT_NGINX=$(/etc/init.d/mysqld restart)
if [[ $(echo $?) != 0 ]]; then
# Shoot an email to administartor in case restart fails
echo -e "An attempt to restart MySQL service FAILED!" | mutt -s "MANUAL INTERVENTION REQUIRED - mysql" -- $EMAIL

function main() {
# End

After that, just add a cron entry as following:

# crontab -e

*/5 * * * * /bin/sh /path/to/script_name.sh > /dev/null

In case you have any comments or questions, or advice on how can I make this script more advanced, feel free to update the comments section below.

Coming from irssi, getting accustomed to weechat was not that difficult as both these IRC clients are very robust and works on a terminal directly. Weechat adds a nifty feature which is not supported by irrsi so far which made me to make this transformation at the first place.

Few words about weechat:

From the wiki, “WeeChat (Wee Enhanced Environment for Chat) is a free and open-source Internet Relay Chat client, which is designed to be light and fast. 

The client uses a curses frontend, and there are remote interfaces for Web, Qt, Android and Emacs.

In WeeChat everything can be done with a keyboard, though it also supports mouse. It is customizable and extensible with plugins and scripts.” In addition to that, it also supports SSL connections, Proxy connections Scripting support for various languages such as Perl, Python, Ruby, Tcl, Ruby etc. You can check out full feature list at weechat website or wiki.

Case Scenario:

One server (normally a VPS) runs weechat in a nifty utility called screen, this instance of weechat being a relay so that it accepts connections from anywhere around the world. You (being at the client end) and not on the server directly, connects to this relay and use weechat just like it is running on your own system.

Reason: If your ISP blocks connection to IRC or if you are at your work place where connection to IRC is blocked, then this setup will surely work for you and at the same time makes sure that your actual IP (work pace or ISP) does not show up in IRC logs, the IP will be of your server where this instance of weechat is running. As a server administrator, we love IRC because we can share different ideas on different technologies, that too in different channels. It is important to mention here that although IRC is very useful, it is also very dangerous. Dangerous in terms of network hacking, system crashing etc. IRC, for a layman is an invite to a hacking attempt but if you know how to use it, there is nothing better than this.

Below image can depict the scenario more clearly.



IRC weechat explained

Now that you have acquainted with the required setup, let’s dive into the setup.

Configuring WeeChat for Relay:

This is time to configure the setup. Follow the steps mentioned below:

1. First, install two following programs called ‘screen‘ and ‘weechat‘:

# yum install screen -y
# yun install weechat -y

2. Run weechat in the screen program so that even if you quit the SSH session, weechat will be running in the background. Important point to keep in mind here is to run the weechat as normal user and not as ‘root’ for security reasons:

# su - username
$ screen && weechat

3. Following command must be run inside weechat to configure the setup properly and not on shell/terminal itself:

/set weechat.network.gnutls_ca_file "/etc/pki/tls/certs/ca-bundle.crt"
/set irc.server.freenode.ssl_dhkey_size 1024
/set weechat.network.gnutls_ca_file "/etc/pki/tls/certs/ca-bundle.crt"
/set irc.server.freenode.addresses "chat.freenode.net/7000"
/set irc.server.freenode.ssl on
/set irc.server.freenode.ssl_dhkey_size 1024
/connect freenode

Some changes: /etc/pki/tls/certs/ca-bundle.crt” is the path to ca-certificates bundle package. If you do not have them installed, you can install it as:

# yum install ca-certificates -y

4. Basic configuration is now finished and you should have your weechat configured. It is now time to configure the relay so that you can connect to it using any weechat client, my favorite is “Glowing Bear“. It’s time to configure Glowing Bear to make connection to the weechat relay that we have configured in previous step.

Configuring Glowing Bear for relay connection:

Glowing Bear is my favorite tool to connect to my unattended weechat relay that is running on one of my VPS’s. It is browser based, so any modern browser should be able to run it without any issues. Let’s get it configured:

1. Visit glowing bear homepage which will present a nice and sleek design interface. The relay has not yet been configured, hence we will do that first. To setup relay, head back to weechat window and run the following to add an unencrypted relay:

/set relay.network.password yourpassword
/relay add weechat 9001

2. The above step will run the relay on port 9001 which is not encrypted. To get the connection encrypted, you need to generate the SSL certificates first. On the server shell/terminal (not the weechat window), run the following as normal user:

$ mkdir -p ~/.weechat/ssl
$ cd ~/.weechat/ssl
$ openssl req -nodes -newkey rsa:4096 -keyout relay.pem -x509 -days 365 -out relay.pem -subj "/CN=localhost/"

3. The above step will generate a self-signed SSL certificate which we will make use of in order to encrypt the connection. Next, head over to the weechat window and run the following:

/relay sslcertkey
/relay add ssl.weechat 8000

4. Now your relay is configured and that too encrypted. You can check from the server shell (not weechat) if any service is running on port 8000 using:

# lsof -i:8000

Having said that, everything is in place and now there is only one minor thing to take care of: before trying to connect, you actually need to accept the self signed certificate manually in order to connect to your relay. This is something browser specific and not an issue with either weechat or glowing bear. If you have already opened up the glowing bear homepage, click on “Encryption instructions” and you will see the reason.

Head over to a browser (Chrome or Firefox) and access: https://yoursiteURL.xxx:8000 and accept the certificate. Then try to connect using glowing bear’s homepage (Connection Settings).

1. “localhost” should be replaced with your own URL/IP of VPS on which this relay has been configured.

2. Port number ‘9001’ should be replaced with ‘8000’ as we are running encrypted connection there.

3. “WeeChat relay password” is the one which we used at the time of relay configuration.

If you face any issues or have any queries, you are most welcome to leave a comment below!

postfix, dovecot and roundcube on CentOS 6

This is part 3 in this series and the last one. Once you have finished this part, you should have a very robust email server which is battle ready for any small to middle size enterprises as in this tutorial, we will add DKIM signatures and add a roundcube plugin called ‘Seive’ to fight against SPAM messages easily as it will allow you to add rules to emails directly from your mailbox settings in roundcube instead of adding them from command line, which is a complex task for most of the normal users. Let’s first start by configuring the openDKIM and integrate it with your postfix installation.

Configuring openDKIM:

A word: DKIM is short for ‘Domain keys Identified Mail’ which is used widely to sign and verify an email. Basically it works in a way that receiving SMTP server check the DKIM signatures for verification that the message was actually sent/originated from the domain in question and is not a spam. Configuring OpenDKIM with your postfix server is pretty straight forward and should not take more than 10 – 15 minutes. So, let’s dive in.

Steps involved are as follows:

1. Install EPEL repo if you have not done so already:

rpm -Uvh http://mirror.pnl.gov/epel/6/i386/epel-release-6-8.noarch.rpm

2. Install opendkim package:

# yum install opendkim

3. Configure openDKIM: The main configuration file is located at: /etc/opendkim.conf and we need to edit it, before we do so, make sure you have the backup of this file.

# cp /etc/opendkim.conf /etc/opendkim.conf.bak

# vim /etc/opendkim.conf

AutoRestart				Yes
AutoRestartRate			10/1h
LogWhy					Yes
Syslog					Yes
SyslogSuccess			Yes
Mode					sv
Canonicalization		relaxed/simple
ExternalIgnoreList		refile:/etc/opendkim/TrustedHosts
InternalHosts			refile:/etc/opendkim/TrustedHosts
KeyTable				refile:/etc/opendkim/KeyTable
SigningTable			refile:/etc/opendkim/SigningTable
SignatureAlgorithm		rsa-sha256
Socket					inet:8891@localhost
PidFile					/var/run/opendkim/opendkim.pid
UMask					022
UserID					opendkim:opendkim
TemporaryDirectory		/var/tmp

Setup Public and Private Keys:

We will need to define the domain name at a couple of places in this section, hence we will create a simple variable with domain name in it. It is nothing but less typing :)

# DOMAIN="domain.com"

NOTE: This ‘domain.com’ parameter here is the one that you will be using to send out emails, for example, if you will be using email address in format: abc@example.com, then ‘domain.com’ here will be ‘example.com’.

1. We will first need to generate the keys for your domain name as follows:

# mkdir /etc/opendkim/keys/"$DOMAIN"

opendkim-genkey -D /etc/opendkim/keys/"$DOMAIN"/ -d "$DOMAIN" -s default

chown -R opendkim: /etc/opendkim/keys/$DOMAIN

mv /etc/opendkim/keys/"$DOMAIN"/default.private /etc/opendkim/keys/"$DOMAIN"/default

2. Add the domain name in key table by editing the file at: /etc/opendkim/KeyTable

# echo "default._domainkey."$DOMAIN" "$DOMAIN":default:/etc/opendkim/keys/"$DOMAIN"/default" >> /etc/opendkim/KeyTable

3. Add the following record in the file /etc/opendkim/SigningTable as:

echo "*@$DOMAIN default._domainkey.$DOMAIN" >> /etc/opendkim/SigningTable

4. Edit the file at /etc/opendkim/TrustedHosts and add/append the following (this must include the loopback address, the domain name and the hostname of your server):

# vim /etc/opendkim/TrustedHosts

5. It is time to edit/update the DNS zone file from your DNS manager. Open up the file at: /etc/opendkim/keys/mydomain.com/default.txt and copy the contents. In this file, you should find something similar to:

default._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDApHRr7ZmXRaAB+RQRbP4VdMwIrIHIP18KFtXRsv/xpWc0Gix6ZXN13fcG03KNGKZo2PY+csPkGC5quDnH5V0JEhDZ78KcDWFsU6u4fr9ktVAdt6P7jWXjcyqdHOZ8+YN4cAeU4lRFNgQvdupIcByYwzPYMgBFHfJm9014HvRqhwIDAQAB" ) ; ----- DKIM key default for domain.com

In your DNS manager, the should go in a similar way as depicted in the following image. DNS managers differ from provider to provider but the DKIM records should be TXT records and nothing else.

dkim entry in DNS manager

dkim entry in DNS manager


6. In addition to DKIM, it is advisable to add SPF records as well which is a mechanism to check which mail servers are permitted to send email on behalf of your domain. The purpose of an SPF record is to prevent spammers from sending messages with forged From addresses at your domain. An SPF record is also a TXT record and should be updated from your DNS manager as well. In order to generate an SPF record for your domain, you can refer to the links here and here.

Integrate OpenDKIM with Postfix:

In order to make recently configured OpenDKIM with Postfix, you need to add the following lines to configuration file of postfix (/etc/postfix/main.cf):

smtpd_milters = inet:
non_smtpd_milters = $smtpd_milters
milter_default_action = accept
milter_protocol = 2

That is it, the configuration is updated and not it’s time to test it. Try to send an email and keep an eye on the maillog file at: /var/log/maillog. When you send an email, the DKIM should do it’s magic and add the signatures. You should see something similar to following:

dkim signatures

dkim signatures


Also, in the mailbox of receiving end, you should see that the email that we sent is signed:

dkim signatures

dkim signatures


To test yet again if the setup is configured correctly, you can send in a test email to “check-auth@verifier.port25.com”. After few minutes, you will receive a detailed report in following format:



Summary of Results
SPF check: pass
DomainKeys check: neutral
DKIM check: pass
DKIM check: pass



Next, we will configure server-side email filtering with dovecot’s seive using roundcube.

Getting Sieve setup and running:

The Seive plugin is a part of a project called “Pigeonhole” which makes use of the Sieve language and ManageSieve protocol and also adds to the Dovecot. These rules can be managed easily using roundcube for adding/managing server side filter rules.

Let’s get our hands dirty and configure this yet another add-on to your setup:

1. ManageSieve protocol in Dovecot is enabled by a package called dovecot-pigeonhole which we will install:

# yum install dovecot-pigeonhole

2. Next, we need to edit the main configuration file for Dovecot which is at: /etc/dovecot/dovecot.conf:

# vim /etc/dovecot/dovecot.conf

protocols = imap lmtp sieve

add auth-master unix-listener to service auth

service auth {
 unix_listener auth-client {
 group = postfix
 mode = 0660
 user = postfix

unix_listener auth-master {
 group = virtmail
 mode = 0660
 user = virtmail

user = root

and add the following to the end of the configuration file:

service managesieve-login {
 inet_listener sieve {
 port = 4190
service managesieve {
protocol sieve {
 managesieve_max_line_length = 65536
 managesieve_implementation_string = dovecot
 log_path = /var/log/dovecot-sieve-errors.log
 info_log_path = /var/log/dovecot-sieve.log
plugin {
 sieve = ~/.dovecot.sieve
 sieve_global_path = /etc/dovecot/sieve/default.sieve
 sieve_dir = ~/sieve
 sieve_global_dir = /etc/dovecot/sieve/global/
lda_mailbox_autocreate = yes
lda_mailbox_autosubscribe = yes
protocol lda {
 mail_plugins = $mail_plugins autocreate sieve quota
 postmaster_address = postmaster@domain.com
 hostname = mail.domain.com
 auth_socket_path = /var/run/dovecot/auth-master
 log_path = /var/log/dovecot-lda-errors.log
 info_log_path = /var/log/dovecot-lda.log
protocol lmtp {
 mail_plugins = $mail_plugins autocreate sieve quota
 log_path = /var/log/dovecot-lmtp-errors.log
 info_log_path = /var/log/dovecot-lmtp.log

3. Add/create the files that are necessary which are mentioned in the above configuration:

# touch /var/log/dovecot-lda-errors.log
# touch /var/log/dovecot-lda.log
# touch /var/log/dovecot-sieve-errors.log
# touch /var/log/dovecot-sieve.log
# touch /var/log/dovecot-lmtp-errors.log
# touch /var/log/dovecot-lmtp.log

# mkdir -p /etc/dovecot/sieve/global
# chown virtmail: -R /etc/dovecot/sieve
# chown virtmail:mail /var/log/dovecot-*

4. This is the point where we restart dovecot service:

# service dovecot restart

5. Make sure that sieve is running on port number 4190

# netstat -tunlp | grep :4190

6. Next, we will create a SPAM rule such that anything that match this up, should be marked as SPAM by SpamAssassin, also it will be moved to ‘spam’ directory automatically. For this to happen, we need to add this rule to the file at /etc/dovecot/sieve/default.sieve:

# vim /etc/dovecot/sieve/default.sieve

require ["fileinto"];
# rule:[SPAM]
if header :contains "X-Spam-Flag" "YES" {
fileinto "Spam";
# rule:[SPAM2]
elsif header :matches "Subject" ["*money*","*Viagra*","Cialis"] {
fileinto "Spam";

7. To make these rules work, we need to make few entries in the two main configuration files for postfix (/etc/postfix/main.cf and /etc/postfix/master.cf):

# vim /etc/postfix/main.cf

virtual_transport = dovecot
dovecot_destination_recipient_limit = 1


# vim /etc/postfix/master.cf

dovecot unix - n n - - pipe
flags=DRhu user=virtmail:virtmail argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${recipient}

8. Restart postfix service to make the changes effective:

# service postfix restart

Enable Sieve in roundcube configuration:

In order to use Sieve, we need to enable this plugin for sieve in roundcube configuration. Luckily, there is already a plugin available for roundcube and all that needs to be done is to enable it. Steps for roundcube > 1.x are different than 1.x versions. If you are using older version of roundcube, then you need to consult the documentation for that version only. It is not at all hard if you have reached this far ;).

Configuring Sieve plugin for roundcube:

Steps are as follows:

1. Edit the file “config/main.inc.php” which should in the document root of your roundcube installation:

# vim main.inc.php

## search for the string "plugins" and enable managesieve

$config['plugins'] = array(
# 'plugin_manager',

2. That is it! Now log into your mailbox account using roundcube and when you browse to Settings, you will see another option added there by the name of ‘Filters’. You can have a look into it and add new rules or delete old ones according to your wish. This filter setting will be enabled to all of your clients who log into their mailboxes using roundcube.

Postfix, Dovecot, RoundCube and Sieve along with SSL certificates configured makes a very strong, enterprise level SMTP server which you can configure using the documentation here. This was part 3 and last in the series of these postfix tutorials.

You can find the previous two parts in this series below:

Postfix, Dovecot and roundcube – Part 1

Postfix, Dovecot and roundcube – Part 2

I hope you enjoyed reading this documentation as much as I enjoyed writing them.

Adios till next time!

postfix, dovecot and roundcube on CentOS 6


This is the follow up of previous tutorial in the series where we configured postfix, dovecot with roundcube webmail interface. You can find the first part here. In this part, we will configure SSL certificates for webmail and dovecot so that all your traffic will be encrypted. In this setup, I will first be generating self signed SSL certificates and then incorporate them with roundcube webmail interface along with dovecot for encrypted IMAP/POP3 connections. So let’s get to work.


Configure SSL certificates:

I will generate SSL certificates in a temporary directory and then move them to appropriate location.

# mkdir -p /tmp/ssl/domain.com
# cd /tmp/ssl/domain.com
# openssl genrsa -des3 -out domain.com.key 2048
# openssl req -new -key mydomain.com.key -out domain.com.csr
# openssl x509 -req -days 365 -in domain.com.csr -signkey domain.com.key -out domain.com.crt
# cp -v domain.com.key domain.com.key.original
# openssl rsa -in domain.com.key.original -out domain.com.key

# chmod 0400 domain.com.key
# cp -v domain.com.crt /etc/pki/tls/certs
# cp -v domain.com.key domain.com.csr /etc/pki/tls/private

Next, will use these generated SSL certificates in webmail configuration, SMTP and IMAP/POP3.

Setup roundcube over SSL:

Installing SSL certificates differs from web server to web server, as I am using nginx as web server, I will be adding the necessary details in my webmail configuration file under nginx. The entries below should go under the server block directly in webmail configuration file.

# vim /etc/nginx/conf.d/webmail.conf
ssl on;
ssl_certificate /etc/pki/tls/certs/domain.com.crt;
ssl_certificate_key /etc/pki/tls/private/domain.com.key;
ssl_session_timeout 5m;

Really, that is it, reload the nginx service and you have your webmail running on port number 80 and 443 (/etc/init.d/nginx reload). If you want to redirect plain requests (port 80) to SSL enabled ones (port 443) automatically, then you need to add a rewrite rule in your nginx configuration file such that any request received at port 80 should be forwarded automatically to port 443. For this, you would need to add following rule in server block in your webmail configuration which is catering plain requests:

server {
listen 80;
servername mail.domain.com;
return 301 https://$host$request_uri;

Setup SMTP over SSL:

In order to send emails using SMTP over SSL, you would need to enable SSL support in postfix. Edit the two files below, start with /etc/postfix/main.cf and add the following towards the end:

# vim /etc/postfix/main.cf

smtpd_use_tls = yes
smtpd_tls_key_file = /etc/pki/tls/private/domain.com.key
smtpd_tls_cert_file = /etc/pki/tls/certs/domain.com.crt

smtpd_tls_loglevel = 3
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom

after that edit /etc/postfix/master.cf and add/append the following:

# vim /etc/postfix/master.cf

smtps inet n - n - - smtpd
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes

Restart the Postfix service so that the changes made above could be in effect using: /etc/init.d/postfix restart

Setup IMAPs and POP3s:

In order to enable SSL with IMAP and POP3, edit configuration file for dovecot and add/append the following:

# vim /etc/dovecot/dovecot.conf

protocols = imap pop3
ssl = yes
ssl_cert = </etc/pki/tls/certs/domain.com.crt
ssl_key = </etc/pki/tls/private/domain.com.key

restart the dovecot service as: /etc/init.d/dovecot restart. You can check if the IMAPs and POP3s services are up by doing lsof as:

# lsof -i:993
# lsof -i:995

Install Spamassassin:

Spamassassin is an application (more of a tool) which is used for e-mail spam filtering. It does so by matching the content in an email and the rules defined. We will go ahead and install it first, followed by some configurations.

# yum install spamassassin

Next, we will create a group and user which will be used to start/stop/restart the spamassassin service:

# groupadd spamfilter
useradd -g spamfilter -s /bin/false -d /usr/local/spamassassin spamfilter
chown spamfilter. /usr/local/spamassassin

Configure the SPAM rules by editing the following file:

# vim /etc/mail/spamassassin/local.cf

required_hits 5
report_safe 0
rewrite_header Subject [***SPAM***]
required_score 5.0

Next, change the user under which the spamassassin service should run, if not defined, then it will be run as root but as we have already added a new dedicated user for this, let’s change that in the following file:

# vim /etc/sysconfig/spamassassin

SPAMDOPTIONS="-d -c -m5 --username ${SUSER} -H ${SAHOME} -s ${SAHOME}/spamfilter.log"

It’s time to start the spamassassin service: /etc/init.d/spamassassin start and make it start it on every boot as: chkconfig spamassassin on.

Postfix Configuration for Spamassassin:

This is necessary in order to incorporate the newly configured spamassassin with postfix such that postfix will receive an email and then it will be passed onto spamassassin to check if the received email is a SPAM or not, based on the rule-matching criteria. Edit master.cf file which is placed at /etc/postfix:

# vim /etc/postfix/master.cf

smtp inet n - n - - smtpd -o content_filter=spamassassin
spamassassin unix - n n - - pipe user=spamfilter argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}

restart the postfix service as: /etc/init.d/postfix restart.

Testing the setup:

In order to test the spamassassin setup, you would first need to create a rule for content-matching. You can create a rule in file /etc/mail/spamassassin/local.cf or if you face any issues, you may head over to Dave Taylor’s tutorial on how to do this by clicking here.

Once you have the desired rules added, try to send in a test email with the same words that you have blocked and check your mailbox, that particular email should’ve landed in SPAM folder automatically.

In the next part, we will be adding OpenDKIM signatures to your emails along with configuration of Dovecot Sieve so that you can add spam rules directly from roundcube web interface instead of making entries in the files manually.

For previous tutorial, please click the below:

Postfix, Dovecot and roundcube – Part 1

I hope this was informative for, if you have any queries or comments, leave them below in the comments section. Bye for now!

ejabberd chat server on CentOS 7

Hi people, every now and then, I feel to have a need of a private chat server which me and my friends can use and are sure that no matter what we talk about, the logs should not go out to third party servers. Well, it’s pretty easy actually, you can create your own chat server using good old ejabberd software which has been around for a pretty decent time now and is well tested within organizations.

In this tutorial, I will walk you through the steps you need to configure a chat server on CentOS 7 machine. Fasten your seat belts, we are going to take a small ride (of course virtual one) in the technology wagon and explore ejabberd.

Installing ejabberd on CentOS 7

As there is no RPM package as of now for EL7 (not even in epel), we need to go ahead and install it from source, so head over to the website and get the installer package, which as of this writing is 16 MB. To go to the download page, click here. Download the installer package which suits your CentOS installation (32-bit or 64-bit), in my case, I downloaded 64-bit version. This will download the installer package named as: “ejabberd-14.07-linux-x86_64-installer.run”. Once download completes, make sure this is executable by running the following command:

# chmod +x ejabberd-14.07-linux-x86_64-installer.run

Run the installation and follow the on screen instructions:

# ./ejabberd-14.07-linux-x86_64-installer.run

1. Language selection, press ‘Enter’ for English.

2. Read the license agreement, press ‘Enter’ a couple of times and when finished, it will ask you to accept it by pressing ‘y’ for yes or ‘n’ for no. Press ‘y’ and hit enter.

3. Specify the installation directory, by default it will place the files at: ‘/opt/ejabberd-13.07’ which is fine for most of the cases, hit ‘Enter’ to chose this default installation path or specify your own.

4. Next, specify the domain name, by default ‘localhost’ will be set but I would recommend you to set to FQDN which must be resolvable using hosts file or the DNS. This is because when you will add users, you will need to use this domain (resolvable) as well, in my case, i choose ‘techlinux.net’, so when I create a user, it will be as: aman@techlinux.net which will be my XMPP ID on this server.

5. Administrator username: ‘admin’ is by default and I will let it be, because I can add other users after the initial configuration. This ‘admin’ user will only be used to manage ‘stuff’ from a GUI.

6. Administrator password: Make sure to set it to something very strong and safe it in a secure location. If someone get’s their hands on this password, then they can control your XMPP (chat) server from a web browser as we will see in few steps.

7. Is this node a part of a cluster? I don’t think so, hit ‘Enter’ and it will choose ‘No’ by default.

8. Installation is ready to be performed, hit ‘y’ and hit ‘Enter’ to install the setup.

9. View ‘Read Me’ file, press ‘n’ and hit ‘Enter’.


What you should see?:

ejabberd installation

You can view the directory structure by “cd’ing” into: /opt/ejabberd-14.07/, we are mostly interested into two of them, that is: bin/ and conf/ directories.

bin/ – it contains all the binaries to start/stop the ejabberd services.

conf/ – it has all the configuration files which you can play with on your own.

We will go ahead and start the service now:

# cd /opt/ejabberd-14.07/bin/

# ./ejabberdctl start //this will start the service and web interface on port number 5280

To manage the users and hosts, and apparently anything, you can log into the web interface as:


where X.X.X.X is the IP address of the server or you may use the domain name if it is resolvable.

What you should see?:

ejabberd web interface

NOTE: When you first access the web interface, it will ask for a username and a password, use the full username including the domain as: admin@FQDN (in my case, I used: admin@techlinux.net) with the associated password.


<h2>How to connect to your server using Pidgin </h2>

<h3>  Some notes about pidgin </h3>

Pidgin (previously known as GAIM), as most of the people who uses Linux OS for their daily use know, is the favorite chat client that can add multiple accounts (AIM, Facebook [XMPP], Gadu-Gadu, Google Talk, ICQ, IRC, MSN, Yahoo etc.) at a single place. It also let you add any chat service that works on XMPP. That is where our chat server comes into action, as it is also based on XMPP, we can certainly configure it using Pidgin. Steps are as follows:

1. Download and install Pidgin for windows from: https://www.pidgin.im/download/windows/.

People using Linux as their desktops can install it from their OS repository, for example, in Arch Linux, I would simply do the following which will install Pidgin:

# pacman -Sy pidgin

2. Run it and click on ‘Accounts > Manage Accounts > Add‘.

3. Details should be as follows:

Protocol: XMPP

Username: aman.hanjrah (this would be the user using which you want to connect to your chat server)

Domain: techlinux.net (this would be the domain name for which you have configured your chat server in one of the steps mentioned above in the section: Installing ejabberd on CentOS 7)

Resource: You can leave this empty.

Password: Associated password.

Remember password: checked.

Local alias: If you want to give a local alias to the users that would appear in your friend list.

4. Click ‘Add’.

5. Accept the certificate and you should be logged in successfully. If not, you will see the error message in the main Pidgin window to the downward as shown in the screen shot below.

error message while connecting


6. You have now configured your chat server correctly and it should be all set to accept chats. Add another account and ‘add’ that user in your friend list for testing purposes, then try to send messages over.

For advanced options, you can download (or view online) the “ejabberd” documentation which has some pretty neat functionality you may opt for your chat server. You can find it at:


I hope this has been informative for you, in case you have any queries, feel free to leave a comment below.

postfix, dovecot and roundcube on CentOS 6

Hi there people. I know it’s not my thing to post tutorials one after another but I could not resist. This one is big and is divided into few parts (as you can tell ;)). In this tutorial, I will walk you through creating a perfect mail server on a CentOS 6.5 box using the best MTA out there, that is, postfix, dovecot roundcube. Before moving forward, make sure your server’s hostname is a FQDN. Once you are sure of that, continue with the below.

From here, you have three options to save the users and their respective emails on the server which are mentioned below:

1. On the physical system: You will create physical user accounts on the system for each user who will be using the email service on your server.

2. In MySQL database: User data along with their passwords will be saved in MySQL database and users will be authenticated from there.

3. Virtual users: In this setup, you will create a list of virtual users on the server and their mailboxes will be defined in a directory (one directory per user). This is the setup we are going with in this series.


# yum update -y


Create the following group and user that will be used by the services

# groupadd virtmail -g  2100

# useradd virtmail -r -g  2100 -u 2100 -d /var/virtmail -m


Remove any other MTA from the server if any

# yum remove sendmail exim -y

# yum install postfix -y

Edit postfix configuration file and add/append the following:

# vim /etc/postfix/main.cf
queue_directory = /var/spool/postfix
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix
mail_owner = postfix
unknown_local_recipient_reject_code = 550

alias_maps = hash:/etc/aliases
alias_database = $alias_maps

inet_interfaces = all
inet_protocols = ipv4

mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain

debug_peer_level = 2
debugger_command =
         ddd $daemon_directory/$process_name $process_id & sleep 5

sendmail_path = /usr/sbin/sendmail.postfix
newaliases_path = /usr/bin/newaliases.postfix
mailq_path = /usr/bin/mailq.postfix
setgid_group = postdrop
html_directory = no

manpage_directory = /usr/share/man
sample_directory = /usr/share/doc/postfix-2.6.6/examples
readme_directory = /usr/share/doc/postfix-2.6.6/README_FILES

relay_domains = *

virtual_mailbox_base = /var/virtmail
virtual_minimum_uid = 2100
virtual_transport = virtual
virtual_uid_maps = static:2100
virtual_gid_maps = static:2100

smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = /var/run/dovecot/auth-client
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
smtpd_sasl_local_domain = $mydomain
broken_sasl_auth_clients = yes

smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

Create virtmail-mailbox file which will hold the user’s mailboxes

vim /etc/postfix/virtmail_mailbox

#user                                 #Mailbox Directory
aman.hanjrah@techlinux.net            techlinux.net/aman.hanjrah/
a.hanjrah@techlinux.net               techlinux.net/a.hanjrah/
a.hanjrah@seconddomain.com            seconddomain.com/a.hanjrah/
aman.hanjrah@seconddomain.com         seconddomain.com/aman.hanjrah/

The above will create the directories at: ‘/var/virtmail/techlinux.net/aman.hanjrah’ and ‘/var/virtmail/seconddomain.com/a.hanjrah’, for examples.

Next, we will add the virtual domains on this server, create a file named virtmail_domains

# vim /etc/postfix/virtmail_domains
techlinux.net          OK
seconddomain.com       OK

Create the virtual aliases (virtmail_aliases) file which will hold the records for aliases, but they would be virtual, as

# vim /etc/postfix/virtmail_aliases
aman.hanjrah@techlinux.net          aman.hanjrah@techlinux.net
a.hanjrah@seconddomain.com          anything@foobar.tld

Virtual aliases works in the same way as aliases work, they forward the message to another account if defined.

Next, hash the above three files using postmap, any changes to these files will not work unless you hash them

# postmap /etc/postfix/virtmail_domains
# postmap /etc/postfix/virtmail_mailbox
# postmap /etc/postfix/virtmail_aliases
# touch /etc/postfix/aliases

Open the submission port/service

# vim +/submission /etc/postfix/master.cf

submission inet n       -       n       -       -       smtpd


Install dovecot if you haven’t done that already and edit the configuration file

#yum install dovecot

# vim /etc/dovecot/dovecot.conf
listen = *
ssl = no
protocols = imap lmtp
disable_plaintext_auth = no
auth_mechanisms = plain login

mail_access_groups = virtmail
default_login_user = virtmail

first_valid_uid = 2100
first_valid_gid = 2100

mail_location = maildir:/var/virtmail/%d/%n

passdb {
    driver = passwd-file
    args = scheme=SHA1 /etc/dovecot/passwd
userdb {
    driver = static
    args = uid=2100 gid=2100 home=/var/virtmail/%d/%n allow_all_users=yes
service auth {
    unix_listener auth-client {
        group = postfix
        mode = 0660
        user = postfix
    user = root
service imap-login {
  process_min_avail = 1
  user = virtmail

Next, create a ‘passwd’ file which will store all the usernames and passwords for authentication. We will generate hashed values instead of plain text passwords

# touch /etc/dovecot/passwd
# doveadm pw -s sha1 | cut -d '}' -f2

save the generated password in following file

# vim /etc/dovecot/passwd


Setup permissions on ‘passwd’ file

# chown root: /etc/dovecot/passwd
# chmod 600 /etc/dovecot/passwd


# chkconfig postfix on
# chkconfig dovecot on
# service postfix restart
# service dovecot restart

This completes the basic email server setup which is without any SSL certificates or spam filters, in the coming articles, we will set that up to create a simple yet robust email server.


In order to add another account, just edit the files ‘/etc/postfix/virtmail_mailbox‘ and ‘/etc/postfix/virtmail_aliases‘ and fill in the details just as you did previously. In addition to that, generate a hashed password using ‘doveadm’ and make an entry for this newly created mailbox account in: ‘/etc/dovecot/passwd‘.

Do not forget to run the folowing otherwise the new account will not be operational:

# postmap /etc/postfix/virtmail_mailbox
# postmap /etc/postfix/virtmail_aliases


Roundcube is my favorite web client among others such as squirrelmail and horde, because of it’s speed and features available through plugins. Here, we will install it on our server so that you can access it using a browser and check/send/draft etc. an email just like you do with GMAIL or any other email service providers. As roundcube is a web based email client, it requires a web server, MySQL database (or a variant) and PHP in order to get going. In this setup, I already have web server, MySQL server and PHP installed on my server and all I need to do is add a server block to the web server’s configuration file and point that domain to server’s IP address. For example, if I will be using ‘virtmail.techlinux.net’, then I will be adding a server block for this domain in my web server’s configuration file and point ‘virtmail.techlinux.net’ to my server’s IP address. Having done that, let’s get roundcube up and running.


1. Download the latest roundube archive using wget and save it in /tmp, after that extract it in the document root of, for example, virtmail.techlinux.net, as:

# wget -c "http://sourceforge.net/projects/roundcubemail/files/latest/download?source=files" > /tmp/roundcube.tar.gz

# tar -xvzf /tmp/roundcube.tar.gz -C /usr/share

# cd /usr/share

# mv -v roundcube* roundcubemail

# chown -cR root: roundcubemail/

# chown -cR nginx: roundcubemail/temp/

# chown -cR nginx: roundcubemail/logs/


2. Create the database and grant privileges to this database, make sure you use a strong password as:

# mysql -uroot -p

mysql> create database roundcube;

mysql> grant all privileges on roundcube.* to 'round_user'@'localhost' identified by 'strong_password';

mysql> flush privileges;

mysql> exit;


Next, create the necessary tables for roundcube:

# mysql -u round_user -p roundcube < /usr/share/roundcubemail/mysql.initial.sql


3. Copy the ‘config.inc.php.sample’ file to ‘config.inc.php’ inside the directory structure (/usr/share/roundcubemail/config/) and edit it as:

# vim /usr/share/roundcubemail/config/config.inc.php


$config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail'; 


$config['db_dsnw'] = 'mysqli://round_user:strong_password@localhost/roundcubemail';


$config['smtp_server'] = '';


$config['smtp_server'] = 'localhost';


4. Save and close the above file. Also, remove the ‘installer’ directory as we do not need it, we did the configuration manually.

# rm -rf /usr/share/roundcubemail/installer


5. Finally, restart the web service. I am using ‘nginx’, so I will do the following, in case you are using some other web server, restart the service accordingly:

# /etc/init.d/nginx restart


You can now access your webmail client (roundcube) by accessing the URL:



http://virtmail.techlinux.net (in case you have added a domain/subdomain)

NOTE: In order to receive emails, you need to set a reverse DNS entry as well otherwise the sending SMTP server will not know the location of your server (newly configured ;)) and incoming emails will never make to the inbox of your user’s mailbox.

Now you have the basic webmail server which work with your own domain name.

Next related articles will walk you through configuring SSL certificates for encrypted connections in Postfix, Dovecot and nginx along with how to configure OpenDKIM signatures and SPF records so that the probability of your emails be increased to land in receiver’s inbox instead of SPAM/JUNK folder. That might take some time 😉

Till then, enjoy!

kvm on centos 7

So, I hope everyone of you are doing great. This post has taken more time than I thought and I apologize for that. I was provided a server in office and was told to get some kind of virtualization setup on it for my colleagues so that they can have their own Linux based virtual machines for testing purposes. I am more of a OpenVZ guy and working with KVM was one hell of a ride. Why KVM? First of all, I was told that installation of CentOS 6 over i7 processor did not went so well, hence they had CentOS 7 up and running on this beast. To add more to it, there is no OpenVZ kernel for EL 7 variant yet, so I knew from day one that I need to get my hands dirty. Well, why not, it’s an opportunity to learn something new, so I start my search with KVM. Few words about KVM:
1. It is a Kernel based virtualization, integrated with EL7 by default (lucky me).
2. Unlike OpenVZ, it creates a total isolated environment for guest operating systems, so the wall are strong enough in this one.
3. It does takes toll on the hardrive I/O speeds sometimes but with less number of KVM’s (less than 15) on this i7 hardly made any difference.
Enough said, let’s get to the configuration.
1. Make sure your server supports hardware virtualization by running the following as root, if nothing is displayed, then you are either out of luck or you need to enable virtualization from within the BIOS:

egrep '(vmx|svm)' --color=always /proc/cpuinfo

2. Install the necessary packages (most of them will/should be present, in case they are not, install them):

yum install kvm libvirt python-virtinst qemu-kvm

3. Start ‘libvirt’ daemon and enable it at boot time as:

systemctl start libvirtd && systemctl enable libvirtd

To check if KVM is installed successfully, run the following:

virsh -c qemu:///system list

and you should see something like

[root@techlinux ~]# virsh -c qemu:///system list
Id Name                 State
[root@techlinux ~]#

If you see any errors, then OH BOY!, you did something wrong and go back from here and check the setup again.

4. Install ‘bridge-utils’ package and setup a network bridge so that our guests machines could use it and can be accessed from each other:

yum install bridge-utils

Next, we actually need to create a network bridge. Create a file at: “/etc/sysconfig/network-scripts/ifcfg-br0” and edit it with your favorite editor (vi, vim, nano etc.; I least care unless and until you make the entries right):

vim /etc/sysconfig/network-scripts/ifcfg-br0


Next, modify the main network file for your interface, for example, if your interface is named as ‘eth0’ or ‘eno1’ or ‘enp0s3’ etc, then edit the file at: /etc/sysconfig/network-scripts/ifcfg-eno1′ and make it like following:

vim /etc/sysconfig/network-scripts/ifcfg-eno1


Next, restart the network as:

systemctl restart network

Make sure that the newly created network bridge is listed by doing:

[root@techlinux ~]# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet netmask broadcast
inet6 fe80::56be:f7ff:fe37:ceba prefixlen 64 scopeid 0x20<link>
ether 54:be:f7:37:ce:ba txqueuelen 0 (Ethernet)
RX packets 1749877 bytes 142150172 (135.5 MiB)
RX errors 0 dropped 40 overruns 0 frame 0
TX packets 129457 bytes 25039760 (23.8 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

eno1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
 ether 54:be:f7:37:ce:ba txqueuelen 1000 (Ethernet)
 RX packets 1751503 bytes 173788501 (165.7 MiB)
 RX errors 0 dropped 801 overruns 0 frame 0
 TX packets 129465 bytes 25566348 (24.3 MiB)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
 device interrupt 20 memory 0xf7c00000-f7c20000 

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
 inet netmask
 inet6 ::1 prefixlen 128 scopeid 0x10<host>
 loop txqueuelen 0 (Local Loopback)
 RX packets 28 bytes 3520 (3.4 KiB)
 RX errors 0 dropped 0 overruns 0 frame 0
 TX packets 28 bytes 3520 (3.4 KiB)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
 inet netmask broadcast
 ether 52:54:00:08:e2:b8 txqueuelen 0 (Ethernet)
 RX packets 0 bytes 0 (0.0 B)
 RX errors 0 dropped 0 overruns 0 frame 0
 TX packets 3 bytes 222 (222.0 B)
 TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

[root@techlinux ~]#

5. Installing virt-manager on Archlinux desktop: The following command will install it on your archlinux desktop:

[aman@arch ~]$ sudo pacman -S virt-manager

6. Create CentOS 6 guest from command on the server and make sure you have the CentOS 6 ISO already placed in the following directory on server:


Create the image based CentOS 6 guest as:

virt-install --connect qemu:///system -n cent6tmp -r 1024 --vcpus=2 --disk path=/var/lib/libvirt/images/cent6tmp.img,size=50 -c /var/lib/libvirt/images/CentOS-6.4-x86_64-bin-DVD1.iso --vnc --noautoconsole --os-type linux --os-variant rhel6 --accelerate --network=bridge:br0 --hvm

Output for the above command should be as:

Starting install... Allocating 'cent6tmp.img'              |  50 GB     00:0
Creating domain...                 |    0 B     00:00
Domain installation still in progress. You can reconnect to
the console to complete the installation process.
[root@techlinux ~]#

If you have reached this far, pat yourself on the back because most of the work is done.I have named this guest as ‘cent6tmp’ because this will act as a template for other CentOS 6 guests and instead of installing same variant guest (which is time consuming), we will simply clone this one which is pretty fast on an i7 server (not sure on what processor you are, so speed may vary).Your template guest machine is now ready to be installed. We will not head over the the Archlinux desktop system where we have ‘virt-manager’ waiting to be fired up and do the other tasks. Let’s get that done.

On the ArchLinux box:
1. Start the ‘virt-manager’ application and click on: File > Add Connection, this will show the screen similar to following:



2. Go ahead and edit and fields as:
a). Check the box “Connect to remote host”
b). Method: SSH
c). Username: root
d). Hostname: (IP address of the server)

  1. Once connected, you will see the list of guest OS’es installed as shown in the screen shot below, in my case I have already added (cloned) the guest VM’s, what you will see is only ‘cent6tmp’ with a ‘Running’ status:


4. Double click on ‘cent6tmp’ and it will ask you for the root password of host machine, once you fill in that, you will see the virtual guest OS ready to install, go ahead and install it as you will install CentOS 6 on a physical machine.

  1. Once done, configure that machine (upgrade and stuff) and shut it off from ‘virt-manager’ itself. Now you have a template machine ready to reproduce similar ones and as many as you need, server is the limitation though 😉

Cloning the template guest OS:
1. Right click on ‘cent6tmp’ (keep it shut down) and click on ‘Clone’, you will see a similar window as below:



Some changes: I have my template saved as vm01 instead of cent6tmp, hence think ‘vm01’ as ‘cent6tmp’ whereever necessary.

  1. Change the name of the guest which will be created after clone, you can leave it as it is if you do not care about the names.

  2. Well, hit ‘Clone’. Depending upon the endurance power of your server, this might take some time to finish, I tried it on Core 2 Duo as well, which took around 30 minutes. If you are also on such processor, go grab a cup of coffee and let it finish.

  3. Once done, you will have a clone of ‘cent6os’ which you can boot into using the same username password that you have set for ‘cent6os’ and configure accordingly.

In case you have any queries after that, feel free to ask your questions in the comment section or drop me an email at:


Hope this was informative for you, have a nice day!