Difference between revisions of "Debian stable Web Server step-by-step"

From Nick Jenkins
Jump to: navigation, search
m (Be explicit about atd load parameter)
(+ Logcheck configuration)
Line 919: Line 919:
  chmod 660 /var/log/btmp
  chmod 660 /var/log/btmp
  chmod 600 /boot/grub/menu.lst
  chmod 600 /boot/grub/menu.lst
== Logcheck configuration ==
"nano /etc/logcheck/logcheck.conf"
- REPORTLEVEL="server"
+ REPORTLEVEL="paranoid"
- SENDMAILTO="logcheck"
+ SENDMAILTO="your@full.email.com"
If you are using atd, then do "nano /etc/logcheck/ignore.d.paranoid/atd" (which will be a new file) and add this:
^\w{3} [ :0-9]{11} [._[:alnum:]-]+ atd\[[0-9]+\]: \(pam_unix\) session opened for user INSERT_USERNAME by \(uid\=1\)$
^\w{3} [ :0-9]{11} [._[:alnum:]-]+ atd\[[0-9]+\]: \(pam_unix\) session closed for user INSERT_USERNAME
To stop alerts about time synchronisation, do "nano /etc/logcheck/ignore.d.paranoid/ntp" (which will be a new file), and add this:
^\w{3} [ :0-9]{11} [._[:alnum:]-]+ ntpd\[[0-9]+\]: synchronized to ([0-9.]{7,15}|[0-9a-fA-F:.]{4,39}), stratum [0-9]+$
== Specify atd load parameter ==
== Specify atd load parameter ==

Revision as of 03:21, 11 August 2010

This is a series of specific steps for setting up Debian Etch 4.0 as a nice PHP web server. You are welcome to correct any mistakes or errors, improve the content, or add anything that seems to be missing.

Run memtest overnight

First run Memtest86+ on the machine overnight, to test that the CPU and memory are error-free. Also run a CPU stress test for 5 to 10 minutes to check CPU is reliable and adequately cooled. The easiest way to download and run these memory and CPU testing tools is with the Ultimate Boot CD.

Also use System Rescue CD to check bad blocks on the hard drive, before trusting it with any data: badblocks -v -s -w -c 4096 /dev/sda

If the machine does not pass memtest and CPU stress and HDD tests without any errors or warnings at all, then do NOT proceed any further until this is rectified.

Install Debian Etch 4.0 base on an HP netserver 1000R with a NetRAID card.

  • Boot from Debian 4.0r0 i386 Netinst CD
  • Enter (default installation)
  • Lang: English [default]
  • Country: Australia
  • Keymap: American English [default]
  • Primary network interface: Eth0 [default]
  • "Go back" after network autodetection
  • Configure network manually
  • as IP address, and then take the defaults for netmask, gateway, and DNS.
  • Hostname: netserver
  • Domain name: YourHostName.com
  • Partitioning method: Guided - yes entire disk [default]
  • Disk to partition: "SCSI3 (1,0,0) (sda) - 18.2 Gb MegaRAID LD 0 RAID1 17G" [default, only choice]
  • Partitioning scheme: All files in one partition [default]
  • Finish partitioning, and write changes to disk [default]
  • Yes, write changes to disk. [default]
  • City: Sydney [default]
  • Root password: standard
  • Extra Username: nickj
  • Extra Username Password: standard
  • Use a network mirror: Yes [default]
  • Australian mirror [default]
  • use: ftp.au.debian.org [default]
  • Proxy: leave blank [default]
  • Participate in package user survey: No [default]
  • Choose software to install: Web server + File server + Mail server + SQL database + Standard system
  • Continue installing libc-client without maildir support: Yes [default]
  • Workgroup name: WORKGROUP
  • Modify smb.conf to use WINS settings for DHCP: Yes
  • Install the GRUB boot loader to the master boot record: Yes [default]
  • remove CD
  • Continue [default]
  • Machine reboots
  • Check boots okay, login as root, check networking okay, check SSH running.
  • SSH into the box, and can now do remaining stuff below remotely via SSH.

Update /etc/apt/sources.list.

"nano /etc/apt/sources.list", and comment out the "deb cdrom:" line or lines.

This makes all data come off the Internet, which is what we want.

Get the latest and greatest packages.

Get the latest and greatest packages (currently there are no updates, but later there probably will be).

aptitude update
aptitude upgrade
aptitude dist-upgrade

Remove unneeded or unwanted packages.

Remove unneeded or unwanted packages for a headless webserver, most especially those that talk to the network.

Note: if you are using the system as a Linux desktop, and especially if you are running Ubuntu, then either skip this step, or take care to make sure that the following doesn't remove packages needed for the desktop to work. For example, on Ubuntu, do NOT remove anything where it will also remove the "ubuntu-desktop" package (use 'q' to quit if aptitude says it is going to remove this).

# remove NFS
aptitude --purge remove nfs-common nfs-kernel-server 

# Remove appletalk compat:
aptitude --purge remove netatalk

# Remove PHP4 (we'll install PHP5 later)
aptitude --purge remove php4-common libapache2-mod-php4

# RPC daemon
aptitude --purge remove portmap

# Remove postgres (we'll install MySQL later)
aptitude --purge remove postgresql postgresql-client postgresql-common \
 postgresql-doc postgresql-contrib

# remove email related stuff :
aptitude --purge remove qpopper sa-exim uw-imapd

# remove ident:
aptitude --purge remove pidentd

# remove analog
aptitude --purge remove analog

# Remove unneeded packages:
aptitude --purge remove spamassassin spamc python-newt mutt libapache2-mod-perl2 \

These are steps that make sense on a webserver, but you should probably skip these on a laptop or Linux Desktop:

# DHCP and related functionality
aptitude --purge remove winbind dhcp3-client dhcp3-common 

# remove samba:
aptitude --purge remove samba samba-common samba-doc smbfs

Then purge the old RC files from uninstalled packages:

dpkg --purge $(COLUMNS=132 dpkg -l | grep ^rc | awk '{ print $2; }')

Need to close down open ports. Check what ports are open with these 3 commands, should be stripped back now:

nmap localhost
lsof -i
netstat -l

Install LAMP.

# Install LAMP:
aptitude install php5 php5-gd php5-cgi php5-mysql mysql-server mysql-client php5-curl lynx php-pear \
ca-certificates xml-core apache2 libapache2-mod-php5

Install extra useful software.

Installing extra useful software:

aptitude install nmap

# This will install the Exim V4 mail server - when prompted, select the "internet site; mail is sent and received directly using SMTP" configuration option :
aptitude install logcheck

aptitude install diffstat
aptitude install zip unzip
aptitude install subversion subversion-tools patch

# Tidying web pages.
aptitude install tidy

# package info:
aptitude install grep-dctrl

# for debugging apache crashes:
aptitude install gdb

# useful utility
aptitude install curl

# For building PHP modules:
aptitude install php5-dev

# For converting HTML to text in a console-only environment
aptitude install html2text

# To be able to compile PHP from snaps.php.net
aptitude install flex libxml2-dev

# Get the "dig" command:
aptitude install dnsutils

# Get the "cruft" command:
aptitude install cruft

# Get the "sloccount" command:
aptitude install sloccount

# Get the p7zip command:
aptitude install p7zip

# Install mailer for sending attachments
aptitude install mutt

# Other useful packages:
aptitude install bzip2 deborphan p7zip-full fakeroot indent fdutils xsltproc

# Get the "uprecords" command:
aptitude install uptimed

# S.M.A.R.T. monitoring tools (skip if running inside a virtual machine/box/VPS - cannot monitor disks from inside a guest - needs to be done by the host O/S).
aptitude install smartmontools
# Then enable smartd:
nano /etc/default/smartmontools
# ... and uncomment the start smartd line.

# Get pinfo, a better GUI for viewing info and manual pages.
aptitude install pinfo

# Get ddrescue, useful for recovering data from failing hard disks (skip if running inside a virtual machine/box/VPS).
aptitude install ddrescue

# Get the "lsb_release -a" command (not installed by default).
aptitude install lsb-release

# The at, atd, and batch commands:
aptitude install at

Disable IPv6.

Disabling IPv6:

nano /etc/modprobe.d/aliases

and change this line:

- #alias net-pf-10 ipv6
+ alias net-pf-10 off

Then have to reboot for this change to take effect:


Can check has been successfully disabled with:

ip a | grep inet6

(should give no output when IPv6 disabled)

... and:

/usr/bin/lsof -i | grep LISTEN

Should only list "IPv4" entries.

... and:

netstat -l

Should not show "tcp6" and "udp6" after the reboot if it is working.

Stop console screen from blanking.

Stop console screen from blanking, due to power-saving:

nano /etc/console-tools/config

Change this line:




Exim 4 configuration.

Exim 4 configuration:

Need to configure exim rather than remove it because the "at" package depends on a mail-transport-agent package.

dpkg-reconfigure exim4-config

Then choose these options, for a server in a data centre:

General type of mail configuration:  internet site; mail is sent and received directly using SMTP
System mail name: YourHostName.com   <Note: this should be a valid domain to reply to, so use this instead of the machine's name>
IP-addresses to listen on for incoming SMTP connections:
Other destinations for which mail is accepted:  <blank>
Domains to relay mail for: YourOtherHostName.com
machines to relay for:  <blank>
Keep number of DNS-queries minimal (Dial-on-Demand)?  No
Delivery method for local mail:  mbox format in /var/mail/
Split configuration into small files? No [default]

[this allows mail to be sent locally, but not by other hosts connecting to this one]

For a development or test server, on a broadband connection, have to use smarthosts, as most ISPs block port 25 for outgoing mail. For example, the Exim4 config for Telstra BigPond is the same as above, except for the following:

General type of mail configuration:  mail sent by smarthost; received via SMTP or fetchmail 
IP address or host name of the outgoing smarthost: mail-hub.bigpond.net.au
Hide local name in outgoing mail? No

If sending mail is not working:
To see the queue, and try to clear it out, do this:

exim4 -v -v -v -qff

To view the log messages, do this:

tail -f /var/log/exim4/mainlog

Customizing Apache configuration.

Customizing Apache:

nano /etc/apache2/conf.d/security 

Make these changes:

- ServerTokens Full
+ ServerTokens Prod
- ServerSignature On
+ ServerSignature Off
- TraceEnable On
+ TraceEnable Off

Save, and test config:

apache2ctl -t

Restart the web server:

/etc/init.d/apache2 force-reload

Then to test from the command line that these changes have taken effect:

telnet localhost 80
GET / HTTP/1.1
(press enter twice).

... and the response header should contain "Server: Apache", without the version number.

Then general configuration:

nano /etc/apache2/mods-enabled/alias.conf

Comment this out:

#    Alias /icons/ "/usr/share/apache2/icons/"
#    <Directory "/usr/share/apache2/icons">
#        Options Indexes MultiViews
#        AllowOverride None
#        Order allow,deny
#        Allow from all
#    </Directory>

Removing some more unwanted things:

nano /etc/apache2/sites-available/default

Then change these lines:

- ServerAdmin webmaster@localhost
+ ServerAdmin some@valid.email.com
  <Directory /var/www/>
- Options Indexes FollowSymLinks MultiViews
+ Options -Indexes FollowSymLinks MultiViews

... and delete this section (special directory we don't use):

-        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
-        <Directory "/usr/lib/cgi-bin">
-                AllowOverride None
-                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
-                Order allow,deny
-                Allow from all
-        </Directory>

... and delete this section (another special directory we don't use):

-    Alias /doc/ "/usr/share/doc/"
-    <Directory "/usr/share/doc/">
-        Options Indexes MultiViews FollowSymLinks
-        AllowOverride None
-        Order deny,allow
-        Deny from all
-        Allow from ::1/128
-    </Directory>

Test config:

apache2ctl -t

Then reload apache so that it gets these changes:

/etc/init.d/apache2 reload

Note: if HTTPS has already been setup, then need to repeat the above steps for the SSL site configuration files too.

Then remove mod_autoindex, not needed:

a2dismod autoindex

Then reload apache so that it gets this change:

/etc/init.d/apache2 force-reload

To see a list of which Apache2 modules are enabled, do:

ls /etc/apache2/mods-enabled/

Can then remove unwanted modules like so:

a2dismod perl
a2dismod mod_python

(although these modules won't be enabled if following these instructions).

Reload apache:

/etc/init.d/apache2 force-reload 

Enable the expires module:

a2enmod expires

Reload apache:

/etc/init.d/apache2 force-reload

Few more apache tweaks - allow index.php3 as index file - "nano /etc/apache2/mods-enabled/dir.conf", and change:

- DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm
+ DirectoryIndex index.html index.cgi index.pl index.php index.xhtml index.htm index.php3

Then "nano /etc/apache2/mods-enabled/php5.conf", and change to prevent PHP .inc file source code from being visible (e.g.: http://IP-address/lib-functions.inc )

- AddType application/x-httpd-php .php .phtml .php3
+ AddType application/x-httpd-php .php .phtml .php3 .inc

Then check above syntax is OK:

apache2ctl -t

Then restart apache:

/etc/init.d/apache2 force-reload

Set up the HTTP / Apache auth / passwords. Needed to be prompted for a password when accessing directories with .htaccess and .htpasswd files.

nano /etc/apache2/sites-available/default

... and replace all occurrences like this, with the line below:

- AllowOverride None
+ AllowOverride AuthConfig

Test config:

apache2ctl -t

Then reload apache so that it gets these changes:

/etc/init.d/apache2 reload

Note: if HTTPS has already been setup, then need to repeat the above steps for the SSL site configuration files too. ( nano /etc/apache2/sites-available/ssl )

Set up Apache virtual hosting.

Setting up Apache virtual hosting:

Load the mass virtual hosting module:

a2enmod vhost_alias

Then "nano /etc/apache2/apache2.conf", and add this to the end of the file to enable mass virtual hosting:

# ---------------------------------------------------
# ---------------- Virtual Hosting ------------------
<IfModule mod_vhost_alias.c>

# Get the server name from the Host: header
UseCanonicalName Off

# The virtual document root is under /var/www/__name_of_whatever_was_requested__
VirtualDocumentRoot /var/www/%0

# Note: Regrettably, cannot set up separate SSL certs for each virtual host here (need different IPs or ports)
# see: http://www.mail-archive.com/modssl-users@modssl.org/msg15648.html

# ---------------------------------------------------

Then check above syntax is OK:

apache2ctl -t

Then restart apache:

/etc/init.d/apache2 force-reload

Then try to access a page by the hostname (e.g. "http://IP-address"). Should get an error like "The requested URL / was not found on this server." Also a "tail -f /var/log/apache2/error.log" should show an entry like: "File does not exist: /var/www/IP-address". This indicates that virtual hosting is working.

Apache content compression.

Setting up Apache content compression:


Load the headers module:

a2enmod headers

Then "nano /etc/apache2/sites-available/default", and add this to the end of the file (but inside the <VirtualHost> block) to enable mod_deflate, and turn on logging for it.

# ---------------------------------------------------
# -------------- Enabling Mod_Deflate ---------------
<IfModule mod_deflate.c>
  # Compress all content, manually excluding specified file types
  # place filter 'DEFLATE' on all outgoing content
  SetOutputFilter DEFLATE
  # exclude uncompressible content via file type
  SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png|rar|zip)$ no-gzip

  # properly handle requests coming from behind proxies
  <IfModule mod_headers.c>
      Header append Vary User-Agent env=!dont-vary

  # Keep a log of compression ratio on each request
  DeflateFilterNote Input instream
  DeflateFilterNote Output outstream
  DeflateFilterNote Ratio ratio
  LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' deflate
  CustomLog /var/log/apache2/deflate.log deflate

  # Properly handle old browsers that do not support compression
  BrowserMatch ^Mozilla/4 gzip-only-text/html
  BrowserMatch ^Mozilla/4\.0[678] no-gzip
  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# ---------------------------------------------------

Then check above syntax is OK:

apache2ctl -t

Then restart apache:

/etc/init.d/apache2 force-reload

Can then check it is working by accessing some pages, and doing:

tail -f /var/log/apache2/deflate.log

Note: Have to paste this into /etc/apache2/sites-available/ssl too (if have created it), or otherwise just do HTTPS / SSL setup at the end, which makes things easier.

Configure php.ini.

Configuring PHP.ini (note: for Ubuntu rather than debian, the path is probably /etc/php5/cgi rather than /etc/php5/apache2)

cp /etc/php5/apache2/php.ini /etc/php5/apache2/orig-php.ini
nano /etc/php5/apache2/php.ini

... and make these changes:

- ;date.timezone =
+ date.timezone = Australia/Sydney

# hide PHP in the headers
- expose_php = On
+ expose_php = Off

- max_execution_time = 30
+ max_execution_time = 300 ; Equals 5 mins
- upload_max_filesize = 2M
+ upload_max_filesize = 10M

- allow_url_fopen = On
+ allow_url_fopen = 0

Then need to restart apache for changes to take effect:

/etc/init.d/apache2 force-reload

Then soft-link the command line php.ini to the apache php.ini, so that they can have a shared configuration:

# diff -u --ignore-all-space /etc/php5/cli/php.ini /etc/php5/apache2/php.ini
mv /etc/php5/cli/php.ini /etc/php5/cli/php.ini-orig
ln -s /etc/php5/apache2/php.ini /etc/php5/cli/php.ini
ls -al /etc/php5/cli/php.ini

Enable SSL in Apache 2.

Enabling SSL in Apache 2:

a2enmod ssl
mkdir /etc/apache2/ssl
export RANDFILE=/dev/random
openssl req $@ -new -x509 -days 365 -nodes -out \
 /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.pem

When prompts, will ask a series of questions. Some fictional answers:

Country: AU
State: NSW
City: Sydney
Organisation Name: FooBar Pty Ltd
Dept: YourHostName
YOUR name: www.YourHostName.com   [must be the host's fully qualified name, or will get a msg that the certificate doesn't match the site name]
Email address: webmaster@YourHostName.com


chmod 600 /etc/apache2/ssl/apache.pem
  • This should come after the default sites-available config, in the previous sections, to avoid having to repeat steps for both non-SSL and for SSL.
  • "nano /etc/apache2/sites-available/default-ssl", and update as per the "default" file (delete doc, icons, update email address, AllowOverride, Options -Indexes, and add the mod_deflate block).
  • Then just have to update the SSL to use the certificate generated above:
   SSLCertificateFile /etc/apache2/ssl/apache.pem

Or, if have already bought a signed certificate from a CA (with the .CRT server certificate file, and a .KEY private key file), then use this instead of the "SSLCertificateFile" line above:

   #   Server Certificate:
   #   Point SSLCertificateFile at a PEM encoded certificate.  If
   #   the certificate is encrypted, then you will be prompted for a
   #   pass phrase.  Note that a kill -HUP will prompt again. A test
   #   certificate can be generated with `make certificate' under
   #   built time.
   SSLCertificateFile /etc/apache2/ssl/server.crt

   #   Server Private Key:
   #   If the key is not combined with the certificate, use this
   #   directive to point at the key file.
   SSLCertificateKeyFile /etc/apache2/ssl/server.key

Then enable this site:

a2ensite default-ssl

Then reload apache with:

/etc/init.d/apache2 force-reload

Change the date.

Check if the time and date are correct:


To change the time and date, if it's wrong:

date --set 0:42:05
hwclock --systohc --utc

See the NTP step as the long-term solution to keeping time accurate.

Tweak MySQL configuration.

Edit configuration file:

nano /etc/mysql/my.cnf

... and add these settings to increase performance a bit:

# change from listed default of 16 to 64  :
- key_buffer              = 16M
+ key_buffer              = 64M
# uncomment, and change from default of 64 to 256:
- # table_cache             = 64
+ table_cache             = 256
# Add this on the line after the above
+ sort_buffer             = 4M

Also increase query cache a bit:

query_cache_limit       = 2M
query_cache_size        = 50M

Then to make changes take effect:

/etc/init.d/mysql restart

Installing and configuring portsentry.

installing and configuring portsentry:

aptitude install portsentry


nano /etc/portsentry/portsentry.conf

... and change to add some ignored ports:

+ ADVANCED_EXCLUDE_TCP="113,139,25,445,135"

# Enable blocking:

# Make a little less likely to react:


nano /etc/portsentry/portsentry.ignore.static

... and add:

# Put hosts in here you never want blocked. This includes the IP addresses
# of all local interfaces on the protected host (i.e virtual host, mult-home)
# Keep and to keep people from playing games.
# Add the local IP address, the gateway address, DNS addresses,
# addresses of hosts you know you will be connecting from, etc etc.


nano /etc/default/portsentry

... (will be an empty or non-existent file), and add / change the two lines to ATCP and AUDP modes (these are the inverse modes) :


Can then reload portsentry by doing:

/etc/init.d/portsentry restart

Can then test with:


Note: when not using atcp and audp, portsentry will open lots of ports, which will show up with the above command.

Locking down the IP functionality.

Locking down the IP functionality to make the system behave sensibly: [from http://www.debian.org/doc/manuals/securing-debian-howto/ch4.en.html , section 4.17.3 ]:

nano /etc/sysctl.conf

... and add the following to the end of that file:

# Additional settings - adapted from the script contributed
# by Dariusz Puchala (see below)
# Ignore ICMP broadcasts
net/ipv4/icmp_echo_ignore_broadcasts = 1
# Ignore bogus ICMP errors
net/ipv4/icmp_ignore_bogus_error_responses = 1
# Do not accept ICMP redirects (prevent MITM attacks)
net/ipv4/conf/all/accept_redirects = 0
# _or_
# Accept ICMP redirects only for gateways listed in our default
# gateway list (enabled by default)
# net/ipv4/conf/all/secure_redirects = 1
# Do not send ICMP redirects (we are not a router)
net/ipv4/conf/all/send_redirects = 0
# Do not forward IP packets (we are not a router)
# Note: Make sure that /etc/network/options has 'ip_forward=no'
net/ipv4/conf/all/forwarding = 0
# Enable TCP Syn Cookies
# Note: Make sure that /etc/network/options has 'syncookies=yes'
net/ipv4/tcp_syncookies = 1
# Log Martian Packets
# Commented out as this can create heavy load on server flooded with information:
# net/ipv4/conf/all/log_martians = 1
# Turn on Source Address Verification in all interfaces to
# prevent some spoofing attacks
# Note: Make sure that /etc/network/options has 'spoofprotect=yes'
net/ipv4/conf/all/rp_filter = 1
# Do not accept IP source route packets (we are not a router)
net/ipv4/conf/all/accept_source_route = 0

... then do:

cat /proc/sys/net/ipv4/tcp_syncookies

... should say "0". Then do:


... then do again:

cat /proc/sys/net/ipv4/tcp_syncookies

... and if it worked, it should say "1".


nano /etc/security/limits.conf

... and add these two lines:

*                hard    core            0
*                hard    nproc           150

This makes DOS attacks marginally harder - sets the core size to 0 K, and the maximum number of processes to 150.

Install bastille.

aptitude install bastille

On Debian 5 there are two files that need to be modified after installing the bastille package, so that it can run (otherwise get an error about not being a supported OS) -

  • /usr/lib/Bastille/API.pm
  • /usr/lib/Bastille/IOLoader.pm

Search for DB4.0 and you will see it grouped with the OS compatibility listings. Just add DB5.0 right after the DB4.0 and you're set. At least, it worked fine for me.

Then run:


... to configure it. Some possible answers to questions:

accept terms
restrictive permissions on admin utils: no  [default]
disable SUID status for mount/unmount: yes [default]
disable SUID status for ping: yes [default]
disable SUID status for at: no   [differs from default, needed for my setup]
Should Bastille disable clear-text r-protocols that use IP-based authentication? [Y]  [default]
enforce password aging:  no [differs from default, don't want to have to do this]
restrict use to cron to admin accounts:  Yes. [default]
set default umask:  Yes. [default]
Umask: 002 - 
disallow root login on all ttys: n [default]
password-protect the GRUB prompt? [N] [default]
disable CTRL-ALT-DELETE rebooting? [N] [default]
password protect single user mode [Y] [default]
default-deny on TCP Wrappers and xinetd? [N]    [default]
ensure the telnet service does not run on this system? [y]  [default]
ensure inetd's FTP service does not run on this system? [y] [default]
display "Authorized Use" messages at log-in time? [Y]   [default]
disable the gcc compiler? [N] [default]
put limits on system resource usage? [N]  [default]   [would say yes to this next time, since did this manually above].
restrict console access to a small group of user accounts? [N] [default]
add additional logging? [Y]     [default]
remote logging host? [N]   [default]
install TMPDIR/TMP scripts? [N]    [default]
run the packet filtering script? [N]    [default] [asks all sorts of over-detailed Qs]
make changes? [y]        [default]

Install Sun's JDK

First we have to enable the non-free and contrib repositories, by adding these 3 sources. "nano /etc/apt/sources.list"

deb http://ftp.us.debian.org/debian/ lenny contrib non-free
deb http://security.debian.org/ lenny/updates contrib
deb-src http://security.debian.org/ lenny/updates contrib

Installing the SUN JDK:

aptitude install sun-java6-jdk sun-java6-jre

... and say "yes, accept" when prompted about the terms and conditions.

To show the available JVMs & JDKs :

update-alternatives --display java

Check current default java version with:

java -version

If you have multiple versions of Java installed, then you have the option of changing the system default from GCJ to sun's JDK:

update-java-alternatives --verbose --set java-6-sun

Check version has been updated with:

java -version

If ever need to restore to GCJ (if using this), can do so with this:update-java-alternatives --verbose --set java-gcj

Install some useful java libraries:

aptitude install libmysql-java junit junit-doc

Install the NTP daemon to keep the time current.

Install NTP daemon to keep the time current:

aptitude install ntp ntp-doc


nano /etc/ntp.conf

... and set up as follows:

# /etc/ntp.conf, configuration for ntpd

driftfile /var/lib/ntp/ntp.drift
# Enable this if you want statistics to be logged.
#statsdir /var/log/ntpstats/

statistics loopstats peerstats clockstats
filegen loopstats file loopstats type day enable
filegen peerstats file peerstats type day enable
filegen clockstats file clockstats type day enable

# deny-by-default policy
restrict default ignore

# You do need to talk to an NTP server or two (or three).
server clock.psu.edu       iburst
server ntp0.cornell.edu    iburst
server ntp0.nl.net         iburst
server ntp2a.mcc.ac.uk     iburst
server salmon.maths.tcd.ie iburst

# Have to grant access to the above servers - however the servers are not allowed
# to modify the run-time configuration or query the NTP server.
restrict clock.psu.edu       nomodify nopeer notrap noquery
restrict ntp0.cornell.edu    nomodify nopeer notrap noquery
restrict ntp0.nl.net         nomodify nopeer notrap noquery
restrict ntp2a.mcc.ac.uk     nomodify nopeer notrap noquery
restrict salmon.maths.tcd.ie nomodify nopeer notrap noquery

# Local users may interrogate the ntp server more closely.
restrict           nomodify nopeer notrap

Then restart with:

/etc/init.d/ntp restart

Check that there were no errors in the system log with:

tail -f /var/log/syslog

Should get output like this:

Jul  7 17:17:31 ludo ntpd[3473]: ntpd 4.2.2p4@1.1585-o Sun Mar  4 13:21:35 UTC 2007 (1)
Jul  7 17:17:31 ludo ntpd[3474]: precision = 2.000 usec
Jul  7 17:17:31 ludo modprobe: WARNING: Not loading blacklisted module ipv6
Jul  7 17:17:31 ludo ntpd[3474]: Listening on interface wildcard, Disabled
Jul  7 17:17:31 ludo ntpd[3474]: Listening on interface lo, Enabled
Jul  7 17:17:31 ludo ntpd[3474]: Listening on interface eth0, Enabled
Jul  7 17:17:31 ludo ntpd[3474]: kernel time sync status 0040
Jul  7 17:17:31 ludo ntpd[3474]: frequency initialized -70.588 PPM from /var/lib/ntp/ntp.drift

Can then check if it is working with:

ntpq -p

Should get output like this:

     remote           refid      st t when poll reach   delay   offset  jitter
*otc2.psu.edu    2 u    1   64    1  256.700   -0.417   1.318
 cudns.cit.corne     2 u    2   64    1  263.631   -4.051   0.580
 ntp0.nl.uu.net  .GPS.            1 u    1   64    1  350.644    0.044   1.723
 maverick.mcc.ac     2 u    2   64    1  325.238   -3.433   0.123
 salmon.maths.tc    3 u    1   64    1  335.144   -0.182   0.198

Can then check for open UDP connections, like so:

netstat -l

Should get output which includes something like this:

udp        0      0 ludo.yourhostname.c:ntp *:*
udp        0      0 localhost:ntp           *:*
udp        0      0 *:ntp                   *:*

(There does not seem to be any way to turn these udp connections off, which is why we use the deny-by-default policy)

Automatic daily downloading and email notification of pending security updates.

Automatic daily downloading and email notification of pending security updates. source. Note: this step is probably only appropriate for a headless web server, and a laptop or desktop-system has synaptic, which provides a nicer interface to package updating. Install:

aptitude install cron-apt


nano /etc/cron-apt/config

Change this line:


To test, can run with:


This will then automatically download any security updates each night, and send a daily email to root about what updates need to be applied. Then install apt-listchanges for a printout and emailed list of package changes when actually installing:

aptitude install apt-listchanges

Configure apt-listchanges to show information about what an update contains, before we actually install it:

dpkg-reconfigure apt-listchanges
Method for changes display: text
skip changes that have already been seen? No.
E-mail Address(es) which will receive changes: root
Changes displayed with apt: both
Prompt for confirmation after displaying changes? Yes

Then check the above configuration applied successfully:

cat /etc/apt/listchanges.conf

When ready to apply package updates, can then manually install the updates with:

aptitude update
aptitude upgrade

This won't apply any kernel updates, however. For these, need to do:

aptitude dist-upgrade

... and then "reboot". Note: a log of package upgrades, downloads, and installations is also kept locally, and can be viewed with:

less /var/log/aptitude

Test if all CPUs are being used.

Q: On an SMP kernel, how to test if both CPUs are being used? How to see the load on each CPU?

aptitude install sysstat

Then to see the load on each CPU, do:

mpstat -P ALL

Output will be like so for 2 CPUs, or more entries if more are being detected and used:

www:~# mpstat -P ALL
Linux 2.6.18-4-686 (www)        04/07/07

21:06:12     CPU   %user   %nice    %sys %iowait    %irq   %soft  %steal   %idle    intr/s
21:06:12     all    0.40    7.09    0.24    0.12    0.00    0.00    0.00   92.15    253.26
21:06:12       0    0.40    6.99    0.23    0.15    0.00    0.00    0.00   92.23    252.79
21:06:12       1    0.39    7.20    0.24    0.10    0.00    0.00    0.00   92.07      0.48

Move Cronjobs forward a few hours.

Start the overnight cron jobs earlier - seem to be ending around 7:00 am, and this is too late. By default, crontab runs some jobs at 6:52 AM - this is way too late, want things to run from 1:55 AM instead, so that they are well and truly finished by the early morning, so as to not impact early-morning users.

nano /etc/crontab

Change as follows:

- 25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
- 47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
- 52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
+ 55 1    * * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
+ 01 4    * * 7   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
+ 02 5    1 * *   root    test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )

Alias the poweroff command.

Sooner or later, probably at 5 PM on a Friday afternoon as you're rushing to get out of the office and down to the pub, you're going to stuff up and do something silly. For me, that silly stuff-up was mistaking a shell on an important production server for a shell on a testing machine, and powering it off, requiring an embarrassed call to a data centre tech to get it turned back on again ASAP. Because of this, I now like to alias the poweroff command, because on a production server, it's a command that you will hopefully only ever want to use once - and that's when it's about to be removed from the data centre. To do this:

nano ~/.bashrc

Uncomment the lines for a coloured ls, and then add these 2 lines:

# Warning on "poweroff" command.
alias poweroff='echo This is a production machine! If you REALLY want to poweroff, do /sbin/poweroff'

Then reload your bashrc with:

source ~/.bashrc

Permission changes.

A few permission changes recommended by Tiger (a security auditing program) -

Fix the permissions in one manually created directory:

chmod g-w /usr/local/lib
chmod g-w /usr/local

Some other changes:

chmod 660 /var/log/btmp
chmod 600 /boot/grub/menu.lst

Logcheck configuration

"nano /etc/logcheck/logcheck.conf"

- REPORTLEVEL="server"
+ REPORTLEVEL="paranoid"
- SENDMAILTO="logcheck"
+ SENDMAILTO="your@full.email.com"

If you are using atd, then do "nano /etc/logcheck/ignore.d.paranoid/atd" (which will be a new file) and add this:

^\w{3} [ :0-9]{11} [._[:alnum:]-]+ atd\[[0-9]+\]: \(pam_unix\) session opened for user INSERT_USERNAME by \(uid\=1\)$
^\w{3} [ :0-9]{11} [._[:alnum:]-]+ atd\[[0-9]+\]: \(pam_unix\) session closed for user INSERT_USERNAME

To stop alerts about time synchronisation, do "nano /etc/logcheck/ignore.d.paranoid/ntp" (which will be a new file), and add this:

^\w{3} [ :0-9]{11} [._[:alnum:]-]+ ntpd\[[0-9]+\]: synchronized to ([0-9.]{7,15}|[0-9a-fA-F:.]{4,39}), stratum [0-9]+$

Specify atd load parameter

The atd load parameter in Debian used to be explicit, but in 5.0, it's not, but you can make it explicit by doing the following:

"nano /etc/init.d/atd", and change as follows:

         log_daemon_msg "Starting deferred execution scheduler" "atd"
-        start_daemon $DAEMON
+        start_daemon $DAEMON -l 1.5 -b 22
         log_end_msg $?

Then restart atd:

/etc/init.d/atd restart

Install APC as the PHP opcode cache.

Installing APC as the opcode cache:

Benchmark before installing, on some PHP page on your site:

ab -kc 10 -t 30 http://yourhostname.com/some_php_page.php

Install required dependencies:

aptitude install apache2-dev
aptitude install build-essential

Install APC (choose "yes" when prompted) :

pecl install apc


nano /etc/php5/apache2/php.ini

... and add these 3 lines to the end:

; APC opcode cache:

Then reload apache:

/etc/init.d/apache2 restart

Check that there are no errors in the error log:

tail -20 /var/log/apache2/error.log

Benchmark after installing:

ab -kc 10 -t 30 http://yourhostname.com/some_php_page.php
  • For me this showed an increase from 895 completed requests to 3728 completed requests on a test box.
  • For me this showed an increase from 2889 completed requests to 12023 completed requests on a production box.

That's around a 4.1 times speed increase on two systems - not bad.