Apache Basic Guide/Cheatsheet
Table of Contents
Updated on 2021-10-07
Setup a Basic Apache server #
Install Apache
:
dnf update; dnf install httpd
Start and enable the service:
systemctl start httpd && systemctl enable httpd
Install firewalld
and open up port 80
:
dnf install firewalld -y
firewall-cmd --permanent --add-service=http
firewall-cmd --reload
Browse to https://localhost
or http://server_IP
. Your Apache Web Server should be up and running.
Note: By default, the Apache Test Page will be presented. Create an
index.html
file with some HTML in/var/www/html/
and reload the page.To prevent the test page from ever being used, follow the instructions in the file
/etc/httpd/conf.d/welcome.conf
.
The structure of /etc/httpd #
The /etc/httpd/
directory contains the following(as of this writing):
[root@centos httpd]# ls -l
total 0
drwxr-xr-x. 2 root root 37 Sep 27 17:14 conf
drwxr-xr-x. 2 root root 82 Sep 27 17:14 conf.d
drwxr-xr-x. 2 root root 226 Sep 27 17:14 conf.modules.d
lrwxrwxrwx. 1 root root 19 Sep 15 19:42 logs -> ../../var/log/httpd
lrwxrwxrwx. 1 root root 29 Sep 15 19:42 modules -> ../../usr/lib64/httpd/modules
lrwxrwxrwx. 1 root root 10 Sep 15 19:42 run -> /run/httpd
lrwxrwxrwx. 1 root root 19 Sep 15 19:42 state -> ../../var/lib/httpd
-
conf - The main configuration file
httpd.conf
-
conf.d - Additional configuration files for the Apache server. Any file that ends with
.conf
will be processed as httpd configuration files. By default, it contains the Test Page configuration, and a configuration template on how to serve a user’s home directory. -
conf.modules.d - Configurations to load a module under an alias or name.
-
logs - The global location for
access
anderror
logs. -
modules - Modules compiled during installation.
-
run - Holds the
PID
of the server, and itsUnix Socket
. -
state - Dynamic/internal data about
httpd
(the daemon).
Main Configuration file #
The main config file is /etc/httpd/conf/httpd.conf
. It contains directives
or default settings to control the server. There’re a certain set of directives
which you may define with different values for multiple Virtual Hosts to override the defaults.
Partial list of the ones mentioned in the config file:
-
ServerRoot - The directory under which the server will contain configuration, error, and log files. The default directory is
/etc/httpd
. -
Listen - The
IP Address
orport
the server will serve its content and listen on. -
IncludeOptional - Includes other configuration files(e.g vhosts or modules) within the
ServerRoot
. -
LoadModule - Load a Dynamic module
-
User/Group - Run Apache under another user or group
-
ServerAdmin - Specify an email address, where problems/error messages should be sent.
-
DocumentRoot - The location where you’ll serve the content of your web sites. The default is
/var/www/html
. -
DirectoryIndex - Specify a file to serve if the root domain or IP is requested
-
ServerName - Name and port of the server in this format:
www.example.com:80
. If you don’t have a DNS name, enter its IP address(a static address is preferable). It’s not enabled by default.
Note: You’ll always get this particular message, during a configuration check “httpd: Could not reliably determine the server’s fully qualified domain name”. Just set the ServerName to
localhost
.
Here’s a list of all the directives.
Directive Context #
A Directive
is only allowed in a context or in a combination of contexts. The list of contexts:
-
server config - directive allowed in the main server configuration file “
httpd.conf
”. -
virtual host - directive allowed inside
<VirtualHost>
. -
directory - directive allowed or valid inside
<Directory>
,<Location>
,<Files>
,<If>
,<Proxy>
. -
.htaccess - directive allowed inside
.htaccess
file.
Examples:
-
Directive - is allowed in bothserver config
, andvirtual host
. -
ServerRoot Directive - is only allowed in
server config
Virtual Host #
Virtual Hosting is a purpose of serving multiple web sites on a single server. There’re two types of virtual hosts:
-
Name-based - Names-based virtual host is a method of hosting multiple web sites on a single IP address.
-
IP-based - With IP-based, the server has a unique IP address for each web site.
Setup a basic Name-based virtual host #
The conventional way to setup a a virtual host, is to place its config inside /etc/httpd/conf.d/
. Some users prefer to mimic the environment of debian/ubuntu by creating folders like site-enabled/available
.
Note: To use a custom directory, SElinux permissions should be adjusted. I won’t be covering that. Maybe in the future.
I prefer to create a folder called vhost.d
, and update the main config file with the following lines to define the new location:
# Load vhosts config files in the "/etc/httpd/vhosts directory"
IncludeOptional /etc/apache/vhost.d/*.conf
Then run httpd -t
or apachectl configtest
to perform to configuration syntax test. Always run either of these commands after you add/update a config file.
Tip Make a copy of any config file before editing, in case you mess things up.
Start by creating a simple vhost config file, and save it as dev_local.conf
:
<VirtualHost *:80>
ServerName dev.local.com
ServerAlias dev.local.com
ServerAdmin admin@local.com
DocumentRoot /var/www/vhost/dev.local.com/html/
ErrorLog /var/www/vhost/dev.local.com/log/error.log
CustomLog /var/www/vhost/dev.local.com/log/access.log combined
</VirtualHost>
The <VirtualHost>
directive takes an IP or Port as argument in this format IP:Port
. Here it’s listening on port 80 on all IP addresses. Create the specified directories and change the owner to apache
:
mkdir -p /var/www/vhost/dev.local.com/{html,log}
chown apache:apache /var/www/vhost/dev.local.com/
Create an index.html
file in the html folder:
echo "<p>TEST</p>" > /var/www/vhost/dev.local.com/html/index.html
Update /etc/hosts
and browse to dev.local.com
.
About SElinux #
If SElinux was enabled and its required permissions were not set, you wouldn’t be able to restart apache. Even apachectl status
or journalctl
doesn’t show the real issue. You can look into /var/httpd/logs/error.log
, but there’s no hint about SElinux.
Here’s an example from /var/httpd/logs/error.log
:
(13)Permission denied: AH00091: httpd: could not open error log file /var/www/vhost/dev.local.com/log/error.log.
To find the right information, look into /var/log/audit/audit.log
and grep for http
(partial list):
type=AVC msg=audit(1601535154.263:97): avc: denied { append } for pid=2381 comm="httpd" name="error.log" dev="dm-0" ino=17316040 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=0
Directory Directive #
The <Directory>
tag controls access to a directory(including all its contents). This allows you to serve or deny contents to specific IP ranges, limit access to files, enable or disable directory listing, and so on.
The syntax is <Directory /directory_path/
. Here’s an example:
<VirtualHost *:80>
ServerName example.com
ServerAlias example.com
ServerAdmin admin@example.com
DocumentRoot /var/www/vhost/example.com/html/
ErrorLog /var/www/vhost/example.com/log/error.log
CustomLog /var/www/vhost/example.com/log/access.log combined
<Directory /var/www/vhost/example.com/>
Options FollowSymlinks
AllowOverride None
</Directory>
<Directory /var/www/vhost/example.com/html/livechat/>
Require ip 192.168.100 10.10.10
</Directory>
<Directory /var/www/vhost/example.com/html/exam/>
Options +Indexes
</Directory>
</VirtualHost>
The Options
directive is used to enable and disable server features. The FollowSymlinks
option allows the webpage to use symbolic links located only in the directory(including subdirectories) specified in the <Directory>
tag.
The AllowOverride
works alongside .htaccess
file. It basically tells the server if whether the Options set in .htaccess
can be overridden by the ones set in <Directory>
. The default is None
, and it’s best to leave it that way.
Require
is used to control user access to a website or webpage.
https://serverfault.com/questions/267583/directory-inside-or-outside-virtualhosts https://www.binasss.sa.cr/manual/vhosts/examples.html
Implement TLS #
To enable HTTPS, you need to install mod_ssl
, and get a certificate from a Certificate Authority. You can create your own with openssl
, and or use a Certificate Authority like Let’s Encrypt. It’s free and open-source.
Self Signed Certificate #
A virtual host with a basic self-signed certificate is very easy to setup. First, install openssl
and mod_ssl
:
dnf install openssl mod_ssl -y
Open port 443:
firewall-cmd --permanent --add-port=443/tcp && firewall-cmd reload
Generate SSL key and certificate with openssl
. You’ll be prompted to enter some information. You can leave everything blank except the common name:
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/pki/tls/private/dev_tls_com.key -out /etc/pki/tls/certs/dev_tls_com.crt
-
req -x509 : Use
x509
certificate signing request(CSR). You can read more about it here. -
-nodes : Don’t encrypt private keys with a passphrase. A passphrase would prevent apache from starting without entering the passphrase.
-
-days 365 : Number of days to consider the certificate valid.
-
-newkey rsa:2048 : Generate a 2048-bits RSA key(public and private keys). You can also use a 4096 bits RSA key.
-
-keyout : Where to place the private key.
-
-out : Where to place the certificate(the certificate contains the public key and relevant information).
Tip: You can make a dedicated directory like
/etc/httpd/conf.d/ssl/domain.com
to store your self-signed certificates.
Create a virtual host that’s listening on port 443:
<VirtualHost *:443>
ServerName dev.tls.com
ServerAlias dev.tls.com
ServerAdmin admin@tls.com
DocumentRoot /var/www/vhost/dev.tls.com/html/
ErrorLog /var/www/vhost/dev.tls.com/log/error.log
CustomLog /var/www/vhost/dev.tls.com/log/access.log combined
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/dev_tls_com.crt
SSLCertificateKeyFile /etc/pki/tls/private/dev_tls_com.key
</VirtualHost>
# redirect request on port 80 to 443
<VirtualHost *:80>
ServerName dev.tls.com
Redirect / https://dev.tls.com/
</VirtualHost>
-
SSLEngine - Enable TLS for this virtual host
-
SSLCertificateFile - Certificate or public key
-
SSLCertificateKeyFile - Private key
-
The additional
<VirtualHost>
- is to listen on port 80 for requests(if any), and redirect all the requests on port 443.
Restart apache and browse to https://dev.tls.com
.
Basic Authentication #
HTTP Basic Authentication is the most simplest way of implementing access control to web contents. It doesn’t require cookies or anything like that. Just use it for internal purposes.
By convention, you would create a file called .htaccess
to configure your login prompt and additional directives. According to the apache documentation:
.htaccess
files should be avoided completely if you have access to the main config file. Using .htaccess will slow down the server. Any directive that you can include in a.htaccess
file is better set in aDirectory
orLocation
block, as it will have the same effect with better performance.
If you use .htaccess
file, you can set the following option: AllowOverride All
(assuming you’re only using .htaccess for authentication and not addtional configurations.). This way, only authenticated users can access certain features, like directory listing.
My configuration file:
<VirtualHost *:443>
ServerName test.com
ServerAlias test.com
ServerAdmin admin@test.com
DocumentRoot /var/www/vhost/test.com/html/
ErrorLog /var/www/vhost/test.com/log/error.log
CustomLog /var/www/vhost/test.com/log/access.log combined
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/test_com.crt
SSLCertificateKeyFile /etc/pki/tls/private/test_com.key
<Directory /var/www/vhost/test.com/html/>
AuthType Basic
AuthName "Restricted"
AuthUserFile /var/www/vhost_htpasswd/.htpasswd_test.com
Require valid-user
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName test.com
Redirect / https://test.com/
</VirtualHost>
Note: For security reason,
.htpasswd
files should be stored in/etc/httpd
or/etc/apache2
. I don’t think there are any official best practices for this, correct me if I am wrong.
Create the htpasswd file(-c
), create an account for user testadmin
, and set the required permissions:
mkdir /var/www/vhost_htpasswd
htpasswd -c /var/www/vhost_htpasswd/.htpasswd_test.com testadmin # prompt for password
chown apache:apache /var/www/vhost_htpasswd/.htpasswd_test.com
chmod 600 !$
Note: You can keep
.htpasswd
in your website’s document root.
Restart apache, and browse to test.com
.
With Location #
The <Location>
directive only works for URLs. The following configuration will prompt for a pair of credentials to gain access to domain.com/server-status
, and is only available for the specified IP range.
<Location /server-status>
SetHandler server-status # from mod_status
Require ip 192.168.100.0/24
AuthType Basic
AuthName "Restricted"
AuthUserFile /var/www/domain.com/.htpasswd
Require valid-user
</Location>
LAMP Stack #
The LAMP stack consists of:
Linux
- the OSApache
- the http ServerMariaDB
- the database to store backend data- and
PHP
- for dynamic processing
Install MariaDB #
dnf install mariadb-server -y
Start and enable the service:
systemctl start mariadb ; systemctl enable mariadb
Run the secure installation script:
mysql_secure_installation
Install PHP and its MySQL module: #
dnf install php php-mysqlnd -y
Restart apache
:
systemctl restart httpd
Test PHP #
Create a file called test.php
in your main or vhost document root:
<? php
phpinfo();
?>
Browse to YOUR_DOMAIN/test.php
Test MariaDB #
Log into mariadb
(if you didn’t set a password just run mysql
):
mysql -u root -p
Create a new database called phptest:
CREATE DATABASE phptest;
Create a new user with full privileges to the newly create database:
GRANT ALL ON test.* TO 'sqltest'@'localhost' IDENTIFIED BY 'sqltest' WITH GRANT OPTION;
Both Username and Password are set to “sqltest”. The user won’t be able to create or modify other databases.
Save the changes and exit:
FLUSH PRIVILEGES;
exit;
Log in as the new user:
mysql -u sqltest -p
Use the phptest
database and create a new table:
USE test;
CREATE TABLE test_list(id INT AUTO_INCREMENT, whisky VARCHAR(255), PRIMARY KEY(id));
Insert some data:
INSERT INTO test_list (whisky) VALUES ("Jack Daniel's Old No.7");
INSERT INTO test_list (whisky) VALUES ("Monkey Shoulder Blended Malt Scotch");
Confirm the data:
SELECT * FROM test_list;
Exit, and create the following index.php
in your document root:
<?php
$link = mysqli_connect("127.0.0.1", "sqltest", "sqltest", "phptest"); // host, username, passwd, db
if (!$link) {
echo "Error: Unable to connect to MySQL." . PHP_EOL;
echo "Debugging errno: " . mysqli_connect_errno() . PHP_EOL;
echo "Debugging error: " . mysqli_connect_error() . PHP_EOL;
exit;
}
echo "Success: A proper connection to MySQL was made! The database is great." . PHP_EOL;
echo "Host information: " . mysqli_get_host_info($link) . PHP_EOL;
mysqli_close($link);
?>
The script was found here. Browse to YOURDOMAIN/index.php
:
Success: A proper connection to MySQL was made! The database is great. Host information: 127.0.0.1 via TCP/IP
Require directive Cheatsheet #
https://apacheadmin.com/require/
Debian Based #
Installation #
apt install apache2
Configuration Files #
kavish@ubuntu-local:/etc/apache2$ ls -l
total 80
-rw-r--r-- 1 root root 7244 Mar 23 07:10 apache2.conf
drwxr-xr-x 2 root root 4096 Mar 24 08:11 conf-available
drwxr-xr-x 2 root root 4096 Mar 24 08:11 conf-enabled
-rw-r--r-- 1 root root 1782 Apr 13 2020 envvars
-rw-r--r-- 1 root root 31063 Apr 13 2020 magic
drwxr-xr-x 2 root root 12288 Mar 23 07:08 mods-available
drwxr-xr-x 2 root root 4096 Mar 23 07:08 mods-enabled
-rw-r--r-- 1 root root 320 Apr 13 2020 ports.conf
drwxr-xr-x 2 root root 4096 Mar 23 07:08 sites-available
drwxr-xr-x 2 root root 4096 Mar 23 07:08 sites-enabled
- apache2.conf - Main configuration file.
- conf-available - Contains configuration files not associated with virtual hosts.
- conf-enabled - When Configuration files from
conf-available
are enabled, they will be symlinked here. - envvars - Environment variables for the internal Apache structure. Not the ones found on a Linux system.
- magic - A text file that contains instruction for determining MIME type of a file, or simply a file type like, jpeg, mpeg, and so on.
- mods-available - Contains configuration files for available modules.
- mods-enabled - When modules from
mods-available
are enabled, they will be symlinked here. - ports.conf - Determine the ports Apache2 is listening on. For both HTTP and HTTPS.
- sites-available - Contains Virtual Hosts Configurations.
- sites-enabled - When Virtual Hosts from
conf-available
are enabled, they will be symlinked here.
Additional Commands #
kavish@ubuntu-local:/usr/sbin$ ls a2*
a2disconf a2dismod a2dissite a2enconf a2enmod a2ensite a2query
- a2disconf - Disable configuration files in
conf-enabled
. - a2dismod - Disable modules in
mods-enabled
- a2dissite - Disable virtual hosts in
sites-enabled
- a2enconf - Enable configuration files from
conf-available
by creating a symlink inconf-enabled
. - a2enmod - Enable modules
- a2ensite - Enable virtual hosts
- a2query - Get information about available modules, if sites are enabled, and so on.
VirtualHost Configuration #
If you don’t remember all the syntax required to create a vhost configuration, you can copy the default template, edit it according to your needs:
$ cd /etc/apache2/sites-available/
$ cp 000-default.conf test.com.conf
Remove all the comments from the file:
sed -i '/^[[:blank:]]*#/d;s/#.*//' test.com.conf
My virtual host file looks like this:
<VirtualHost *:80>
ServerAdmin admin@localhost
ServerName test.com
ServerAlias www.test.com
DocumentRoot /var/www/vhosts/test.com
ErrorLog ${APACHE_LOG_DIR}/test.com_error.log
CustomLog ${APACHE_LOG_DIR}/test.com_access.log combined
</VirtualHost>
Create the DocumentRoot
, and give it the required permissions:
$ mkdir vhosts
$ chown www-data:www-data vhosts/
$ mkdir test.com
Create an index.html
file in the DocumentRoot
:
<h1>test.com is up and running</h1>
Enable the vhost, disable the default test page, and restart apache2:
$ a2ensite test.com.conf
$ a2dissite 000-default.conf
$ systemctl reload apache2
Edit /etc/host
, and browse to the site:
kavish@ubuntu-local:~$ curl test.com
<h1>
test.com is up and running
</h1>
Disable Apache Signature and Banner #
ServerSignature Off
ServerTokens Prod
Disable Directory Indexing #
<Directory /var/www/html>
Options -Indexes
</Directory>
Turn on directory browsing #
<Location /images>
Options +Indexes
</Location>
Restrict access to “root” Directory #
<Directory />
Options None
AllowOverrride None
Order allow,deny
Allow from all
</Directory>
Custom 404 Error message #
ErrorDocument 404 /404.html
Only allow access from a specific IP #
Order Deny,Allow
Deny from all
Allow from 127.0.0.1
Only allow access for a subnet #
Order Deny,Allow
Deny from all
Allow from 176.16.0.0/16
ModSecurity #
https://www.youtube.com/watch?v=MB7nQrlP5Yc
https://www.atlantic.net/vps-hosting/securing-your-apache-web-server-with-mod-security/
https://www.linuxbabe.com/security/modsecurity-apache-debian-ubuntu
Benchmark - Load Test with ab #
http://httpd.apache.org/docs/current/programs/ab.html
With Vegeta #
https://github.com/tsenart/vegeta
Check HTTPD resource limits #
https://code.google.com/archive/p/check-httpd-limits/wikis/Documentation.wiki
Common Errors #
https://www.digitalocean.com/community/tutorial_series/common-apache-errors