I’m currently re-architecting my non-profit accounting SaaS (Treasurer’s Briefcase) to use Docker containers for a portable development environment and eventually for running under Kubernetes. The current architecture designed in 2012 uses an EC2 based environment for both development and run-time execution.
As part of that effort I’m migrating from Apache 2.2 to 2.4. In the
new development environment I’m using my Chromebook to access the
containerized application running on the EC2 dev server. I described
that setup in my previous
blog. In
that setup I’m accessing the application on port 8080 as http://local-dev:8080
.
If, as in the setup describe in my blog, you are running Apache on a
non-standard port (e.g., :8080
) - perhaps in Docker, EC2, or
via an SSH tunnel you may have noticed an annoying issue after
migrating from Apache 2.2 to Apache 2.4…
Previously, when requesting a directory without a trailing slash
(e.g., /setup
), Apache automatically redirected to /setup/
while preserving the port. However, in Apache 2.4, the redirect is
done externally AND drops the port, breaking relative URLs and
form submissions.
For example let’s suppose you have a form under the /setup
directory that
has as its action
“next-step.html”. The expected behavior on that page
would be to post to the page /setup/next-step.html
. But what really
happens is different. You can’t even get to the form in the first
place with the URL http://local-dev:8080/setup
!
http://yourserver:8080/setup
=> http://yourserver:8080/setup/
http://yourserver:8080/setup
=> http://yourserver/setup/
(port 8080
is missing!)This causes problems for some pages in web applications running behind Docker, SSH tunnels, and EC2 environments, where port forwarding is typically used.
If you’re experiencing this problem, you can confirm it by running:
curl -IL http://yourserver:8080/setup
You’ll likely see:
HTTP/1.1 301 Moved Permanently
Location: http://yourserver/setup/
Apache dropped 8080
from the redirect, causing requests to break.
Several workarounds exist, but they don’t work in our example.
DirectorySlash
: Prevents redirects but causes 403 Forbidden
errors when accessing directories.FallbackResource
: Works, but misroutes unrelated requests.Instead, we need a solution that dynamically preserves the port when necessary.
To restore Apache 2.2 behavior, we can use a rewrite rule that only preserves the port if it was in the original request.
<VirtualHost *:8080>
ServerName yourserver
DocumentRoot /var/www/html
<Directory /var/www/html>
Options -Indexes +FollowSymLinks
DirectoryIndex index.html index.php
Require all granted
DirectorySlash On # Keep normal Apache directory behavior
</Directory>
# Fix Apache 2.4 Directory Redirects: Preserve Non-Standard Ports
RewriteEngine On
RewriteCond %{REQUEST_URI} !/$
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_URI} -d
RewriteCond %{SERVER_PORT} !^80$ [OR]
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^(.*)$ http://%{HTTP_HOST}/$1/ [R=301,L]
UseCanonicalName Off
</VirtualHost>
/setup
=> /setup/
).!=80
, !=443
):8080
, making it flexible for any non-standard port8080
locally to 80
on the jump box./setup
redirected externally without the port, causing failures.mod_rewrite
and a RewriteRule
that ensures that port 8080
is preservedApache 2.4’s port-dropping behavior is an unexpected regression from 2.2, but we can fix it with a simple rewrite rule that restores the expected behavior without breaking anything.
If you’re running Docker, EC2, or SSH tunnels, this is a fix that will prevent you from jumping through hoops by altering the application or changing your networking setup.
Hmmmm…maybe we can use internal redirects instead of an external redirect??? Stay tuned.
Next post: How to Fix Apache 2.4 Broken Directory Requests (Part II)
Previous post: Web Development on a Chromebook