Use alternative to .htaccess file if it exists? - apache

Background: I used to use an environment variable to enable me to differentiate between my dev and production server, using this in .htaccess: -
<IfDefine DEV_SERVER>
# dev server specific stuff here
</IfDefine>
<IfDefine !DEV_SERVER>
# production server specific stuff here
</IfDefine>
The environment variable "DEV_SERVER" was only ever set on my dev server, and never on production, obviously.
This approach worked a treat until my production server host installed Litespeed as a replacement for Apache. Litespeed doesn't like the above, and ignores everything.
I tried having different versions of .htaccess files for dev and production, but that's messy and dangerous, I like to be able to interchange all files at any time between the two.
My dev server runs Apache 2.4 and I have no plans to change this. I read that you can specify a different filename for .htaccess by putting this in httpd.conf: -
AccessFileName .htaccess.dev
Which is half way there - now I can have a .htaccess.dev file which only my dev server will use in place of .htaccess. But ideally I would like the dev server to: -
use .htaccess if that's all there is
use .htaccess.dev if that's all there is
use .htaccess.dev if there are both .htaccess and .htaccess.dev present
It does (2) and (3), but unfortunately not (1).
Is there any solution? Any help greatly appreciated, as always!

You can specify multiple files in AccessFileName so you can do: AccessFileName .htaccess.dev .htaccess
What this will do is to prefer .htaccess.dev over .htaccess if it exists, and will use .htaccess if .htaccess.dev doesn't exist.
However, in my opinion you're doing something wrong, if you have to customize your .htaccess per environment :)
Update with working example:
If you put AccessFileName .htaccess.dev .htaccess in your Apache configuration (Such as the vhost it will work as it should):
# curl -sI http://example.com/test.html | grep "x-htaccess"
x-htaccess: dev
# mv .htaccess.dev htaccess.dev
# curl -sI http://example.com/test.html | grep "x-htaccess"
x-htaccess: default
The content of .htaccess is Header set x-htaccess default and the content of .htaccess.dev is Header set x-htaccess dev.

Related

Is there a way for Apache to silently ignore unrecognized .htaccess directives?

I'm in the unfortunate position of having an Apache staging server combined with a Zeus web server. (Not my choice).
I'd like to be able to include a Zeus-specific directive in the .htaccess file (e.g. ContentCompressionEnabled) and, if possible, include the Apache equivalent (AddOutputFilterByType DEFLATE) in the same file too.
Is there a way of doing this which doesn't involve separate .htaccess files for Zeus and Apache?
Only in 2.4, where there is an Nonfatal option to AllowOverride.
If I understood correctly, you can use httpd.conf file do this configuration for all requests. .htaccess file configurations effect only requests to where the file located.
You could put any Apache only directives into either Apache's main httpd.conf file, or the sites vhost config file - along with AllowOverride None.
This would mean that Apache would get all it's config info from there and ignore any .htaccess files completely.
You could then place anything you wanted in the .htaccess files, including all the Zeus config you need - and Zeus would be configured only from there - thus separating the two configs.

htaccess if statement

I have the following line in my .htaccess file to select which version of PHP to use:
AddType x-httpd-php53 .php
This works great in the live environment but doesn't apply to the test environment and breaks the site.
Is there a way I can put it in an if statement or something by IP of the server or URL of website or something so that it only comes into effect in the live environment?
With Apache 2.4, it is easy with <If>/<Else> directives (on %{HTTP_HOST}?).
<If "%{HTTP_HOST} == 'foo'">
# configuration for foo
</If>
<Else>
# default configuration
</Else>
For Apache 2.2 and earlier, I would add a parameter to the startup command line of Apache (-D option) in one of the two environments then test if it is present or not via <IfDefine>.
To do this on Windows, with Apache started as a service, modify key registry HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Apache2.<VERSION>\ImagePath
by appending -DFOO. Then, you can write:
<IfDefine FOO>
# configuration for foo
</IfDefine>
<IfDefine !FOO>
# default configuration
</IfDefine>
Another alternative you can do is to change httpd.conf in the test environment to use ".htaccess-test" instead of ".htaccess".
This is simply done by modifying httpd.conf and adding the following line outside of any block:
AccessFileName .htaccess-test
NOTE: You can add AccessFileName inside a <VirtualHost> block if you want to apply it to a specific VirtualHost.
What this means is that the test environment will use .htaccess-test while the production environment will use .htaccess. Hence, you get the freedom of configuring each environment separately.
Then create a file named .htaccess-test adjacent to .htaccess.
Modify .htaccess-test with your test configuration, then finally restart Apache Web server in the test environment server.

.htaccess in Multiple Environments

I know similar questions have been asked before but I haven't found any really specific answers for my situation.
I have an ExpressionEngine site running on multiple environments (local, dev, production), and each of those environments needs different .htaccess rules:
All Environments
Remove index.php
Set a 404 file
Set 301 Redirects
Development
Password Protect with .htpasswd
Force HTTPS protocol
Prevent search engine indexing with X-Robots-Tag
Production
Force HTTPS protocol
Redirect non-www subdomains to www
Local
No unique rules.
I've seen a lot of examples of how you can set specific environments per-module. Like RewriteCond %{REQUEST_HOST} ^dev.myurl.com for the mod_rewrite module, and tricks like this for .htpasswd requirements.
But what I would really prefer is some way to set global environment variables, then re-use those variables in the .htaccess file per-environment. To use pseudo-javascript as an example, something like:
var local = 'mysite.local';
var development = 'dev.mysite.com';
var production = 'www.mysite.com';
// Global .htaccess rules
if(environment == local){
// Local environment .htaccess rules
}
if(environment == development){
// Development environment .htaccess rules
}
if(environment == production){
//Production envirotnment .htaccess rules
}
This way all of the environment-specific rules are all grouped together, making a really clean file, and only one variable needs to be changed if an environment is changed.
I've seen a few references to altering settings in Apache's config files, but obviously that's not a viable option if I'm dealing with 3rd-party hosts.
So is this pie-in-the-sky wishful thinking, or can it be done?
Jon's answer is a good one. Unfortunately, not all web hosts will allow you to control that -D parameter for starting Apache.
Here's a way to use a single htaccess file on dev and production, but only have the dev site password protected:
# ----------------------------------------------------------------------
# Password protect staging server
# Use one .htaccess file across multiple environments
# (e.g. local, dev, staging, production)
# but only password protect a specific environment.
# ----------------------------------------------------------------------
SetEnvIf Host staging.domain.com passreq
AuthType Basic
AuthName "Password Required"
AuthUserFile /full/path/to/.htpasswd
Require valid-user
Order allow,deny
Allow from all
Deny from env=passreq
Satisfy any
So is this pie-in-the-sky wishful thinking, or can it be done?
IMO, yes. You're never going to be able to get predictable "scoping" of rules based on ENV variables or anything like that. There doesn't exist arbitrary if(something) { do everything in here } in apache. Lots of directives won't work inside certain scopes, and in later on, when you need to change how something works, you're more likely to break what you have than simply amending it.
The best way is to not use htaccess files at all:
You should avoid using .htaccess files completely if you have access to httpd main server config file. Using .htaccess files slows down your Apache http server. Any directive that you can include in a .htaccess file is better set in a Directory block, as it will have the same effect with better performance.
Create a separate vhost for local, dev, and production. Turn them on or off as needed, whatever global config they share, store that elsewhere (like in a file called global.includes) and then use the Include directive in all 3 vhosts. If you need to apply rules to specific directories, use the <Directory> block instead of htaccess files.
If you'd rather stick everything inside htaccess files, you could try putting everything in <IfDefine> blocks, it's probably the closest thing you'll have to your pseudo-code in your question. Essentially something like:
# Global htaccess rules
RewriteEngine On
RewriteRule ^foo$ /bar [L]
# Only local
<IfDefine LocalInstance>
RewriteRule ^local/foo /bar [L]
</IfDefine>
# Only dev
<IfDefine DevInstance>
RewriteRule ^dev/foo /bar [L]
</IfDefine>
# Only production
<IfDefine ProductionInstance>
RewriteRule ^dev/foo /bar [L]
</IfDefine>
Then when you start apache, you'd need to pass in -DLocalInstance, -DDevInstance, or -DProductionInstance as command line paramaeters or using the Define directive (with only one argument) somewhere in your vhost config. This isn't guaranteed to work as smoothly as it looks like it should, I've ran into unexplained issues with <IfDefine> before, especially if you try to get too fancy.

Conditional settings for a specific domain in .htaccess?

I would like to have a conditional setting for a specific domian in my .htaccess file. My use case is I have dev (example.dev) and live (example.com). The htaccess file is in my git repo but I have some settings in .htaccess that should only apply to the live site. Ideally I would like to have a conditional setting like the pseudo code below:
<sometag domain=my_prod_domain example.com>
#code specific to only the live domain here
</sometag>
Do you have access to the main configuration files?
If yes, then you could specify a different configuration file for your different hosts using
AccessFileName .public.htaccess
and
AccessFileName .dev.htaccess
And then you could work with the Include directive to load configurations common to both.
Include .common.htaccess
Another idea would be to try to work with the If-Directives, but it all really depends on your setup and level of access to the configurations: http://httpd.apache.org/docs/2.4/mod/core.html#if
Edit:
Okay I think with IfDefine you can do something even more along the lines with you original though:
Start your dev. Server with httpd -DDevServer and have on your statements like this:
<IfDefine DevServer>
#Config specific for your dev. server
</IfDefine>
<IfDefine !DevServer>
#Config specific for your live server.
<IfDefine>
For this solution you do not need even root access on your live-server.

PHP: How to code .htaccess to make it work both on localhost & online without editing

I have a .htaccess file & I currently I am working on localhost. For a 404 page error, I have the following code in the .htaccess file:
ErrorDocument 404 /my_local_domain/404.php
But when I upload this file to my website online, the functionality of the file breaks. It no longer shows the 404.php page. It works if I modify the code in the .htaccess file of my online website to the following:
ErrorDocument 404 /404.php
Now all through the changes that I do in the .htaccess file, I would have to remember to remove the domain name before I upload it to the website or I risk breaking the functionality. So with this in mind, here are my questions:
1. How do I solve the above problem without needing to edit the .htaccess file each time (by stripping it off the my_local_domain) I make a change & upload it online?
2. How do I setup 404 page redirection for all the nested folders? (I don't want to setup a .htaccess file for each of the folders. A single .htaccess file that resides in the root folder of the website & controls all the redirection for all the sub-folders would be awesome)
All help is appreciated.
Thank you.
I believe you have two different issues here.
First of all, you should not need to have different paths in development and live site. It appears that you've configured your local Apache to host only one site and each actual sites goes in a subdirectory. It's not a good idea: you'll soon be mixing cookies and sessions between all your dev sites. Have a look at the name based virtual hosts feature: you can configure as many independent sites as you need. You don't even have to buy real domains in you set them in the hosts file.
Secondly, under certain circumstances it can be useful to have different Apache directives. I've been using the following trick.
Pick a keyword for the dev server, e.g. DEV_BOX.
Pass that keyword to Apache in the -D parameter. If you run it as service, you can run regedit and find the HKLM\SYSTEM\CurrentControlSet\Services\Apache2.2\Parameters key. Append -D DEV_BOX to the ConfigArgs value. Restart Apache.
Now, you can use the <IfDefine> directive to set local directives:
-
#
# Common stuff
#
AddDefaultCharset UTF-8
#
# Local-only stuff
#
<IfDefine DEV_BOX>
Options +Indexes
</IfDefine>
#
# Live-only stuff
#
<IfDefine !DEV_BOX>
Options -Indexes
</IfDefine>
First of all I suggest you setup local domains for development. For example if you are developing a website which will go under www.example.com, you can setup a local.example.com in your HOSTS file. You'll do a VirtualHost setup in your apache and the .htaccess will then be the same.
Also, you can setup a build process (e.g via Ant) which will allow you to prepare and generate a zip file with the files which go on the live server. This build will feature the correct configuration files (db configs, mail servers, htaccess etc).