Codeigniter 2 and .htaccess - how to implement "down for maintenance" mode? - apache

I know this question might have been asked a few times already, but I need a specific solution for CodeIgniter, using an .htaccess file that would send every request to an index_failsafe.php file instead of the normal index.php but ONLY if the url doesn't start with 'admin'. Example:
www.myhost.com/admin -> work as usual
www.myhost.com/welcome -> sent to failsafe page
in case 1:
RewriteRule ^.*$ index.php/$1 [L]
in case 2:
RewriteRule ^.*$ index_failsafe.php/$1 [L]
My rewrite conditions are:
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
Is it possible to do this?

Personally I do it by IP - so I can take my site offline, but I still have full access to it (to test new functions and make sure it is working before bringing back up)
RewriteEngine on
# For maintenance:
# If your IP address is 1.1.1.1 - then dont re-write
RewriteCond %{REMOTE_ADDR} !^1\.1\.1\.1
# If the person is requesting the maintenance page, also dont rewrite (prevent loops)
RewriteCond %{REQUEST_URI} !/maintenance.html$
# Otherwise rewrite all requests to the maintenance page
RewriteRule $ /maintenance.html [R=302,L]
# do not rewrite links to the documentation, assets and public files
RewriteCond $1 !^(assets)
# do not rewrite for php files in the document root, robots.txt or the maintenance page
RewriteCond $1 !^([^\..]+\.php|robots\.txt|maintenance\.html)
# but rewrite everything else
RewriteRule ^(.*)$ index.php/$1 [L]
just change !^1.1.1.1 to your current IP. i.e. !^121.65.56.65
If your not sure what your IP is - just google "what is my IP" - and it will show up as the first hit
But in terms of your specific question - this should work:
RewriteCond %{REQUEST_URI} !/admin$
RewriteRule $ /index_failsafe.php [R=302,L]
edit:

If you use cookies to store session data for users then it might be simpler to change the cookie name to force everyone to log out, then change the login page controller to load a view that says "down for maintenance" or whatever.
When you're done just change the cookie name back to what it was and everyone will still be logged in, and make sure to change back the view that the login page controller loads so users can log in normally.
To change the session cookie for CI, open up config.php and change the value for:
$config['sess_cookie_name']
You can take it a step further by creating an alternate login controller and view titled "maintenance login" or something like that, and then you can still log in for testing.
This is the method that I use when I need to take my saas down for maintenance, and it works great. Our public facing sales page is unaffected, and I don't have to mess with htaccess.

Related

Apache mod_rewrite - unwanted redirect instead of rewrite

I have an issue with mod_rewrite and I can't seem to solve it. I stripped the example down to the bare bones and I don't understand why a specific rule forces my browser to redirect instead of rewrite:
RewriteEngine on
#if request is for a physical-file OR for one of the language paths - skip (return as-is)
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{REQUEST_URI} ^/de [OR]
RewriteCond %{REQUEST_URI} ^/en-US
RewriteRule ^ - [L]
#otherwise: rewrite to en-US folder
RewriteRule ^(.*)$ /en-US/$1 [NC,L,QSA]
I read the documentation very carefully and it seems like this should actually rewrite every call, so https://example.com/fuBar.html should actually retrieve the file /en-US/fuBar.html from my server - the users browser shouldn't know about it.
What's really happening is that for some reason the browser is redirected to https://example.com/en-US/fuBar.html. While this does display the correct content, it's just not what I want or what I thought this RewriteRule should do. What am I doing wrong?
*add - the .htaccess of the subfolders de and en-US:
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
There's nothing in the code you've posted that would trigger an external "redirect".
Make sure you have cleared your browser (and any intermediary) cache(s) to ensure you are not seeing an earlier/erroneous 301 (permanent) redirect. (301 redirects are cached persistently by the browser.)
Check the "network traffic" in the browser's developer tools to see the precise nature of this redirect to see what it redirects from/to, and well as the 3xx HTTP status code of the redirect (if indeed this is an external redirect).
It would seem the front-end (JavaScript/Angular) is manipulating the URL in the address bar (there is no redirect). From comments:
Actually there was no redirect happening at all! Rather since I set <base href="/en-US"> somehow my frontend (Angular) seems to have outsmarted me, manipulating the address without me realizing it. Turns out I don't even need to change the base href, I just need the rewrites.

How to setup request proxy using URL rewriting

I have an e-commerce site that resides in:
http://dev.gworks.mobi/
When a customer clicks on the signin link, the browser gets redirected to another domain, in order for authentication:
http://frock.gworks.mobi:8080/openam/XUI/#login/&goto=http%3A%2F%2Fdev.gworks.mobi%3A80%2Fcustomer%2Faccount%2Flogin%2Freferer%2FaHR0cDovL2Rldi5nd29ya3MubW9iaS8%2C%2F
I'm trying to rewrite http://dev.gworks.mobi/* to http://frock.gworks.mobi:8080/openam/*, without redirection.
I've tried this in the .htaccess of the dev.gworks.mobi site:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/openam(.*)$ [NC]
RewriteRule ^(.*)$ http://frock.gworks.mobi:8080/$1 [P,L]
</IfModule>
But when I access http://dev.gworks.mobi/openam, it shows a 404 page not found page.
Can anyone help me to achieve my use case?
Try this:
RewriteEngine on
RewriteBase /
# Make sure it's not an actual file being accessed
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# Match the host
RewriteCond %{HTTP_HOST} ^dev\.gworks\.mobi
# Rewrite the request if it starts with "openam"
RewriteRule ^openam(.*)$ http://frock.gworks.mobi:8080/$1 [L,QSA]
This will rewrite all the requests to dev.gworks.mobi/openam to frock.gworks.mobi:8080.
If you want to mask the URI in a way that it's not visible to the visitor that she's visiting the authentication app, you need to add a P flag. Please note that it needs Apache's mod_proxy module in place:
RewriteRule ^openam(.*)$ http://frock.gworks.mobi:8080/$1 [P,L,QSA]
Feel free to drop the L flag, if it's not the last rewrite rule. See RewriteRule Flags for more information.
The 404
If it's all in place and you're still getting a 404 error, make sure that the target URL is not throwing 404 errors in the first place.
Second, check if you're still getting the error with the correct referrer URI set. It might be designed in a way to throw a 404, if the referrer is not correctly set. If that's the case, which I suspect, you need to use the R flag and redirect instead of proxying the request.
Last thing that comes to my mind, some webapps are not built in a way to figure out the URI address. The host, as well as the port number, might be hard-coded somewhere in the config files. Make sure that the authentication app is able to be run from another URL without the need to edit the configs.
Test
You can test the rewriterule online:

Mod Rewrite and Redirecting directories

A little explanation and then 2 questions....
Essentially I am building a single page app to display media (by tags, by type, etc.. etc..). All the media is uploaded & tagged by me, so I am not scrapping for content or relying on 3rd party services (twitter, facebook, flickr, imgur, etc...). I am doing most of the work with JS (RequireJS modules...) and am leveraging ToroPHP for a simple, lightweight & restful API
My end goal is this:
Allow returning users to type in URLs like: / OR //, and always load my root index.php (maintaining the url). At the same time i need several subdirectories available for the api to
fetch data:
/assets/ (CSS, Font Files, Sprites or SVG Icons)
/components/ (for RequireJS scripts)
/api/ (this is just a sub directory that has a ToroPHP instance for the API)
I believe the below snippet solves this issue (I was wondering if I could get a good explanation of what this is doing though? I have pieced it together from snippets on the internet):
RewriteEngine on
RewriteRule ^/?assets/.+$ - [L]
RewriteRule ^/?components/.+$ - [L]
RewriteRule ^/?api/.+$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php)
RewriteRule ^(.*)$ /index.php [L]
Additionally, I was hoping you could help me figure out a way to only allow my "app" (that is, internal calls (is there a server user on apache?) initiated by RequireJS modules to the API) to have access to /assets/ & /components/ & /api/ so if a user types in /api/test?subject=123 they are routed to a page that isn't the index.php, but isn't the actual API either. I would like this to be the same for /components/ & /assets/ as well.
*Summary questions:
1). Help explain the code snippet above.
2). Can I allow my server access to /assets/ & /components/ & /api/ but not allow a user to type into them?
Obviously, Apache isn't my specialty, but I am fairly confident in learning.
Thanks!
Help explain the code snippet above.
RewriteEngine on
Turns on the rewrite engine, none of the rules will do anything unless the rewrite engine is turned on
RewriteRule ^/?assets/.+$ - [L]
RewriteRule ^/?components/.+$ - [L]
RewriteRule ^/?api/.+$ - [L]
These rules are called "pass-through" rules. The - target means "do nothing" and the L flag stops the rewriting for the current pass. These essentially just mean: if URI starts with /assets/, do nothing and stop rewriting. If the URI starts with /components/, do nothing and stop rewriting. If the URI starts with /api/ then do nothing and stop rewriting.
The next rule has a few conditions associated with it. The rule won't get applied unless all conditions are met:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
These check if the requested URI maps to an existing file or directory, The !-f means the request isn't for a file, and the !-d means the request isn't a directory.
RewriteCond $1 !^(index\.php)
This checks if the request doesn't start with /index.php.
Finally, if all 3 conditions are met, then:
RewriteRule ^(.*)$ /index.php [L]
rewrite whatever the request is to /index.php, and stop rewriting.
Can I allow my server access to /assets/ & /components/ & /api/ but not allow a user to type into them?
No. If someone goes to your page and your page links to something in one of these directories, the browser loads it just like it would if someone typed it into the URL address bar. The only difference is that (sometimes) the browser will include a "Referer" header request letting the server know what page told the browser to load the file. It's not always going to be used by all browsers and it can easily be forged. So checking the referer isn't going to guarantee that people can't still directly load your files.
In order to check the referer, add this right below the RewriteEngine On line:
RewriteCond %{HTTP_REFERER} !^https?://example.com/
RewriteRule ^(assets|components|api)/ - [L,F]
This is essentially a condition that checks the referer, and if it doesn't start with "http://example.com" or "https://example.com", assuming that "example.com" is your site, then the rule checks that the request starts with either /assets/, /components/, or /api/, and passes it through without changing anything, except the F flag causes the server to return a 403 Forbidden.

How do I make a custom URL parser with Apache?

I heard this can be done with the web.config file. I want to make it so, for instance, my URL http://help.BHStudios.org/site might go to http://BHStudios.org/help.php?section=site, or http://i.BHStudios.org/u3Hiu might redirect to some other URL stored in a database with the hash u3Hiu as the key, or if something goes wrong and the internal file structure is exposed like http://Kyli.BHStudios.org/http/bhstudios/v2/self/index.php (something that happens with GoDaddy's servers for whatever reason) it'll change it to its intended URL http://Kyli.BHStudios.org before that's exposed tot he user.
Since I've never done this before, could you please also explain why you gave the answer you did?
A few Apache mod_rewrite rules in either your servers httpd.conf or in a .htaccess file, in your htdocs directory will do the majority of what you want e.g.
RewriteEngine On
RewriteBase /
# Default Rule - for non physical objects (not a file or directory):
# Internally rewrite (user won't see the URL) to /index.php
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ /index.php [L]
#If the Browser request contains a .php, instruct the browser to remove it.
RewriteCond %{THE_REQUEST} \.php [NC]
RewriteRule ^/?(.*)\.php$ http://%{HTTP_HOST}/$1 [R=301,NC,L]
# Specific rule
RewriteRule ^/?site /help.php?section=site
The masking of real file system objects will not be perfect, and slightly pointless, as a user just needs to right click and view source on any served page, to obtain the actual URL's.

Using Apache mod_rewrite for conditional redirection if URL exists

I'm migrating a large site (with significant changes to each page), and want a test group of users to be automatically redirected from the current site to the new site as each page is completed.
What was
www.mysite.com/admin/somefile.php
will become
admin.mysite.com/somefile.php
As each page is migrated to the new site, I want users from a specific IP address to be automatically redirected to it. This looks like a case for the '-U' (existing URL) flag of RewriteCond. The mod_rewrite statements (for www.mysite.com) would be something along the lines of
RewriteEngine On
RewriteCond %{REMOTE_ADDR} 123\.123\.123\.123 # for test users only
RewriteCond http://admin.mysite.com/$1 -U # if new page exists
RewriteRule /admin/(.*) http://admin.mysite.com/$1 [R=302,L] # then redirect
However, this doesn't seem to work - perhaps because the $1 parameter is being referenced before being defined?
Can anyone advise how this can be achieved?
Thanks, Chris
Thanks, LazyOne – you gave me confidence to pursue it (if you make it an answer I'll accept it).
I think the problem was simply in using /admin instead of ^admin; my final mod_rewrite statements are:
RewriteEngine On
RewriteCond %{REMOTE_ADDR} 123\.123\.123\.123 # for test users only
RewriteCond http://admin.mysite.com/$1 -U # if new page exists
RewriteRule ^admin/(.*) http://admin.mysite.com/$1 [R=302,L] # then redirect
...which seems to correctly serve the page from the new site if it exists, otherwise serves the page from the old site.
You could use it this way to manipulate URI
RewriteCond %{REQUEST_URI} ^/admin/(.*)$
RewriteRule .* http://admin.mysite.com/#1 [R=302,L]
Hope this works. BTW, you can test your rewrite online here http://martinmelin.se/rewrite-rule-tester/