© 2015 X2Engine Inc.
Preparing a Linux Server Environment
This aims to be a generic guide for manually preparing a Linux-based web server, which applies both to physical servers and virtual servers, i.e. Amazon EC2 instances. It will cover two main families of Linux distributions: RHEL (Red Hat Enterprise Linux) based and Debian-based. RHEL-based distributions include, most notably: CentOS, Oracle Linux and Amazon Linux. Debian-based distributions include the popular Ubuntu and Ubuntu derivatives, as well as Linux Mint, Knopper Linux and many others[1].
Introduction
It will be assumed in this guide, unless otherwise noted:
- Command line operations are being performed as the root user
- Names enclosed in angle brackets (< >) are intended as placeholders for actual input and should not be used verbatim
- The server is dedicated, i.e. will be used mainly for X2CRM on a single domain name, and will not be set up with multiple virtual hosts.
- The Linux system's software package manager has been configured properly
- Software will be installed using pre-built packages available through the particular distribution's software package repositories.
- A distribution of Linux based on Red Hat Enterprise Linux or Debian is in use.
When installing packages, note: there may be slight differences in the names of software packages between distributions of Linux. Thus, in cases where a package name copied verbatim from this guide does not exist, the package manager's search utility should be used to determine the proper package name.
The command for searching for packages by name is as follows:
apt-cache search <package name> # (Debian-like) yum search <package name> # (RHEL-like)
In each case, use parts of the full name to increase the likelihood of getting search results. Note that Debian's apt-cache search utility will accept regular expressions (if quoted properly). To search for packages on RHEL-based systems with regular expressions, search results from yum can be simply piped to grep:
yum search <package name> | grep <package regex>
Installing the Web Server
Acquiring Software Packages
To begin, refresh the software package database:
apt-get update # (Debian-like) yum update # (RHEL-like)
There may also be software updates. If any are available, yum will download prompt you if you want to install them. Debian's apt, on the other hand, only updates the package databases. To install software updates, if any are available, run apt-get upgrade.
Next install Apache, PHP and MySQL. Debian-based systems should have a utility called "tasksel" that can begin installation of all the necessary packages for a LAMP (Linux, Apache, MySQL & PHP) server in one command:
tasksel install lamp-serverHowever, this task usually does not include the package for the PHP cURL extension, so it must be installed separately via
apt-get install php5-curl
On RHEL-based systems: run
yum install mysql mysql-server php-mysql php httpd php-mbstring php-curl
On many RHEL-based systems, PHP will be built without POSIX support (the compile flag '--disable-posix' should appear in the "Configure Command" section of phpinfo() ). Thus, the requirements checker script will not display the proper warning when the apache UID doesn't match the ownership of the web document root. Although it is not necessary (the next steps will ensure that this requirement is met anyway), the POSIX extension can be added if desired by installing the package php-process or php-posix (depending on the distribution and release version).
There are two more optional but useful PHP extensions: APC (caching extension) and Suhosin (PHP security). These packages should be available in most Debian-based distributions and can be installed via apt-get install php5-suhosin php-apc. In CentOS, they can be acquired by enabling the EPEL software repository [2] and then running yum install php-suhosin php-pecl-apc.
Starting the Server
To start the server, run:
service apache2 start # (Debian-like) service httpd start # (RHEL-like)
Navigate to the server with a web browser to verify that the web server is running and responding to requests on its IP address / fully-qualified domain name.
Assigning a Domain Name
Due to the great diversity of DNS[[wikipedia:Domain Name System]]: a naming system for computers, services, or any resource connected to the Internet or a private network (i.e. that identifies "google.com" with its internet protocol address) services and tools, the exact procedure for associating a domain name with the web server is beyond the scope of this guide. However, the most important facts are:
- To direct a domain name to an IP address, use the A type DNS[[wikipedia:Domain Name System]]: a naming system for computers, services, or any resource connected to the Internet or a private network (i.e. that identifies "google.com" with its internet protocol address) record.
- To direct a domain name to another domain name, use the CNAME type DNS[[wikipedia:Domain Name System]]: a naming system for computers, services, or any resource connected to the Internet or a private network (i.e. that identifies "google.com" with its internet protocol address) record.
For instance, given the hostname of an Amazon Web Services EC2 instance, one would associate a domain name with it via a CNAME record (to ensure proper resolution).
Server Preparation
The default DocumentRoot of Apache Webserver on most distributions of Linux will be owned by the root user immediately after installation, whereas its default User and Group will be set to "www-data" (Debian) or "apache" (RHEL). This configuration makes it so that no web application whatsoever will have write permissions to the directory it runs in (which is problematic). Thus, the first step of preparation once the server has been installed and started is to ensure the ownership of the files and Apache process are the same.
Determining the DocumentRoot
This is a rather important aspect of a web server is where the files to be served are stored in the local filesystem, and will be necessary in the next steps of this process. To obtain it, search for the DocumentRoot directive in the configuration as follows:
grep -r '^ DocumentRoot' /etc/apache2/ # (Debian-like) grep -r '^ DocumentRoot' /etc/httpd/ # (RHEL-like)
In most cases, the directive will be set to /var/www on Debian-based distributions and /var/www/html on RHEL-based ones.
Determining the Apache User/Group
On Debian-based systems, these directives are typically set to "www-data", and on RHEL-based systems, to "apache". However, if in doubt, there are at least three methods of finding out the values to which the User/Group directives set.
Direct Method
The most reliable way of finding out what they are is by searching the configuration files for the directives:
grep -r '^ *\(User\|Group\)' /etc/apache2/ # (Debian-like) grep -r '^ *\(User\|Group\)' /etc/httpd/ # (RHEL-like)
Note that on Debian-based systems you may see that, in place of literal strings, there are references to environment variables, i.e. ${APACHE_RUN_USER}. To find their actual values, search for them in the same manner:
grep -r '^ *export *APACHE_RUN_' /etc/apache2/
Using ps
One can search for the process and see its user, if Apache is already running, using ps:
ps aux | grep '\(apache\|httpd\)'
The first column of output should be the user name or id of the running process, whereas the last should be the executable file of the process. Locate the web server process (the path to the executable should be something like /usr/sbin/apache2 or /usr/sbin/httpd).
Using PHP's POSIX Library
If the POSIX library is available in PHP, you can find the UID by creating a PHP script in the DocumentRoot with the following contents and opening it in a web browser:
<?php
echo 'UID (Server): '.posix_geteuid().'<br>';
echo 'UID (Directory owner): '.fileowner(realpath(dirname(__FILE__)));
?>
If the web server is properly set up, both of the numbers displayed should be equal.
Changing DocumentRoot Ownership
Once the UID of the webserver has been determined, change the ownership of the public web directory as follows:
chown -R <user>:<group> <DocumentRoot> # (Debian-like) chown -R <user>:<group> <DocumentRoot> # (RHEL-like)
Use the user name or ID of the running webserver process in place of <user> and <group>, and the server's DocumentRoot in place of <DocumentRoot>.
Testing the Webserver
When done, download the requirements checking script:
cd <DocumentRoot> wget http://x2planet.com/installs/download/requirements.php chown <apache user>:<apache user> requirements.php
Next, open the file in a web browser to verify that the system meets all of the requirements. Note that, if you see no "posix" section in the phpinfo() output and the flag "--disable-posix" appears in the configure command, and you skipped changing ownership, the results of the requirements check will not be accurate.
Preparing a Database
X2CRM needs a MySQL database for storing persistent data. To prepare this final requirement, you will first need to start the MySQL server daemon:
service mysql start # (Debian-like) service mysqld start # (RHEL-like)
Next, log into the database server as the database administrator (typically root).
mysql -u root -p
You may have to enter a password. On Debian systems, during the installation of the MySQL server, you should have been prompted for a root password, and thus you will need to use it for logging in. On Amazon Linux and some other RHEL derivatives, the root password won't be set, and so you can log in without the -p flag.
Once you have logged in, create the database, and create a non-admin user with full access to it. The database name "x2crm" and user name "x2crmuser" will be used in this example.
mysql> CREATE DATABASE x2crm; Query OK, 1 row affected (0.00 sec) mysql> CREATE USER x2crmuser@localhost IDENTIFIED BY '<password>'; Query OK, 0 rows affected (0.00 sec) mysql> GRANT ALL ON x2crm.* TO x2crmuser@localhost; Query OK, 0 rows affected (0.00 sec) mysql>
When you install X2CRM on the server, user "localhost" in the database "Host Name" settings, the database name you used in place of "x2crm", and the username/password you used in place of "x2crmuser" and "<password>."
Finally, if the root user on your MySQL server does not have a password set, it is a very good idea security-wise to set a password to protect the server. Do so using the following command (from the system shell, logged out of mysql>):
mysqladmin -u root password <newpassword>
Enabling Login as the Webserver User
To greatly ease the process of installing and maintaining X2CRM, the default Apache web user (assumed www-data in the Debian family and apache in the RHEL family, and denoted <apache user> in the general case) can also be used for logging into the server and uploading / altering files, thus avoiding all permissions issues. In many cases, the ability to log in as the web server user will be disabled for security purposes. This is mostly due to how the usernames are easy to guess in brute-force remote login attempts, although this problem can be circumvented. See Securing Login for details.
Setting the Shell
In most cases, login as the user is disabled via the shell environment variable. To check that this is so, use the getent command as follows:
getent passwd <apache user>
You should see output that looks like this:
www-data:x:33:33:www-data:/var/www:/bin/false
Or:
apache:x:48:48:Apache:/var/www:/sbin/nologin
In both cases, the last field in the (colon-delinated) line indicates the login shell; /bin/false and /sbin/nologin each make it impossible to run a shell as the user. Note also that the second-to-last field is the home directory of the user. If the field is blank (i.e. there are two colons side-by-side before the login shell) it is recommended at this stage to set the home directory of the user as follows:
usermod -d <DocumentRoot> <apache user>
If that command returns the error message that the user is currently logged in, try again after shutting down the web server as follows:
service apache2 stop # (Debian-like) service httpd stop # (RHEL-like)
Finally, to change the login shell, use chsh:
chsh <apache user> -s /bin/bash
Securing Login
The risk of brute-force logins can be avoided by ensuring that the main method of logging into the server and transferring files is through the secure shell daemon (SSHD), and that SSHD is configured to disallow password-based logins. SSHD will then require asymmetric key pairs to log in instead of passwords, thus making brute-force password attempts a non-issue. If your server is an Amazon Web Services EC2 instance, this will be the case already; the key pair is selected/generated before instantiation as the primary means of accessing the virtual server.
Configuring SSH For Key-based Authentication
On a generic Linux server:
- Begin a shell session as the web server user:
sudo -u <apache user> -i
All of the following commands will be run as this user. - Create a ".ssh" directory in the user's home:
mkdir -p ~/.ssh
- Ensure the directory has the proper permissions:
chmod 700 ~/.ssh
- Run:
ssh-keygen -t rsa
and (optionally) enter a passphrase to protect the key. The keypair, when done, should be stored as the files ~/.ssh/id_rsa (private) and ~/.ssh/id_rsa.pub (public). - Create the authorized_keys file with the public key to enable authenticating with the private key on the remote end:
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
- Ensure the authorized_keys file has the proper permissions:
chmod 600 ~/.ssh/authorized_keys
- Download the private key (~/.ssh/id_rsa) and delete it from the server as soon as possible.
If the server is an Amazon EC2 instance, it is not necessary to create a new key pair; the existing key pair can be used for authentication, if desired, by using the existing authorized_hosts file in the .ssh directory of "ec2-user" (Amazon Linux) or "ubuntu" (Ubuntu) into the .ssh/, as follows:
- Make the directory and copy the files:
mkdir -p ~<apache user>/.ssh; cp ~<default user>/.ssh/authorized_keys ~<apache user>/.ssh/
- Ensure proper user/group ownership of the files:
chown -R <apache user>:<apache group> ~<apache user>/.ssh
- Ensure proper permissions of the files:
chmod 700 ~<apache user>/.ssh; chmod 600 ~<apache user>/.ssh/*
Note that you may still have to protect the .ssh directory.
Protecting ~/.ssh
If the user's home directory is the same as (or lies within) the web server's DocumentRoot (this is the case for the default LAMP configuration on Ubuntu 12.04), it is generally a very good idea to prevent all HTTP access to the directory storing the public key, regardless of whether the key pair is password-protected. The most straightforward way of doing this is by editing the main Apache configuration (/etc/apache2/apache2.conf Debian, /etc/http/conf/httpd.conf RHEL ) and adding the following lines to it (for Apache versions 2.0-2.2):
<Directory /var/www/.ssh>
Order allow,deny
Deny from all
</Directory>
If using Apache 2.4 or later, you can use the non-deprecated configuration directive "Require"[3] as follows :
<Directory /var/www/.ssh>
Require All Denied
</Directory>
In both of these examples, it is assumed that the home directory is /var/www.
For extra privacy and security, it may also be desirable to deny access to all hidden dotfiles and directories used by the user shell and local programs (i.e. .bashrc, .bash_history, .viminfo etc.), in which case you can use the following directive:
<DirectoryMatch /var/www/\..*>
# Denial directives i.e. "Require All Denied" go here
</DirectoryMatch>
Disabling Password-based Authentication
To verify that password authentication is disabled, search for the directive in the SSHD configuration (which should be in the same place on almost every Linux and Unix system[4]):
grep '^PasswordAuthentication' /etc/ssh/sshd_config
In the output of grep you should see this:
PasswordAuthentication no
If this is not the case, i.e. if it reads "yes" instead of "no", or the only instance of "PasswordAuthentication" is commented in the file by having its line begin with a hash symbol ("#"), edit the file /etc/ssh/sshd_config so that it contains a line that reads PasswordAuthentication no and then restart the SSH daemon to enact the changes via service ssh stop (Debian) or service sshd stop (RHEL). However, before doing this, ensure that the primary administrative user already has a key pair set up for remote access; you will otherwise be locked out of your server. To do this, the same method that was used for creating a key pair for the web server user can be used to do so for the administrative user.
Notes & References
- ↑ See: Debian Derivatives Census
- ↑ CentOS / RHEL / Scientific Linux 6 Enable (Install) EPEL Repo
- ↑ See: Apache 2.4 Documentation: Access Control
- ↑ Assuming the ubiquitous OpenSSH server is the software in use. All RHEL-based and Debian-based Linux systems, as well as FreeBSD, use OpenSSH as their chosen SSH server, and as of this writing none of the mainstream distributions are known to build OpenSSH such that the path to the daemon's configuration file is any different.