How to use Mod Rewrite to access non-document-root folder files?

I have the following structure for my website codes at /var/www/html

-- files
---- test.txt

-- app
---- SomePhpCodes.php
---- SomePhpCodes.php

-- public
---- index.php
---- .htaccess

The document root is set to be "/var/www/html/public" but I also want to have files accessible via path "http://mywebsite/files/test.txt".

I think this must be possible using mod_rewrite in the .htaccess file inside public but I am struggling to do so.

I tried to add a rule to the default .htaccess that is provided by the Laravel framework. The current .htaccess looks like the following:

<IfModule mod_rewrite.c>
    <IfModule mod_negotiation.c>
        Options -MultiViews -Indexes
    </IfModule>

    RewriteEngine On

    # Handle Authorization Header
    RewriteCond %{HTTP:Authorization} .
    RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

    # Redirect Trailing Slashes If Not A Folder...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_URI} (.+)/$
    RewriteRule ^ %1 [L,R=301]

    # The following rule is added by me
    RewriteRule files/(.*\.txt) /var/www/html/files/$1 [L]

    # Send Requests To Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
</IfModule>

The current result is Internal Server Error when trying to access "http://mywebsite/files/test.txt". I have a feeling I might have missed some settings to make the "files" folder public but I don't have any idea how to do so.

I am stuck and if anyone can help me I will appreciate.


You can create a symlink

ln -s /var/www/html/files /var/www/html/public/files

You will need Options +FollowSymLinks for this to work. Please note that this option adds a security risk as it allows accessing files outside of DocumentRoot.

Alternatively you can add Alias /files /var/www/html/files to your VirtualHost configuration for this site. It is a more secure option but you can't do it with .htaccess.


In addition to @AlexD's answer...

think this must be possible using mod_rewrite in the .htaccess file

This IS possible using mod_rewrite, but not in .htaccess. You would need to do this directly in the main server config (or VirtualHost container).

In a directory (or .htaccess) context you are restricted to rewriting to a URL-path only. However, in a server (or virtualhost) context you can rewrite to a URL-path or an absolute filesystem path.

However, this is not the cause of your Internal Server Error...

RewriteRule files/(.*\.txt) /var/www/html/files/$1 [L]

This is most probably resulting in a rewrite-loop (hence 500 Internal Server Error response) because the unanchored RewriteRule pattern also matches the substitution string (a root-relative URL-path) and so the rewritten URL-path is rewritten again and again...

In a server context, you could write it like this:

RewriteRule ^/files/(.+\.txt)$ /var/www/html/files/$1 [L]

(If you are not expecting subdirectories of the /files directory then the regex should be made more restrictive, eg. ([^/]+\.txt))