April 16, 2011, 10:32 a.m.
posted by jack
Once you've got Apache up and and it starts running with its default settings, you can begin to tinker. Because Apache is so configurable, it's likely that any two given installations differ greatly. You will learn, through testing and experience, what settings work best for your particular web server's needs. Here are some ideas and tricks that the Internet/Linux Administrators at Rackspace have come to rely on over the years.
Apache allows you to test your configuration file for syntax errors, invalid commands, and other problems. It's always a good idea to do this before restarting the Apache process with a new configuration, rather than bringing up the server with a problem that may cause it to crash. Test the Apache configuration file with the -t flag to httpd:
# httpd -t Syntax error on line 1205 of /etc/httpd/conf/httpd.conf: Invalid command ':wq', perhaps mis-spelled or defined by a module not included in the server configuration
In this example, you can see the :wq command not an Apache command or directive at all, but a common typing mistake from the vi text editor, which "somehow" made its way into the configuration file. (Of course, nobody reading this book has ever made such a mistake, but it never hurts to be aware of the problems that your coworkers may face.)
If you attempt to restart the service with such errors present in the configuration file, the service will refuse to start back up and all of the websites hosted on that Apache installation will go down. As any administrator knows, downtime generates phone calls and phone calls are rarely pleasant. It's so easy to test httpd.conf before bringing up Apache that it should be a regular part of your routine.
Sometimes it is preferable to let nonroot users define their own access control rules for user and host access to their sites. This can be done with the .htaccess file, which allows you to delegate control of specific per-directory access to your users. If this file is used in conjunction with an .htpassword file to contain username and hashed passwords, the website owner can fully control nonsystem username and password access into their own site. This is good for security reasons, as you never want to allow website owners access to real system accounts other than their own.
The following VirtualHost example contains a Directory directive that enables the use of this user-level .htaccess control file:
The allow fromall line can be used to lock access down this Directory level directive to particular IP addresses or ranges. If you are especially concerned about security, this is a useful tool.
In this instance, you will need files named .htaccess (for delegated access control) and .htpasswd (to house nonsystem username/passwords). These files, working together, will create password protection for the /home/bob/html/private-dir/ directory. For this to work, the .htaccess file should be placed in the directory defined in the Directory directive as shown earlier. To enable password protection, you must insert the following directives into the site owner's .htaccess file:
order allow,deny allow from all require valid-user AuthName "My Directory Name" AuthType Basic AuthUserFile /home/bob/web/.htpasswd
Note that the final line of .htaccess points to the .htpasswd file, and that it is in a secure directory that is not accessible from the website's document root. This is an important security setting.
Now you, or the website owner, must create the user/password file /home/bob/web/htpasswd. Do so with the htpasswd command and the -c (create) flag the first time you do this:
$ cd /home/bob/web/ $ htpasswd -c .htpasswd bob New password: <type password once> Re-type new password: <type password again> Adding password for user bob
If you want to add additional users to the file, use htpasswd without the flag:
$ htpasswd .htpasswd mike New password: Re-type new password: Adding password for user mike
Once some users have been added to the file, the contents of .htpasswd will look something like this:
Note each user has his or her own username entry and hashed password.
The .htaccess and .htpasswd files should be set with permissions 755, or rwxr-xr-x. You do this on the example file with the command chmod 755 /home/bob/web/.htpasswd/home/bob/web/html/private-dir/.htaccess.
It is always safer to place the .htpasswd file on the server somewhere outside the virtual host's own web space. Then, if a deviant websurfer gets into the file content of the website, there is no password file in a compromised location. As long as you define .htpasswd's location properly in .htaccess, its location is not an issue to Apache.
By default, Apache does not authenticate against any of the main system authentication files such as /etc/passwd or /etc/shadow. This is good security practice, as access to these files should be limited as much as possible. However, if your system has particular need to authenticate in this way, Apache modules like Radius or LDAP can be configured to work with other forms of centralized and centrally monitored login access.
Earlier, in the Apache Configuration section we mentioned that it is necessary to restart Apache after you make configuration changes. There are two common init script methods of doing this: restart and reload. The difference is that restart is more like a reboot of the Apache daemon itself. The restart command gracefully stops all Apache processes, reloads the configuration file, and restarts the daemon. This can cause up to several seconds of downtime on large websites, so it is not recommended unless absolutely necessary. The reload command, however, merely asks Apache to reparse and reload the Apache daemon, using the new parameters in the configuration file. It is almost always faster than restarting and causes no downtime of the Apache daemon.
The restart command is a more complete method of implementing changes to websites after a configuration file change. However, it takes longer and will create some downtime for sites hosted on that machine, as well as possibly lose client session data. Unless you're changing IP or port bindings, the reload command is probably sufficient and will cause least inconvenience to your users. It will also warn you if there is a typo in the configuration file, such as the :wq that we saw when we tested our httpd.conf file previously.
Here's what the syntax and output of these commands look like on Red Hat and Fedora Core based systems:
# service httpd restart Stopping httpd: [ OK ] Starting httpd: [ OK ]
# service httpd reload Reloading httpd: [ OK ]
For non-Red Hat based systems try /etc/init.d/httpd reload or restart.
Again, if you get a [FAILED] reply and don't get a message to your console, then check the system log file /var/log/messages for an httpd: - related error.
If you run a number of virtual hosts on one machine, you may need to see a complete listing of those hosts on a regular basis. An easy way to get such a vhost listing is to use the -S flag to the httpd daemon.
# httpd -S VirtualHost configuration: 10.1.1.1:* is a NameVirtualHost default server mydomain.com (/etc/httpd/conf/httpd.conf:1057) port * namevhost mydomain.com (/etc/httpd/conf/httpd.conf:1057) port * namevhost example.com.com (/etc/httpd/conf/httpd.conf:1062) wildcard NameVirtualHosts and _default_servers: _default_:443 localhost.localdomain (/etc/httpd/conf.d/ssl.conf:99) Syntax OK
Commands like httpd -S or httpd -t are quite different from other Apache commands, such as /etc/init.d/httpd configtest. With the former, you're actually calling the Apache binary daemon (/usr/sbin/httpd in most cases; the latter simply calls a SysV init script that takes in options like configtest, restart, and reload and then calls the binary on your behalf. Partly the reason for system initialization scripts is to standardize the location, method, and syntax of system startup scripts. However, sometimes you still need to call the daemon binary directly.
If you did not compile the Apache binary yourself, or you need a listing of the compiled-in modules, you can use the httpd binary to list such modules. Do so with the -l flag, as follows:
# httpd -l core.c prefork.c http_core.c mod_so.c
If you need more information, such as the compile time options and settings use the -V flag. With this flag, you'll see more data about the flags used at compilation, along with other relevant and useful information:
# httpd -V Server version: Apache/2.0.47 Server built: Oct 23 2003 06:48:44 Server's Module Magic Number: 20020903:4 Architecture: 32-bit Server compiled with.... -D APACHE_MPM_DIR="server/mpm/prefork" -D APR_HAS_SENDFILE -D APR_HAS_MMAP -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled) -D APR_USE_SYSVSEM_SERIALIZE -D APR_USE_PTHREAD_SERIALIZE -D SINGLE_LISTEN_UNSFRIALIZED_ACCEPT -D APR_HAS_OTHER_CHILD -D AP_HAVE_RELIABLE_PIPED_LOGS -D HTTPD_ROOT="/etc/httpd" -D SUEXEC_BIN="/usr/sbin/suexec" -D DEFAULT_PIDLOG="logs/httpd.pid" -D DEFAULT_SCOREBOARD="logs/apache_runtime_status" -D DEFAULT_LOCKFILE="logs/accept.lock" -D DEFAULT_ERRORLOG="logs/error_log" -D AP_TYPES_CONFIG_FILE="conf/mime.types" -D SERVER_CONFIG_FILE="conf/httpd.conf"
Advanced Apache administrators should be aware of the two options highlighted in the preceding code: the MPM compile time setting (for multiprocessing module support) and the all-important SUEXEC_BIN compile time path. For the MPM setting, also check the output of httpd -l, as it shows that the prefork.c MPM support is compiled in. This is the default behavior on most distributions that include Apache. The suexec binary is the package that allows certain CGI-based systems to run securely. Server Appliance control panels such as Plesk modify this with their own version of suexec.
Two other useful system commands can be used to find the number of current Apache connections and the number of running Apache processes. To get the number of connections, issue this command:
# netstat -an | grep [:]80 | wc -l
To see the number of running Apache processes, issue the following command:
# ps auxw | grep [h]pptd | wc -l
One of the most common mistakes made in defining new virtual hosts involves file system permissions. If you don't set the content directory and file permissions correctly, then Apache can't see the web content stored in that vhost's document root web directory, and thus the content cannot be seen from the web. You'll know you have this problem if you see an error, like the following one, in your browser:
Forbidden You don't have permission to access / on this server. Additionally, a 403 Forbidden error was encountered while trying to use an ErrorDocument to handle the request. Apache/2.0.47 (Fedora) Server at mydomain.com Port 80
If you look at the home directory permissions for the user whose site is having trouble, you can see the reason for this error (shown in the bold italics):
# ls -la /home total 24 drwxr-xr-x 6 root root 4096 Jan 1 16:41 . drwxr-xr-x 21 root root 4096 Jan 1 16:05 .. drwx------ 4 bob bob 4096 Jan 1 16:42 bob drwx------ 4 mike mike 4096 Jan 1 16:42 mike
The user bob's home directory is locked down tight, with permissions of 700 or owner=rwx group= world=. This means that the owner, bob, has full read/write/execute permissions, but people in the group bob have no access to his files, and the rest of the world-including the apache user and group-also have no access. Without access, the files can't be seen by Apache/httpd service, and the error occurs.
There are a few ways to fix this problem. An old school solution and first impulse might be to recursively make the apache group the default group of bob's home directory. Doing so would look like this:
# chgrp apache /home/bob # chgrp -R apache /home/bob/web # chmod 2775 /home/bob/web/html <--"SGID" bit for group dirs
Then, you can relax the group permissions on /home/bob/ a bit so that Apache can get to the web content when it's requested:
# chmod 750 /home/bob
This yields the permissions owner=rwx group=r-x world=, and with the user apache being the group, the Apache/httpd can now see and serve this user's web content.
With these settings in place, the output of ls -la should now look like this:
# ls -la /home/ total 24 drwxr-xr-x 6 root root 4096 Jan 1 16:41 . drwxr-xr-x 21 root root 4096 Jan 1 16:05 .. drwxr-x--- 4 bob apache 4096 Jan 1 16:42 bob drwx------ 4 mike mike 4096 Jan 1 16:42 mike
This is much better, at least from Apache's point of view. Any web content in this directory should now be available. However, this isn't the best solution to the file permissions problem since it involves changing the user bob's reliance upon his User Private Group, which may affect other non-web system functions on Red Hat-based systems.
Changing a user's User Private Group (UPG) violates several best-practice standards on Red Hat- and Fedora Core-based systems. It is advised that you not use the methodology outlined here unless you are running a non-UPG based system (like SuSE) or have first examined the feasibility of other methods (outlined in the following sections). You can tell which system you're using since a stock non-UPG system will usually have its group ownership set to something like "users" instead of the username (for UPG-based systems).
Another option (mainly for non-Red Hat/Fedora Core-based systems) is simply to open up world executable (group= --x or 701) access to bob's directory. Remember, the execute permission on a directory allows users (or web visitors in the case of our example) to only traverse a directory. If you leave world Read access turned off but eXecute turned on, then visitors can't get to files unless they know exactly where they are and what they are called. The layout of bob's home directory remains secret, but Apache can get in to obtain requested files because it knows it needs to serve the content form /home/bob/web/html/. Use chmod to set these directory permissions:
# chmod 701 /home/bob # ls -la /home/bob total 40 drwx-----x 4 bob bob 4096 Jan 1 16:42 . drwxr-xr-x 6 root root 4096 Jan 1 16:41 .. -rw------- 1 bob bob 84 Jan 1 16:44 .bash_history -rw-r--r-- 1 bob bob 24 Jan 1 16:41 .bash_logout -rw-r--r-- 1 bob bob 191 Jan 1 16:41 .bash_profile -rw-r--r-- 1 bob bob 124 Jan 1 16:41 .bashrc -rw-r--r-- 1 bob bob 237 Jan 1 16:41 .emacs -rw-r--r - 1 bob bob 120 Jan 1 16:41 .gtkrc drwxr-xr-x 3 bob bob 4096 Jan 1 16:41 .kde drwxrwxr-x 4 bob bob 4096 Jan 1 16:41 web
Now, the user apache (or any user who knows the directory structure) should be able to get into bob's home directory. However, no user will be able to get a directory listing (read) or modify (write) any files. But since Apache knows that it is going directly to /home/bob/web/html/, it has full read/write access in web, and it can get into the top /home/bob/ directory to reach those directories (which are all already opened up to rwxrwxr-x), there should be no trouble accessing the web content now.
To test this, put a sample index.html file in place and check it. For purposes of speed, you can use the simple text web browser links or lynx (no use firing up a GUI browser for this test):
# echo "This is Bob's Web Site" >/home/bob/web/html/index.html # links --dump http://example.com This is Bob's Web Site
Problem solved-and in a much better way than it could have been by recursively changing all of the user's group and permission settings simply to fix an Apache problem.
One caveat of this approach is that it does create somewhat less secure environment. Such a method is often jokingly referred to as Security Through Obscurity (which implies that such a system is not secure at all, but just well-hidden). This is not something you want to implement if user home directory security is important to you. Instead, look into the next solution, especially if you're running Red Hat-, Fedora Core-, or Debian-based systems.
Red Hat-based distributions use a user ID (UID) and group ID (GID) allocation scheme called User Private Groups (UPG). One of the features of this standardized methodology is that users get their own group with the same name as their username. One nice thing about this system is that you can put users in another user's group, such as putting mike in bob's group. bob can then control what the people in his group can access by adjusting his own home directory and subdirectory permissions. The alternatives to UPG, shown in the preceding sections, are far more messy from an administrative perspective, especially when multiple people want to share the same files.
To implement UPG for our Apache user example, we can simply place the user apache into bob's user private group (instead of changing the group /home/bob/ altogether, or changing permissions to 701). Do this with the following command:
# usermod -G bob apache
After doing this, verify that apache is in the bob group with one of these commands:
# cat /etc/group|grep bob: bob:x:502:mike apache # # groups apache apache : apache bob
Now you can see that the apache user is in bob's group (as is mike). The first method looks for the bob group in the system's group file /etc/group and displays the GID and users in the group bob. The second method, using the groups command, shows to the groups to which the user apache belongs.
Normally, you could use the Red Hat GUI tool redhat-config-users to carry out this change; however, this tool is for real people user accounts only (that is, UIDs starting at 500, like adding mike to bob's group) and is not currently able to allow modification of system accounts (like apache).
Can you see why this is the preferred methodology? Let's look at what this does for us. Here are the old hacked up permissions from the "security through obscurity" method:
# ls -la /home/ total 24 drwxr-xr-x 6 root root 4096 Jan 1 16:41 . drwxr-xr-x 22 root root 4096 Apr 7 20:20 .. drwx-----x 18 bob bob 4096 Mar 18 12:40 bob drwx------ 5 mike mike 4096 Jan 11 14:26 mike
Now try the convenience of UPGs by changing the group permissions of /home/bob/ back to what they should be:
Now no one can even peek or get into bob's home directory without being given explicit permission (by being put in his UPG), creating a much more secure and user-controllable environment. Since the apache user has been added to bob's UPG, bob can serve web content out of his secured home directory as well as allow his group members to get in with read-only access, while keeping his content locked down from all other users. We now have the best security arrangement this side of file system-level ACLs.
To finish this exercise, you may have to restart Apache, and then use links again to test it:
# ls -lad /home/bob/ drwxrwx--- 18 bob bob 4096 Mar 18 12:40 /home/bob/ # /etc/init.d/httpd restart Stopping httpd: [ OK ] Starting httpd: [ OK ] # links --dump http://example.com This is Bob's Web Site
Now you're good to go.