»
Introduction
This guide will take you through each step required to build a Linux web server from the ground up. Starting with a new installation of CentOS 4.x, using Yum for updates and package installation, the LAMP components (Linux, Apache, MySQL and PHP), other modules such as Perl, Webalizer and FTP using VSFTP.
By following this guide, you can get a web server up and running within an hour or two depending on whether you follow it step by step, or prefer to experiment first.
What you need : Download CentOS!
CentOS is completely free and developed by a small but growing team of core developers provided to the public by a prominent North American Enterprise Linux vendor. In turn the core developers are supported by an active user community including system administrators, network administrators, enterprise users, managers, core Linux contributors and Linux enthusiasts from around the world.
CentOS has numerous advantages over some of the other clone projects including: an active and growing user community, quickly rebuilt, tested, and QA'ed errata packages, an extensive mirror network, developers who are contactable and responsive, multiple free support avenues including IRC Chat, Mailing Lists, Forums, a dynamic FAQ. Commercial support is offered via a number of vendors.
CentOS is distributed on four CD's, but for purposes of building a web server, only CD 1 is required. At the time I write this the latest version on CentOS is 4.2.
phpMyAdmin:
phpMyAdmin is a tool written in PHP intended to handle the administration of MySQL over the Web. Currently it can create and drop databases, create/drop/alter tables, delete/edit/add fields, execute any SQL statement, manage keys on fields, manage privileges,export data into various formats and is available in 50 languages.
»
Insert the CentOS boot CD into your computer, and boot from it.
At the installation menu, just press enter for the graphical installation wizard.
When prompted for an installation type select custom installation.
Use automatic partitioning for the disks.
Remove all partitions from system (make sure you are happy to wipe all existing data!!).
Boot Loader: Leave default settings.
Network Configuration: Configure this with an internal IP address and DNS name.
Firewall: Select ‘No firewall’ as this will be installed and configured later.
Enable SELinux: ‘Disabled’. This is still very experimental so I would leave this switched off unless you really know what you are doing.
Authentication: Set a secure root password using random characters and numbers (upper an lower case).
Package Selection: Choose minimal configuration (Other packages can be installed at a later stage according to the server role).
WARNING!! – The server should not be connected to the internet until the configuration is completed and secure.
»
First you need to install the product signing key from CentOS by typing the following command:
# rpm --import http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-4
To check for updates type the following:
# yum check-update
Now perform the update process. Note, the -y is to accept all updates which I recommend.
# yum –y update
Now reboot the computer.
»
Services
The following command will list all services that are currently running on the server. This is useful to identify any unnecessary services such as CUPS (used for printing), APMD (power management), NETFS (Network File System), and PCMCIA (expansion card slot).
To display list of services that will start on boot type:
# chkconfig –list|grep on
Switching off any redundant services:
# chkconfig cups off
# chkconfig apmd off
# chkconfig netfs off
# chkconfig pcmcia off
# chkconfig smartd off
# chkconfig anacron off
# chkconfig mdmonitor off
# chkconfig isdn off
Host Access (TCP_WRAPPER)
There are two host access files (/etc/hosts.allow and /etc/hosts.deny), that are part of the TCP_WRAPPER package. These files should be changed to only allow SSH access from your IP address or subnet. In the example below, it will allow anyone on the 192.168.20.x network to SSH to the web server.
Edit the hosts.allow and hosts.deny files:
# vi /etc/hosts.allow
sshd:192.168.20.
# vi /etc/hosts.deny
ALL:ALL
SSH
The root account should never be able to login via SSH (without first logging in as a user). To change this, you need to edit /etc/ssh/sshd_config and ensure the following is set:
# vi /etc/ssh/sshd_config
Change the following lines as follows:
PermitRootLogin no
Protocol 2
Note: Some of these lines may already exist but will be commented out using #. To enable these commands the # needs to be removed.
Add Default Accounts
Before proceeding with any of the steps below, first create a ‘sysop’ account that will be used to log in to this server. Next, we will create a special FTP account called adminftp, that can be used to access the /.sites directory.
# adduser sysop
# passwd sysop
# adduser –s /sbin/nologin adminftp
# passwd adminftp
Next we need to change the home directory of the adminftp account. This will allow us to use this account to access all folders in the /.sites directory.
# vi /etc/passwd
Change the home directory from /home/adminftp to /home/.sites.
»
Pre-configuring CentOS
Edit /etc/hosts and /etc/sysconfig/network with hostnames
Install Packages
Example of /etc/hosts:
# Do not remove the following line, or various programs
# that require network functionality will fail.
127.0.0.1 localhost
67.34.32.11 www.mydomain.com
Example of /etc/sysconfig/network
NETWORKING=yes
HOSTNAME=www.mydomain.com
Installing Packages
# yum -y install httpd openssl-devel openssl mod_ssl vsftpd rpm-build rpm-devel autoconf automake lynx gcc
# yum -y install mysql mod_auth_mysql mysql-devel mysql-server
# yum -y install mod_python python python-devel
# yum -y install perl mod_perl mod_perl-devel openssl-perl perl-Convert-ASN1 perl-Date-Calc perl-DateManip perl-HTML-Parser perl-libwww-perl perl-CPAN perl-DBD-MySQL perl-XML-Parser
# yum -y install php-devel php php-domxml php-gd php-mbstring php-mysql php-ncurses php-pear
# yum -y install webalizer
# yum -y install sendmail sendmail-cf
NOTE: Before continuing with the rest of the configuration, I recommend that you reboot the server (shutdown -r now).
Creating Directory Structure
All websites will be held in /home/.sites/<sitename>. The first site that needs to be created is the _default site, which will be used as this servers default website.
# mkdir /home/.sites
# cd /home/.sites
# mkdir _default
# cd _default
# mkdir logs private cgi-bin web
# cd web
# mkdir stats
Now change the ownership of these directories to adminftp as follows:
# cd /home/.sites
# chown adminftp _default -R
Configure the required server daemons to start at boot:
# chkconfig httpd on
# chkconfig mysqld on
# chkconfig vsftpd on
# chkconfig sshd on
Before continuing with the installation the server must be rebooted to apply any updates that have occurred.
Configuring TCPWrappers (hosts.allow and hosts.deny):
# vi /etc/hosts.allow
Ensure this file only contains the following:
sshd:192.168.20.
vsftpd:ALL
sendmail:ALL
# vi /etc/hosts.deny
Ensure this file only contains the following:
ALL:ALL EXCEPT httpd
»
Apache runs as the httpd daemon, and it’s configuration file is contained in /etc/httpd/conf. To run in a ‘virtual’ hosting environment, we will now configure the httpd.conf file.
First, make a backup of the httpd.conf file
# cd /etc/httpd/conf
# cp httpd.conf httpd.conf.backup
Now edit httpd.conf and make the following changes:
ServerAdmin admin@mydomain.com
ServerName www.mydomain.com:80
NameVirtualHost *:80
DirectoryIndex index.html index.htm index.html.var
<VirtualHost *:80>
ServerAdmin admin@mydomain.com
DocumentRoot /home/.sites/_default/web
ServerName www.mydomain.com
ScriptAlias /cgi-bin/ /home/.sites/_default/cgi-bin/
ErrorLog /home/.sites/_default/logs/error_log
TransferLog /home/.sites/_default/logs/access_log
<Directory /home/.sites/_default/web>
Options FollowSymLinks
Options +Includes
AllowOverride All
</Directory>
</VirtualHost>
At the very end of the configuration file add the following line. Make sure you include the # otherwise it will not work.
# END
NOTE: Please be careful when editing the httpd.conf file not to forget that some lines may be commented out with a #.
Save and exit the httpd.conf file (:wq), and then restart the httpd service.
# /etc/init.d/httpd restart
»
VSFTPD stands for Very Secure File Transfer Protocol Daemon. However using the installation defaults isn't actually that secure as it allows anonymous access and doesn't restrict which users can access the servers FTP service.
In order to harden the security of VSFTP, several configuration changes must be made. Please note that some of these lines may be commented out by default, with a #, so remember to remove this if required.
# vi /etc/vsftpd/vsftpd.conf
anonymous_enable=NO
xferlog_file=/var/log/vsftpd.log
idle_session_timeout=600
nopriv_user=nobody
ascii_upload_enable=YES
ftpd_banner= **** WARNING - Your actions are being logged ****
pam_service_name=vsftpd
userlist_enable=YES
listen=YES
tcp_wrappers=YES
chroot_local_user=YES
userlist_deny=NO
Next, we need to configure vsftpd.userlist and specify which users can FTP to the server. This compliments the userlist_deny setting in vsftpd.conf. When set to NO, this makes the vsftpd.userlist file a list of users that ARE allowed to log in.
# vi /etc/vsftpd.userlist
Remove all of the users that are listed in this file by default, and add ONLY the users that require access to the FTP server including adminftp.
»
MySQL is configured using /etc/my.cnf, but prior to any configuration this configuration file has only the bare minimum required to start the MySQL daemon. However there are 5 templates that we can base the configuration on; my-huge.cnf, my-innodb-heavy-4G.cnf, my-large.cnf, my-medium.cnf, and my-small.cnf. These are each configured depending on the RAM and the priority that MySQL has on this server.
We will use my-medium.cnf as this has been based on a web server where MySQL is not the primary role of the server but could have frequent use.
# cd /usr/share/doc/mysql-server-<VERSION>
# cp my-medium.cnf /etc/my.cnf
Once this has overwritten my.cnf, the mysqld daemon must be restarted.
# /etc/init.d/mysqld restart
Now the root password for MySQL must be set using the following command. Do NOT use the same root password as the Linux root password.
# mysqladmin -u root password <PASSWORD>
»
Administration of MySQL is carried out using phpMyAdmin which is a free open source software package licensed under the GNU.
1) Download phpMyAdmin from www.phpmyadmin.net
2) Extract the contents to a directory called phpMyAdmin (case sensitive)
3) Transfer the phpMyAdmin directory to /home/.sites/_default/web (Use FTP and login using adminftp, as described in the Configuring FTP using VSFTPD section).
Now we need to configure the confic.inc.php file as follows:
# vi /home/.sites/_default/web/phpMyAdmin/config.inc.php
Look for:
$cfg['Servers'][$i]['auth_type'] = 'config’;
Change ‘config’ to ‘http’ then restart MySQL.
# /etc/init.d/mysqld restart
You should now be able to log into phpMyAdmin by going to http://www.mydomain.com/phpMyAdmin. Log on using ‘root’ and the password you specified for MySQL. You will now be presented with the phpMyAdmin web control panel. By default, MySQL contains a test database which is not required, so as a security measure, this needs to be deleted.
To do this, click on ‘Databases’, then tick test. Click ‘Drop’ and then click ‘Yes’ to confirm.
»
In order for Webalizer to run properly in a virtual hosted server using multiple websites, each site will have it’s own log directory which should have been created earlier.
Once Webalizer has been installed, you need to create a central configuration directory that contains a config file for each domain as follows: (Note: each config file should be named after the domain name, e.g. www.mydomain.com.conf)
# mkdir /etc/webalizer
Webalizer doesn’t run as a daemon, therefore a script must be created to process all of the configuration files in the /etc/webalizer directory. To do this we’ll first setup the script, then configure crontab to run the script every hour.
# cd /etc/webalizer
# vi webalizer.sh
Enter the following:
# This will run Webalizer against all *.conf files in the /etc/webalizer directory
for i in /etc/webalizer/*.conf; do webalizer -c $i; done
Once the file has been saved, use chmod to give it execute permissions:
# chmod 755 webalizer.sh
Now configure crontab:
# crontab -e
Enter the following:
# Run Webalizer to update Apache Log files every 28 minutes.
0 * * * * /etc/webalizer/webalizer.sh > /var/log/webalizer.log 2>&1
Note: The 2>&1 at the end of the crontab entry disables cron from sending an email to root which occurs by default. If any other crontab entries are created then make sure to include this.
»
In the following steps, we will base our configuration on a fictitious company called Happy Burger who has already registered the domain name, happyburger.net. We will point www.happyburger.net to the IP address of this web server. When you are creating your own site, substitute the customer name and domain name for that of the actual customer.
Create a User Account
The first step is to create a user account that will be used to authenticate via FTP. When creating the password, make sure that it is at least 8 characters, alphanumeric, mixed case and includes numbers. The following website can be used to generate a random password: http://www.winguides.com/security/password.php
# adduser –s /sbin/nologin happyburger
# passwd happyburger
Creating the directory structure
Each website must have the following directory structure in order to support access logs, web statistics, .htpasswd files, CGI scripts and the public web directory.
/home/.sites/happyburger/: This path will contain a directory for each website. Each directory should be named after the customer name, in lowercase.
/home/.sites/happyburger/web/: This path contains the website contents (public root).
/home/.sites/happyburger/web/stats/: This path will contain the Webalizer statistics, and is password protected using .htaccess.
/home/.sites/happyburger/private/: This path is not accessible from the internet, and contains the .htpasswd file.
/home/.sites/happyburger/cgi-bin/: Apache uses this path as the CGI script directory, by using a script alias.
/home/.sites/happyburger/logs/: This path stores the log files that Apache generates.
Create the structure as follows:
# cd /home/.sites
# mkdir happyburger
# cd happyburger
# mkdir web cgi-bin private logs
# cd web
# mkdir stats
Now change the ownership of these directories:
# cd /home/.sites
# chown happyburger happyburger -R
Configuring Apache
As Apache will be configured using multiple ‘virtual hosts’, we will create a separate configuration file for each virtual host. To do this we will create a vhost directory, and configure the Apache configuration file to read each of these virtual host configurations.
# cd /etc/httpd/vhost (If this directory does not exist then you will need to create it)
Now we will create the virtual host configuration file for this particular customer.
# vi happyburger.conf
Now enter the following into the newly created configuration file:
<VirtualHost *:80>
DocumentRoot /home/.sites/happyburger/web/
ServerName www.happyburger.com
ServerAlias test.happyburger.com
ServerAdmin admin@myserver.com
ScriptAlias /cgi-bin/ /home/.sites/happyburger/cgi-bin/
ErrorLog /home/.sites/happyburger/logs/error_log
TransferLog /home/.sites/happyburger/logs/access_log
<Directory />
Options FollowSymLinks
Options +Includes
AllowOverride All
</Directory>
</VirtualHost>
Once this has been saved, we will then need to configure Apache to include this in it’s configuration.
# vi /etc/httpd/conf/httpd.conf
At the end of the configuration file (just before # END) add the following line:
Include /etc/httpd/vhost/happyburger.conf
Now restart httpd:
# /etc/init.d/httpd restart
Configuring FTP (VSFTP)
Before the new account can login via FTP, you must add the new user to vsftp.user_list which contains a list of all accounts permitted to use the FTP service.
# vi /etc/vsftpd.user_list
Add the new user to the list.
Configuring Webalizer
Webalizer will need to be configured to support multiple virtual hosts, so as we did with Apache, we will create a configuration file for each customer (in this case, happyburger.conf). Rather than creating a new configuration file from scratch, we can use the default webalizer.conf.
# cp /etc/webalizer.conf /etc/webalizer/happyburger.conf
Now edit the configuration file:
LogFile /home/.sites/happyburger/logs/access_log
OutputDir /home/.sites/happyburger/web/stats
ReportTitle Usage Statistics for
HostName www.happyburger.com
As configured previously with the main web server build, crontab has been setup to run webalizer.sh every hour. This will look for any .conf files and update the stats. They can be viewed by going to www.happyburger.com/stats.
However, so these are not publicly accessible we will password protect the stats using .htaccess:
# cd /home/.sites/happyburger/web/stats/
# vi .htaccess
Enter the following:
AuthName "Web Stats"
AuthType Basic
AuthUserFile /home/.sites/happyburger/private/stats/.htpasswd
Require valid-user
Now we’ll create the .htpasswd file which will be used to protect the web stats:
# cd /home/.sites/happyburger/private
# mkdir stats
# cd stats
# htpasswd –c .htpasswd happyburger (This will prompt you to enter the password)
»
Problems with sendmail
When setting up my first Linux web server, it was actually sendmail that caused me the most trouble. If you get the following errors:
<< 550-Verification failed for <admin@rayheffer.com>
<<< 550-Unrouteable address
<<< 550-<admin@rayheffer.com> does not appear to be valid. Sender verify
<<< 550 failed.
550 5.1.1 <test@test.com>... User unknown
<<< 503 valid RCPT command must precede DATA
1) This is almost certainly a problem with the hostname of the server. So check make sure the hostname of the server (e.g. linuxweb.mydomain.com) is actually resolvable over the internet. This hostname must be the same in /etc/hosts, /etc/sysconfig/network, and /etc/mail/relay-domains.
2) The /etc/mail/local-host-names and /etc/mail/relay-domains file should contain the hostname of the server, and also localhost. If the relay-domains file does not exist, then you can create it.
3) Check /etc/hosts.allow and make sure it has sendmail:ALL
4) This is unlikely but it may be a problem with the sendmail configuration (/etc/mail/sendmail.cf). Do not edit /etc/mail/sendmail.cf directly, instead use /etc/mail/sendmail.mc which is a meta-config file. When done, you can use m4 sendmail.mc > sendmail.cf to write the meta-config to the actual sendmail.cf file.
The sendmail.mc file has various entries beginning with dnl (do not load). For sendmail to work properly on a virtual hosting server then make sure you add dnl to the following:
dnl FEATURE(delay_checks)dnl
dnl FEATURE(`mailertable',`hash -o /etc/mail/mailertable.db')dnl
dnl FEATURE(always_add_domain)dnl
dnl FEATURE(`blacklist_recipients')dnl
dnl FEATURE(`relay_based_on_MX')dnl
dnl FEATURE(masquerade_envelope)dnl
dnl FEATURE(masquerade_entire_domain)dnl
Then, the following entries should be enabled (without dnl at the beginning)
FEATURE(`accept_unresolvable_domains')dnl
FEATURE(`no_default_msa',`dnl')dnl
FEATURE(`smrsh',`/usr/sbin/smrsh')dnl
FEATURE(`virtusertable',`hash -o /etc/mail/virtusertable.db')dnl
FEATURE(redirect)dnl
FEATURE(use_cw_file)dnl
FEATURE(use_ct_file)dnl
FEATURE(local_procmail,`',`procmail -t -Y -a $h -d $u')dnl
FEATURE(`access_db',`hash -T<TMPF> -o /etc/mail/access.db')dnl
5) As a final resort, re-install sendmail then go back to step 1.
# yum remove sendmail sendmail-cf
# yum install sendmail sendmail-cf