Mar 05 2008
Blake's CentOS LAMP Server Guide, Single Page HTML edition
Blake's CentOS LAMP Server Set-up Guide For Do-It-Yourself System Admins
Also Known As: Blake Forgets Things A Lot So He Put Them Here
- 1 Introduction
- 2 Installing CentOS
- 2.1 Installing from CD
- 2.2 Package Selection
- 2.3 Post-Installation
- 3 LAMP Essentials
- 3.1 GeoIP
- 3.2 Apache
- 3.3 mod_geoip2
- 3.4 MySQL
- 3.5 PHP
- 3.6 SSL Certificates
- 3.7 Logrotate
- 3.8 AWStats
- 3.8.1 Install AWStats
- 3.8.2 Install the GeoIP Perl module
- 3.8.3 Configure AWStats
- 3.8.4 AWStats Daily Analysis
- 3.8.5 Apache configuration
- 3.9 Postfix
- 3.10 Postgrey
- 3.11 Dovecot
- 3.12 BIND
- 4 Fun Stuff You Might or Might Not Want
1 Introduction
1.1 Preamble
As a part-time small business operator, I run Linux servers for the stability and reliability. However, because most of my day-to-day work is done in Windows, I often find myself getting very rusty on the ins-and-outs of administrating the various parts of the servers I work with. Once I get something set up, I rarely, if ever, have to come back to change it. In October of 2007 I made a decision to migrate one of my existing servers, and old Redhat 8.0 box that was past its prime and falling too far out of date. This server had been running for four and a half years, but with all the changes Redhat had been through (leaving this box unsupported), it was time to move on. I made the decision to move to a CentOS 4 box at the same hosting company.
Before phoning to order the new server, I started my adventures by building a local box next to my desk from the CentOS CDs. I have always kept notes on my server activities, mostly so that I can come back later and figure out why the hell I used that specific set of ./configure options, or where I put some sort of important file. I dug out my notes from nigh on a half-decade ago, and it became apparent after awhile that some of them needed updating. As you might guess, with a little work, that ended up turning into this guide.
1.2 Who Should Use This Guide
Anyone who wants to see how I manage to get my LAMP (Linux/Apache/MySQL/PHP) servers up and running. I generally run small-scale database-driven web applications and static HTML sites off of these boxes, and manage them remotely via SSH. The primary services I configure include Apache, MySQL, PHP, Postfix, Dovecot, SSL and BIND. My boxes are generally limited to one or two local users, so I don't require a lot of user-level security or user/group management.
In a nutshell, this guide will help you set up a LAMP server that is remotely-administered via SSH.
The guide assumes you are familiar with the following things:
- A basic command-line UNIX shell. CentOS's default shell is
bash, which I use exclusively throughout this guide. You may have to troubleshoot any differences between shells if you use something else. - Basic familiarity with some form of text-editor, such as vi/vim, nano, or (may god have mercy on your soul) emacs
1.3 Formatting Conventions
Entropy runs rampant throughout this guide, but I tried to stick to some basic conventions while writing it up.
1.3.1 Commands
- Commands will appear in this format
- Generally with one command per line
- Run them in order!
1.3.2 Config files or file changes
edit them with your favourite editor
1.3.3 Code snippets
Random commands, file names or code snippets will look like this throughout the document.
1.4 Disclaimer
Keep in mind that this guide grew out of a stack of notes. It's really just a place that I wanted to put the procedures that I personally use. The way I set stuff up may not work for you… in fact, it could be totally wrong!
Moreso, I am a minimalist at heart. My philosophy is "If I don't need it, I don't want it installed". I find that several of the normal LAMP applications that I install in this guide (such as Apache and PHP) will often be distributed in a binary package (RPM) with a lot of extra options built in. For this reason, I will sometimes choose to compile from source to keep things slim.
The servers I describe in this guide are pruned down, bare-bones installs. I have no test data to compare performance to standard installations (I'm too busy!), so please take this guide with a hefty dose of salt. If you don't like what I'm doing, by all means, install things with extra options, or from base RPMs, or whatever way you want. The goal here is to get it working with a minimum of effort. I've spent plenty of time fussing with this stuff, and the end result is this guide, which I'm passing along to you in the hopes that it will save you some time, or teach you something.
If I'm doing something wrong (likely), or there's a better way to do it (very likely), please enlighten me! If you have something you'd like to see included in this guide, I can do my best to accomodate, although if it's not something that doesn't fit the theme of "LAMP for us little guys", I probably won't include it.
That being said, I hope you find it useful!
2 Installing CentOS
2.1 Installing from CD
I have only ever installed CentOS from CD for machines on my local network. I usually pay for dedicated hosting, so generally when I order a server, it comes with whatever the going package is at the hosting company. A lot of the time they will perform a base install, which loads the server with all sorts of things that I will never use (such as entire X-windows packages). If this is the case with you, skip down to Clean Up Packages section. If you're installing from CD, read on.
- Boot the machine with your CentOS Server CD.
- At the CentOS boot screen with the 'boot:' prompt, go in to text mode by typing 'linux text' and hitting Enter.
- If you want to test your CD to see if it's good, select 'OK', then 'Test' at the next prompts, otherwise select 'Skip'. I like to test new CDs and/or old machines, as I've found both bad CDs and bad CD drives here. Once it's passed the test, select OK and hit Enter. The CD will eject. Re-insert it and select 'Continue'.
- Anaconda will load and your hardware will be probed. Eventually you get a "Welcome to CentOS_ServerCD" notice. Select 'OK'.
- Choose your language (English)
- Choose your keyboard (us)
- A Disk Partitioning Setup prompt comes next. Choose 'Autopartition', unless you have something in mind for Disk Druid.
- Select 'Remove all partitions on this system', and confirm this choice at the next prompt. I'm assuming you only have a single hard drive in the machine, which will be /dev/hda. This procedure will wipe all the data off that hard drive, so be careful.
- The Partitioning layout comes up next. I just choose OK here, but if you have a specific partitioning scheme in mind, now's the time to specify it.
- Select 'Use GRUB Boot Loader' and hit 'OK'
- Leave the next prompt (passing boot options to the kernel) blank and just hit 'OK'
- Leave the next prompt (use boot loader password) blank as well. hit 'OK'
- If you care about your boot label, use 'Edit' in the next prompt to change it, otherwise hit 'OK'.
- Select 'Master Boot Record' and hit 'OK'.
- You can configure your IP at the next prompt if you want. Most people probably just want to have 'Configure using DHCP' and 'Activate on boot' selected, which is the default. If you want a static IP on your box, you can enter it now. Hit 'OK' when you're done.
- Hostname Configuration: Select 'manually' and enter a name for your new box.
- Firewall: Select 'enable firewall'
- Security Enhanced Linux: Select 'active'
- Language Support: Select any additional languages you want
- Time Zone Selection: Choose your timezone
- Finally, enter the root password and confirm it. Make sure you keep track of it.
2.2 Package Selection
CentOS helpfully groups a bunch of software packages into groups for us. I generally choose 'Customize software selection' at this point and pick the packages I want as follows:
- Text-based Internet
- Server configuration tools
- Mail server
- Windows file server (home network only for Samba)
- Administration tools
If you don't need to access this machine via Samba, you probably don't want the Windows file server option.
Hit 'OK' when you're done, then 'OK' again to begin installing. Sit back and relax, it could take a few minutes. When it's done, you'll get a happy "Congratulations" message to lift your spirits. Remove the CD and reboot, and we'll get the real fun started.
2.3 Post-Installation
Now, if you're installing from CD and you want to get away from the console so you can go sit on the couch and work from your laptop, at this point you might want to configure the firewall, add some users and groups, set up sudoers, and then set up SSH at this point so you can do everything else from the comfort of your couch. Come back here when you're done, otherwise, continue reading and we'll get there soon.
Note that up until you've completed the sections up to Sudoers, you'll need to be logged in as root. After that, sudo will be the best way to go.
2.3.1 Modify Installed Software Packages
2.3.1.1 Clean up packages
Time to delete some crap! Now, if you installed via CD, you shouldn't have a ton of extra stuff on there if you only selected the package groups I mentioned earlier. However, if you ordered your server from somewhere, it might be piled high with junk. A log of installed pacakages can be found in /root/install.log, you may want to give it a browse. You can always use yum info [package name] to help figure out what something does.
Tip: If you are not familiar with the yum command, it might behoove you to take a moment and read the man page. It's your primary tool for installing, removing and updating software on your system.
That being said, take a look below for a huge list of things to uninstall. I probably didn't even manage to write all of them down by the time I was finished with my last production server. The base install put so much on there I was sort of glazing over as I ran endless 'yum remove' commands. That being said, here's a list of things you're not either not going to need on your remotely-administered Linux server, or that we'll install later. I formatted it as a single yum remove command in a giant block of text for easy copy-and-paste; you can do the whole thing at once.
- yum remove gpm apmd irda-utils bluez-utils bluez-libs bluez-hcidump bluez-bluefw wireless-tools NetworkManager minicom libwstreams wvdial libogg libvorbis sox system-config-soundcard system-config-mouse acpid samba-client system-config-samba samba-common samba finger ypbind yp-tools squid nfs-utils system-config-nfs nfs-utils-lib tux pcmcia-cs portmap netdump fbset talk krb5-workstation nano cups cups-libs redhat-lsb pinfo at htmlview redhat-menus system-config-date system-config-services system-config-users system-logviewer jpackage-utils ipsec-tools isdn4k-utils elinks mysql dovecot postgresql-libs xorg-x11-xauth system-config-network system-config-lvm system-config-network-tui system-config-packages libgnome gnome-python2 gnome-python2-bonobo gnome-python-canvas libbonoboui libgnomeui esound alsa-utils indexhtml audiofile libbonobo gnome-vfs2 libart_lgpl libgnomecanvas libwvstreams cadaver neon lrzsz ppp rp-pppoe telnet spamassassin shared-mime-info gnome-mime-data desktop-file-utils redhat-menus pyorbit alsa-lib ash system-config-mouse comps-extras pdksh
yum remove them all! If you remove something accidentally that it turns out you need later, then you can just do a yum install and get it back. Mmm, yum. You may have noted that I'm removing some core LAMP packages such as MySQL. I mentioned this earlier. If you're concerned about a particular LAMP package, take a look at the installation section of this guide and see what I've done with it.
2.3.1.2 Update Everything
With some of the extras gone, we need to update the rest. Run yum update to update everything else on the system. That's it! Depending on how recent your install is, you might have to wait a few minutes for all the updates to download. You might get some kernel upgrades here as well, which is fine, now is the best time to be installing those. You may also get asked to import some GPG keys for package verification. This is generally ok to do.
2.3.1.3 Add some important stuff
I compile a lot of stuff from source, so I generally install the following packages. Note that some of them are devel libraries.
- yum install gcc autoconf rpm-build ttmkfdir freetype-devel openssl-devel libxml2-devel
Confirm any dependencies they need and install those as well.
Noob tip: If you are unfamiliar with devel libraries, here's the short version: they are libraries of code that other programs can integrate into themselves to gain some sort of functionality. Example: if you build your PHP module from source, and you want to be able to use the PHP functions related to SSL in your PHP scripts, you need to compile PHP with a reference to the OpenSSL devel libraries so that it includes the latest OpenSSL code. This is easier than it sounds, and all it requires is that you have installed the '-devel' package of whatever you're working with when you go to compile PHP, ie. openssl-devel.
If you ever get errors when compiling something from source, one of the first things to check is whether you have installed the proper devel libraries for your configuration options.
We're all done with packages (for now)!
2.3.2 Delete Unused User Accounts
If any of the following default users exist, you should get rid of them for security. Use userdel [username]:
- userdel wnn
- userdel canna
- userdel webalizer
- userdel squid
- userdel games
- userdel gopher
- userdel ftp
- userdel halt
- userdel news
- userdel shutdown
- userdel uucp
- userdel operator
- userdel lp
- userdel sync
2.3.3 Configure The Firewall
This is an optional step depending on your setup. If you're building a production box, you might already have a decent firewall setup going. If you're putting a new box on an unprotected home network, you might want to have the firewall running. Depending on what you want running will depending on which ports you want to open.
Run:
- system-config-securitylevel
Configure the following options once you're in the super hi-tech interface:
- Select "Enabled" for Security Level, then move to 'Customize' and hit Enter.
- Select the 'WWW' option
- For other services, enter the port information into "Other ports" box. Only do this if you plan to run a particular service.
- SSH custom port: 2002:udp 2002:tcp
- Samba: 137:udp,137:tcp,138:udp,138:tcp,139:udp,139:tcp
- Svnserve: 3690:tcp,3690:udp
- Once you're done, hit 'OK', then 'OK' again.
2.3.4 Automatic Updates
You can configure your system to automatically download and install updates from various sources using up2date. If you choose to do this, you can download and install up2date using yum install up2date, then configure it by running up2date --configure.
If you don't want your system updating automatically, you can periodically run yum update and review what needs updating first. This is my preferred option, as I like to keep informed as to what the latest updates are and what they fix, and sometimes automatic package updates will overwrite an important configuration file and I end up spending an hour trying to figure out why a service that worked perfectly yesterday isn't working today. Your mileage may vary.
If you do utilize up2date, it's a common option to leave out any kernel packages from the automatic updates.
2.3.5 Add Users And Groups
Now to get off the root account if you haven't done so already. Create your own user and whatever groups you like. I generally create a 'webdev' group and put apache in it (later), which allows my web developers to create areas in their web trees where apache can write to if necessary.
- useradd blake
- passwd blake
- groupadd webdev
- gpasswd -a blake webdev
2.3.6 Sudoers
Sudo is the way to go when you're doing stuff that requires root privileges. You shouldn't run around the system logged in as root, as that can be dangerous. Sudo helps keep you out of that habit by allowing you to run single commands as root as required.
The easiest way to work with sudo is to configure it to allow everyone in the 'wheel' group to have sudo access. This is a historical group, traditionally used for this sort of purpose. Run:
- visudo
to edit the sudoers file. Activate the wheel group by uncommenting the following line (delete the '#' at the front of the line):
Use :wq to save and exit vi. Your wheel group is all set for sudo access, so just add yourself to it:
- gpasswd -a blake wheel
See http://fedorasolved.org/post-install-solutions/sudo for more on sudo.
Now, if you're on a remote server, open a new session and log in with your new personal account. If you're on a local box, just log out (CTRL-D) and log back in. Check that you can become root using sudo:
- sudo su -
The '-' option sets your environment to the root account (as if you logged in normally using root), without it you'll still have your own environment (paths, etc). Once you confirm sudo is working, close down any other root sessions you might have open and continue working with from your personal user id. This is the way you should log in from now on.
2.3.7 Change Your Timezone
This is an easy one. Check that the timezone is correct by running date. If it's not, look at the timezone files in /usr/share/zoneinfo. Find your timezone, then copy it to /etc/localtime:
- sudo cp /usr/share/zoneinfo/Canada/Pacific /etc/localtime
It's a good idea to set the ZONE in /etc/sysconfig/clock as well, as I've noticed some yum upgrades have a nasty habit of defaulting to this timezone and changing your system time when you least expect it.
Run date again to make sure things are ok. Some services won't pick up any system time changes automatically, and you may want to reboot the machine or restart these services. The cron daemon for certain will require a restart (sudo /sbin/service crond restart).
Make sure you sync any changes to the hardware clock as well, or the system time might be off the next time you reboot:
- sudo hwclock --systohc
2.3.8 Change Host Name
If you've changed your mind on the host name, or weren't there for the base installation, you can change the hostname with the following steps:
- sudo vi /etc/sysconfig/network script and change the HOSTNAME variable to your new HOSTNAME
- sudo hostname [new hostname]
- sudo vi /etc/hosts and change any instance of your old hostname to your new HOSTNAME
- sudo /sbin/service network restart
2.3.9 Sync Time
I used to use cron jobs and ntpdate to sync the system time, but all that has been replaced with a nifty service called ntpd. It's way more complicated than setting your time needs to be, but it is rather interesting, so if you want to know more about it, Google for ntpd and read up. In the meantime, to keep your clock synced, all you need to do is start the service. We'll also use chkconfig to make sure it starts at boot time.
Set your clock manually, close to the current time, with the following command:
- sudo date --set="Thu Feb 14 11:10:42 PST 2008"
Now turn on ntpd:
- chkconfig ntpd on
- service ntpd start
ntpd may take awhile at first to establish appropriate readings before syncing your time exactly. You can see ntpd notifications in /var/log/messages.
2.3.10 Configure Services
Speaking of chkconfig, there's a whole list of services installed on your machine that you don't necessarily need. We un-installed some of them back in our Post-installation package removal frenzy, which is good (take off, gpm mouse server, eh hoser?) Others we can turn off. You'll need to be root, or sudo these commands.
- sudo su -
- service haldaemon stop
- chkconfig haldaemon off
- service netfs stop
- chkconfig netfs off
- service autofs stop
- chkconfig autofs off
2.3.11 Configure SSH Server
A good reference for configuring your SSH server is here: http://fedorasolved.org/post-install-solutions/securing-ssh/
I got annoyed with seeing all the random log-in attempts from bots and script kiddies on port 22, so I ended up moving my SSH port to somewhere else. The options below will help tighten up your SSH a little bit without doing anything too crazy. Using key authentication instead of password authentication can be a good idea for the security-concious, but I generally set up password auth for ease-of-use, as I never know when or where I might need to log in from.
I edit the following options in the SSH daemon config file at /etc/ssh/sshd_config.
Protocol 2
LoginGraceTime 30s
PermitRootLogin no
PermitEmptyPasswords no
MaxStartups 4:50:10
The MaxStartups option is in the format start:rate:full. sshd will begin to refuse connections randomly at rate/100 (ie. 50% here) once there are more than start connections. This refusal probability increases linearly until full number of connections is reached, whereby all connections are refused until some open connections clear up (time out or finish).
Be careful with your SSH config! Any screwups in the config file might cost you your running SSH server, and if it's remotely hosted, you might have to make an embarrassing call to tech support to ask them to fix your config so you can log in. If in doubt, read some docs or leave it alone.
Now, do a sudo /sbin/service sshd reload (NOT restart), and open a new session to the server on the new port BEFORE closing your old connection. Make sure it works!
3 LAMP Essentials
3.1 GeoIP
I have some web applications that use GeoIP. If you don't know what it is, or don't care about it, skip this step. It's not important unless you have applications that will need it.
I was going to install GeoIP from yum, as there is a GeoIP package available. However, I could not find one for mod_geoip2, which is what you need to integrate it with Apache. It's an easy install, and I like the database to be up to date, so rather than fool with RPMs, I just downloaded the source and compiled it. The latest version of the C API can be found at http://www.maxmind.com/download/geoip/api/c/.
- sudo su -
- cd /usr/src/
- mkdir geoip
- cd geoip
- wget http://www.maxmind.com/download/geoip/api/c/GeoIP.tar.gz
- tar zxvf GeoIP.tar.gz
- cd GeoIP-1.4.4
- ./configure
- make
- make install
We'll also need mod_geoip2, but we need apache first so that we have the apxs tool. So read on to Apache, then we'll revisit mod_geoip2.
3.2 Apache
The backbone of any LAMP box is the Apache HTTP server. As I explained earlier, there are some packages I like to compile from source, and Apache is one of them. It's one of the core features of your box, and I like to make sure it's not full of cruft. Compiling from source can occasionally create some problems, however. One problem I've run into before is that other software packages that rely on Apache may be tough to install from yum if yum can't find the 'httpd' package (which is the standard Apache package distributed through yum). On the other hand, when the fine team at Apache fixes a security bug, you can get the latest version from source whenever you want, without the (sometimes extremely long) wait time associated with getting the official distribution. Joining the mailing lists for projects such as Apache is a good way to keep up on the latest releases.
3.2.1 Install Apache
If you have problems or don't care about slimming down Apache, you can simply run yum install httpd. Otherwise, the instructions below will guide you through the relatively painless process of installing from source. We'll do all this as root:
- sudo su -
- mkdir /usr/src/apache
- cd /usr/src/apache
Go to http://httpd.apache.org/download.cgi to find the download link for the latest version of Apache 2.2 (it'll be something like "Unix Source: httpd-2.2.8.tar.gz"). Copy the link and paste it into wget:
- wget http://[mirror path]/httpd-2.2.[version].tar.gz
Next to the download link on the apache page will be a link to the MD5 checksum of the package you're downloading. Click on it, and compare it to the results of:
- md5sum httpd-2.2.[version].tar.gz
If they aren't the same, something's wrong with your tarball, so re-download it. Otherwise, continue:
- tar zxvf httpd-2.2.[version].tar.gz
- cd httpd-2.2.[version]
The following configuration command will set up the executable code in /usr/sbin, conf files in /etc/httpd, and the rest in /usr/local/apache. It also enables dynamic module loading, mod_rewrite, mod_geoip2, mod_ssl, and mod_deflate. Remove or add whichever configuration directives you may or may not need.
- ./configure --prefix=/usr/local/apache --sbindir=/usr/sbin --sysconfdir=/etc/httpd --enable-so --enable-rewrite --enable-geoip --enable-ssl --enable-deflate
- make
- make install
Add an apache system account for the daemon to run under, and make it part of our web development group:
- useradd -r apache
- gpasswd -a apache webdev
Edit the Apache config file at /etc/httpd/httpd.conf to use these credentials to run under. We want to set the following options in this file:
Group apache
Save and close. Now, Apache provides a handy script called apachectl, found at /usr/sbin/apachectl, that we can use to start and stop the server. This script is so handy, I just copy it to the SysV control script directory and modify it slightly to make it work with chkconfig (SysV is a system of 'runlevels' that controls what gets started and stopped at boot or init time… Google around on it if you're interested). By copying and editing the apachectl script slightly, we can easily set up Apache to work with the service command, and have it started at boot time.
- cp /usr/sbin/apachectl /etc/init.d/apache
- vi /etc/init.d/apache
Add the following lines immediately after the very first line (the 'shebang' line that says #!/bin/sh):
#
# chkconfig: 2345 85 15
# description: Apache is a World Wide Web server. It is used to serve \
# HTML files and CGI.
# processname: httpd
If you're curious about the inner workings of what we just did, see http://spiralbound.net/2006/11/15/controlling-services-with-chkconfig/ for more on chkconfig.
Now we can use apache as a service!
- chkconfig --add apache
Great! Now all we have to do to start and stop apache is use commands like service apache stop/start/restart. It's also configured to load at boot time. Give it a try:
- service apache start
Now hit your IP address or hostname in your browser (http://x.x.x.x). Apache should be serving up documents from it's default directory, which contains a basic HTML page. You should see a page that says "It works!". Nice job! Log out of your root session (CTRL-D) and take a break.
3.2.2 Configuring Apache
All that's left to do is work with the configuration file. Now, everyone who uses this guide is likely to have significantly different requirements in the way they host their websites, so I won't go into a lot of detail about each configuration option. It's really in your best interests to learn how to carefully configure Apache if you're going to be serving web pages, and it doesn't take much googling to figure out the configs. Start here if you're stuck.
I use name-based virtual hosting, so that I can host multiple web sites at a single IP address. I serve all of my files out of /srv/www/[sitename], put all my logs into a separate directory for each web site under /var/log/httpd/[sitename], and keep separate virtual host configuration files for each site in /etc/httpd/vhosts/[sitename].conf. This gives me the flexibility I need for per-site configuration and log analysis. So, to set this all up:
- sudo su -
- mkdir /srv/www
- chown apache.webdev /srv/www
- chmod g+w /srv/www
- mkdir /var/log/httpd
- chown apache.apache /var/log/httpd
- mkdir /etc/httpd/vhost
- exit
With that all done, there's not much to do in the main configuration file. Change the following configuration options in /etc/httpd/httpd.conf. You'll need to sudo to edit it.
ErrorLog "/var/log/httpd/error_log"
CustomLog "/var/log/httpd/access_log" combined
ServerAdmin blake@example.com
ServerName 192.168.1.50
Look for the second <Directory> configuration and change it to /srv/www. It might look something like this:
# This should be changed to whatever you set DocumentRoot to.
#
<Directory "/srv/www">
Near the bottom where all the Include directives are, add this:
Enable GeoIP if you're installing it (see the GeoIP section) by placing the following at the bottom of the file:
<IfModule mod_geoip.c>
GeoIPDBFile /usr/tmp/GeoIP.dat
</IfModule>
We'd also like to use mod_deflate to compress as much served content as possible. This is better than using PHP's built-in compression, as you can easily compress static content as well. See http://httpd.apache.org/docs/2.2/mod/mod_deflate.html for more on mod_deflate, and be sure you understand what the config options we're about to set are going to do.
Add this to the bottom of the config file:
SetOutputFilter DEFLATE
# Netscape 4.x has some problems…
BrowserMatch ^Mozilla/4 gzip-only-text/html
# Netscape 4.06-4.08 have some more problems
BrowserMatch ^Mozilla/4\.0[678] no-gzip
# MSIE masquerades as Netscape, but it is fine
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
# Don't compress images
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
Save your edits, then restart apache:
- service apache restart
If you'd like to test it again now, your documents are being served out of /srv/www. So place a file called index.html into that directory with the line "hello" in it, and hit your IP address with a web browser. You should see your basic page appear! If you don't, check the error log in /var/log/httpd/error_log.
Not so bad, eh? Now you've got a lean and mean web server!
Log out of your root session with exit or CTRL-D.
3.3 mod_geoip2
mod_geoip2 is the module that allows Apache to gather GeoIP data. You'll need GeoIP installed to use mod_geoip2.
Use your web browser to check out http://www.maxmind.com/download/geoip/api/mod_geoip2/ and find the latest version number. Copy the link so you can paste it into wget.
- cd /usr/src/geoip
- wget http://www.maxmind.com/download/geoip/api/mod_geoip2/mod_geoip2_[version]
- tar zxvf mod_geoip2_[version]
- cd mod_geoip2_[version]
- /usr/sbin/apxs -i -a -L/usr/local/lib -I/usr/local/include -lGeoIP -c mod_geoip.c
Done! apxs automatically enables it in the Apache config file for us (although we already did that above). If you run the following command you should see geoip_module listed in the module list.
- /usr/sbin/httpd -M
Once we get PHP installed, you can use the following test script (inside a web page, this won't work from the command line) to see the GeoIP data in the $_SERVER global variable.
<?php
print_r($_SERVER);
?>
3.4 MySQL
3.4.1 Install MySQL
I install MySQL from the rpms released on the MySQL website as they are the most up to date. Installing from source has little advantage for MySQL as it is already heavily optimized.
Create a place to put our downloaded RPMs:
- sudo su -
- mkdir /usr/src/mysql
- cd /usr/src/mysql
Now head over to http://dev.mysql.com/downloads/mysql to find the download links for the three packages you'll want. Since we're working with CentOS 4 here, you'll want the Redhat Enterprise Linux 4 RPMs. You have to go through a couple of annoying screens to get to each mirrored download.
Download the Server, Client and Headers and libraries packages. The rpms you should end up with are named MySQL-server-community-[version].rhel4.[architecture].rpm, MySQL-client-community-[etc], and MySQL-devel-community-[etc]. Place them all in /usr/src/mysql.
Now, we need to get the MySQL GPG key to verify these RPMs before we can install them. Go to the MySQL manual at http://dev.mysql.com/doc/refman/4.1/en/checking-gpg-signature.html, and copy the key text on the page in the blue block (they point it out). Paste it into a new file, /usr/src/mysql/mysql_gpg_public_key.asc and save it. Now we'll import the key to our RPM keyring and verify the RPMs:
- rpm --import mysql_gpg_public_key.asc
- rpm --checksig MySQL-*
Make sure they all say 'OK' after each check. If so, install them with yum:
- yum localinstall MySQL-*.rpm
The install creates the mysql user on the system, and places a handy startup script in /etc/init.d/mysql. It also installs MySQL as a service, which means we can start it using service mysql start. Easy as pie.
3.4.2 Configure MySQL
Now run:
- /usr/bin/mysql_secure_installation
Follow the prompts to set a MySQL root user password and whatever else you'd like to do. Once you have a root password set, you'll want to modify the MySQL config files. There are some example configs found in /usr/share/mysql, called my-large.cnf, my-huge.cnf, etc. Take a look at them. Any half-decent machine will generally fit at least the my-large.cnf file these days. I'm not going to tell exactly you how configure your server, as it's important that you figure out what you need based on what your hardware is like. My general approach is to take the my-huge.cnf file and make slight modifications:
- sudo su -
- cp /usr/share/mysql/my-huge.cnf /etc/my.cnf
- vi /etc/my.cnf
Add or change the following:
read_rnd_buffer_size = 1M
#Set to number of CPU's * 2
thread_concurrency = 4
#Slow query logging
log-slow-queries
long_query_time=2
#Kill threads after they've been idle this long
wait_timeout = 300
#Max number of connected clients. Keep it in-line with Apache's MaxClients setting.
#A good rule of thumb is that Total Physical Memory = max_connections * (sort_buffer_size + read_buffer_size) - key_buffer
max_connections = 160
#This is a per-user connection maximum.
max_user_connections = 160
All done? Start 'er up and get out of your root session.
- service mysql start
- exit
Now you can connect to MySQL with mysql -u root -p and start making databases and users. Remember to not use the root user for your web applications!
3.5 PHP
PHP is the other key LAMP component that I insist on installing from source. A lot of PHP's functionality can be added in as modules, and a base PHP distribution installed via yum or RPM will include most or all of these modules for compatibility reasons. Some of them I'll never use, and some I've never even heard of. I definitely do not want the memory overhead of unused modules.
3.5.1 Pre-installs
Make sure you have the following packages installed.
- yum install zlib-devel gdbm-devel libjpeg-devel libpng libpng-devel
3.5.2 Install PHP
Download the latest PHP tarball from http://www.php.net/downloads.php into /usr/src/php.
- sudo su -
- mkdir /usr/src/php
- cd /usr/src/php
- wget [mirror url for tarball]
- tar zxvf php-5.[version]
- cd php-5.[version]
This is the configure line I use. Your mileage may vary, but I'm fond of it. Please note that this is a very minimal set of options! If you start getting errors from PHP saying such-and-such function doesn't exist, you're missing a module, and you'll need to come back here, re-run the configure script with your module added, and recompile the whole thing.
- ./configure --disable-all --with-apxs2=/usr/sbin/apxs --with-mysql --disable-short-tags --with-zlib --with-gdbm --with-gd --enable-gd-native-ttf --with-freetype-dir=/usr/lib --with-jpeg-dir=/usr/lib --with-png-dir=/usr/lib --enable-ctype --with-pcre-regex --enable-session --enable-xml --enable-libxml --enable-dom
- make
- service apache stop
- make install
- service apache start
3.5.3 Configure PHP
Copy the example .ini file to a place where PHP will read it:
- cp /usr/src/php/php-[version]/php.ini-recommended /usr/local/lib/php.ini
Verify some of the following settings. I'll give you the settings I use for a development box. You may want to change the error reporting level and/or logging for a production box. For zlib.output_compression, remember that we set up apache with mod_deflate,
so we don't want to compress output in PHP as well.
zlib.output_compression = Off
magic_quotes_gpc = Off
For a development machine, I use the following error settings:
log_errors = Off
error_reporting = E_ALL
On a production machine, you might want this instead:
log_errors = On
error_log = /var/log/php
error_reporting = E_ALL & ~E_NOTICE
3.5.4 Configure Apache to use PHP
The PHP install script may have added some or all of the necessary configuration lines in the Apache config file. The following options need to be set inside, so double-check each one in /etc/httpd/httpd.conf:
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
DirectoryIndex index.html index.php
Restart apache. Try making a test page! If you've been following this guide straight through, just go to /srv/www and create a test.php page, and hit it with your browser.
3.6 SSL Certificates
It's nice to make a SSL certificate for your server, so you can use it for serving secure web pages. As an added benefit, you can use it to provide a secure log in for your mail users! Most POP3/IMAP programs support an SSL layer, so if you want to run mail server, you can set it up to only accept secure connections. This is a real benefit, and I highly recommend doing so.
I generally make self-signed certificates, because I don't do anything secure that isn't for my own personal use, or something that I can easily explain to my users. The whole "pay money to get a signed certificate" thing is a scam in my opinion. If people only knew that the Certificate Signing Authority (CSA) companies don't care who you are as long as you pay 'em the cash (*cough* VeriSign), then they'd realize that the whole accept-certificate rigamarole that browsers give you is a joke. If you're doing business on my server, you're already trusting me, so there's no reason you shouldn't accept a certificate SIGNED BY ME.
*Ahem*. I'll get on with it.
If you want more detail on what we're doing here, look at http://www.jm-solutions.com/OpenSSL/Setup/setup02.php, or do some googling.
3.6.1 Create a set of keys and certificates
- sudo su -
- mkdir /etc/ssl
- cd /etc/SSL
Make the private key and a Certificate Signing Request (CSR):
- openssl req -config /usr/share/ssl/openssl.cnf -new -out certname.csr
Remove the passphrase from the keyfile we just made, so Apache won't ask for it on boot:
- openssl rsa -in privkey.pem -out certname.key
Create a self-signed certificate good for 10 years:
- openssl x509 -in certnam.csr -out certname.crt -req -signkey certname.key -days 3650
Protect everything you just made:
- chmod 400 certname.csr certname.key certname.crt
When you're ready to use the certificate, you may have to adjust the permissions a bit depending on your needs. I generate a separate set of keys and certificates for my mailserver (named mailserver.csr, etc) and store them in /etc/ssl beside any webserver key I might have.
3.7 Logrotate
Set up any log rotations you want by putting configure files into /etc/logrotate.d. The only logs I need to configure are the Apache web logs for each website I run. The following logrotate setup handles them all at once:
- cd /etc/logrotate.d
- sudo vi apache
Add the following:
# rotate log files daily
daily
# keep x days of backlogs
rotate 14
nocompress
sharedscripts
postrotate
endscript
}
Save and exit. Check the man pages of logrotate for more info on each option.
3.8 AWStats
Awstats is a web log analyzer that produces some good info. You have to modify your websites to load a javascript file if you want the full reports, but I've done that by placing the script on the footer of every page. You also have to ensure that your web logs are logging in Apache "combined" format.
3.8.1 Install AWStats
Visit the AWStats home page to get the download link for the latest tarball. Then do the standard wget/unpack:
- cd /srv/www
- wget http://prdownloads.sourceforge.net/awstats/awstats-[version]
- tar zxvf awstats-[version]
- mv awstats-[version] awstats
AWStats is Perl-based, so you'll need to enable cgi scripting under Apache for a particular directory in order to view output. We'll make that directory and copy our configs there, then set up scripting in Apache in a few minutes:
- sudo mkdir /etc/awstats
- sudo cp awstats/wwwroot/cgi-bin/awstats.model.conf /etc/awstats/
- sudo vi /etc/awstats/awstats.model.conf
Now set up your awstats conf files from this base model file.
3.8.2 Install the GeoIP Perl module
I use the GeoIP analysis option with AWStats, so I need to install the Perl GeoIP plugin in addition to the normal GeoIP libraries I've already installed previously.
Run CPAN by typing:
- cpan
If you haven't used cpan up until now, you'll have to fill in all the questions until you get to the actual cpan> prompt. I just type "no" at the first prompt to allow CPAN to try to automatically configure itself. Then:
- cpan> install Geo::IP
- cpan> exit
Done! Now AWStats can use GeoIP.
3.8.3 Configure AWStats
I generally keep one configuration file per site I wish to have analyzed, ie. /etc/awstats/awstats.[site name].conf. Copy and modify the awstats.model.conf file as needed:
SiteDomain="your.site.domain"
HostAliases="localhost 127.0.0.1 REGEX[yourserver\.com$]"
That should be enough to get you up and running. If you want to analyze your first log, run /srv/www/awstats/wwwroot/cgi-bin/awstats.pl -config=[conf name] -update, where [conf name] is the awstats.[conf name].conf file of the configuration file in /etc/awstats.
3.8.4 AWStats Daily Analysis
What I normally do now is have Logrotate configured to rotate all my website log files each day (remember how we set them up in separate log directories on a per-site basis?) Once they've been rotated, I have an AWStats cron entry set up to analyze the day-old log. The cron entry looks like this (I usually have a user named "webcron" or something to handle all my website-related cron jobs):
So at 4:30 every morning, awstats analyzes the log specified in the config file awstats.sitename.conf (which in my naming scheme will be /var/log/httpd/[sitename]/access_log.1).
3.8.5 Apache configuration
Now I set up an Apache virtual host so I can view the stats. Put this into one of your virtual host sites files. (p.s. I also create a DNS entry to get a stats.yoursite.com address that I can use to access this virtual host. You can just use an Alias directive instead if you don't feel like having a separate virtual host).
Here's the vhost entry I use:
DocumentRoot /srv/www/awstats/wwwroot
ScriptAlias /awstats/ "/srv/www/awstats/wwwroot/cgi-bin/"
Alias /awstatsclasses "/srv/www/awstats/wwwroot/classes/"
Alias /awstatscss "/srv/www/awstats/wwwroot/css/"
Alias /awstatsicon "/srv/www/awstats/wwwroot/icon/"
<Directory "/srv/www/awstats/wwwroot">
AllowOverride All
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
The aliases are to tell your webserver to run those URLs as scripts (AWStats is written in Perl, so Apache needs to be told to execute any URL inside that directory as a script).
Now you can go to http://stats.yoursite.com/awstats/awstats.pl?config=yoursite and get some web stats. Neat! As a final step, I generally use an Apache .htaccess file to put some basic HTTP Authentication on my AWStats area, just so people can't snoop my web stats.
3.9 Postfix
Postfix is an excellent and simple way to run your mail system. I switched from an old version of Exim, as the configurations were just too much to deal with. I hear the newer Exims are a bit better, but I haven't tried them. Postfix is fairly standard these days, so unless you have specific mail system requirements, you can't go wrong with it.
3.9.1 Install Postfix
- sudo su -
- yum install postfix system-switch-mail
- system-switch-mail
Choose postfix, then 'OK'. Postfix is now installed, with all the necessary configuration files in /etc/postfix. It's also been installed as a service, which I love so much. Start 'er up:
- service postfix start
Log out of your root session.
3.9.2 Configuring Postfix
Since I run multiple web sites, but only have a few people who actually use the system for mail, I set up both virtual aliases and virtual mailboxes. For instance, I might host a small-business website, and they'll want a bunch of email addresses for their store, but I don't want them to have a user account on the machine. Virtual mailboxes to the rescue. Virtual aliases allow me to have the same address at different domains go to different mailboxes as well, which is handy from a user and maintenance perspective, and also for reducing spam (bob@domain1.com will go to a different place than bob@domain2.com). The key directives to set are in /etc/postfix/main.cf:
mydomain = sitename.com
inet_interfaces = all
relayhost =
mynetworks_style = host
#Blank, for virtual domains
mydestination =
#Blank, for virtual domains
local_recipient_maps =
#Some helpful spam settings
smtpd_helo_required = yes
smtpd_helo_restrictions =
reject_non_fqdn_hostname
smtpd_sender_restrictions =
# hash:/etc/postfix/access
reject_unknown_sender_domain
smtpd_data_restrictions =
#Other tweaks
max_idle = 300s
anvil_status_update_time = 1h
anvil_rate_time_unit = 300s
export_environment = TZ MAIL_CONFIG SENDER
Virtual mailboxes and aliases are acheived by adding all the following directives (at the end of main.cf):
virtual_mailbox_domains = $myhostname, localhost.$mydomain, localhost, your-domain-1.com, your-domain-2.com
#The virtual "spool" dir
virtual_mailbox_base = /var/mail/vhosts
#Maps file for delivery to virtual mailboxes (virtual domains + virtual users)
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_minimum_uid = 100
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
#Maps file for delivering to virtual aliases (virtual domains + real users)
virtual_alias_maps = hash:/etc/postfix/virtual1.hash
With all those virtual settings, we'd better set up what it needs in the real system. Still as root, run the following:
useradd virtual -u 5000 -g 5000 -r
usermod -s /sbin/nologin virtual
mkdir /var/mail/vhosts
chown virtual.virtual /var/mail/vhosts
3.9.2.1 Adding a Virtual Mailbox
For each domain you want to accept mail at:
- sudo mkdir /var/mail/vhosts/domainname.com
- sudo chown virtual.virtual /var/mail/vhosts/domainname.com
Each virtual user should have a spool file, and then you can point all the email addresses you want at it. Edit /etc/postfix/vmailbox
blake@mydomain.com mydomain.com/blake
That puts the spool file for 'blake' into /var/mail/vhosts/mydomain.com/blake. If I want aliases to go to that spool, point them at my main email address by editing /etc/postfix/virtual.hash:
CentOS.guide@mydomain.com blake@mydomain.com
imnotwearingpants@mydomain.com blake@mydomain.com,webmaster@mydomain.com
When you're all done setting up mailboxes and aliases, run postmap on each file:
- sudo postmap /etc/postfix/vmailbox /etc/postfix/virtual
3.9.2.2 Transports for piping mail with virtual aliases
This was a bit complex and it took me a long time to get right for my particular set up. Remember, this guide is pretty much a giant notepad for me to keep track of all my linux sysadmin fun! You can probably safely ignore this part if you want, unless you also need special piping procedures. While ensuring that I have virtual aliases and mailboxes, I also had to set up a special transport to allow incoming mail to a special address to be piped to a web script. That's the transport_maps setting below, which also goes into the main.cf file:
#I discovered that you cannot do anything other than a local mailbox delivery using virtual aliases.
#To get piping, etc, I have to use transports.
transport_maps = hash:/etc/postfix/transport
Now, at the very bottom of the ever-so-fun /etc/postfix/master.cf (not main.cf), I created a transport named "mycatch":
#It sends the email to a script based on the local part, so if you catch an email
#to test@mydomain.com, it will redirect it to mailcatcher_test.php
mycatch unix - n n - - pipe
flags=Fq user=apache argv=/srv/www/mydomain/bin/mailcatcher_${mailbox}.php ${sender}
Almost there. Now we just have to set up the specific address in /etc/postfix/transport, like so:
puppies@mydomain.com mycatch:Sent to puppy catcher
#Goblin attacks, oh no! - mail is piped to /srv/www/mydomain/bin/mailcatcher_goblin_attacks.php
goblin_attacks@mydomain.com mycatch:Sent to goblin defender script
#etc
Note that these addresses also have to be set up in the virtual mailbox file as well, as the addresses need to be recognized. Transports happen after mail acceptance, but before delivery, so the email needs to be valid (ie. in the mailbox file) in order for it to be accepted. Edit /etc/postfix/vmailbox:
#mailbox.
puppies@mydomain.com mydomain.com/devnull
goblin_catcher@mydomain.com mydomain.com/devnull
Note that the mail will never be delivered to the devnull mailbox, as the transport we just set up will intercept it. You get the idea. Now run:
- sudo postmap /etc/postfix/transport
and try out your pipe scripts by sending an email.
3.10 Postgrey
Postgrey is a charming little piece of work by David Schweikert that cut down my email spam by 90%. For real. Maybe 95%. The first time I installed it, I actually spent the better part of an entire day watching the mail logs scroll by, rejecting spam after spam. It was a beautiful sight. The theory is simple: A good portion of spammers use distributed bot networks (ie. infected Windows machines) to send out spam. By sending out a control signal, the "bot-master" can have an infected computer process and send a piece of spam. You could describe these bots as using a "pump and dump" method. They connect to a mail server, dump out a spam, and disappear into the void. With a network of thousands of machines, it's easy for a spammer to send a large number of spams very quickly without using a centralized location that can be blocked.
The way Postgrey works is that every time your server receives an incoming email connection, it says "Hey, I'm busy here. Try again later", even if it's not busy. This is a perfectly acceptable response in the gloomy world of mail protocols. Any valid email server doing the sending will simply think "Hmm, looks like Blake's server is busy. I'll queue that piece of mail and try it again in a few minutes." Here's the key point: spam bots aren't valid email servers. Most don't even wait around for a response after they've hurled their spam at you. They won't try again. In the meantime, when Yahoo's valid server comes back and says "Hey, I'm back, can you take this mail yet?", Postgrey recognizes that Yahoo tried a previous delivery, and thinks "Odds are you're not a spammer. Sure, I'll take that."
It's genius. Some spammers are adapting to this technique, but by doing so, they have to sacrifice a significant portion of their spamming resources in order to get their mail to you (they have to queue mail, wait for re-trys, etc). So it's win-win, even if you do still get the occasional spam. I'm serious when it cuts back 90% though. It's an amazing difference.
There's a downside of course, and that is that all mail deliveries are delayed, even valid ones. This means that Postgrey may not be a viable solution for a large business or one that deals with extremely time-sensitive email. If that's the case, more traditional filtering methods will have to be used. For me however, it works and it works well.
So here we go. See http://www.howtoforge.com/greylisting_postfix_postgrey for more.
3.10.1 Install Postgrey
First we configure yum to be able to work with the Dag package repository, as the postgrey packages can be found there.
- sudo su -
- cd /etc/yum.repos.d
- vi Dag.repo
Paste the following and save:
[Dag]
name=Dag APT Repository
baseurl=http://apt.sw.be/redhat/el$releasever/en/$basearch/dag
gpgcheck=1
gpgkey=http://dag.wieers.com/packages/RPM-GPG-KEY.dag.txt
enabled=1
Now:
- yum check-update
- yum install postgrey
You may have to install a GPG key for some of the Perl packages that come as dependencies.
This install happily creates the 'postgrey' user to run itself under, and once again to my delight, includes a chkconfig startup script for us in /etc/init.d/postgrey, so we can use my ever-favourite service commands to start and stop postgrey.
At this point I'll disable the Dag repository again so that yum doesn't check it every time. I'd rather just use the official repositories for most things. Do a sudo vi /etc/yum.repos.d/Dag.repo and set:
3.10.2 Configuring Postgrey
The service script references a source file for run-time options, located in /etc/sysconfig/postgrey. You may want to adjust the default greylisting delay of 10 minutes to something smaller. This reduces the effectiveness of greylisting, but also reduces delivery delay. Find your balance. I also tweak the default greylist text that gets logged in the mail log. Therefore, the entire contents of my /etc/sysconfig/postgrey file contains:
We also need to tell Postfix to consult the Postgrey service whenever it received an email. The following option set in the Postfix main configuration file /etc/postfix/main.cf will do it (note that it's only the last line that activates Postgrey, the rest are other restrictions you may or may not want):
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination,
reject_unlisted_recipient,
check_policy_service inet:127.0.0.1:60000
That's it! Start up Postgrey and reload Postfix's configuration file:
- service postgrey start
- service postfix reload
Don't forget to turn the Postgrey service on as well.
- chkconfig postgrey on
Run a tail -f /var/log/maillog and send yourself an email. Note the rejection message that scrolls by. Send yourself another one and it'll get through instantly, as Postgrey will recognize the combination of to/from addresses and the sending email server signature. Don't despair about the first email… it'll get through soon, generally within an hour, usually less.
Suck on it, spammers.
3.11 Dovecot
Dovecot provides POP3, IMAP, or secure versions of either service.
3.11.1 Install Dovecot
The dovecot package that comes with CentOS has MySQL 4 and postgres package dependencies, which I didn't want, which is why it was included at the top of my guide as one of the packages to uninstall. We'll get the latest source from http://www.dovecot.org/download.html and compile it from there.
- sudo su -
- mkdir /usr/src/dovecot
- cd /usr/src/dovecot
- wget http://www.dovecot.org/releases/1.0/dovecot-[version]
- tar zxvf dovecot-[version]
- cd dovecot-[version]
- ./configure --prefix=/usr/local/dovecot --sbindir=/usr/sbin --sysconfdir=/etc/dovecot
- make
- make install
Note that this configure doesn't add any SQL drivers, and auto-detects the SSL libraries.
Dovecot is now installed under /usr/local/dovecot, with the conf file in /etc/dovecot/dovecot-example.conf, which must be renamed to dovecot.conf
3.11.2 Configuring Dovecot
See http://www.howtoforge.com/linux_postfix_virtual_hosting_2 and http://wiki.dovecot.org/QuickConfiguration for more configuration fun. Keep in mind that my set-up uses virtual hosting, so you might not want to follow my configs!
I only serve secure POP3 at the moment, and since I have "virtual" users, I don't need the PAM authentication parts of the configuration. However, because the users are virtual and not real UNIX accounts, we need to set up a users file and a passwords file to verify them when they log in. You'll see all this in the configuration changes I make below:
log_path = /var/log/dovecot
ssl_cert_file = /etc/ssl/mailserver.crt
ssl_key_file = /etc/ssl/mailserver.key
ssl_parameters_regenerate = 48
verbose_ssl = yes
login_max_processes_count = 32
login_greeting = Dovecot ready.
mail_location = mbox:~/mail:INBOX=/var/mail/vhosts/%d/%n
valid_chroot_dirs = /var/mail/vhosts
protocol pop3 {
login_executable = /usr/local/dovecot/libexec/dovecot/pop3-login
mail_executable = /usr/local/dovecot/libexec/dovecot/pop3
pop3_uidl_format = %08Xu%08Xv
}
auth_executable = /usr/local/dovecot/libexec/dovecot/dovecot-auth
auth_verbose = yes
auth default {
mechanisms = plain digest-md5
}
# passdb pam {
# }
passdb passwd-file {
# Path for passwd-file
args = /etc/dovecot/passwd
}
userdb passwd-file {
# Path for passwd-file
args = /etc/dovecot/users
}
You'll note that I commented out the passdb pam { section, including the closing brace, and enabled the passdb passwd-file and userdb passwd-file sections. You'll also notice that I set up some SSL options. See the SSL certificate section earlier in the guide where I generated some keys for the mailserver to use.
Now, the following needs to be done to bring our system up to speed with our config file:
- useradd -r dovecot
- usermod -s /sbin/nologin dovecot
- touch /etc/dovecot/users
- touch /etc/dovecot/passwd
The users file needs to be in the same format as the standard system passwd file (/etc/passwd). The dovecot passwd file also uses the standard system passwd file format to encrypt passwords. This means that in order to generate passwords, you need a tool that utilizes the basic crypt() system call. I couldn't find anything to do it because I'm a total noob, so I wrote a php script called make_md5crypt_password that just called it:
#!/usr/local/bin/php
<?php
echo crypt($argv[1]);
?>
I'm sure there's a better way, but that's what I did for now. Simply run it like ./make_md5crypt_password.php mypassword, and it'll output a password suitable for copying and pasting into the dovecot passwords file.
When you're done, you'll have a dovecot users file that looks something like this:
user2@mydomain.com::5000:5000::/var/mail/vhosts/mydomain.com/:/bin/false::
And a dovecot passwd file that looks something like this:
user2@mydomain.com:$1$7TAORxMd$3y/PMe5fGO7lodxLdpJLE.
Finally, to set dovecot up as a service, we'll apply a standard init.d script to it. A copy of such a script can be found at http://wiki.dovecot.org/DovecotInit. Copy it to /etc/init.d/dovecot, and change the DAEMON=/usr/local/sbin/dovecot line to DAEMON=/usr/sbin/dovecot. Then put the following at the top of the file:
# Startup script for the Dovecot mail daemon
#
# chkconfig: 2345 82 29
# description: Dovecot is a mail serving daemon with POP3/IMAP services.
# processname: dovecot
Hooray! Another service controlled via the service command. Add it to chkconfig (so it'll start at boot time), then start 'er up:
- chkconfig --add dovecot
- service dovecot start
Log out of your root session and take a break.
3.12 BIND
BIND is a popular package for running DNS services. I like to run my own DNS servers, just so I can be in control of the records if I ever need to make a quick change.
3.12.1 Install BIND
This one's easy. I like using the bind-chroot package with this one as well, which places our BIND daemon into a chroot jail. Given the number of BIND exploits over the years, it's a nice security precaution.
- sudo su -
- yum install bind bind-chroot
A control script has been placed at /etc/init.d/named, so we've got service functionality again. An entry for named has even been added to chkconfig for us, although it is set to be off at all runlevels. Do a
- chkconfig named on
to turn it on at levels 2345. Now, for each domain you want to set up, you'll have to place a zone entry into /var/named/chroot/etc/named.conf, and put the DNS record in /var/named/chroot/var/named/mydomain.com.zone. I set the zone entries up to point to /var/named/mydomain.conf, so I will create a symlink to each zone file from that directory.
Don't forget to email your ISP and get a reverse DNS entry set up for your mail server!
4 Fun Stuff You Might or Might Not Want
4.1 Subversion
Subversion is great, but you probably don't want it on a production webserver. Keep it on a development box in-house, or a production server separate from any with essential web services.
4.1.1 Install Subversion
- sudo su -
- yum install subversion
The svnserve daemon needs a control script and a chkconfig entry to run as a service. I found a script at http://www.fedoraforum.org/forum/archive/index.php/t-165130.html, but it doesn't work (for CentOS anyway). I modified it to a version that works. Copy it to /etc/init.d/svnserve, then create a file at /etc/sysconfig/subversion that contains:
The init script will use these options when launching the svnserve daemon. Now:
- chmod 755 /etc/init.d/svnserve
- chkconfig --add svnserve
- service svnserve start
4.1.2 Creating a new repository
- sudo su -
- cd /srv
- svnadmin create svn
4.1.3 Importing a backed-up repository
Assuming you're just setting up a fresh repository named svn under /srv, you can just import your old repository:
- sudo su -
- svnadmin create svn
- svnadmin load svn < repository-name.dmp
Set up at least some basic authentication options in /srv/svn/conf/svnserve.conf file:
anon-access = none
auth-access = write
password-db = passwd
And if you're setting up a new repository, you'll have to create /srv/svn/conf/passwd to go along with that conf file:
blake = yourpassword
user2 = user2password
Don't forget to set the permissions on this clear-text password file:
- chmod 600 passwd
If you've just moved the repository between servers, make sure to set your SVN clients to use the new repo!
4.2 Samba
Samba you almost definitely don't want on a production web server. It's quite useful on a home network so that you can transfer data easily between file shares however, and it also provides the service required for a windows machine to recognize a linux machine by hostname only.
4.2.1 Install Samba
- yum install samba
- chkconfig smb on
- smbpasswd -a blake
Give yourself a samba password, and that's it!
4.2.2 Configure Samba
Edit your Samba config to set up whatever shares you want. I change/add the following options as well:
dns proxy = no
Start samba up:
- service smb start
4.3 JpGraph
I use JpGraph for some websites I run. It's a PHP package that produces good-looking graphs.
4.3.1 Installing JpGraph
You have to do a fun bunch of setup to get JpGraph all the stuff it needs to work with. We're going to need to be able to extract some stuff from some CAB files for starters. Re-enable the yum Dag repository by setting enabled=1 in /etc/yum.repos.d/Dag.repo (see the Postgrey section where I set this repository up).
Once that's done, continue on. First we need to install cabextract, then get some Microsoft TT fonts. See http://corefonts.sourceforge.net/ for updated instructions on that, otherwise:
- yum install cabextract
- mkdir /usr/src/msttcorefonts
- cd /usr/src/msttcorefonts
- wget http://corefonts.sourceforge.net/msttcorefonts-2.0-1.spec
- rpmbuild -bb msttcorefonts-2.0-1.spec
The fonts should be downloaded from SourceForge and compiled into an RPM. The new RPM will reside under the standard RPM build architecture. Install it:
- rpm -ivh /usr/src/redhat/RPMS/noarch/msttcorefonts-2.0-1.noarch.rpm
Now for Jpgraph. Go to http://www.aditus.nu/jpgraph/jpdownload.php and get the download link for the latest version.
- cd /srv/www
- wget [link]
- tar zxvf jpgraph-[version].tar.gz
- ln -s jpgraph-[version]/ jpgraph
- rm jpgraph-[version].tar.gz
The JpGraph code sits above any website document roots I might have set up. I can include Jpgraph into my web code and use it there, but the code itself is not directly accessible from the web.
Disable the Dag repository again by setting enabled=0 in /etc/yum.repos.d/Dag.repo
4.3.2 Configure JpGraph
Edit /srv/www/jpgraph/src/jpg-config.inc.php and set the following line:
Note: If fonts aren't appearing in your graphs, make sure that you compiled PHP with the "-dir" options pointing to the right lib*.so files (/usr/lib)
4.4 Xdebug
Xdebug is a profiling and debugging tool for PHP. It's quite handy. However, you definitely do not want this enabled on a production server! My own tests have shown that it slows down the execution of a PHP script simply by being loaded with Apache (it overrides some of the internal PHP functions with its own). Put it on your development machines though, by all means! It's good for what ails your code.
4.4.1 Install Xdebug
Go to xdebug.org and download the source tarball to /usr/src/xdebug:
- sudo su -
- mkdir /usr/src/xdebug
- cd /usr/src/xdebug
- wget [download url]
- cd xdebug-2.x.x
- phpize
- ./configure --enable-xdebug
- make
- cp modules/xdebug.so /usr/local/apache/modules/
4.4.2 Configure Xdebug
Edit /usr/local/lib/php.ini and add the following under the "Dynamic Extensions" section:
Restart Apache for the changes to take effect.
- service apache restart
You can also check to see if Xdebug shows up under php -m from the command line.
The following is some of the options I used with Xdebug. They have to go into the main Apache config files, under a VirtualHost entry or in the main configuration, as they are php_admin_value settings and can't be used in .htaccess files. When I want to do profiling, I'll toggle the xdebug.profiler_enable flag to 1, otherwise it's best to leave it off as it will generate a lot of output. Make sure to create the directory you're putting the output files into as well.
php_admin_value xdebug.extended_info 1
php_admin_value xdebug.profiler_enable 0
php_admin_value xdebug.collect_return 1
php_admin_value xdebug.collect_params 3
php_admin_value xdebug.collect_vars 1
php_admin_value xdebug.output_dir /home/blake/xdebug
php_admin_value xdebug.trace_output_dir /home/blake/xdebug
php_admin_value xdebug.profiler_output_dir /home/blake/xdebug
php_admin_value xdebug.profiler_output_name timestamp
4.5 Mono
Mono is an open-source platform designed to bring the .NET architecture to non-Windows platforms. If you want to run any .NET code on Linux, Mono is your key. This is a great project! Check out http://www.mono-project.com/ for more.
4.5.1 Install Mono
Copy the following into a yum repository information file at /etc/yum.repos.d/mono.repo:
name=Mono for rhel-4-i386 (stable)
baseurl=http://go-mono.com/download-stable/rhel-4-i386/
enabled=1
gpgcheck=0
We also need a couple of packages, due to some fun issues I found with Mono during one of my original installs. These packages are needed for systems without the 'inotify' patch on the kernel, as they provided a FileSystemWatcher called FAM that is more efficient for the mono server to use than it's default polling mechanism. Without it, on CentOS4.4 anyway, the mono server would use 10% of the CPU even while idle. So:
- yum install gamin gamin-devel
Now the real stuff:
- yum install mono-core mono-web mono-data mono-winforms xsp pkgconfig
4.5.2 Install mod_mono
Due to httpd package dependency issues (see notes under Install Apache for more on that), I compiled mod_mono from source. Get it from http://go-mono.com/sources-stable/, and download it to /usr/src/mod_mono:
- sudo su -
- mkdir /usr/src/mod_mono
- cd /usr/src/mod_mono
- wget http://go-mono.com/sources/mod_mono/mod_mono-1.[version].tar.bz2
- bunzip2 mod_mono-1.[version].tar.bz2
- tar xvf mod_mono-1.[version].tar
- cd mod_mono-1.[version]
- ./configure --prefix=/usr
- make
- make install
4.5.3 Configure Apache to use mod_mono
Edit the main Apache config file (/etc/httpd/httpd.conf) and add:
MonoServerPath "/usr/bin/mod-mono-server2"
Alias /demo /usr/lib/xsp/test
<Directory "/usr/lib/xsp/test">
Options None
Order allow,deny
Allow from all
</Directory>
Restart apache and exit your root session:
- service apache restart
- exit
Check the server at http://localhost/demo/index.aspx; you're running .NET code!
I'll leave it at that for Mono… it's a whole 'nother ball of worms. To get applications up and running, you'll want to check out the Mod mono docs as well as the general Mono docs. Mono is still a work in progress for me, and I don't run any websites with it yet, but I might at some point very soon!





[...] here you go… may I present Blake's CentOS LAMP Server Guide, single-page edition, and the perhaps friendlier multi-page [...]
this is the best guide I've seen ever for how to setup a linux server from start to finish.
Wow…, it's amazing tutorial….!!
This is what I need here.
Thanks very much….
Thanks guys! I'm glad you find it useful.
[...] Blake's CentOS LAMP Server Guide, Single Page HTML edition | PHP vs .Net [...]
A+++ Great. I agree, one of the best ive seen, Sort of like a cliff notes for LAMP install.
one little observation.
removing indexhtml with yum seems to want to remove 214 packages, including yum itself.
superb job
oooppss for the redundancy
The first command totally ruined my install. Yum is gone and none of the shell commands work, like ls, etc…
Hello webmaster
I would like to share with you a link to your site
write me here preonrelt@mail.ru
Awesome article, bookmarked, thanks