Apache
References
- Apache Documentation (a bit fuzzy...)
- Apache HTTP Server Wiki (much clearer but incomplete)
Parsing configuration sections
See Official Apache documentation - sections for details.
- Difference between
and
[1]
Directory
directive works only for filesystem objects (e.g. /var/www/mypage, C:\www\mypage),- while
Location
directive works only for URLs.
- So
Location
overridesFiles
, - which overrides
DirectoryMatch
, with paths matchingDirectory
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 [4]):
Stop! Don't use htaccess files for mod_rewrite unless you have no other choice. Doing so is slow and confusing.
- 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.
- 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.
- 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.
- If none of the above steps help, try a very simple rewrite to check if the module is enabled. For example:
DocumentRoot /var/www
<Directory />
Options FollowSymLinks
AllowOverride FileInfo # Must *NOT* be ''none''
</Directory>
RewriteEngine On
# Redirect all requests to example.com
RewriteRule ^ http://example.com/
Rewrite Rules
- References: [5], [6]
- 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 [7] 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 [8], 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 [9]:
--- 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 [10]. 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 [11], [12].
- 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 [13], 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 [14]:
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 [15]:
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