I’m not a big fan of windows servers, but sometimes small bussiness have an old computer running an outdated windows server in a more outdated hardware, deal with this systems is not a pleasant experience, old psu and hard disk with a lot of hours are the gates of a disaster, if you can virtualize the OS, you don’t have to deal with outdated hardware.

Virtualization provides a base hardware where you system can run, and this isolates your os <–> physical server relationship.

In a recent case I found an old Pentium D executing W2003 in a degraded intel smart raid ( Fake raid controller ), If one hard disk has died the other one will follow same path.

unfortunately kvm doesn’t emulate fake raid controller that means that when you start your virtualized legacy server it will fail showinga blue screen because is searching for a no present controller.

this is a big problem you should make some steps to avoid BSOD and another hassles.

First you will need to load all IDE references into windows registry, this step is easy, just donwload Mergeide file, uncompress and open mergeide.reg file (more info).

If system was installed directly against raid controller you will need to add some files, Atapi.sys, Intelide.sys, Pciide.sys, Pciidex.sys because aren’t installed and OS will be unable to connect to IDE devices

these files should be in %SystemRoot%\System32\Drivers folder.

if not, you can get from %SystemRoot%\Driver Cache\I386\Driver.cab. Just extract Atapi.sys, Intelide.sys, Pciide.sys, Pciidex.sys files on %SystemRoot%\System32\Drivers folder.

Reboot your old server, check that is still working in the old server, and now you can migrate it. Using clonezilla for example.

To avoid problems with hostname resolution the easy way is use NotworkManager-tui to set you hostname to a FQDN, when you configure your MX registers these point to a hostname, like mail.mydomain.com select your desired FQDN and execute

nmtui

this will show nmtui dialog

select Set system hosname

put your desired hostname and click OK

finaly exit nmtui

and apply changues

systemctl restart systemd-hostnamed

Step 4: Verify postifx local delivery

At this step we will ensure that postfix can send email to local users firstly we will add a two new users joe and alfred

At this point we have an antivirus in our server that is’s updated every 3 hours, viruses is a problem for our users but the BIG problem is spam, most of your users incoming mail will be spam, and our users will complaining about that they can work because lost his precious time removing spam in his incoming mail, another part will be losing her time buying magical blue pills, expensive watches and helping African kings moving her money outside Africa.

more childres uses more ram but delivers more mail at once, one amavisd children consumes near 40% of cpu in a low end server, be careful if you receive a lot of mails at once can be a big punch in your cpu have too many childrens

Amavisd will pass all incoming mail to our antivirus and antispam and verify that we are receiving a clean mail, but at this moment we have postfix and amavisd isolated, we need make a small integration.

At this point we have a working postfix mail server with antivirus and antispam, at this point we can add local user accounts and they will get a mail account. But i prefer to have all users in a database and foget to have hundreds of accounts

vim /etc/my.cnf.d/server.cnf

#
# These groups are read by MariaDB server.
# Use it for options that only the server (but not clients) should see
#
# See the examples of server my.cnf files in /usr/share/mysql/
#
# this is read by the standalone daemon and embedded servers
[server]
innodb_file_per_table
innodb_file_format = Barracuda
# this is only for the mysqld standalone daemon
[mysqld]
# this is only for embedded server
[embedded]
# This group is only read by MariaDB-5.5 servers.
# If you use the same .cnf file for MariaDB of different versions,
# use this group for options that older servers don't understand
[mysqld-5.5]
# These two groups are only read by MariaDB servers, not by MySQL.
# If you use the same .cnf file for MySQL and MariaDB,
# you can put MariaDB-only options here
[mariadb]
[mariadb-5.5]

enable mariadb service

systemctl enable mariadb.service

Start mariadb database server

systemctl start mariadb.service

secure mariadb installation

mysql_secure_installation

follow screen instructions

Optional: if you will need access to database open port using this command

firewall-cmd --permanent --add-service=mysql
firewall-cmd --reload

Remember configure a backup script for your database

Step 10: Generate SSL Certificate

genkey --days 3650 mail.yourdamain.com

follow on screen instructions and this will generate two files.

private part of certificate at

/etc/pki/tls/certs/mail.yourdomain.com.0.csr

and public part of certificate at

/etc/pki/tls/private/mail.yourdomain.com.key

you should get your certificate signed by a certification autority search for one pay and follor certification authority instructions 🙁

At this moment if user try send an email using your new server, it only has support for smtp that is a plain protocol, that means that is really easy read communication contents and get his password. we don’t want this for us.

A long time ago, at the beginning of secure smtp times, that’s 1997. Some people decided that best way to secure smtp will be wrap it over a ssl or tls connection, that means that all connections should be realized starting a ssl/tls session since first data packet.

To differentiate secure and insecure smtp servers the best way it use a port for insecure smtp, 25, and another for secure connections 465. This strategy is a bit irritating because if another server want deliver a email in a secure mode it should verify if port 465 it’s opened.

Two years after some people decided that the best way should be implement STARTTLS this allows to secure our communication over a plain textcommunication at port 25.

it’s recommendable have our certificate signed by and certification authority, sorry you must pay 🙁 . Otherwise you can generate a self-signed certificate which will you a lot of security warnings in mail clients.

with smtp user can send mails but can’t read new emails and maintain philosophical conversations about last season most viewed soap opera.

Receiving emails from server can be done using POP, IMAP or both

In my case i preffer use only IMAP but i will both configurations

POP is older than IMAP if your users reads email from multiple devices IMAP should be better, check users email volume and number of devices to select what configuration fits better for each one, new soap operas are really intense.

For provide POP and IMAP connectivity we will use dovecot, Dovecot also includes SASL support for centralized logins, Tradicionally tutorials uses cyrus-sasl to implement authentication, but dovecot includes a SASL implementation, i will try to use it instead include cyrus-sasl package.

Security parameters appear to be well configured, but if we leave configuration in hand of users, they will try to use plain login, this is easily to sniff we avoid these options

vim /etc/postfix/main.cf

and append these lines

#disallow plain login
smtpd_tls_auth_only = yes

step 31: enable smtp submission port

At this moment we know that our smtp service should run only in port 25, unfortunately some Internet Service Providers decided that the best way to stop spam is deny conections to smtp port. If you leave only port 25 opened some users can’t send email because their ISP deny connections. To solve this problem we can enable SMTP submission port, 587. and forget phone calls from users complaining about that they can’t send email from cafes, or their homes.

amavisd default config will discard spam mail we want to changue this behavior

vim /etc/amavisd/amavisd.conf

and edit final_spam_destiny variable

$final_spam_destiny = D_PASS; #!!! D_DISCARD / D_REJECT

now amavisd will deliver spam messages to inbox and knows what domains are hosted with postfixadmin.

Amavisd sends a copy of email to spamassasin and reads spamassasin results, this means that if spamassasin modifies email subject these will not appears in our detected email. we should modify several parameters in amavis config file to always write spamassasing analysis results.

Our detected spam travels to junk folder, but if forget to train spamassasin we will get a lot of spam in our Inbox folder or false positives in our Junk folder.

To avoid this we can launch sa-learn command but do this by hand is a tedious work. Good sysadmins automatize these task, I make a small script in python, my first python script, to launch sa-learn automatically.

This script will scan each mailbox and check if user has created an extra imap folder, to ignore pop3 only users, adding all mail in junk folder as spam and rest of folders as ham mail.

I created a project in github if you want to colaborate I will accept all help

adding a little of python magic helps to forget about what is learning spamassasin.

A small trick to start this is tell to our user that they should create a folder called nospam or whatever you prefer and recommend users to move false posivitives to this folder and undetected spam to junk folder.

This script scans all mail folders in account and ads all mail as ham except junk folder which is added as spam. You should need to change this behavior feel free to modify this script and colaborate.

Step 37:Enabling greylisting (optional)

One technique to avoid spam is use a greylisting, basically when we receive a mail for first time our mailserver will answer with an internal error forcing to sender, if senders server is well configures it will try in a few minutes to deliver message again and it will be acepted. Spamers doesn’t resend emails they simply forget our mailserver.

So using a greylisting adds delay receiving mails or they can be undelivered because another server isn’t well configured.

SPF (Sender Policy Framework) is basically a TXT dns record that indicates what ips and/or domains are authorized to send email.

A minimal spf record should be like this

spf=v1 mx -all

if your webserver send emails too

spf=v1 a mx -all

if you want to add an ip

spf=v1 a mx ip4:255.255.255.255 -all

in function of what servers will be generating email you should configure your spf records.

Maintain a spf record in your domains is important to avoid that spammers use your domain as as sender part of domain

Step 40: Enabling DKIM

DKIM, DomainKeys Identified Mail, helps to verify that a received email is sender from a valid mail server. Basically is a digital signature that can be verified using a public key published into senders domain dns record.

quarantine -> if check dkim and/or spf fails, Depending on the capabilities of the Mail Receiver, this can mean “place into spam folder”, “scrutinize with additional intensity”, and/or “flag as suspicious”.

quarantine -> if check dkim and/or spf fails, Depending on the capabilities of the Mail Receiver, this can mean “place into spam folder”, “scrutinize with additional intensity”, and/or “flag as suspicious”.

some domains can use aname.domain.com instead top-level domain this can be a problem during dmarc verification, Mozilla maintais a database calle Public Suffix list that can be added to our opendmarc server to make it more effective

Now your postfix has dmarc support and every hour will send necesary reports

Step 43: Configuring Roundcube webmail

Smartphones are a inclredible good technology but sometimes we don’t have signal and we need to check our email, using roundcube we provide a webmail infrastructure to our users, where they can read and send emails using a web browser.

In order to configure roundcube we need to create a database, yes another one, using these commands

now we can open a web browser write our fqdn and check our roundcube webpage

log with and account and check if everything is working, send an email respond create a folder …

Now you have a working webmail to your users 😛 .

Step 44: Protecting against brute force attacks using fail2ban

At this point we are filtering spam and using a huge number of antispam technologies. Unfortunately your mailserver will be exposed to internet and a lot of automatic tool will try get your passwords using bruteforce attacks.

To mitigate these actions we will use fail2ban, fail2ban reads system logs and block temporaly a ip making a bruteforce attacks, generally this means that we attackers avoid our server because temporally block makes bruteforce attack imposible

To make this fail2ban read logs and counts invalid logins when a number of invalid logins is detected fail2ban adds a rule to firewalld blocking source ip of invalid logins during a penalty time, typical brute force attacks abandom because they can’t test more

Some users will send a lot of attachments , and they need to know how many free space leave in their mailbox, we will enable imap_quota plugin to avoid support call about that they can’t receive or send mails with titanic attachments.

Responsive of inform about how many free space left in their mailbox is dovecot, we need to enable some plugins.

Sometimes hardware Raid controllers are very expensive to fit in low budget solutions, when this happens you can use software raid, like mdadm.

Normally hard disks have a limited lifetime. To avoid disasters I replace hard disk every two years, at same time that means that new hard disk will come in a bigger capacity. I will simulate this workflow.

Unfortunately I’m not a rich engineer yet and need to simulate hard disk, if you want to donate some hard disk leave me a comment 🙂

step 1 and 2 are for create virtual hard disk,

REMEMBER MAKE BACKUPS BEFORE DO DANGEROUS THINGS LIKE THESE

Step 1: Create virtual hard disk

Imagine that in a beginning we have a couple of two hard disk with a capacity of one terabyte (1HD and 2HD), and after two years we acquired two new hard drives with a capacity of three terabyte (3HD and 4HD).

One common mistake when we configure a server is forgot run backups, No enough time and other excuses can convince you that make a backup of a new server is not a priority, but sometimes a hipervisor fails and recover data from your virtual machine is hard or impossible. Trust me i saw a lot of unrecoverable databases in development environments unrecoverable after a power outage or hardware fail.

There are a big set of possible ways to backup mysql databases, it depends of several factors like database size, number of databases, reliability …

This tutorial will covered a basic backup for a database server with a small number of small – medium size databases.

Suppose that you have a MariaDB, Percona or Mysql service running and secured,

2 step install Mysql-zrm

3 Step create a backup dir

mkdir /var/backup

*trick in my case I mounted a nfs share in this directory.

4 Step configure Mysql-zrm

We need edit mysql-zrm config file

vim /etc/mysql-zrm/mysql-zrm.conf

#
# Template for Zmanda Recovery Manager for MySQL configuration file
#
# Global configuration file is /etc/mysql-zrm/mysql-zrm.conf
# The file should be copied to /etc/mysql-zrm/<backup set name>/mysql-zrm.conf
# if backup set specific modifications are required.
#
# MySQL ZRM configuration file describes the backup configuration for
# a backup set. This file is organized into five sections for convenience
# - Backup parameters,
# - Databases/tables that are part of backup set,
# - MySQL server parameters
# - ZRM parameters.
# - ZRM plugin parameters.
#
# For more information about Zmanda Recovery Manager for MySQL, please
# see mysql-zrm(1) and/or Administration manual at Zmanda Network.
#
#
# Any line starting with '#' are comments and will be ignored
#
# Backup parameters
#
# Backup comment. This is a text string which can be retrieved
# using the mysql-zrm-reporter(1) tool. You can store some notes
# about the backup set.
# This parameter is optional and has no defaults.
#comment=This is a comment
# Backup level. It can be full or incremental
# Use 0 for full and 1 for incremental backups
# This parameter is optional and default value is full backup.
#
backup-level=0
# Backup method
# Values can be "raw" or "logical". Logical backup are backups using
# mysqldump(1) tool
# This parameter is optional and default value is "raw".
#
backup-mode=logical
# Size of LVM snapshot. This parameter is optional and is required only
# for "raw" backup-mode and if the MySQL database data are stored in
# LVM logical volumes.
# A size suffix of k for kilobyte, m for megabyte, g for gigabyte
# or t for terabyte
#
#lvm-snapshot=10M
# specifies the plugin for snapshot operations
#
#snapshot-plugin="/usr/share/mysql-zrm/plugins/lvm-snapshot.pl"
# Specifies the type of backup
# Values can be "regular" or "quick".
# Quick backup type uses the snapshot itself as the backup
# without copying the data from the snapshot volume
#backup-type=quick
# Directory to which backups are done. All backups are stored under this
# directory. This parameter is optional and the default
# value is "/var/lib/mysql-zrm"
#
destination=/var/backup/database
# Specifies how long the backup should be retained. The value can be
# specified in days (suffix D), weeks (suffix: W), months (suffix: M) or
# years (suffix Y). 30 days in a month and 365 days in a year are assumed
# This parameter is optional and the default is the backups are retained
# forever.
#
retention-policy=1Y
# This parameter should be set to 1 if MySQL ZRM backups are being on done on a
# MySQL replication slave.
#replication=1
# This parameter should be set to 1 if backups should be compressed. If this
# parameter is set, gzip(1) command is used by default. If different
# compression algorithm should be used, it must be set in "compress-plugin"
# parameter. Default: There is no data compression.
compress=1
# This specifies the program to be used for compression. The "compression"
# parameter must be set for this parameter to be used. The compression
# command should also support -d option for uncompress backup images. If
# value is not specified then gzip(1) is used for compression.
#compress-plugin=/usr/bin/gzip
# This parameter should be set to 1 if backups should be encrypted.
# The "encrypt-plugin" parameter must be configured. Default: There is no
# data encryption.
#encrypt=1
# This parameter specifies that the program that should be used for
# backup data encryption. "decrypt-option" parameter should also be specified.
#encrypt-plugin="/usr/share/mysql-zrm/plugins/encrypt.pl"
# This specifies the option to be passed to the encryption
# program specified as "encrypt-plugin" parameter for decryption.
#decrypt-option="-d"
#
# Databases/Tables in the backup set
#
# One of the "all-databases" or "databases" or "tables"/"database" parameters
# should be specified. If none of the them are specified, "all-databases"
# is assumed.
#
# This parameter should be set to 1 if all databases are part of this backup set
#
all-databases=1
# List of databases that are part of this backup set. Multiple database
# names are separated by space character. This parameter is ignored if
# "all-databases" is set 1.
#
#databases=wikidb forums
# List of specific tables that are part of this backup set. This parameter
# should not be specified if all tables in the databases in "databases"
# parameter are part of the backup set. Multiple table names should be
# separated by space character. The database to which these tables belong
# to should be specified in "database" parameter.
#
#tables=text user page
#database="wikidb"
#
# The list of databases or tables that are excluded from the backup if the
# database name or table name matches the pattern. Wildcard characters *, ?,
# [, ] are supported. See mysql-zrm-backup man page for details
#
# exclude-pattern=<pattern>
# MySQL server parameters
#
# MySQL database user used for backup and recovery of the backup set.
# This parameter is optional. If this parameter is not specified, values from
# my.cnf configuration file.
#
user="zrmbackup"
# MySQL database user password.
# This parameter is optional. If this parameter is not specified, values from
# my.cnf configuration file or no password is used.
#
password="pass123"
# Fully qualified domain name of the MySQL server.
# This parameter is optional. If this parameter is not specified, values from
# my.cnf configuration file.
#
#host="localhost.company.com"
# Port to which the MySQL server is listening to. This parameter is optional
# and default value is 3306
#
#port=3306
#Name of Socket file that can be used for connecting to MySQL
#
#socket=/var/lib/mysql/mysql.sock
# ssl-options are arguments that are passed to MySQL client commands
# for SSL connection to the MySQL server. This parameter is optional and is
# required only if MySQL server allows SSL connections.
#
#ssl-options="--ssl --ssl-ca=file1 --ssl-cert=file2 --ssl-key=file3"
# This can be set to specify that mysqldump should dump stored routines also.
# This paramter is optional and the default is that stored routines are
# not dumped my mysqldump
routines=1
# This can be set to 0 to specify that the --single-transaction
# should not be used for mysqldump
single-transaction=1
# This can be used to specif the character set name that mysqldump should
# use as default. This parameter is optional.
# If not specified utf8 is used as the default character set.
#default-character-set=latin1
# Directory where MySQL commands can be found. The parameter is optional.
#
#mysql-binpath="/opt/lampp/bin"
# Directory where MySQL binary logs can be found. The parameter is optional.
#
#mysql-binlog-path="/var/log/mysql"
# Directory to use for temporary storage. This parameter is optional
#
#tmpdir=/tmp
#
# ZRM parameters
#
# This parameter controls the verbosity of MySQL ZRM logging. The MySQL ZRM logs
# are available at /var/log/mysql-zrm/mysql-zrm.log. This parameter is optional
# default value is 0 (less verbose).
# The valid values are 0 and 1
#
verbose=1
# After a backup run the backup report is emailed to the mailto address
# This parameter is optional and default behavior is not to send mail
# notifications.
#
mailto="backups@youremail.com"
# Policy on when the mail should be sent
# Values can be "always", "never" or "only-on-error"
mail-policy=only-on-error
# The list of backup reports that are generated after each backup run if
# "html-report-directory" parameter is specified.
# If this parameter is not specified, "backup-status-info" report is generated.
# Valid report names are : backup-method-info, backup-status-info,
# backup-retention-info, backup-performance-info,
# restore-full-info, restore-incr-info,
# replication-info, backup-app-performance-info
# See mysql-zrm-reporter(1) for details of backup reports.
# Multiple report names should be separated by ",".
#
html-reports=backup-status-info
# Directory in which Text/HTML reports will be created by mysql-zrm-reporter(1)
# tool. If this parameter is specified, the mysql-zrm-reporter(1) creates the
# backup reports in this directory after each successful or unsuccessful
# backup run.
# Text reports will be created under "Text" sub-directory
# HTML reports will be created under "Html" sub-directory
#
#html-report-directory=/var/www/mysql-zrm/reports/
# If backup reports are required as RSS feed, "webserver-url" parameter must
# be specified. The value must be set to a valid location on the web server
# in which HTML reports are located and that URL can be used by
# administrator/user to browse HTML reports and can get to the RSS feeds.
# If this parameter is not specified, backup reports are not generated as
# RSS feeds. The list of reports that are available as RSS feed is specified
# in "html-reports".
#
#webserver-url=http://www.company.com/reports/html/
# Location of RSS header file. Administrators can customize RSS channel
# properties using this file. A template for RSS header is available in
# /usr/share/mysql-zrm/plugins/RSS.header file. Location of RSS header
# must be provided if "webserver-url" is specified.
#
#rss-header-location=/etc/mysql-zrm/
#
# ZRM plugin parameters.
# ZRM provides plugin interfaces to allow MySQL administrators to customize
# the backup to their environment.
#
# COPY plugin: Only one copy-plugin must be configured for a backup set.
#
# Socket Copy plugin is to used to transfer backup files from MySQL server to
# the machine running ZRM for MySQL with sockets.
#
# Please read the Notes at /usr/share/doc/mysql-zrm/README-plugin-socket-copy
#
#copy-plugin=/usr/share/mysql-zrm/plugins/socket-copy.pl
# SSH Copy plugin is to used to transfer backup files from MySQL server to
# the machine running ZRM for MySQL with ssh
#
# Please read the Notes at /usr/share/doc/mysql-zrm/README-plugin-ssh-copy
#
#copy-plugin=/usr/share/mysql-zrm/plugins/ssh-copy.pl
# PRE-BACKUP plugin: Plugin that will be called before a backup run for
# the backup set.
#pre-backup-plugin="/usr/share/mysql-zrm/plugins/pre-backup.pl"
# Set of parameters passed to the pre-backup-plugin. These parameters are
# passed to "pre-backup-plugin" before a backup run for the backup set.
# "pre-backup-plugin" parameter must be specified.
#pre-backup-plugin-options="option1 option2"
# POST-BACKUP plugin: Plugin that will be called after a backup run for
# the backup set.
#post-backup-plugin="/usr/share/mysql-zrm/plugins/post-backup.pl"
# Set of parameters passed to the post-backup-plugin. These parameters are
# passed to "post-backup-plugin" after a backup run for the backup set.
# "post-backup-plugin" parameter must be specified.
#post-backup-plugin-options="option1 option2"
# PRE-SCHEDULER plugin: Plugin that can be used to dynamically determine the
# start time for a backup run.
#pre-scheduler-plugin="/usr/share/mysql-zrm/plugins/pre-scheduler.pl"
# ZRM Plugin configuration parameters
# This parameter is used by the encrypt plugin and
# specifies the file containing the passphrase.
#passfile="/tmp/a.pass"
# This parameter is used by ssh-plugin.pl plugin to specify the user to be
# used to ssh to the remote host
#ssh-user="root"
# This parameter is used by the ssh-copy.pl and socket-copy.pl plugins
# to specify the location of mysql client binaries on the remote host.
#remote-mysql-binpath="/usr/bin"
# This parameter is used by the socket-copy.pl plugin to specify the port
# to be opened on the remote host.
#socket-remote-port="25300"
# This parameter is used by the windows-copy.pl plugin to specify the port
# to be opened on the windows machine during backup
#windows-backup-port="10080"
# This parameter is used by the windows-copy.pl plugin to specify the port
# to be opened on the windows machine during restore
#windows-restore-port="10081"

Step 5. Launch a backup

Having small servers at office requires try to avoid a small number of problems one of then are electrical supply falitures, a quick way to solve this is connecting a UPS to the server and forget about cross your fingers when a power outtage makes act of presence.

In my case i have to configure a couple of small servers one with an old Yukai UPS and other with a Salicru ups.

If you want to get an ups linux communication working follow this steps: