July 3, 2013 You'll probably want to host multiple domains on your server. To do that we will need to set up Apache virtual hosts. There is more than one way to do this. The configuration below assumes that there is one server administrator who manages multiple hosted domains. In other words, this setup is good for web developers who host their own clients and manage their client's sites.
First, change permissions on the admin user's directory:
$ sudo chmod 755 /home/admin
Create the First Hosted Domain
Create a home directory for your first hosted domain. We'll use www.mydomain1.com as an example. Note that further down when we edit the Apache settings in the httpd.conf file we'll be enforcing the www version as our canonical domain, so we need the directory name to match. If you plan to enforce the non-www version, then don't include the www in the directory name either.
$ mkdir -p /home/admin/sites/www.mydomain1.com/public_html
Add an index.html file to the hosted domain's public folder:
$ vim /home/admin/sites/www.mydomain1.com/public_html/index.php
And add some code to the index.php file:
<?php
echo phpinfo();
You can repeat the steps above for each domain you want to host.
Configure Apache for Virtual Hosting
Open the Apache config file httpd.conf:
$ sudo vim /etc/httpd/conf/httpd.conf
Near the bottom of the file uncomment the line that reads:
NameVirtualHost *:80
Normally each hosted domain gets an separate entry in httpd.conf. However, this makes it cumbersome to add new domains. The following setup can be used for mass virtual hosting so that we won't need to add each new hosted domain to httpd.conf. With these settings, all we'll need to do is add a new directory to /home/admin/public_html/ for each new site we host. Pretty cool.
We'll also enforce the www version as the canonical domain here in httpd.conf because it's more efficient than using .htaccess.
<VirtualHost *:80>
# Redirect non-www to www for all domains
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} !^www..+$ [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Set the home directory for each domain based
# on the request. %0 will be the domain name.
VirtualDocumentRoot /home/admin/sites/%0/public_html
# Fix the broken $_SERVER_[DOCUMENT_ROOT] with this hack
php_admin_value auto_prepend_file /home/admin/docroot.php
</VirtualHost>
Apache can run into memory problems if each virtual host has it's own log file. So what we'll do is combine the logs for all the domains into a single, common log file. The log file can be split programmatically on a per-virtualhost basis for reporting, etc.
In httpd.conf, search for LogFormat. Add the following 2 lines right after the existing entries for LogFormat:
LogFormat "%V %h %l %u %t "%r" %>s %b" vhost
CustomLog /home/admin/logs/vhost.log vhost
Save and close httpd.conf.
Logging
Create a directory to store the log files:
$ mkdir /home/admin/logs
$ touch /home/admin/logs/vhost.log
$ chmod 664 /home/admin/logs/vhost.log
Log files can get big quickly, so we need to make sure the logrotate program knows about our vhost.log file. We just need to add our new log file to the existing Apache logrotate configuration:
$ sudo vim /etc/logrotate.d/httpd
The first line of the file should look like this:
/var/log/httpd/*log {
We're going to add the path to our vhost.log file right after the existing path. Make sure there's a space separating the file paths. So your first line should now be:
/var/log/httpd/*log /home/admin/logs/vhost.log {
The next few lines of the file are a stack of commands (see this Slicehost article for more details). We'll leave them as is, but let's add one additional command right at the top of the stack:
size 10M
Now our logs will rotate every week, or when they reach 10 megabytes, whichever comes first. I would also recommend installing Logwatch to get daily email reports about the state of your server.
Finishing Up
In the last line of the VirtualHost block in httpd.conf you may have noticed a reference to a file called docroot.php. That file is a hack that is used to fix the broken DOCUMENT_ROOT that results from this mass virtual hosting configuration. With the hack in place we will be able to use $_SERVER[DOCUMENT_ROOT] in PHP and get the correct result. Create the file with $ vim /home/admin/docroot.php, then add the following contents:
<?php
$docroot = str_replace($_SERVER['SCRIPT_NAME'], '',
$_SERVER['SCRIPT_FILENAME']);
$_SERVER['DOCUMENT_ROOT'] = $docroot;
apache_setenv("DOCUMENT_ROOT", $docroot);
Finally, let's restart Apache so the new configuration takes effect:
$ sudo service httpd restart
Now we should be able to go to www.mydomain1.com and see our test page (assuming we've set up the DNS for www.mydomain1.com of course).
Additional Resource: Slicehost article on another virtual host configuration
Next > Part 5: Postfix Email Forwarding
July 3, 2013 Firewall
First we need to enable iptables (the CentOS firewall) and open some ports to allow access from the web:
$ sudo service iptables start
Let's make sure the server always starts iptables after a reboot:
$ sudo chkconfig iptables on
Now we need to open some ports in our firewall. We'll do that using the GUI we installed:
$ sudo system-config-firewall-tui
# If it refuses to start run the command below, for this bug fix:
# https://bugzilla.redhat.com/show_bug.cgi?id=1123919
$ sudo service messagebus start
- Hit the tab key to highlight the Customize button, then press enter. Use the arrow key to scroll through the list. Hit enter to enable the ports that need to be opened. A star will appear next to each service name that we've enabled. For now let's just open 3 ports:
[*] SSH
[*] Secure WWW (HTTPS)
[*] WWW (HTTP) - Hit the tab key again to highlight the Close button, then press enter. On the next screen select OK, then press enter.
Note: Don't open the FTP port. You should aways use SFTP, which works just like FTP but runs over the SSH port making it more secure.
Now we need to restart iptables so that our rules will take effect:
$ sudo service iptables restart
The iptables configuration file is located in /etc/sysconfig/iptables. This is the file that the GUI modified. You can modify it directly if you prefer.
Note: On Linode I ran into an error restarting iptables. If you see the error below, see this blog post for the solution.
iptables: Setting chains to policy ACCEPT: security raw nat[FAILED]filter
Fail2Ban (Requires EPEL)
Fail2Ban monitors log files looking for suspicious behavior, like too many failed login attempts. When if finds a evil IP address, it adds a rule to iptables to block that IP. If you installed the EPEL repos in the earlier section, you can install fail2ban to give your server some added protection.
$ sudo yum -y install fail2ban
$ sudo chkconfig fail2ban on
$ sudo service fail2ban start
Now we'll copy the .conf file and edit the .local version so we can tweak the settings:
$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
$ sudo vim /etc/fail2ban/jail.local
In jail.local, look for the section beginning with [DEFAULT]. Add your IP address to the ignoreip setting (use spaces to separate multiple IPs). You can change the values of bantime and maxretry if you wish. Then restart the service:
$ sudo service fail2ban restart
You can see that fail2ban is active by checking the iptables rules.
$ sudo iptables -L
Apache
Let's get the Apache web server (known as httpd) up and running:
$ sudo service httpd start
And we'll make sure the server always starts Apache after a reboot:
$ sudo chkconfig httpd on
We can check that the above command worked by typing:
$ sudo chkconfig --list httpd
# this should output:
# httpd 0:off 1:off 2:on 3:on 4:on 5:on 6:off
MySQL
Finally let's start MySQL:
$ sudo service mysqld start
$ sudo chkconfig mysqld on
Run the setup script:
$ sudo mysql_install_db
And security harden the installation a bit by running this next script.
$ sudo mysql_secure_installation
# Just hit enter here
Enter current password for root (enter for none):
You will then be asked to create a root MySQL password. After that, say yes to all the remaining questions (type Y at each prompt and hit enter).
You can test your MySQL login:
$ mysql -u root -p
$ Password:
If you see a MySQL prompt, all is well. You can exit MySQL:
> exit
Visit Your Server
Open your web browser and enter your server's IP address in the address bar. You should see an Apache welcome screen, indicating that the server is up and running.
Next > Part 4: Apache Virtual Hosts
July 3, 2013 We'll need to install the various pieces of software. The easiest way to do that is with the yum package manager. After entering each yum command you will be asked to confirm the installation by typing the y key and pressing enter.
First, let's update the OS and any preinstalled packages. Notice we now have to use the sudo command to run system admin tasks. You will be prompted for your password when using sudo.
$ sudo yum -y update
Next, I'm going to add the Extra Packages for Enterprise Linux 6 (EPEL) repository. This is not required, but EPEL has additional packages that I want (e.g. Fail2Ban, phpMyAdmin).
$ curl -L https://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm > epel-release-6-8.noarch.rpm
$ sudo yum -y install epel-release-6-8.noarch.rpm
$ rm -f epel-release-6-8.noarch.rpm
Next let's install a collection of useful developer tools. This includes things like git, subversion, make, and the gcc complier. Most people won't use all of these tools, so you could also install tools individually if you want to be more selective. But we'll take the easy way in this tutorial.
$ sudo yum -y groupinstall 'Development Tools'
You may want to install debugging tools like gdb and valgrind as well. If you're only going to use PHP on the server side you can skip this step.
$ sudo yum -y groupinstall 'Debugging Tools'
Now let's install the Apache web server:
$ sudo yum -y install httpd mod_ssl
You'll probably want PHP, so let's install PHP along with a set of common PHP extensions:
$ sudo yum -y install php php-common
And let's install a few additional useful PHP extensions, including MySQL support, Pear, and mcrypt:
$ sudo yum -y install php-mysql php-pear php-devel php-gd php-pecl-memcache php-pspell php-snmp php-xmlrpc php-xml php-mbstring.x86_64
Finally, we'll add MySQL to complete our LAMP stack:
$ sudo yum -y install mysql mysql-server
Okay, one last thing. We'll need to manage iptables (the CentOS firewall). To make that easier let's install a GUI:
$ sudo yum -y install system-config-firewall-tui system-config-firewall
That's it for software. In the next section we'll get our web server up and running.
Next > Part 3: Starting the Web Server
July 2, 2013 Securing the Server
Change the Root Password
The passwd command allows you to change the root password. After entering the command you will be prompted to enter the new password two times:
# passwd
Add a New User with SUDO Privileges
The sudo command allows non-root users to temporarily take on root privileges. It's a good practice to create a new user with sudo privileges and then disable root login. So first let's create a new user. I'll use the username admin, but you can choose any username you want:
# useradd admin
# passwd admin
Now let's grant the new user sudo privileges. The following command opens the sudoers file in the vi text editor.
# visudo
Add the following line at the very bottom of the file, then save:
admin ALL=(ALL) ALL
Alternative: Add a Group With SUDO Privileges
If you plan to have several users with sudo privileges you can assign the privileges to a group and then add your users to that group. In the sudo file, replace the line we added above with this one:
%admins ALL=(ALL) ALL
This gives sudo priviliges to the group called admins. Now we need to create the admins group:
# groupadd admins
And finally, let's add our admin user to the admins group. We also have to add the user to the wheel group to allow them to use sudo:
# usermod -a -G admins,wheel admin
Grant New User SSH Access
Now that we have a user who can perform system administration tasks via sudo, let's grant him SSH access. Open the ssh config file:
# vi /etc/ssh/sshd_config
Scroll down to the section with the heading Authentication and add the following lines, then save:
# Authentication
AllowUsers admin
# or if you used the group method:
# AllowGroups admins
MaxAuthTries 6
Restart ssh:
# service sshd restart
Log In as the New User
Let's log out and log back in as our new admin user.
# exit
# this will exit the server and return you to the
# command prompt on your local computer.
# now we'll log back in as admin
$ ssh admin@12.34.56.78
If all goes well you'll be logged in as the admin user.
Disable Direct Root Login
Now that we're sure our new user can access the server, we can disable direct root login. Open the ssh config file again, but using the sudo command this time:
$ sudo vi /etc/ssh/sshd_config
Scroll down to the Authentication section and add:
# Authentication
PermitRootLogin no
Restart ssh:
$ sudo service sshd restart
Next >Part 2: Installing Packages
July 1, 2013 Updated for CentOS 6.5.
Before you can begin configuring your server, you'll first need to create a new server instance using the Rackspace cloud control panel. We're using CentOS 6.4 in this tutorial. Make note of the password — it will only be shown once! After the server is finished building, make note of the IP address as well. With the IP address and password in hand, we're ready to get started. For this example we'll assume that the IP is 12.34.56.78.
Open your terminal and let's SSH to the server so we can begin:
$ ssh root@12.34.56.78
You may receive a security warning about the RSA key. If so, type yes and then hit enter. When prompted, enter your password. You should now be logged in to the server and ready to get started.
Next, let's give our server a unique name. It can be anything:
$ echo "HOSTNAME=plato" >> /etc/sysconfig/network
$ hostname "plato"
Now add a fully qualified domain name in /etc/hosts. You'll probably want to use your hostname plus your primary domain name, like so:
12.34.56.78 plato.example.com plato
# you may also wish to add your ipv6
Be sure to add an A record to your DNS that points plato.example.com to your server's IP address.
Finally set the server timezone. We'll use UTC time:
$ ln -sf /usr/share/zoneinfo/UTC /etc/localtime
Next Steps
- Securing the Server
- Installing Packages
- Starting the Server
- Apache Virtual Hosts
- Postfix Email Forwarding
June 7, 2013 Here is a great Slicehost article on setting up custom logrotate functions:
Part 1 | Part 2
May 4, 2013 Rewrite www.example.com to example.com
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
</IfModule>
Rewrite example.com to www.example.com
<IfModule mod_rewrite.c>
RewriteCond %{HTTPS} !=on
RewriteCond %{HTTP_HOST} !^www\..+$ [NC]
RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>