Reputation: 109
I've been sitting with this a long time now and can't get my head around it.
Essentially, the functionality I'm looking for in the end would be similar to the following:
http://example.com
redirects to https://example.com
- currently working
and for
http://*.example.com
and https://*.example.com
to redirect to https://example.com/*
- Not working. Currently, all subdomains get redirected to the main-domain, without their respective folder path. Also, when going to https://test.example.com
, it doesn't redirect at all.
Here's the example.com.conf
from sites-enabled
:
<IfModule mod_ssl.c>
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
# Redirect permanent / https://example.com/
<Directory /var/www/example.com/public_html>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<IfModule mod_rewrite.c>
# Redirect all traffic to HTTPS
RewriteCond %{HTTPS} !on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [QSA,R=301,L]
</IfModule>
</VirtualHost>
<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
<Directory /var/www/example.com/public_html>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>
<IfModule mod_rewrite.c>
# Remove www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ http://%1%{REQUEST_URI} [QSA,R=301,L]
RewriteCond %{HTTP_HOST} !^(www)\. [NC]
RewriteCond %{HTTP_HOST} ^(.*)\.example\.com [NC]
RewriteRule ^(.*)$ https://example.com/%1/$1 [R=301,L]
</IfModule>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/ssl/civrpssl/example.com.crt
SSLCertificateKeyFile /etc/ssl/civrpssl/example.com.key
SSLCACertificateFile /etc/ssl/civrpssl/ca-example.com.crt
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
</VirtualHost>
</IfModule>
And finally, here's the .htaccess
from example.com/public_html/
:
removed, see edit #2.
I'm hoping it's a rather obvious issue that I've failed to see. Otherwise, please could someone enlighten me where I should start looking for the issue? I'm assuming that the HTTPS redirect interferes with the subdomain redirect in the .htaccess file but don't know how I could put it any differently.
EDIT #1: I just noticed that www.example.com
throws error "URL not found" rather than re-directing to https://example.com
. How comes it isn't caught by the first rewrite in .htaccess
?
EDIT #2:
.htaccess
to example.com.conf
(code updated in post).http://test.example.com
would only lead to https://example.com
.a2enmod rewrite
, since apparently it wasn't enabled.Upvotes: 2
Views: 927
Reputation: 45829
ServerName example.com ServerAlias www.example.com
Neither of the <VirtualHost>
containers accept requests for any subdomains, except for www
. The vHost may still catch additional subdomains (in fact, any hostname) if it is the first defined vHost in the server config. To catch "any" subdomain, you would need another "wildcard" ServerAlias
of the form:
ServerAlias *.example.com
Remove the <IfModule mod_rewrite.c>
wrappers - they are not required. They will only mask the error if mod_rewrite is not available. The <IfModule>
wrapper should only be used if these directives are entirely optional and the config is to be ported to other systems where mod_rewrite is not available.
UPDATE: You were also missing the RewriteEngine On
directive in the vHost. Unless the rewrite engine was already enabled elsewhere in the server config (unlikely) then these mod_rewrite directives would simply be skipped altogether.
In HTTP vHost (port 80)...
# Redirect all traffic to HTTPS RewriteCond %{HTTPS} !on RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [QSA,R=301,L]
There's no point checking HTTPS
in the vHost for port 80 as it will always be off
. If you want to redirect directly from the subdomain to the subdirectory, you would need to change the above to read:
# Redirect HTTP subdomains to HTTPS subdirectory (excluding www)
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com [NC]
RewriteRule ^/(.*) https://example.com/%1/$1 [R=301,L]
# Redirect HTTP to HTTPS
RewriteRule ^/(.*) https://example.com/$1 [R=301,L]
However, if you have any intention to implement HSTS in the future then you will need to redirect to HTTPS on the same host first and issue a second redirect to the subdirectory in the vHost for port 443 only. (Redirect from HTTP to HTTPS using the Redirect
directive - currently commented out - although this would require a separate (minimal) vHost for each subdomain, which may not be desirable.)
^/(.*)
- Note the addition of a slash prefix outside of the capturing subpattern in the RewriteRule
pattern. In a virtualhost context, the full URL-path is matched by the RewriteRule
pattern. The trailing $
is not required since regex is greedy by default.
Note also the regex ([^.]+)
(instead of (.*)
) that specifically matches a subdomain only (no dots).
In your vHost for HTTPS (port 443) you have:
# Remove www RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] RewriteRule ^(.*)$ http://%1%{REQUEST_URI} [QSA,R=301,L]
You are redirecting back to HTTP (although this seems to be a bug you have introduced after your edit?).
No need to capture the RewriteRule
pattern if you are using the REQUEST_URI
variable.
Then the same edit applies to the subdomain to subdirectory redirect as mentioned above.
Bringing the above points together we have something like:
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
ServerAlias *.example.com
#Redirect permanent / https://example.com/
RewriteEngine On
# Redirect HTTP subdomains to HTTPS subdirectory (excluding www)
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com [NC]
RewriteRule ^/(.*) https://example.com/%1/$1 [R=301,L]
# Redirect HTTP to HTTPS (www and domain apex)
RewriteRule ^/(.*) https://example.com/$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerAdmin webmaster@localhost
ServerName example.com
ServerAlias www.example.com
ServerAlias *.example.com
DocumentRoot /var/www/example.com/public_html
<Directory /var/www/example.com/public_html>
Options FollowSymLinks
# Set "AllowOverride None" to disable .htaccess altogether
AllowOverride All
Require all granted
</Directory>
RewriteEngine On
# Remove www
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [QSA,R=301,L]
# Redirect other subdomains to subdirectory
RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com [NC]
RewriteRule ^/(.*) https://example.com/%1/$1 [R=301,L]
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
SSLEngine on
SSLCertificateFile /etc/ssl/civrpssl/example.com.crt
SSLCertificateKeyFile /etc/ssl/civrpssl/example.com.key
SSLCACertificateFile /etc/ssl/civrpssl/ca-example.com.crt
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
</VirtualHost>
You should first test with 302 (temporary) redirects to avoid potential caching issues.
And clear your browser cache before testing (any erroneous 301s will have been cached by the browser).
Upvotes: 1