Debian 7 Wheezy Dedicated Web Server Setup Step by Step

Debian 7.0 Wheezy has been officially released on May 5, 2013. Wheezy is powered by Linux kernel 3.2 and multiarch support. Concerning LAMP software, Apache 2.2.22 MySQL 5.5.30 and PHP 5.4.4 are included. Debian 7 supports systemd. More information here.

In this post I describe a dedicated server setup, using Debian Wheezy. It is a Hetzner EX4S dedicated server with IP 144.76.70.100 My blog, my company website and some other web projects will be hosted in this server.

I use Dyn.com for all my DNS and e-MAIL needs, so I will not setup bind name server or a full blown mail server. Default Debian MTA (exim4) is enough for the server to send emails.

I selected a minimal Debian amd64 server (basic Debian system and SSH). Thanks to Hetzner staff, the server was up and running in less than an hour. As usual, they sent me the IP and root password. Below I describe the whole procedure after this point.

Connect using SSH

This is the first and should be the last time you are remotely connected with the server as root:

1
ssh 144.76.70.100 -l root

Change root password

Use:

1
passwd

remove /robot.sh

This step concerns only Hetzner servers.

/etc/rc2.d/S99Zrobot (symbolic link to /robot.sh) is just for reporting a successful install and should normally have been removed immediately. Remove them in case has been not automatically removed.

1
2
mv /robot.sh /robot.sh.bak
rm /etc/rc2.d/S99Zrobot

If /robot.sh is present, apt-get will fail with the following message

1
insserv: warning: script 'S99Zrobot' missing LSB tags and overrides

Perform a full system update

Using apt-get:

1
apt-get update && apt-get -V upgrade

Update files database

Use:

1
updatedb

Color Bash Prompt

To add color to bash prompt, you can follow this guide, where a global solution is provided (recommended).

As an alternative:

To add color to common user prompt:

1
2
cd /<span id="s4of1x0u52h_4" class="s4of1x0u52h">home</span>/pontikis
nano .bashrc

uncomment #force_color_prompt=yes

1
2
3
...
force_color_prompt=yes
...

To add red color to root prompt:

1
2
cd /root
nano .bashrc

Set PS1 as follows:

1
PS1='${debian_chroot:+($debian_chroot)}\[33[01;31m\]\u@\h\[33[00m\]:\[33[01;34m\]\w\[33[00m\]\$ '

Also, find # You may uncomment the following lines if you want `ls’ to be colorized: and uncomment the following lines

To see the changes you have to logoff and login again, or go to home and give

1
. .bashrc

Customize nano text editor

To dislpay line numbers, uncomment # set const

1
nano /etc/nanorc
1
2
# set const
set const

Install systemd

Use:

1
apt-get install <span id="s4of1x0u52h_7" class="s4of1x0u52h">systemd</span>

Update grub and reboot

1
nano /etc/default/grub

Modify GRUB_CMDLINE_LINUX_DEFAULT adding init=/bin/systemd

1
GRUB_CMDLINE_LINUX_DEFAULT="nomodeset init=/bin/systemd"

Finally

1
update-grub && reboot

Install ntp (Network Time Protocol)

Using apt-get

1
apt-get install ntp

Set server timezone

Using dpkg

1
dpkg-reconfigure tzdata

From http://wiki.debian.org/TimeZoneChanges

Restarting Daemons and Long-Running Programs

After the zoneinfo files are updated, you may need to restart daemons and other long-running programs to get them to use the new zone information. Examples of such programs include apache, bind, cron, fetchmail -d, inetd, mailman, sendmail, and sysklogd. A common symptom of this problem is seeing incorrect timestamps mixed in with the correct timestamps in your log files (e.g. /var/log/syslog). Even interactive programs like “mutt” may continue to use the old timezone information until they are restarted.

For example, restart cron

1
systemctl restart cron.service

An easier way is to restart your system

1
reboot

REMARK: Server date and time settings are very important for services like Amazon S3 backup, OpenVPN, NFS etc, where “client” and “server” machines must have the same settings.

Install webmin

Add the following lines to /etc/apt/sources.list

1
2
deb http://download.<span id="s4of1x0u52h_10" class="s4of1x0u52h">webmin</span>.com/download/repository sarge contrib

Add apt key:

1
2
3
cd /root
wget http://www.webmin.com/jcameron-key.asc
apt-key add jcameron-key.asc

Finally

1
2
apt-get update
apt-get install webmin

Create common user

You can use webmin interface (recommended)

Otherwise, you can use adduser srcipt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
adduser pontikis
Adding user `pontikis' ...
Adding new group `pontikis' (1001) ...
Adding new user `pontikis' (1001) with group `pontikis' ...
Creating home directory `/home/pontikis' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for pontikis
Enter the new value, or press ENTER for the default
  Full Name []: Christos Pontikis
  Room Number []:
  Work Phone []:
  Home Phone []:
  Other []:
Is the information correct? [Y/n] y

or the original linux commands

1
2
3
groupadd pontikis
useradd -m -g pontikis -s /bin/bash pontikis
passwd pontikis

It is also important to create a Webmin user (pontikis in my case), to avoid login to Webmin as root.

Harden SSH

Edit SSH configuration:

1
nano /etc/ssh/sshd_config

Make the following changes

1
2
3
4
5
6
7
...
PermitRootLogin no
...
X11Forwarding no
...
AllowUsers pontikis ...
...

Restart SSH

1
systemctl restart ssh.service

SSH key based authentication

To connect from workstation to server machine, add your public key to server.

1
ssh-copy-id -i ~/.ssh/id_rsa.pub 144.76.70.100

Change hostname

Add the hostname (cosmos.medisign.com in my case) to /etc/hostname and /etc/hosts so local address(es) resolves with the new system name and reboot.

Harden kernel using /etc/sysctl.conf

It was a pleasant surprise to see that Hetzner default installation was included important changes to /etc/sysctl.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
### Hetzner Online AG installimage
# sysctl config
#net.ipv4.ip_forward=1
net.ipv4.conf.all.rp_filter=1
net.ipv4.icmp_echo_ignore_broadcasts=1
# ipv6 settings (no autoconfiguration)
net.ipv6.conf.default.autoconf=0
net.ipv6.conf.default.accept_dad=0
net.ipv6.conf.default.accept_ra=0
net.ipv6.conf.default.accept_ra_defrtr=0
net.ipv6.conf.default.accept_ra_rtr_pref=0
net.ipv6.conf.default.accept_ra_pinfo=0
net.ipv6.conf.default.accept_source_route=0
net.ipv6.conf.default.accept_redirects=0
net.ipv6.conf.default.forwarding=0
net.ipv6.conf.all.autoconf=0
net.ipv6.conf.all.accept_dad=0
net.ipv6.conf.all.accept_ra=0
net.ipv6.conf.all.accept_ra_defrtr=0
net.ipv6.conf.all.accept_ra_rtr_pref=0
net.ipv6.conf.all.accept_ra_pinfo=0
net.ipv6.conf.all.accept_source_route=0
net.ipv6.conf.all.accept_redirects=0
net.ipv6.conf.all.forwarding=0

I will only add

1
net.ipv4.tcp_syncookies = 1

Just in case, default Debian /etc/sysctl.conf is a text file with all extra settings commented. See here.

If you want to make changes, you have two options:

  • First method (recommended): create a file /etc/sysctl.d/local.conf and reboot
  • Alternative method: make direct changes to /etc/sysctl.conf and activate them with sysctl -p (without reboot.)

The contents of /etc/sysctl.d/local.conf should be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# Turn on Source Address Verification in all interfaces to
# prevent some spoofing attacks
#net.ipv4.conf.default.rp_filter=1
net.ipv4.conf.all.rp_filter=1
# ADD THE LINE
# ignore echo broadcast requests to prevent being part of smurf attacks
net.ipv4.icmp_echo_ignore_broadcasts=1
# Uncomment the next line to enable TCP/IP SYN cookies
# Note: This may impact IPv6 TCP sessions too
#net.ipv4.tcp_syncookies=1
net.ipv4.tcp_syncookies=1
# ipv6 settings (no autoconfiguration)
net.ipv6.conf.default.autoconf=0
net.ipv6.conf.default.accept_dad=0
net.ipv6.conf.default.accept_ra=0
net.ipv6.conf.default.accept_ra_defrtr=0
net.ipv6.conf.default.accept_ra_rtr_pref=0
net.ipv6.conf.default.accept_ra_pinfo=0
net.ipv6.conf.default.accept_source_route=0
net.ipv6.conf.default.accept_redirects=0
net.ipv6.conf.default.forwarding=0
net.ipv6.conf.all.autoconf=0
net.ipv6.conf.all.accept_dad=0
net.ipv6.conf.all.accept_ra=0
net.ipv6.conf.all.accept_ra_defrtr=0
net.ipv6.conf.all.accept_ra_rtr_pref=0
net.ipv6.conf.all.accept_ra_pinfo=0
net.ipv6.conf.all.accept_source_route=0
net.ipv6.conf.all.accept_redirects=0
net.ipv6.conf.all.forwarding=0

Install exim4 MTA

Using apt-get:

1
apt-get install exim4

Configure exim

1
dpkg-reconfigure exim4-config

Change default option “local delivery only” to “internet site”

Set system mail name: (cosmos.medisign.com in my case)

Accept the default settings in the remaining steps.

(click the thumb for full image)

Forward root mail

It is important as various software and services send mail to inform root for results or errors (cron for example).

1
nano /etc/aliases
1
2
...
root:pontikis@gmail.com

Then, rebuild aliases:

1
newaliases

iptables firewall

Using webmin

or using command line

1
nano /etc/iptables-up.rules

this is just an example with the most common rules

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Generated by iptables-save v1.4.14 on Fri May 17 20:09:12 2013
*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [189:103951]
-A INPUT ! -i eth0 -j ACCEPT
-A INPUT -p tcp -m tcp --tcp-flags ACK ACK -j ACCEPT
-A INPUT -m state --state ESTABLISHED -j ACCEPT
-A INPUT -m state --state RELATED -j ACCEPT
-A INPUT -p udp -m udp --sport 53 --dport 1024:65535 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 0 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 3 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 4 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 11 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 12 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 113 -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p tcp -m tcp -m multiport --dports 25,587 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 10000:10010 -j ACCEPT
-A INPUT -j LOG
-A FORWARD -j LOG
COMMIT
# Completed on Fri May 17 20:09:12 2013
# Generated by iptables-save v1.4.14 on Fri May 17 20:09:12 2013
*mangle
:PREROUTING ACCEPT [49770:4531554]
:INPUT ACCEPT [49770:4531554]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [48931:39133213]
:POSTROUTING ACCEPT [48931:39133213]
COMMIT
# Completed on Fri May 17 20:09:12 2013
# Generated by iptables-save v1.4.14 on Fri May 17 20:09:12 2013
*nat
:PREROUTING ACCEPT [4223:278291]
:INPUT ACCEPT [1650:94585]
:OUTPUT ACCEPT [2836:192019]
:POSTROUTING ACCEPT [2836:192019]
COMMIT
# Completed on Fri May 17 20:09:12 2013

REMARK: rules -A INPUT -j LOG and -A FORWARD -j LOG force iptables to keep log and needed if psad is used. See details in this post.

To load these rules to iptables firewall:

1
iptables-restore < /etc/iptables.up.rules

To save iptables firewall active rules:

1
iptables-save > /etc/iptables.up.rules

To load these rules on startup:

1
nano /etc/network/interfaces

add to eth0 interface

1
2
...
post-up iptables-restore < /etc/iptables.up.rules

MySQL community database server

Using apt-get:

1
apt-get install mysql-server

After installation, run:

1
mysql_secure_installation

mysql_secure_installation sets a root password (if not exists), removes anonymous users, disables non-local root access, removes the test database and access rules related to it and finally reloads privileges.

REMARK: restart MySQL using systemctl restart mysql.service

Install Apache web server

Using apt-get:

1
apt-get install apache2 apache2-mpm-prefork

Enable mod_rewrite and mod_deflate (gzip compression)

1
2
a2enmod rewrite
a2enmod deflate

Config virtual hosts (settings may vary according to your needs)

1
nano /etc/apache2/ports.conf

Add your IP

1
NameVirtualHost 144.76.70.100:80

Create virtual hosts. This is just an example:

1
nano /etc/apache2/sites-available/www.pontikis.net
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<VirtualHost 144.76.70.100:80>
  ServerName  http://www.pontikis.net
  ServerAdmin christos@pontikis.net
  DocumentRoot /var/www/pontikis.net
  <Directory /var/www/pontikis.net>
    Options FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
  </Directory>
  ErrorLog ${APACHE_LOG_DIR}/pontikis.net_error.log
  LogLevel warn
  CustomLog ${APACHE_LOG_DIR}/pontikis.net_access.log combined
  ErrorDocument 404 /404/
  SetOutputFilter DEFLATE
  SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|ico|png)$ \ no-gzip dont-vary
  SetEnvIfNoCase Request_URI \.(?:exe|t?gz|zip|bz2|sit|rar)$ \no-gzip dont-vary
  SetEnvIfNoCase Request_URI \.pdf$ no-gzip dont-vary
  
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
</VirtualHost>

Enable site

Restart Apache

1
systemctl restart apache2.service

Awstats log analyzer

Using apt-get:

1
apt-get install awstats

Details in a future post soon.

php

Using apt-get:

1
apt-get install php5

Enable php error log. Log file must be writable from Apache. So:

1
2
mkdir /var/log/php
chown www-data /var/log/php

Edit php.ini

1
nano /etc/php5/apache2/php.ini

uncomment ;error_log:

1
error_log = /var/log/php/php_errors.log

Remember to rotate /var/log/php/php_errors.log:

1
nano /etc/logrotate.d/php

add the following:

1
2
3
4
5
6
7
/var/log/php/php_errors.log {
  weekly
  missingok
  rotate 4
  notifempty
  create
}

Install MySQL Native Driver (mysqlnd)

1
apt-get install php5-mysqlnd

REMARK: If, for any reason, you don’t want mysqlnd, try apt-get install php5-mysql instead.

Install php adodb extension.

1
apt-get install php5-adodb

Install php GD library

1
apt-get install php5-gd

Config mbstring

1
nano /etc/php5/conf.d/mbstring-settings.ini
1
2
3
4
5
6
7
8
9
[mbstring]
mbstring.language = English
mbstring.internal_encoding = UTF-8
mbstring.encoding_translation = On
mbstring.http_input = UTF-8,SJIS,EUC-JP
mbstring.http_output = UTF-8
mbstring.detect_order = UTF-8,ASCII,JIS,SJIS,EUC-JP
mbstring.substitute_character = none
mbstring.func_overload = 0

Harden PHP setup (settings may vary according to your needs)

1
nano /etc/php5/conf.d/security.ini
1
2
3
4
5
6
7
8
allow_url_include = Off
allow_url_fopen = Off
session.use_only_cookies = 1
session.cookie_httponly = 1
expose_php = Off
display_errors = Off
register_globals = Off
disable_functions = escapeshellarg, escapeshellcmd,passthru, proc_close, proc_get_status, proc_nice, proc_open,proc_terminate

Restart Apache

1
systemctl restart apache2.service

Install memcached

Using apt-get:

1
2
apt-get install memcached php5-memcached
systemctl restart apache2.service

Install phpMemcachedAdmin (optional):

1
2
3
4
5
6
mkdir /var/www/phpMemcachedAdmin
cd /var/www/phpMemcachedAdmin
wget http://phpmemcacheadmin.googlecode.com/files/phpMemcachedAdmin-1.2.2-r262.tar.gz
tar -xvzf phpMemcachedAdmin-1.2.2-r262.tar.gz
chmod +r *
chmod 0777 Config/Memcache.php

You may want to restrict access to this directory using .htaccess

Install Alternative PHP Cache (APC)

Using apt-get:

1
apt-get install php-apc

Edit configuration (optional)

1
nano /etc/php5/conf.d/20-apc.ini

After extension=apc.so, add the following (modify them according to your needs)

1
2
3
4
5
6
7
8
extension=apc.so
apc.enabled=1
apc.shm_size=128M
apc.ttl=3600
apc.user_ttl=7200
apc.gc_ttl=3600
apc.max_file_size=1M

Restart Apache

1
systemctl restart apache2.service

Install database manager

phpMyAdmin and adminer are popular. I prefer adminer:

1
2
mkdir /var/www/adminer
wget http://downloads.sourceforge.net/adminer/adminer-3.6.4-mysql-en.php

You may want to restrict access to this directory using .htaccess

Install git

Using apt-get:

1
apt-get install git

Install s3cmd for Amazon backup

Using apt-get:

1
apt-get install s3cmd

REMARK: There is a serious BUG with current Debian version of s3cmd (1.1.0-beta3) in multipart uploads to Amazon S3 (mainly using cron). Some changes must be done to /usr/share/s3cmd/S3/S3.py. The patch is available here.

Configure s3cmd with your Amazon credentials

1
2
cd /root
s3cmd --configure

Various tools

Using apt-get:

1
apt-get install mc p7zip-full htop sysstat

Deploy Projects

I use git and Github to deploy my projects (either public or private). For example to deploy my blog in the new server:

1
2
3
chown -R pontikis:pontikis /var/www
cd /var/www
git clone git@<span id="s4of1x0u52h_11" class="s4of1x0u52h">github</span>.com:pontikis/pontikis.net.git

Furthermore, to update this project in the future:

1
2
3
cd /var/www/pontikis.net
git fetch
git merge origin/master

User pontikis public rsa key must be added to github. Details here.

Backup software

There are many backup solutions available. I use bash-cloud-backup.

bash-cloud-backup is a set of bash scripts, which can be used to automate local and cloud backup in Linux/Unix machines. I use Amazon S3 as cloud backup solution.

Simple system monitoring tools

Get email notifications for updates

1
2
3
apt-get install apticron
apt-get install update-notifier-common
apt-get install debian-goodies

More details in this post.

Logwatch

Logwatch is a customizable log analysis system. Logwatch parses through your system’s logs and creates a report analyzing areas that you specify.

Using apt-get:

1
apt-get install logwatch

Configuration:

1
2
3
mkdir /var/cache/logwatch
cp /usr/share/logwatch/default.conf/logwatch.conf /etc/logwatch/conf/
nano /etc/logwatch/conf/logwatch.conf
1
2
#Output = stdout
Output = mail

Simple intrusion detection techniques

rkhunter

1
apt-get install rkhunter

Simple intrusion prevention techniques

fail2ban

fail2ban scans log files and bans IPs that show the malicious signs, for example too many password failures, seeking for exploits, etc.

1
apt-get install fail2ban

Find details in this post.

psad

psad analyze iptables log messages to detect port scans and other suspicious traffic.

1
apt-get install psad

Find details in this post.

Security and system auditing tool

Install Lynis using apt-get:

1
apt-get install lynis

Perform system check:

1
lynis -c

Perform (again) a full system update

Using apt-get:

1
apt-get update && apt-get -V upgrade

Update files database (again)

Use:

1
updatedb

Conclusion

I would prefer a dedicated hardware firewall, but it is not so easy to maintain it. Moreover, Hetzner does not offer dedicated firewall (as far as I know).

I have posted dedicated posts for some topics of this article (e.g. monitoring and intrusion detection techniques, local and Amazon backup and more). See “Related posts” below.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s