How to configure mod_rewrite to serve minified files, if available? - apache

Here is the problem: we have lots of Javascripts and lots of CSS files, which we'd rather be serving minified. Minification is easy: set up the YUI Compressor, run an Ant task, and it spits out minified files, which we save beside the originals.
So we end up with the following directory structure somewhere inside our DocumentRoot:
/
/js
/min
foo-min.js
bar-min.js
foo.js
bar.js
quux.js
/css
...
Now what we need is that Apache serve files from the min subdirectory, and fallback to serving uncompressed files, if their minified versions are not available. The last issue is the one I cannot solve.
For example: suppose we have a request to example.com/js/foo.js — in this case Apache should send contents of /js/min/foo-min.js. There is no minified quux.js, so request to /js/quux.js returns /js/quux.js itself, not 404. Finally, if there is no /js/fred.js, it should end up with 404.
Actually, I'm setting build scripts in such a way that unminified files are not deployed on the production server, but this configuration still might be useful on an integration server and on development machines.

Here is the configuration that finally worked:
/js/.htaccess:
RewriteEngine On
RewriteBase /js
RewriteCond %{REQUEST_URI} ^/js/((.+)\.js)$
RewriteCond %{DOCUMENT_ROOT}/js/min/%2-min.js -f
RewriteRule ^(.+)$ min/%2-min.js [L]
Same for css directory.

You can use RewriteCond to detect the presence of a minified file:
RewriteCond %{REQUESTURI} ^/js/(.*\.js)
RewriteCond js/min/%1 -f
RewriteRule %1 min/%1 [L]

Is it possible to change your build scripts? If so, you can configure them to minify the files and give them the same file name, but only when provided the proper flag, e.g. ant productionDeploy instead of ant integrationDeploy. That way the minification process is completely transparent to everything except the build script.

Related

How to include an .htaccess file wit Nuxt?

I have a Nuxt.js app with an .htaccess file.
The problem is that when I execute nuxt generate in the terminal, my .htaccess file disappears. What can I do to include my .htaccess file when I execute nuxt generate?
You could put your .htaccess file into the /static directory, more info on that in the doc.
That way, you will have direct access to it once pushed to production.
Otherwise, you can also use this approach if you need something more customizable.

Deploying React App to Apache Server

I have a finished react app that works well on my localhost with npm start.
I created the project with create-react-app and used the npm run build to compile a production website.
I have the whole folder with the index.html on my webspace. (They use an apache html server).
I managed to write an .htaccessfile that loads the html correctly. Now there is only a white screen. It seems like the main.js is not being loaded into the root div.
The only error I get in the console is that the service-worker could not be installed as my request comes not from a secure origin. This should not stop the rendering right?
I am not sure what files would be necessary to show here so please do let me know what you need to see to hopefully fix the problem.
Thank you!
After Running npm run build command.
Copy and paste everything in build folder to your server.
Create a “.htaccess” file and add this snippet :
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]
The application should work correctly.
maybe its because you have ProxyPass in your conf file. you need to specific the homepage of your application.
{
"name": "application-name",
"version": "1.0.0",
"description": "",
"homepage": "https://www.yourdomain.com/appliaction-context-path",
}

Apache .so and .c files

I see what there is checks for mod_rewrite.c file in different .htaccess files, but i have only mod_rewrite.so, what is the difference between them?
<IfModule mod_rewrite.c>
# Make sure directory listing is disabled
Options +FollowSymLinks +Indexes
RewriteEngine on
</IfModule>
It sounds kind of backwards but that's just the way it works. The <IfModule> container wants either a module name or a module file. In the case of the module file, it wants the source file (.c). This is because some modules are compiled into apache so there is no shared library file (.so).
In the case of LoadModule, which loads a module that is external to the main apache core, you use the .so file.

Apache redirects based on symlinks

In one app, some public image resources are symlinked to alternative names for historic reasons. For example, we might have
a.png
b.png -> a.png
Google's PageSpeed Insight that identical content should be served from a consistent URL applies to assets like this as well as content. Rather than reorganising the assets we have in place, I would like to have Apache perform an external redirect from b.png to a.png.
With mod_rewrite I can make a RewriteCond to narrow in on symbolic links:
'-l' (is symbolic link)
Treats the TestString as a pathname and tests whether or not it exists, and is a symbolic link.
But how can I get the expanded path of the symlink? I need it partly to ensure that the target is in web scope, and partly to perform the redirect.
(first post here)
I've been looking for a solution to a similar problem. It's possible, but there is no easy answer. I had to mix info from multiple Google searches to make it work.
First of all, a note about symlinks (wiki):
Symbolic links are automatically resolved by the file system. Any
software program, upon accessing a symbolic link, will see the target
instead, whether the program is aware of symbolic links or not.
So, unless the apache devs add specific options to deal with symlinks (like the -l you mentionned), we have to rely on another mean to properly resolve them.
mod_rewrite has the RewriteMap configuration option. With it, you can use different types of external resources to perform the rewriting, such as text files or DB queries. It can also call external programs, such as ... a symlink resolver for example :)
So, here we go. Run all the following commands as root and adapt to your system settings (this is for Debian).
First, if we use the RewriteMap option, we also need the RewriteLock option to prevent race conditions. The RewriteLock option can't be in a <VirtualHost> or <Directory> context. It has to be in the global context, so I added it in a new rewrite.conf and reloaded the module.
Run the following:
lock=/var/lock/apache2/rewrite_lock
touch $lock
chown www-data:www-data $lock
echo "RewriteLock $lock" >> /etc/apache2/mods-available/rewrite.conf
a2dismod rewrite
a2enmod rewrite
Next, create /usr/local/bin/resolve-symlink and add the following code:
#!/bin/sh
while read line
do
echo `readlink "$line"`
done
Make it executable and test it as apache:
chmod +x /usr/local/bin/resolve-symlink
su - www-data
/usr/local/bin/resolve-symlink
The script should wait for your input, then either return a blank line or the target of the given symlink. Use CTRL+C to exit. Example (> is STDIN, < is STDOUT):
> test
<
> /bin/sh
< bash
> /bin/bash
<
test doesn't exist, so a blank line is returned. /bin/sh is a symlink and the script resolved it to bash. Finally, /bin/bash is a file and not a link, thus another blank line.
Now, in your <VirtualHost> configuration, add the following lines:
RewriteEngine On
RewriteMap symlink prg:/usr/local/bin/resolve-symlink
RewriteLog /var/log/apache2/rewrite.log
RewriteLogLevel 9
RewriteMap can't be in a <Directory> context, and won't be active unless RewriteEngine is also set to on in the <VirtualHost> context, even if you later set it to on in a <Directory> contest!!! Pay attention to all those peculiarities and read your log files carefully or you may lose a few hours banging your head on the wall wondering why it says "map lookup FAILED".
Finally, the rewriting, in whatever context you prefer:
RewriteCond %{REQUEST_FILENAME} -l
RewriteCond ${symlink:%{REQUEST_FILENAME}} ^(.+)$
RewriteRule $ ${REQUEST_SCHEME}://${HTTP_HOST}/%1 [R,L]
First line detects symlinks, second one performs the resolution and checks that the results is not empty, third line rewrites the URL (%1 is the result of the mapping) and sends a 302 redirection to the browser. You may need the END flag instead of the L flag.
Now restart apache...
service apache2 restart
... test, check your log files, tweak, rinse and repeat...
When your are done, don't forget to remove the RewriteLog and RewriteLogLevel directives from your configuration because they slow apache down a lot.
Important note. In my case, the symlinks all points to files within the same folder, so the URL rewriting is a little easier. If your symlinks point to sub-directories, or even somewhere else on the filesystem, you will have to modify the script and the configuration to account for it, but even then it might not work as expected, as apache won't always be able to figure out the correct URL to send to the browser. For example, if you have a symlink to, let say, /usr/share/apache2/icons/apache_pb.png, apache might redirect to http://example.com/usr/share/apache2/icons/apache_pb.png which, of course, does not exists...
Also, I would have added a few informative links but I'm limited to 2... Anyway, happy debugging!
I've got more information about this topic. It's been running for quite some time on my side and I made the following amendments to the file /usr/local/bin/resolve-symlinks:
#!/bin/bash
BASE=_ALL_YOUR_BASE_ARE_BELONG_TO_US_
BASE_LEN=${#BASE}
while read FILE
do
# $FILE must be in $BASE
if [[ $BASE != ${FILE:0:$BASE_LEN} ]]
then
echo
continue
fi
REL_FILE=${FILE:$BASE_LEN}
# echo $REL_FILE
# $LINK must also be in $BASE
LINK=$(readlink -f $FILE)
if [[ $BASE != ${LINK:0:$BASE_LEN} ]]
then
echo
continue
fi
REL_LINK=${LINK:$BASE_LEN}
# echo $REL_LINK
# $REL_FILE and $REL_LINK must be different
if [[ $(basename $REL_FILE) == $(basename $REL_LINK) ]]
then
echo
continue;
fi
# success!
echo $REL_LINK
done
Of course, replace _ALL_YOUR_BASE_ARE_BELONG_TO_US_ with your favorite path.
Now it should make sure both the requested file and the link target are in the same directory.

Symlink, Am I Missing Something?

I'm trying to symlink my public folder with a index.php file in it to the httpdocs folder where the public folder is also placed.
When I try and Symlink the public folder I get an error alerting me that the public folder name is already taken. I've also tried Symlinking the index.php file itself which worked but broke the functionality of the site.
Here is the command I'm using when Symlinking the public folder.
ln -s /var/www/vhosts/mysite.co.uk/httpdocs/public /var/www/vhosts/mysite.co.uk/httpdocs
Here is the command I used when Symlinking the index.php file.
ln -s /var/www/vhosts/mysite.co.uk/httpdocs/public/index.php /var/www/vhosts/mysite.co.uk/httpdocs
tldr: I want to use the index.php in the public folder as the index.php file when a user visits my site without having to use mysite.co.uk/public/index.php. The index.php file has to remain in the public folder.
If I understand correctly, you want to access index.php from httpdocs/public, and that folder already exists (as the error in the first case informs). You can link the file to that (exisitng) folder:
ln -s /var/www/vhosts/mysite.co.uk/httpdocs/index.php /var/www/vhosts/mysite.co.uk/httpdocs/public/index.php
Note that you need to specify the file itlsef that you want to link
I've managed to get it to work! I used a soft symlink on public/index.php in the httpdocs folder to make a index.php file also in the httpdocs folder.
ln -s /var/www/vhosts/mysite.co.uk/httpdocs/public/index.php /var/www/vhosts/mysite.co.uk/httpdocs/
I then added a .htaccess file to the httpdocs folder with the following...
Options +FollowSymLinks
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
</IfModule>
Thank you to #Attila for sticking with me and helping out!
Solution (if all files are required in …/public and …/httpdocs.
move your data from /var/www/vhosts/mysite.co.uk/httpdocs/public to /var/www/vhosts/mysite.co.uk/httpdocs
symlink /var/www/vhosts/mysite.co.uk/httpdocs to …/public
Command: ln -s /var/www/vhosts/mysite.co.uk/httpdocs /var/www/vhosts/mysite.co.uk/httpdocs/public
Cons:
infinite recursion, for instance /var/www/vhosts/mysite.co.uk/httpdocs/public/public/public/public/
It is not possible to symlink to an existing file/directory. If it would be possible, you would break your tree structure. In fact you are trying to link a directory to its parent. How should your system resolve overwritten paths?
Example:
You have a file /a/b/c and it would be possible to do the following:
ln -s /a/b /a
How should the system resolve the now not reachable file /a/b/c?
Move your data into the desired directory instead of trying to break your file tree.
It is possible to mount data to existing directories (original data will be unreachable until unmount), but this would not help in your case.