On a centos 7 machine, I'd like to run a python server alongside an apache server. I figured the easiest way would be to configure apache as a reverse proxy. This is my VirtualHost configuration:
<VirtualHost *:443>
DocumentRoot /home/username/mydomain/src
ServerName mydomain.com
ErrorLog logs/mydomain-error_log
CustomLog logs/mydomain-access_log common
DirectoryIndex index.php
<Directory /home/username/mydomain/src>
Options -Indexes FollowSymLinks
AllowOverride None
Require all granted
AddOutputFilterByType DEFLATE text/html text/plain text/xml
</Directory>
ProxyPreserveHost On
ProxyPass /mediaproxy http://127.0.0.1:9001/mediaproxy
ProxyPassReverse /mediaproxy http://127.0.0.1:9001/mediaproxy
LogLevel alert rewrite:trace6
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/api/media/(.*) /data/$1 [L]
RewriteRule ^/api/v1/* /api/v1/index.php [L]
RewriteRule ^/assets/(.*) /site/v1/content/assets/$1 [L]
RewriteRule ^/css/(.*) /site/v1/content/css/$1 [L]
RewriteRule ^/js/(.*) /site/v1/content/js/$1 [L]
RewriteRule ^/fonts/(.*) /site/v1/content/fonts/$1 [L]
RewriteRule ^/* /index.php [L] # problematic rule
// lets encrypt entries
Now, my problem is that rewrite rules takes precedence over ProxyPass. That ism when I visit mydomain.com/mediaproxy/somepage, it serves the content at /index.php
, specified with RewriteRule ^/* /index.php [L]
. Reverse proxy works correctly if I remove the problematic rule. Unfortunately I need to keep it.
How do I tell apache to use ProxyPass
rule first, and use RewriteRule
only if there is no match?
CodePudding user response:
RewriteRule ^/* /index.php [L] # problematic rule
Your rule rewrites everything. You could just make an exception for the URL-path you want to proxy. For example:
RewriteRule !^/mediaproxy /index.php [L]
The !
prefix on the RewriteRule
pattern negates the expression. So it is successful when it does not match.
This now rewrites everything except URL-paths that start /mediaproxy
.
Note that the trailing *
quantifier in the regex ^/*
repeats the preceding token 0 or more times. The preceding token in this instance is the slash. You are missing the preceding .
(dot). Or omit the .*
entirely as it's superfluous (and less efficient).
Aside:
RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^/api/media/(.*) /data/$1 [L] RewriteRule ^/api/v1/* /api/v1/index.php [L] RewriteRule ^/assets/(.*) /site/v1/content/assets/$1 [L] RewriteRule ^/css/(.*) /site/v1/content/css/$1 [L] RewriteRule ^/js/(.*) /site/v1/content/js/$1 [L] RewriteRule ^/fonts/(.*) /site/v1/content/fonts/$1 [L] RewriteRule ^/* /index.php [L] # problematic rule
The two conditions (RewriteCond
directives) are not doing anything here. When used in a virtualhost context, REQUEST_FILENAME
is the same as REQUEST_URI
, since it is processed early, before the request is mapped to the filesystem. Consequently, both (negated) conditions will always be successful and the following rule is always processed. In a vhost context you need to use a lookahead, ie. LA-U:REQUEST_FILENAME
, OR construct the file-path using the DOCUMENT_ROOT
server variable, OR move the rules into a directory context.
However, those two conditions only apply to the first rule that follows. So all the remaining rules (including the last "problematic" rule) are processed unconditionally anyway. This is generally incorrect for a front-controller pattern (the last rule) and should perhaps be written like this instead:
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} !-f
RewriteRule !^/mediaproxy /index.php [L]
This now rewrites everything except URL-paths that do not start /mediaproxy
AND do not map to a directory AND do not map to a file.
Alternatively, if these condtions should be applied to all rules then create a negated rule instead. For example:
DirectoryIndex index.php
RewriteEngine on
# Prevent further processing if root directory or "index.php" requested
RewriteRule ^/(index\.php)?$ - [L]
# Prevent further processing if the request maps to a directory or file
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
RewriteRule ^/. - [L]
RewriteRule ^/api/media/(.*) /data/$1 [L]
# This rule is not required since the DirectoryIndex handles this case (the regex is also "incorrect").
#RewriteRule ^/api/v1/* /api/v1/index.php [L]
RewriteRule ^/assets/(.*) /site/v1/content/assets/$1 [L]
RewriteRule ^/css/(.*) /site/v1/content/css/$1 [L]
RewriteRule ^/js/(.*) /site/v1/content/js/$1 [L]
RewriteRule ^/fonts/(.*) /site/v1/content/fonts/$1 [L]
RewriteRule !^/mediaproxy /index.php [L]