Linux, Nginx, Mysql, PHP, Postfix+SASL, Dovecot, Spamassassin, chkrootkit, firewall, maildrop, rsnapshot
Originally posted by Raj Prakash on rajeshprajash.com. His site disappeared, so this is a mirror of the original document.
v0.05, 15 May
2011
This document describes how to
setup a Debian Linux VPS to replace your standard shared hosting account.
This document started out as a bunch of scribbles on
scrap paper as I built a Virtual Private Server (VPS) into a fully functioning
internet server. It was notes on how I
configured the server for the various pieces of the stack. The need for the server was identified when I
wanted to migrate my cPanel Shared Hosting account at Hostgator to a low end
VPS for more control and freedom to run whatever software I wanted. It was also a good opportunity to get back
into Linux system configurations and serving web content. As a collateral benefit, but not as the main
drive, I was able to save a few dollars a month in web hosting costs.
Use the information in this document at your own risk. I disavow any potential liability for the contents of this document. Use of the concepts, examples, and/or other content of this document is entirely at your own risk.
All copyrights are owned by their owners, unless specifically noted otherwise. Use of a term in this document should not be regarded as affecting the validity of any trademark or service mark.
Naming of particular products or brands should not be seen as endorsements.
You are strongly recommended to take a backup of your system before major installation and backups at regular intervals.
This
document is not intended to describe a secure internet server installation,
only a barebones functioning one. It is
still the responsibility of the reader to take this basic setup document to the
next level and harden it against intruders.
Any comments or suggestions can be mailed to my mail address on my little slice mailto:raj@rajeshprakash.com
You’ve got a newly purchased VPS. Make sure to get a fresh install of Debian on your VPS. As noted in this post (http://www.lowendbox.com/blog/wordpress-cheap-vps-lowendscript/), stick with a 32-bit OS to get the best benefit in RAM usage. I highly recommend reading the entire blog post as many of the steps in this howto are harvested from that work.
After logging into the VPS as root, start by stopping as many pre-installed applications as possible by issuing the proper commands. In my specific case, I prefer to stop apache2, exim, as well as a few others before going on, so :
/etc/init.d/apache2 stop
/etc/init.d/exim4 stop
...
First
thing I like to do is make sure I have my /etc/apt/sources.list for apt to a
useful local mirror. I comment out
whatever was in the default install and add a local mirror similar to the
following. Please choose a local mirror
to reduce bandwidth and to speed up your installations. Choose one from
http://www.debian.org/mirror/list.
deb http://ftp.gtlib.gatech.edu/pub/debian
lenny main contrib non-free
deb http://security.debian.org/debian-security
lenny/updates main contrib non-free
deb
http://volatile.debian.org/debian-volatile lenny/volatile main contrib non-free
Now run an apt-get update.
Next, grab LowEndAdmin’s script. Note that you may have to add the --no-check-certificate option to wget:
wget http://github.com/lowendbox/lowendscript/raw/master/setup-debian.sh
and issue the “system” command :
bash setup-debian.sh system
According to LowEndAdmin (hereafter referred to as LEA), this script does the following items. I highly recommend peeking at the bash script itself to convince yourself, don’t just take our word for it! Looking at the script source will help you troubleshoot any potential issues in the future.
• Installs dropbear to replace openssh. Invoked from xinetd.
• Installs inetutils-syslogd to replace rsyslog.
• Installs cron
• Removes some commonly bundled applications that should not be there in the first place for a minimal distro (apache2, sendmail, bind9, samba, nscd, etc).
I am not a big fan of the simple text editor vi, so I choose to use the simple text editor nano. I have the worst memory, so instead of using the find command to locate files, I like to use locate. These two applications are a personal preference, so you can opt to install them or not. Not installing these two will not affect the system at all. I’ll go ahead and install those:
apt-get install locate nano
updatedb
I also like to make sure that I have all the latest and greatest system libraries and supporting services possible before going forward, so at this point I like to do an upgrade and dist-upgrade. This is a standard package and system upgrade using Debian’s apt function. Further reading and information on this can be found at http://www.debian.org/doc/manuals/apt-howto/. See section 3.4 and section 3.5, specifically. Issue the following commands:
apt-get upgrade
apt-get dist-upgrade
In my particular installation, I have also disallowed logging into dropbear as the root user. It is a basic security measure, and is a simple change. Start by adding a new unix system user, and then doing the following configuration change:
adduser your_new_system_username
Edit /etc/xinetd.d/dropbear with your favorite editor and add -g to the server_args parameter.
Last but not least, it is important to me as a system administrator to make sure I am able to correlate system events in my “real” time. That is, if I can’t correlate the system time with my local time, how can I figure out when thing happen. Here’s an example, lets say you’re sleeping and you wake up and notice your VPS has been hacked. You log in, and check the logs. Your log timestamps say you had a DDOS followed by a brute force attack at 6:32AM system time. If you don’t know what timezone your system is set to, when the heck did that happen in your life time? Lets set our time zone to something we can recognize. From the command line, issue the following command and select your appropriate zone.
dpkg-reconfigure tzdata
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation.
Issue the following commands using LEA’s script retrieved in Section 2.1:
bash setup-debian.sh nginx
bash setup-debian.sh php
Please note that at this point, you still don’t have any sites enabled. In my particular installation, I am using all virtual hosts, so for convenience the virtual host configuration example can be found here: http://wiki.nginx.org/VirtualHostExample.
Nginx is well documented and has a fairly complete wiki on configuration options on its website. For convenience, here is a link: http://wiki.nginx.org.
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server.
First lets get Postfix installed with the supporting packages for SASL authentication.
apt-get install postfix postfix-tls
libsasl2-2 sasl2-bin libsasl2-modules
Debconf will ask you a few questions. Answer “Internet Site” and enter your hostname for the System Mail Name parameter.
Now lets prepare the system for saslauthdb. Note that saslauthd chroots (by default) to /var/spool/postfix for security. Thus, despite the authentication daemon thinking it's checking /etc/sasldb2 and this is where the saslpasswd2 creates the database, it's not there. You can simply copy /etc/sasldb2 to /var/spool/postfix/etc/sasldb2 and the problem will be fixed, or add your users to the saslauthdb database directly to the chrooted location as shows below.
rm -r /var/run/saslauthd/
mkdir -p /var/spool/postfix/var/run/saslauthd
ln -s /var/spool/postfix/var/run/saslauthd
/var/run
chgrp sasl
/var/spool/postfix/var/run/saslauthd
adduser postfix sasl
To add a user to the saslauthdb database, issue the following commands to the chrooted area:
saslpasswd2 -f /var/spool/postfix/etc/sasldb2
-u yourdomain.tld your_sasl_username
chown root:sasl
/var/spool/postfix/etc/sasldb2
Note that the chown is only required the first time you create that database, but it’s good to keep the right ownership handy in case it gets screwed up.
Now lets tell Postfix to use SASL SMTP authentication. Pop open /etc/postfix/main.cf in your favorite editor and add these lines (modifying the smtp_sasl_local_domain parameter, of course):
smtpd_sasl_auth_enable = yes
smtpd_sasl_local_domain = yourdomain.tld
smtpd_recipient_restrictions =
permit_mynetworks,permit_sasl_authenticated,reject_unauth_destination
smtpd_sasl_security_options = noanonymous
Now, restart your mailsystem and you’re ready for SASL!
/etc/init.d/postfix restart
Next step in the process is setting up Postfix to use virtual domains and real system users. With the approach described in this section, every hosted domain can have its own info etc. email address. However, it still uses UNIX system accounts for local mailbox deliveries.
Add these two lines to your /etc/postfix/main.cf
virtual_alias_domains = example.tld
example2.tld ...other hosted domains...
virtual_alias_maps =
hash:/etc/postfix/virtual
The virtual_alias_domains setting tells Postfix that example.tld is a so-called virtual alias domain. If you omit this setting then Postfix will reject mail (relay access denied) or will not be able to deliver it (mail for example.com loops back to myself).
The /etc/postfix/virtual file contains the virtual aliases where you can map
your virtual domains. Here is an example
exerpted from the Postfix documentation.
Create your own with your own domains.
/etc/postfix/virtual:
postmaster@example.com postmaster
info@example.com joe
sales@example.com jane
Note, NEVER list a virtual
alias domain name as a mydestination
domain! Also note that virtual aliases
can resolve to a local address or to a remote address, or both. They don't have
to resolve to UNIX system accounts on your machine.
Execute the command "postmap /etc/postfix/virtual" after changing the virtual
file, and execute the command "postfix reload" after changing the main.cf file. Running postmap is different than newaliases,
so make sure you use postmap specifically.
The command newaliases only rebuilds those postfix aliases identified in
/etc/aliases
I don’t have a real reason to prefer Maildir over mbox mail formats aside from
the fact that all the mailservers I’ve ever build use Maildir, so lets use that
here too. Add the following line to your
main.cf. This setting is important in my
particular mail server setup as future sections rely on Maildir format. If you want to use mbox, you can omit the
setting, but then you must adapt future settings for mbox.
home_mailbox = Maildir/
Obviously, you need to also configure postfix for the most basic
settings, so change these two as well:
mydestination = yourhostname.yourdomain.tld
myhostname = yourhostname.yourdomain.tld
As a RAM memory savings, you can also cut down the number of children threads that saslauthdb starts with. The default is 5, but from a probability standpoint, my particular server setup does not need 5 concurrent authentication processes. Lets tell saslauthd to start at boot and also only load 1 thread.
Edit /etc/default/saslauthd and modify the following two parameters :
THREADS=1
START=YES
Now, just to make sure everything is loaded, restart postfix and saslauthdb by issuing these commands at the command line:
/etc/init.d/postfix
restart
/etc/init.d/saslauthd
restart
To test out the whole installation, follow some of the telnet instructions in the Postfix documentation: http://www.postfix.org/SASL_README.html#server_test.
Now, lets install some bare minimum spam prevention techniques to Postfix. We can perform some basic client and sender restriction checks to stop Postfix from queuing emails from IPs who appear on known spamming block lists, from those emailing from dynamic IPs, and from those who do not have fully qualified domain names as the sender. Add the following lines (or modify the existing lines) in your /etc/postfix/main.cf
smtpd_client_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_rbl_client zen.spamhaus.org,
reject_rbl_client dnsbl.sorbs.net,
reject_rbl_client bl.spamcop.net,
reject_rbl_client cbl.abuseat.org,
reject_rbl_client combined.njabl.org
smtpd_sender_restrictions =
reject_non_fqdn_sender
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server.
Issue the following command to go grab the latest Dovecot package from the repository :
apt-get install dovecot-imapd
Dovecot
is very simple to configure and only requires 3 tweaks to make everything work
nicely.
Tweak 1 : Open /etc/dovecot/dovecot.conf and make the following modifications to the two paramaters (uncomment them in the config file if you need to):
protocols = imap
disable_plaintext_auth = no
Tweak 2 : Now, look for the line that starts with auth default, and just before that line insert the lines below.
auth default {
mechanisms
= plain login
passdb
pam {
}
userdb
passwd {
}
socket
listen {
client
{
path
= /var/spool/postfix/private/auth
mode
= 0660
user
= postfix
group
= postfix
}
}
}
Now, rename previous auth default to auth default2. If you dont rename this then dovecot server will give you error like multiple instances of auth default. Note that it is important to have the opening brace on the same line as the block title. Dovecot will cry if you don’t do this. For example, the opening brace must be on the same line as passdb pam or on the same line as socket listen.
Tweak 3 : To save RAM usage on the low end VPS, limit the number of processes Dovecot can spawn by modifying the following two parameters. The config file is well documented and so you can read about what these two parameters mean. From a statistics standpoint, the domains that I am hosting on my server are relatively low traffic and low frequency. The probability of multiple incoming connections to be processed concurrently is low. This is how I can get away with keeping the login process count low. If you have a higher load mail server, you can opt to bump up this value, but be prepared to lose more allocated RAM for the new child processes.
login_processes_count = 2
login_max_processes_count = 4
Now, just to make sure everything is loaded, restart Dovecot by issuing these commands at the command line:
/etc/init.d/dovecot restart
To
test out the whole installation, follow some of the telnet instructions in the
Dovecot documentation: http://wiki1.dovecot.org/TestInstallation
or open your favorite IMAP client and point it to your server.
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server.
At this point, you have a fully functioning SASL SMTP and IMAP server capable of hosting email for any number of virtual domains mapped to as many real system users (or forwarding users) as you like. That doesn’t mean, however, that your mail server is smart enough to reject the billions of spam messages that fly around the internet all day long. In this section, we install and integrate the very popular, mature, and widely-deployed open source project that serves as a spam mail filter. Grab the packages and setup the basic architecture from the command line:
apt-get install spamassassin spamc
groupadd spamd
useradd -g spamd
-s /bin/false -d /var/log/spamassassin spamd
mkdir /var/log/spamassassin
chown
spamd:spamd /var/log/spamassassin
Now edit /etc/default/spamassassin so these options are set:
ENABLED=1
SAHOME="/var/log/spamassassin/"
OPTIONS="--create-prefs --max-children 1
--username spamd \
-H ${SAHOME} -s ${SAHOME}spamd.log"
The --max-children 1 option specifies the maximum number of children to spawn. Spamd will spawn that number of children, then sleep in the background until a child dies, wherein it will go and spawn a new child. Incoming connections can still occur if all of the children are busy, however those connections will be queued waiting for a free child. The minimum value is 1, the default value is 5.
Note that if you run too many servers for the amount of free RAM available, you run the danger of hurting performance by causing a high swap load as server processes are swapped in and out continually.
From a statistics standpoint, the domains that I am hosting on my server are relatively low traffic and low frequency. The probability of multiple spam mails coming in to be processed concurrently is low. This is how I can get away with keeping the max children low. If you have a higher load mail server, you can opt to bump up this value, but be prepared to lose another 15-20MB of allocated RAM for the new child process.
Now that the architecture is setup, and a few miscellaneous settings are set, lets integrate Spamassassin with Postfix.
Edit /etc/postfix/master.cf and add this line as the first line of the file. Replace XXX.XXX.XXX.XXX with your external IP where you will be receiving incoming email from. The "-o content_filter" line causes Postfix to add one content filter request record to each incoming mail message, with content "spamassassin". This record overrides the normal mail routing and causes mail to be given to the content filter instead.
XXX.XXX.XXX.XXX:smtp inet
n - -
- - smtpd
-o content_filter=spamassassin
127.0.0.1:smtp inet n - - - - smtpd
This makes Postfix pipe email to Spamassassin once it's been received and it uses IPs to specify that we run Spamasssin on incoming email from the external internet, but not on outgoing email sent from the localhost.
Then add this to the end of the same file to identify what the content filter identified above should do :
spamassassin unix - n
n - -
pipe
user=spamd argv=/usr/bin/spamc -f -e
/usr/sbin/sendmail -oi -f ${sender} ${recipient}
Now, just to make sure everything loaded, restart Postfix and Spamassassin by issuing these commands at the command line:
/etc/init.d/postfix
restart
/etc/init.d/spamassassin
restart
To test out the whole installation, follow some of the telnet instructions in the Spamassassin documentation: http://wiki.apache.org/spamassassin/TestingInstallation. Check the email headers when the email arrives to see all the Spamassassin magic!
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification!
If you’re like me, then it’s not enough just to have Spamassassin rewrite the headers in your emails. You want to know, visually, that Spamassassin has done its job. To do that, Spamassassin can rewrite the message headers, as well as rewriting the email’s subject line. This way there is a clear indication that a message is spam.
There are many ways to do sieve or post delivery filtering, but the easiest way for me is to use maildrop for local delivery and filtering. Lets install maildrop, and tell it to deliver anything marked as spam (by Spamassassin’s header rewriting X-Spam-Flag) not to our INBOX, but to a Junk folder.
apt-get install maildrop
Open /etc/maildroprc with your favorite editor, uncomment the DEFAULT=”$HOME/Maildir” line and add the following to the end of the file:
# commands and variables for making the mail
directories
maildirmake=/usr/bin/maildirmake
mkdir=/bin/mkdir
rmdir=/bin/rmdir
MAILDIR=$DEFAULT
# make the user's mail directory if it
doesn't exist
`test -e $MAILDIR`
if ($RETURNCODE != 0)
{
`$mkdir
-p $MAILDIR`
`$rmdir
$MAILDIR`
`$maildirmake
$MAILDIR`
}
# make the .Junk folder if it doesn't exist
JUNK_FOLDER=.Junk
_JUNK_DEST=$MAILDIR/$JUNK_FOLDER/
`test -d $_JUNK_DEST`
if ($RETURNCODE != 0 )
{
`$maildirmake
$_JUNK_DEST`
#auto
subscribe. the following works for courier-imap
`echo
INBOX.Junk >> $MAILDIR/courierimapsubscribed`
}
# If the Spam-Flag is set, move the mail to
the Junk folder
if (/^X-Spam-Flag:.*YES/)
{
exception
{
to
$DEFAULT/.Junk/
}
}
Now, lets make sure that Postfix delivers the mail to maildrop instead of the default procmail. Open /etc/postfix/main.cf in your favorite editor and either modify the mailbox_command parameters, or comment the old one and add a new line, to identify maildrop as the new local delivery agent.
mailbox_command = /usr/bin/maildrop
Last but not least, lets get a visual indication that Spamassassin has done its job. Open /etc/spamassassin/local.cf in your favorite editor and uncomment and modify the following paramaters
rewrite_header Subject [SPAM]
report_safe 0
Now, just to make sure everything loaded, restart the entire mail system by issuing these commands at the command line:
/etc/init.d/postfix
restart
/etc/init.d/spamassassin
restart
/etc/init.d/saslauthdb
restart
/etc/init.d/dovecot
restart
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, and a mail sieve!
If you also need a Backup MX installation, go read Section 5.2 after testing your mail installation.
Issue the following command using LEA’s script retrieved in Section 2.1 above
bash setup-debian.sh mysql
This script installs mysql_server and mysql_client and configures mysql to disables InnoDB in accordance with the discussion here: http://www.lowendbox.com/blog/reducing-mysql-memory-usage-for-low-end-boxes/
The script also issues you a new mysql root password and conveniently saes it under ~/.my.cnf for your viewing pleasure. Good security practice is to go find the password, change it, and delete this file. You can do as you please depending on your situation.
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, a spam mail sieve, and a functioning stripped down Mysql dB engine.
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, a spam mail sieve, and a functioning stripped down Mysql dB engine, with the proper rDNS set to allow sending mail to big mail hosts.
apt-get install chkrootkit
Then open /etc/chkrootkit.conf in your favorite text editor and change the following parameter from false to true:
RUN_DAILY="false" to
RUN_DAILY="true"
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, a spam mail sieve, and a functioning stripped down Mysql dB engine, with the proper rDNS set to allow sending mail to big mail hosts, that will check nightly for rootkits and email the findings to root.
The goal of sa-update is to download new configuration files (rules, scores, etc,) so that SpamAssassin will use them to better catch spam and/or to avoid catching ham messages. The main reason to use sa-update is that the old method of disseminating rules, releasing a new version SpamAssassin, is a lengthy process that can take many months. Spam is rapidly changing, and new rules are often written in response. With sa-update, those rules can quickly (potentially within minutes) be distributed and the new spam caught. Simply put, sa-update allows rules to be distributed as they are developed, while full SpamAssassin releases can focus on bug fixes and new features.
For my systems, I like to make sure I update all my packages as frequently as possible to fix both security and configuration issues. So I like to make sure I keep my spam matching rules as new as I can. I use the scheduling utility cron to keep sa-update up to date.
Go to the command line, and as root, type the command ‘crontab –e’. This opens the crontab entries list for the root user. An example Crontab file Format or syntax would be like this:
* * * * * Command to
be executed
- - - - -
| | | | |
| | | | +----- Day
of week (0-6)
| | | +------- Month
(1 - 12)
| | +--------- Day
of month (1 - 31)
| +----------- Hour
(0 - 23)
+------------- Min
(0 - 59)
To do a nightly update of sa-update, simple add a new line item in root’s crontab list like the following. It will run the sa-update command each night at 2am. You can change the time to whatever time your server loading is normally the lowest. You don’t want to eat up valuable server processing resources when you’re at your statistical high demand time. Once you add the new entry, save and exit and you’re done.
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, a spam mail sieve, and a functioning stripped down Mysql dB engine, with the proper rDNS set to allow sending mail to big mail hosts, that will check nightly for rootkits and run SpamAssassin’s sa-updater and email the results to root.
/sbin/iptables –F
Now, using your favorite text editor, edit or create the file /etc/iptables.up.rules
pico /etc/iptables.up.rules
Then enter the following text into that file making modifications to open up incoming ports as required for your setup. Make note to change the ports for the various services (including SSH) if you are running daemons on nonstandard ports.
*filter
#
Allows all loopback (lo0) traffic and drop all traffic to 127/8 that
doesn't use lo0
-A INPUT -i lo
-j ACCEPT
-A INPUT ! -i lo -d 127.0.0.0/8 -j REJECT
#
Accepts all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED
-j ACCEPT
# Allows
all outbound traffic
-A OUTPUT -j ACCEPT
# Allows HTTP and HTTPS connections from
anywhere (the normal ports for websites)
#-A INPUT -p tcp --dport 80 -j ACCEPT
#-A INPUT -p tcp --dport 443 -j ACCEPT
# Allows SMTP, POP, and IMAP connections from
anywhere (the normal ports for mail)
#-A INPUT -p tcp --dport 25 -j ACCEPT
#-A INPUT -p tcp --dport 143 -j ACCEPT
#-A INPUT -p tcp --dport 110 -j ACCEPT
# Allows DNS from anywhere (the normal ports
for nameserver)
#-A INPUT -p tcp --dport 53 -j ACCEPT
# Allows FTP connections from anywhere (the
normal ports for ftp)
#-A INPUT -p tcp --dport 25 -j ACCEPT
#
Allows SSH connections (only 4 attempts by an IP
#
every 3 minutes, drop the rest to prevent SSH attacks)
-A INPUT -p tcp -m tcp --dport 22 -m state
--state NEW -m recent --set --name DEFAULT --rsource
-A INPUT -p tcp -m tcp --dport 22 -m state
--state NEW -m recent --update --seconds 180 --hitcount 4 --name DEFAULT
--rsource -j DROP
-A INPUT -p tcp -m state --state NEW --dport
22 -j ACCEPT
# Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j
ACCEPT
# log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG
--log-prefix "iptables denied: " --log-level 7
# Reject all other inbound - default deny
unless explicitly allowed policy
-A INPUT -j REJECT
-A FORWARD -j REJECT
COMMIT
Now, you’ve just saved rules you want to use, but they are not in effect yet. To tell iptables to use your new rules, run the command:
/sbin/iptables-restore
< /etc/iptables.up.rules
Although the rules are up and running, they are only active for the current session. If the VPS were to be rebooted they would be lost. Let's ensure they are restored on a reboot. We'll add a small script that the system will run when your network interfaces are started. Create a file using your favorite text editor (mine is pico):
pico /etc/network/if-pre-up.d/iptables
Add
the following lines to the new file:
#!/bin/sh
/sbin/iptables-restore
< /etc/iptables.up.rules
Save your changes, and then make the new script executable:
chmod +x /etc/network/if-pre-up.d/iptables
That should ensure that whenever your network interfaces are brought up (usually just at boot time), the firewall will be too.
One thing to note is that this iptables setup requires use of the iptables modules “recent”. As noted on LowEndTalk, not all VPS providers have the module recent loaded on the host node and so you may fail some of these iptables rules. To check if your box has the recent module loaded, execute the following command
cat /proc/net/ip_tables_matches
If you see the word “recent” in the list, then you’re good to go. If you do not, drop a ticket into your hosting provider to have it enabled on the host node.
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, a spam mail sieve, and a functioning stripped down Mysql dB engine, with the proper rDNS set to allow sending mail to big mail hosts, that will check nightly for rootkits and email the findings to root, with a fully functioning firewall.
By default dropbear
and OpenSSH servers run on TCP port 22. Running SSH on a non-standard port is
akin to re-locating the ignition key slot in a car to the trunk. Security
though obscurity is not security, but it does foil robot scripts that are too
stupid to see the extension cord running from the dash through the back
seat. To take advantage of that
stupidity, and to throw off impatient hackers that don’t run a port scan, we
can run our dropbear instance on a non-standard port.
Open /etc/default/dropbear in your favorite text editor and change the following parameter replacing XXX with whatever port you want:
DROPBEAR_PORT=22 to DROPBEAR_PORT=XXX
Alternatively, if you run dropbear from xinetd you can edit /etc/xinetd.d/dropbear and change the port variable and add the type paramater. For example, (remember we added the –g to the server_args parameter back in Section 2.1)
service dropbear
{
socket_type = stream
only_from = 0.0.0.0
wait = no
user = root
protocol = tcp
server = /usr/sbin/dropbear
server_args = -i -g
disable = no
port = XXX
type = unlisted
}
A note of caution is that if you have followed the iptables tutorial in Section 2.8, be wary to make sure you make the adjoining change to your iptables rules to account for this port change. Another note is depending on your setup, adding port = XXX to /etc/xinetd.d/dropbear may not be enough. You also need to add a new parameter "type = unlisted". The xinetd man page says that the type paramater is required if this is a service not listed in a standard system file (like /etc/rpc for RPC services, or /etc/services for non-RPC services).
Now restart dropbear for the settings to take effect, and logoff and log back in to make sure it took effect.
/etc/init.d/dropbear
restart
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, a spam mail sieve, and a functioning stripped down Mysql dB engine, with the proper rDNS set to allow sending mail to big mail hosts, that will check nightly for rootkits and email the findings to root, with a fully functioning firewall, running dropbear on a non-standard port.
· Adding a simple FTP server, proftpd
· Adding in mailing list support, ecartis
· Add new section to document install of simple, flat file, php webmail client hastymail2
· Add section on how to mount remote samba shares to increase disk space
· Reconfigure postfix to use submission port for relaying sasl authenticated emails
· Reconfigure postfix to disallow sasl auth on smtp port
· DenyHosts/fail2ban install (maybe replaced by iptables throttling)
· Explain that outgoing mail is currently being spam checked for outgoing SASL clients
· Postfix Content Filter for charset
· Rewrite Reply-To Header for simple mailing lists
/usr/lib/ecartis instead of /home/ecartis/ecartis
http://www.hzqbbc.com/blog/arch/2004/05/postfix_ecartis.html
http://baldric.net/mailman-with-postfix/
My VPS was humming
along smoothly for a few months, and then I became aware that I have no backup
plan if the container gets corrupted or the hosting company goes belly up. Holy cow, I’d have to do all of this work all
again to setup the system AND rebuild all my sites/databases/email?!? I’m too much of an engineer to let that
happen! Hmm … what do I need? I need a way to backup the content, config
files, and databases. I’m also too
inconsistent to reliably do it manually on any reasonable frequency, so I’d
need it automated. Please welcome,
rsnapshot!
rsnapshot’s website
says, “snapshot is a filesystem snapshot utility for making backups of local
and remote systems. Using rsync and hard links, it is possible to keep
multiple, full backups instantly available. The disk space required is just a
little more than the space of one full backup, plus incrementals. Depending on
your configuration, it is quite possible to set up in just a few minutes. Files
can be restored by the users who own them, without the root user getting
involved. There are no tapes to change, so once it's set up, your backups can
happen automatically untouched by human hands. And because rsnapshot only keeps
a fixed (but configurable) number of snapshots, the amount of disk space used
will not continuously grow. rsnapshot is written entirely in Perl. It should
work on any reasonably modern UNIX compatible OS, including: Debian GNU/Linux,
Red Hat Linux, Fedora Linux, SuSE Linux, Gentoo Linux, Slackware Linux,
FreeBSD, OpenBSD, NetBSD, Solaris, Mac OS X, and even IRIX.”
To better explain this section, let me set the stage. I have multiple VPS geographically separated. I have a mailserver with RamHost.us in Kansas City, a webserver with Quickweb.co.nz in Phoenix, and a backupserver with Web-Wide-Hosting.co.nz somewhere on the west coast USA. With rsnapshot installed on backupserver, and rsync installed on mailserver and webserver, backupserver can make automated incremental backups of backupserver and mailserver. Even if you don’t have a dedicated backup server VPS, if you have a Linux system (or a windows system with cwRsync, http://www.stillnetstudios.com/2006/12/09/snapshot-backups-howto/) you can install rsnapshot and backup your VPS to that box. For example, you can even use rsnapshot or cwRsync to backup your VPS to your home PC.
First, make sure you have rsync on all the various VPS that you want backed up. For me, this is
apt-get install
rsync
on mailserver and webserver.
Then setup
password-less logins with dropbear between the VPS you want backed up, and
whatever system the data will be backed up to.
To do this, on the system where the data will be backed up to, create
some RSA key pairs by issuing the ssh-keygen command as shown in this example extracted
from http://www.debian-administration.org/articles/152. Do not specify a password.
skx@lappy:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/skx/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/skx/.ssh/id_rsa.
Your public key has been saved in /home/skx/.ssh/id_rsa.pub.
Now, you need to
copy that new public key over to the VPS where the data is that you want backed
up by issuing the following command.
ssh-copy-id -i ~/.ssh/id_rsa.pub root@vpswheredataistobebackedup
If you’re running
dropbear on a non-standard port as described earlier this document, then you
may need to do this instead, where 9210 is your dropbear port. Note those are single quotes, not back ticks.
ssh-copy-id -i
~/.ssh/id_rsa.pub '-p 9210 root@vpswheredataistobebackedup'
Also note that you don't need to use remote root logins unless the files you wish to backup are unreadable to ordinary users upon the machine you're backing up. Although it's fair to say if you're backing up /etc you'll almost certainly wish to do so as root; as otherwise important files such as /etc/shadow will not be readable to normal users.
Issuing the ssh-copy-id command will prompt you for the login password for the VPS where your data is that needs to be backed up, then copy the keyfile for you, creating the correct directory and fixing the permissions as necessary. Once this has been done you should be able to login remotely, and run commands, without being prompted for a password. Try it to make sure.
Now that the VPS
that have data to be backed up are all prepared, lets prepare the system where
the data is to be backed upto. As with any other Debian standard install,
apt-get the package:
apt-get install rsnapshot
Simple enough! Ok,
lets configure it. You’ll want to change
as many paramaters as you like, but the minimum ones I changed in my setup are
as follows.
First, I made sure
all the paths to local system binaries are set properly under the section
header, EXTERNAL PROGRAM DEPENDENCIES.
If the standard utilities don’t work, then how can the entire setup
work?
Second, I set the
directory on the localhost where I want all the backups to reside by assigning
a directory to the snapshot_root parameter.
In my setup, I chose /home/backup/incremental :
snapshot_root
/home/backup/incremental/
As described at the
top of the default config file, rsnapshot requires tabs between elements, not
just spaces. Also directories require a
trailing slash : right: /home/ ; wrong: /home .
I wanted the most
amounts of backups available, so I went ahead and enabled all available backup
frequencies under the section header, BACKUP INTERVALS.
I like logging in
case something goes screwy, so I set the log paramaters as follows. You can
choose whatever you like.
verbose
4
loglevel
3
logfile /var/log/rsnapshot.log
Since I run dropbear
on a non-standard port, I need to tell rsnapshot to try a different ssh port:
ssh_args -p 9210
Here comes the fun
part. Now you need to tell rsnapshot
what directories on mailserver and webserver to backup to
/home/backup/incremental. I’ll post my
actual entries and then explain how it works :
backup root@webserver:/etc/ webserver/
backup root@webserver:/var/log/ webserver/
backup root@webserver:/var/www/ webserver/
backup root@mailserver:/etc/ mailserver/
backup root@mailserver:/home/user1/Maildir/ mailserver/
backup root@mailserver:/var/spool/postfix/etc/ mailserver/
backup root@mailserver:/var/log/ mailserver/
backup_script /root/mysqlbackup.sh run unused0/
backup root@webserver:/tmp/mysqldump/ webserver/
backup_script /root/mysqlbackup.sh clean unused1/
In the first 3
lines, I tell rsnapshot to connect to webserver
over ssh (port 9210 as described earlier) as the user root, and using rsync,
compare the contents of /etc/ and /var/log/ and /var/www/ on webserver to the contents of the latest
copies of /etc/ and /var/log/ and /var/www/ on the system where the backup is
to reside. If there are any differences,
copy them over to the system where the backup is to reside.
Same story for mailserver. It checks /etc/ and /home/user1/Maildir/ and
/var/spool/postfix/etc/ and /var/log/ over on mailserver and compares it to the contents on the system where the
backup is to reside. Any changes get
copied over by rsnapshot.
I chose /etc/
because that is obviously where all the critical configuration files for the
system are housed. I like to backup the
logs in /var/log/ because if anything goes wrong, or the system is comprised
and the logs altered by the hacker, or any other strange event you can think
of, I have the logs to look at to figure out what happened. /var/spool/postfix/etc/ is the chrooted
environment for postfix setup earlier this document, so I snag any
miscellaneous configuration files or SASL specific databases from that
directory. Finally, I backup all the
websites being served up by nginx in /var/www.
Very straight forward.
The last 3 lines are
a bit trickier. I needed a way to backup
the mysql database, while it’s running, without corrupting anything. That’s where mysqldump or mysqlhotcopy comes
in. I took the example from Fredrik
Poller here, http://poller.se/2010/12/rsnapshot-and-mysqldump/,
and it’s shown to work nicely with a simple modification. Frederik’s example works, as is, when
dropbear is running on port 22. I could
not get his setup to work nicely when running dropbear on nonstandard
ports. So instead of running Frederik’s
script directly on the webserver as follows
backup_script /usr/bin/ssh
root@webserver "/root/backup.sh run"
unused0/
I had to run a local
script to manually call ssh with the correct arguments.
backup_script
/root/mysqlbackup.sh run
unused0/
The contents of
/root/mysqlbackup.sh on the system where the backup is to reside is as follows,
where /root/mysqlbackup.sh on webserver
is identical to Frederik’s example. Make
sure to chmod 700 the file so that only root can access it.
#!/bin/bash
case $1 in
run)
/usr/bin/ssh -p 9210 webserver "/root/mysqlbackup.sh run"
;;
clean)
/usr/bin/ssh -p 9210 webserver "/root/mysqlbackup.sh clean"
;;
esac
The first of the
last 3 lines in the rsnapshot.conf calls my local script to call Frederik’s
script to get mysqldump to dump the mysql databases to /tmp/mysqldump on webserver, then the second of the last 3
lines in rsnapshot.conf makes rsnapshot copies over any incremental changes to
the system where the backup is to reside, then the last line calls Frederik’s
script again to clean up any files written to /tmp/mysqldump over on webserver so intruders or unwanted users
can’t access them.
That’s it! Now rsnapshot is all configured. Make sure that rsnapshot is good to go by
running :
rsnapshot configtest
If you get back “Syntax OK”, then you’re ready to do your first
backup! If not, go back and check the
tabbing. Remember that the config file
is tab dependant.
When ready, issue
this command :
rsnapshot hourly
If all goes well
you'll receive your backup files beneath "backup_root"/hourly.0/, and
any errors will be reported in the file /var/log/rsnapshot.log.
After a few days
you'll notice that you have several new files such as:
sh-4.1#
ls -lha
total
64K
drwxrwxr-x
16 root root 4.0K May 13 08:00 .
drwxrwxrwx
9 root root 4.0K Apr 28 11:47 ..
drwxr-xr-x 7 root root 4.0K May 12 04:03 daily.0
drwxr-xr-x 7 root root 4.0K May 11 04:03 daily.1
drwxr-xr-x 7 root root 4.0K May 10 04:03 daily.2
drwxr-xr-x 7 root root 4.0K May 9 04:03 daily.3
drwxr-xr-x 7 root root 4.0K May 8 04:03 daily.4
drwxr-xr-x 7 root root 4.0K May 7 04:04 daily.5
drwxr-xr-x 7 root root 4.0K May 6 04:03 daily.6
drwxr-xr-x 7 root root 4.0K May 13 08:03 hourly.0
drwxr-xr-x 7 root root 4.0K May 13 04:03 hourly.1
drwxr-xr-x 7 root root 4.0K May 13 00:03 hourly.2
drwxr-xr-x 7 root root 4.0K May 12 20:03 hourly.3
drwxr-xr-x 7 root root 4.0K May 12 16:03 hourly.4
drwxr-xr-x 7 root root 4.0K May 12 12:03 hourly.5
drwxr-xr-x 5 root root 4.0K May 1 04:16 weekly.0
These are the
rotated backups which we've saved, the initial backups will be the largest -
the later ones will only contain changes made since the previous run. To see
this you can view the amount of disk space taken up by each backup with
"rsnapshot du":
1.3G /home/backup/incremental/hourly.0/
11M
/home/backup/incremental/hourly.1/
8.4M
/home/backup/incremental/hourly.2/
11M
/home/backup/incremental/hourly.3/
11M
/home/backup/incremental/hourly.4/
11M
/home/backup/incremental/hourly.5/
9.9M /home/backup/incremental/daily.0/
11M
/home/backup/incremental/daily.1/
23M
/home/backup/incremental/daily.2/
8.0M
/home/backup/incremental/daily.3/
8.4M
/home/backup/incremental/daily.4/
12M
/home/backup/incremental/daily.5/
9.5M /home/backup/incremental/daily.6/
20M
/home/backup/incremental/weekly.0/
1.4G total
If all of that worked, then you want to automate it so that you never have to worry about it again. Once again, cron is your friend! Go to the command line, and as root, type the command ‘crontab –e’. This opens the crontab entries list for the root user. Explanation of cron entries is further up in Section 2.7. Add these entries at the end of the file. Remember, you can run these at whatever time you like.
0 */4 * * * root
/usr/bin/rsnapshot hourly
30 3 * * * root /usr/bin/rsnapshot daily
0 3 * * 1 root /usr/bin/rsnapshot weekly
30 2 1 * * root /usr/bin/rsnapshot monthly
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, a spam mail sieve, and a functioning stripped down Mysql dB engine, with the proper rDNS set to allow sending mail to big mail hosts, that will check nightly for rootkits and email the findings to root, with a fully functioning firewall, running dropbear on a non-standard port, and it’s fully backed up with no user intervention with rsnapshot.
I was wondering what would happen to incoming
mail if mailserver went down for any
appreciable amount of time. According to
RFC2821, mail servers are supposed to try the lowest-numbered MX records first
and fall back to higher-numbered MX in the event lower-numbered MX are
unavailable. So we can setup a Postfix backup server, with a higher-numbered
MX, to keep the messages in a queue waiting for mailserver to become available and then deliver to mailserver. This ensures that I do not
lose any emails during the downtime and it’s automatically delivered upon
restoration of connectivity.
However, spammers are known for connecting to backup MX to avoid anti-spam filters that may be running on the primary MX server. This also hides their real IP from my primary MX. This is well known issue. So as well as setting up the backup server to queue mail until mailserver comes back online, system designers urge us to keep the same or better spam filters measures on the backup as the primary. I’ll keep most of it, but skip installing Spamassassin to conserve RAM. I’ve found that rDNS checks, charset checks, and spamhaus.org RBL check kills off the vast majority of the spam, so no reason to run a 45MB Spamassassin for the stragglers that make I through.
Setting up Postfix as a backup MX is extremely simple. All you have to do is tell Postfix which domains to allow relaying for, and then tell Postfix specifically what addresses to allow relaying for. All other domains and addresses will be rejected. Here is the contents of my /etc/postfix/main.cf on my backup mx commented. It is very straightforward.
# Identify which domains to relay for
relay_domains = rajeshprakash.com
# Identify which addresses specifically to
relay for
relay_recipient_maps =
hash:/etc/postfix/relay_recipients
# Check the charset of the incoming
message. If it is in any
# foreign charsets, reject it. I only understand English.
header_checks =
pcre:/etc/postfix/header_checks
# Check various known spam pit falls and
check the SpamHaus.org
# RBL for the incoming client.
smtpd_recipient_restrictions =
permit_mynetworks,
reject_non_fqdn_hostname,
reject_non_fqdn_sender,
reject_non_fqdn_recipient,
reject_unauth_destination,
reject_unauth_pipelining,
reject_invalid_hostname,
reject_rbl_client zen.spamhaus.org
smtpd_helo_required = yes
disable_vrfy_command = yes
smtpd_data_restrictions =
reject_unauth_pipelining,
permit
# Check that the domain->address lookup
and the address->domain
# lookup both return the same address. rDNS check.
smtpd_client_restrictions =
reject_unknown_reverse_client_hostname
Create the file /etc/postfix/relay_recipients with the following example contents. Remember to postmap hash:/etc/postfix/relay_recipients after editing. This file tells postfix specifically which address to queue and deliver.
user1torelay@relaydomain.tld OK
user2torelay@relaydomain2.tld OK
user3torelay@relaydomain3.tld OK
Create the file /etc/postfix/header_checks with the following contents. No need to postmap pcre files. This is the file that will reject some common foreign charsets used by spammers.
#### Header checks file
#### Checks are done in order, top to bottom.
#### /etc/postfix/header_checks
#### non-RFC Compliance
/[^[:print:]]{7}/ REJECT RFC2047
/^.*=20[a-z]*=20[a-z]*=20[a-z]*=20[a-z]*/
REJECT RFC822
/(.*)?\{6,\}/ REJECT RFC822
/(.*)[X|x]\{3,\}/ REJECT RFC822
#### Unreadable NON-acsii un-printable text
/^Subject:.*=\?(GB2312|big5|euc-kr|ks_c_5601-1987|koi8)\?/
REJECT Unreadable
/^Content-Type:.*charset="?(GB2312|big5|euc-kr|ks_c_5601-1987|koi8|iso-2022-jp)/
REJECT Unreadable
#### Character Set Checks
/^(Content-Type:.*|\s+)charset\s*=\s*"?(Windows-1251)\?/
REJECT Bad Content Type
After all of that, restart postfix and you’re done!
/etc/init.d/postfix restart
Voila! You now have a stripped down, current, stable, bare minimum SSH security, Debian installation, with a functioning PHP5 enabled low memory footprint web server, with a SASL authenticating Postfix SMTP server, and a plaintext authenticating IMAP server, complete with spam mail identification, a spam mail sieve, and a functioning stripped down Mysql dB engine, with the proper rDNS set to allow sending mail to big mail hosts, that will check nightly for rootkits and email the findings to root, with a fully functioning firewall, running dropbear on a non-standard port, and it’s fully backed up with no user intervention with rsnapshot, and a backup MX in the event your primary mailserver goes down.