Apache

From miki
Jump to navigation Jump to search

References

How-to

Restart, reload, check configuration

service apache2 reload   # reload apache configuration
service apache2 restart  # restart apache

On Debian, with systemd:

apachectl configtest                # Check apache configuration
systemctl restart apache2.service   # Restart apache
systemctl start apache2.service     # Start apache
systemctl stop apache2.service      # Stop apache

Add new modules

a2enmod   ssl           # Enable SSL module (for https:// support)
a2enmod   rewrite       # Enable rewrite module (for URL rewrite)
a2enmod   include       # Enable include module (for server side include)

Create and enable new (virtual) hosts

Ideally, create your new (virtual) host as a .conf file in /etc/apache2/sites-available. For instance:

vi /etc/apache2/sites-available/www.myhost.org.conf

Example of host file:

<IfModule mod_ssl.c>
    <VirtualHost *:443>
        ServerAdmin webmaster@localhost
        ServerName www.immie.org
        DocumentRoot /var/www/html

        <Location />
            AuthType Basic
            AuthName "www.immie.org"
            AuthUserFile /etc/apache2/www.immie.org.ssl.passwd
            Require valid-user
        </Location>

        SSLEngine on
        SSLCertificateFile	/etc/ssl/certs/ssl-cert-www.immie.org.pem
        SSLCertificateKeyFile /etc/ssl/private/ssl-cert-www.immie.org.key
    </VirtualHost>
</IfModule>

Now enable the virtual host and reload apache configuration:

a2ensite www.myhost.org
service apache2 reload

Using multiple ssl certificates with one IP address

This only works with browser that support the TLS extension Server Name Indication (SNI) [1].

To have several server names on same IP address, each with their own certificate:

# NameVirtualHost *:443                    # This directive is deprecated

# This is the configuration when going to https://www.yoursite.com
<VirtualHost *:443>
    ServerName www.yoursite.com
    DocumentRoot /var/www/site
    SSLEngine on
    SSLCertificateFile /path/to/www_yoursite_com.crt
    SSLCertificateKeyFile /path/to/www_yoursite_com.key
    SSLCertificateChainFile /path/to/DigiCertCA.crt
</VirtualHost>

# This is the configuration when going to https://www.yoursite2.com
<VirtualHost *:443>
    ServerName www.yoursite2.com
    DocumentRoot /var/www/site2
    SSLEngine on
    SSLCertificateFile /path/to/www_yoursite2_com.crt
    SSLCertificateKeyFile /path/to/www_yoursite2_com.key
    SSLCertificateChainFile /path/to/DigiCertCA.crt
</VirtualHost>

To have several server names on same IP address but with the same certificate. All servers must refer to the same IP address in the VirtualHost IP address section.

# This is the configuration when going to https://www.domain.com
<VirtualHost 192.168.1.1:443>              # All configuration must refer to same IP address
    ServerName www.domain.com
    DocumentRoot /var/www/
    SSLEngine on
    SSLCertificateFile /path/to/your_domain_name.crt
    SSLCertificateKeyFile /path/to/your_private.key
    SSLCertificateChainFile /path/to/DigiCertCA.crt
</VirtualHost>

# This is the configuration when going to https://site2.domain.com
<VirtualHost 192.168.1.1:443>              # All configuration must refer to same IP address
    ServerName site2.domain.com
    DocumentRoot /var/www/site2
    SSLEngine on
    SSLCertificateFile /path/to/your_domain_name.crt
    SSLCertificateKeyFile /path/to/your_private.key
    SSLCertificateChainFile /path/to/DigiCertCA.crt
</VirtualHost>

Parsing configuration sections

See Official Apache documentation - sections for details.

Difference between and [2]
  • Directory directive works only for filesystem objects (e.g. /var/www/mypage, C:\www\mypage),
  • while Location directive works only for URLs.
Order of matching [3], [4]
  • So Location overrides Files,
  • which overrides DirectoryMatch, with paths matching Directory at the lowest priority.
  • The last one wins for conflicting directives.
... except for ProxyPass, which appears to work in the other direction.

Enabling .htaccess files

In case the .htaccess files are ignored (see [5]):

Stop! Don't use htaccess files for mod_rewrite unless you have no other choice. Doing so is slow and confusing.

  1. Put a nonsense line (such as Wooga) in your htaccess file and try the request again. If you don't see a 500 Internal Server Error message, your htaccess file is being ignored altogether. The solution is to set both AllowOverride FileInfo and Options FollowSymlinks in httpd.conf (on Ubuntu, check apache2/sites-enabled/000-default, or add your own config file in apache2/conf.d) for the directory in question.
  2. DocumentRoot /var/www
    <Directory />
        Options FollowSymLinks
        AllowOverride FileInfo          # Must *NOT* be ''none''
    </Directory>
    
  3. If you think your rules look ok but you still see a 500 Internal Server Error message, make sure mod_rewrite is loaded in the server.
  4. If you have ensured that mod_rewrite is loaded, and that RewriteRule is enabled for htaccess files, it could be that your rules are looping.
  5. If none of the above steps help, try a very simple rewrite to check if the module is enabled. For example:
  6. RewriteEngine On
    # Redirect all requests to example.com
    RewriteRule ^ http://example.com/
    

Rewrite Rules

  • References: [6], [7]
  • Rewrite rules are either defined in virtual host configuration (i.e. httpd.conf or similar) or in the .htaccess file, per directory (but this is discouraged — I don't know why exactly, slower...}}

Enable Rewrite module

Simply type:

a2enmod rewrite
service apache2 restart

Why they can't simply say so in apache doc is just a mistery.

Frequent errors

  • Make sure that all files in your /var/www (or any other relevant directory) are owned by www:www-data (if not, rule conditions like RewriteCond %{REQUEST_FILENAME} -f may fail!)
sudo chown -R www:www-data /var/www
  • If you changed apache config, make sure that you restarted the server
sudo /etc/init.d/apache2 restart
  • If you use mod_rewrite in .htaccess files, make sure that these files are indeed read by Apache (see section above).
  • Enable rewrite log to ease debugging. Add a file /etc/apache2/conf.d/rewritelog.conf:
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 8                              # Max 9

Some example of rewrite rules

See [8] for more examples, and what-not.

Basic .htaccess template

Basic template for a .htaccess file:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.php [L]
</IfModule>

Rewrite URL for missing resource

From [9], rewrite URL for missing resource.

# For each web request (file or directory) that doesn't start with /en-US/, 
# serve up the original resource if it exists, otherwise serve up the /en-US/ version.
RewriteCond $0 !^en-US/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .+ en-US/$0 [L]

Rewrite URL for missing resources (advanced)

# Try to replace query for non-existing images to white/black images
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -f       # true if file exists
RewriteRule (.*) - [L]                   # Applied if condition above is true, [L] means LAST rule

# 10-0- up to 10-511-
RewriteCond %{REQUEST_URI} /10-[0-9]+-([0-9]|[1-9][0-9]|[1-4][0-9][0-9]|50[0-9]|51[0-1])\.png
RewriteRule (.*) white.png [L]

# 9-0- up to 9-255-
RewriteCond %{REQUEST_URI} /9-[0-9]+-([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.png
RewriteRule (.*) white.png [L]

# 8-0- up to 8-127-
RewriteCond %{REQUEST_URI} /8-[0-9]+-([0-9]|[1-9][0-9]|1[01][0-9]|12[0-7])\.png
RewriteRule (.*) white.png [L]

# 7-0- up to 7-63-
RewriteCond %{REQUEST_URI} /7-[0-9]+-([0-9]|[0-5][0-9]|6[0123])\.png
RewriteRule (.*) white.png [L]

# 6-0- up to 6-31-
RewriteCond %{REQUEST_URI} /6-[0-9]+-([0-9]|[0-2][0-9]|3[01])\.png
RewriteRule (.*) white.png [L]

# 5-0- up to 5-15-
RewriteCond %{REQUEST_URI} /5-[0-9]+-([0-9]|1[0-5])\.png
RewriteRule (.*) white.png [L]

# 4-0- up to 4-7-
RewriteCond %{REQUEST_URI} /4-[0-9]+-([0-7])\.png
RewriteRule (.*) white.png [L]

# 3-0- up to 3-3-
RewriteCond %{REQUEST_URI} /3-[0-9]+-([0-3])\.png
RewriteRule (.*) white.png [L]

# 2-0- up to 2-1-
RewriteCond %{REQUEST_URI} /2-[0-9]+-([0-1])\.png
RewriteRule (.*) white.png [L]

# 1-0- up to 1-1-
RewriteCond %{REQUEST_URI} /1-[0-9]+-0\.png
RewriteRule (.*) white.png [L]

RewriteRule (.*) black.png [L]

Include module

The include module enables server side includes (SSI). To enable the module:

sudo a2enmod include
sudo service apache2 restart

Then edit the site configuration to enable SSI [10]:

--- a/apache2/sites-available/default-ssl.conf
+++ b/apache2/sites-available/default-ssl.conf
@@ -17,6 +17,8 @@
     </Location>
     <Directory /var/www/>
         Options Indexes FollowSymLinks MultiViews
+        Options +Includes
+        XBitHack Full
         AllowOverride FileInfo
         Order allow,deny
         allow from all

Editing .htaccess in local directory is also possible but must be enabled. See Apache website for more detailed information.


Tags

DirectoryIndex

  • Use DirectoryIndex to change list of default name of index file while browsing directory
DirectoryIndex index.php index.html         # Will serve php version first
DirectoryIndex mycustomindex.html           # To point to specific file when browsing directory (no directory listing)

SSL and HTTPS

Install

From [11]. Assumptions:

  • Already a website present at /var/www
  • Package ssl-cert installed (that create snakeoil (i.e. self-signed) certificates in /etc/ssl)
# Load and enable SSL module
sudo a2enmod ssl
sudo /etc/init.d/apache2 force-reload

# Edit file
sudo vim /etc/apache2/sites-available/default-ssl
# ... and change lines as follows (for key/cert we use the snakeoil ones):
#  SSLEngine on
#  SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire

#Enable the default SSL site:
sudo a2ensite default-ssl

# Tell Apache to reload its configuration:
sudo /etc/init.d/apache2 reload     # or sudo service apache2 reload


To also add user authentication, add the following lines to either

  • File .htaccess in website directory
  • Section <Location /> in /etc/apache2/sites-available/default-ssl:
Do not use a Directory tag, it does not work [12], [13].
Also, make suure that password file is not in the html subtree (i.e. can't be downloaded by clients).
<Location "/">
  AuthType Basic
  AuthName "default"
  AuthUserFile /var/www/etc/filename.ssl.passwd
  Require valid-user
</Location>

Then create the password file with the command htpasswd

htpasswd -c -s /var/www/etc/filename.ssl.passwd username          # set password, using SHA-1
sudo chown www-data:www-data /var/www/etc/filename.ssl.passwd     # set permission (or get 500 - Internal server error)

Finally, reload apache2:

sudo /etc/init.d/apache2 reload

In case of problem, check log file /var/log/apache2/error.log.

Parse and generate new self-signed certificates

References:

  • Generate the certificate [14], and change permission
sudo openssl req -x509 -nodes -days 3652 -newkey rsa:2048 -keyout ssl-cert-myserver.key -out ssl-cert-myserver.pem
sudo chown root:ssl-cert ssl-cert-myserver.key
sudo chmod 640 ssl-cert-myserver.key
sudo mv ssl-cert-myserver.key /etc/ssl/private
sudo mv ssl-cert-myserver.pem /etc/ssl/certs
  • Edit SSL config for Apache (typically file /etc/apache2/sites-available/default-ssl.conf):
<VirtualHost _default_:443>
DocumentRoot /var/www/website
ServerName www.yourdomain.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/ssl-cert-myserver.pem
SSLCertificateKeyFile /etc/ssl/private/ssl-cert-myserver.key
</VirtualHost>
  • Restart Apache:
sudo service apache2 restart           # OR   /usr/local/apache/bin/apachectl restart


The server private key is located at /etc/ssl/private/ssl-cert-snakeoil.key and the self-signed certificate at /etc/ssl/certs/ssl-cert-snakeoil.key.

To parse the current private key:

sudo openssl rsa -noout -text -in /etc/ssl/private/ssl-cert-snakeoil.key      # Show coefficient of private key
sudo openssl rsa -noout -modulus -in /etc/ssl/private/ssl-cert-snakeoil.key   # Show private key modulus

To parse the current self-signed certificate:

openssl asn1parse -in /etc/ssl/certs/ssl-cert-snakeoil.pem                    # Show certificate fields

This produces for instance:

 openssl asn1parse -in /etc/ssl/certs/ssl-cert-snakeoil.pem
    0:d=0  hl=4 l= 698 cons: SEQUENCE          
    4:d=1  hl=4 l= 418 cons: SEQUENCE          
    8:d=2  hl=2 l=   3 cons: cont [ 0 ]        
   10:d=3  hl=2 l=   1 prim: INTEGER           :02
   13:d=2  hl=2 l=   9 prim: INTEGER           :C5E28AFC1DC8799C
   24:d=2  hl=2 l=  13 cons: SEQUENCE          
   26:d=3  hl=2 l=   9 prim: OBJECT            :sha256WithRSAEncryption
   37:d=3  hl=2 l=   0 prim: NULL              
   39:d=2  hl=2 l=  21 cons: SEQUENCE          
   41:d=3  hl=2 l=  19 cons: SET               
   43:d=4  hl=2 l=  17 cons: SEQUENCE          
   45:d=5  hl=2 l=   3 prim: OBJECT            :commonName
   50:d=5  hl=2 l=  10 prim: PRINTABLESTRING   :zavcxv0035
   62:d=2  hl=2 l=  30 cons: SEQUENCE          
   64:d=3  hl=2 l=  13 prim: UTCTIME           :150605232158Z
   79:d=3  hl=2 l=  13 prim: UTCTIME           :250602232158Z
   94:d=2  hl=2 l=  21 cons: SEQUENCE          
   96:d=3  hl=2 l=  19 cons: SET               
   98:d=4  hl=2 l=  17 cons: SEQUENCE          
  100:d=5  hl=2 l=   3 prim: OBJECT            :commonName
  105:d=5  hl=2 l=  10 prim: PRINTABLESTRING   :zavcxv0035
  117:d=2  hl=4 l= 290 cons: SEQUENCE          
  121:d=3  hl=2 l=  13 cons: SEQUENCE          
  123:d=4  hl=2 l=   9 prim: OBJECT            :rsaEncryption
  134:d=4  hl=2 l=   0 prim: NULL              
  136:d=3  hl=4 l= 271 prim: BIT STRING        
  411:d=2  hl=2 l=  13 cons: cont [ 3 ]        
  413:d=3  hl=2 l=  11 cons: SEQUENCE          
  415:d=4  hl=2 l=   9 cons: SEQUENCE          
  417:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Basic Constraints
  422:d=5  hl=2 l=   2 prim: OCTET STRING      [HEX DUMP]:3000
  426:d=1  hl=2 l=  13 cons: SEQUENCE          
  428:d=2  hl=2 l=   9 prim: OBJECT            :sha256WithRSAEncryption
  439:d=2  hl=2 l=   0 prim: NULL              
  441:d=1  hl=4 l= 257 prim: BIT STRING
  • The field UTCTIME is coded as YYMMDDHHmmssZ.


To generate a new key and certificate:

openssl req -x509 -nodes -days 3652 -newkey rsa:2048 -keyout ssl-cert-$HOSTNAME.key -out ssl-cert-$HOSTNAME.pem

Typically you can leave all request fields, except the Common Name which should be set to some name, or server FQDN:

Generating a 2048 bit RSA private key
..............................................................+++
..................................+++
unable to write 'random state'
writing new private key to 'ssl-cert-zavcxl0005.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:.
State or Province Name (full name) [Some-State]:.
Locality Name (eg, city) []:.
Organization Name (eg, company) [Internet Widgits Pty Ltd]:.
Organizational Unit Name (eg, section) []:.
Common Name (e.g. server FQDN or YOUR name) []:zavcxl0005.zav.st.com
Email Address []:.

Then install the key and certificate and update /etc/apache2/default-ssl.conf:

sudo mv ssl-cert-$HOSTNAME.pem /etc/ssl/certs
sudo chmod 640 ssl-cert-$HOSTNAME.key
sudo chown root:ssl-cert ssl-cert-$HOSTNAME.key
sudo mv ssl-cert-$HOSTNAME.key /etc/ssl/private

Edit /etc/apache2/sites-available/default-ssl.conf (replacing myhostname as necessary):

-    SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
-    SSLCertificateKeyFile /etc/ssl/private/ssl-cert-myhostname.key
+    SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
+    SSLCertificateKeyFile /etc/ssl/private/ssl-cert-myhostname.key

Generate a new Certificate Authority (CA) and new server SSL certificate

We use script CA.pl from openssl to create a custom CA and generate a new server SSL certificate. By installing the new CA certificate in their browser, users will not get the annoying message about untrusted certificate.

cd /root/etc
cp /usr/lib/ssl/misc/CA.pl .

# Enforce 3650 days validity (10 years)
sed -ri 's/365/3650/; s/1095/3650/' CA.pl

# Create the CA key in demoCA/
./CA.pl -newca                                  # Write down CA key password
/usr/lib/ssl/misc/c_info demoCA/cacert.pem 
openssl x509 -text -fingerprint -sha1 -in demoCA/cacert.pem -out demoCA/cacert.wiki.protonworld.com.crt

# Create the server private key + signing request
./CA.pl -newreq-nodes

# Generate the server certificate
./CA.pl -sign                                   # Requires CA key password

# Install the server certificates
mv newcert.pem /etc/ssl/certs/ssl-cert-wiki.protonworld.com.pem
mv newkey.pem /etc/ssl/private/ssl-cert-wiki.protonworld.com.key
service apache2 restart

Now, users must install the CA certificate /root/etc/demoCA/cacert.wiki.protonworld.com.crt into their browser trusted CA. For internet explorer,

  • Double click on certificate file.
  • Click Install Certificate..., then Next.
  • Select Place all certificates in the following store, and click Browse....
  • Select Trusted Root Certification Authorities, and click OK.
  • Click Next and Finish. The popup window will report a thumbprint. Check the reference value and click Yes if identical.

Tips

Redirecting HTTP to HTTPS
Edit the configuration file as follows [15]:
NameVirtualHost *:80
<VirtualHost *:80>
   ServerName mysite.example.com
   DocumentRoot /usr/local/apache2/htdocs 
   Redirect permanent / https://mysite.example.com/
</VirtualHost>

<VirtualHost _default_:443>
   ServerName mysite.example.com
  DocumentRoot /usr/local/apache2/htdocs
  SSLEngine On
 # etc...
</VirtualHost>
Then restart apache:
sudo service apache2 restart

Another solution is a rewrite rule in httpd.conf [16]:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

Troubleshooting

Invalid command 'ProxyRequests'
Invalid command 'ProxyRequests', perhaps misspelled or defined by a module not included in the server configuration
Solution is to enable module proxy:
sudo a2enmod proxy
sudo service apache2 restart
Invalid command 'RequestHeader'
Invalid command 'RequestHeader', perhaps misspelled or defined by a module not included in the server configuration
Solution is to enable module headers:
sudo a2enmod headers
sudo service apache2 restart
No protocol handler was valid for the URL /...
[proxy:warn] ... No protocol handler was valid for the URL /SOGo. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule
Solution is to enable module proxy_http:
a2enmod proxy_http
a2enmod proxy
sudo service apache2 restart