Nginx reverse proxy apache url silent rewrite and https rewrite

.htaccessapache-2.4mod-rewritenginxrewrite

I have a nginx + apache configuration running. I am VERY VERY new to nginx and I am having quite a time trying to learn it.

First I want to do a basic rewrite. As per my understanding, when nginx is used as a reverse proxy – .htaccess from apache should still work. Sadly – my understanding of it was not exactly correct – some parts work and others don't it seems.

So I tried to do a basic re-write with .htaccess

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^/?index.* /fp/ [P]

I find that using the [P] flag in .htaccess instead of a normal re-write – results in an error that /index.html can't be found (which there isn't any index.html on the entire site so clearly it can't be found).

I tried using the [L] flag as well, but instead of that silently forwarding as I would expect it instead did a redirect so the user could see /fp/ in the address bar – not the outcome I was looking for.

So – I moved the redirect up to the nginx config. That seemed to work okay.

The nginx redirect I did do was very basic using an if statement

    if ($uri = '/'){
        rewrite / /fp/ break;
    }

This redirect only redirects on / not on /index.php or any other files.

Next I have a file called /login.php. I want to forward a user to https:// if the are accessing via http://

So I tried to do an apache scheme check with $_SERVER['REQUEST_SCHEME']; The problem is – that's returning http whether its https:// or http://

The login.php is in /

So for starters, how can I get the http to redirect to https only on the login.php page.

I should also note I attempted to do a redirect from http to https with .htaccess but as the server is returning http and never https that resulted in an infinite loop.

That aside, why is it that the apache .htaccess [P] flag results in searching for an index.html and why do silect redirects suddenly become public?

If I need to show my configs – please tell me which ones 🙂

UPDATING TO SHOW CONFIG

nginx.conf

server {
proxy_pass_request_headers      on;
index index.php;
listen      192.227.210.138:80;
server_name adsactlyhits.com www.adsactlyhits.com;
error_log  /var/log/apache2/domains/adsactlyhits.com.error.log error;

location / {
    if ($uri = '/'){
        rewrite / /fp/ break;
    }
    proxy_pass      http://192.227.210.138:8080;
    location ~* ^.+\.(jpeg|jpg|png|gif|bmp|ico|svg|tif|tiff|css|js|ttf|otf|webp|woff|txt|csv|rtf|doc|docx|xls|xlsx|ppt|pptx|odf|odp|ods|odt|pdf|psd|ai|eot|eps|ps|zip|tar|tgz|gz|rar|bz2|7z|aac|m4a|mp3|mp4|ogg|wav|wma|3gp|avi|flv|m4v|mkv|mov|mpeg|mpg|wmv|exe|iso|dmg|swf)$ {
        root           /home/adsactly/web/adsactlyhits.com/public_html;
        access_log     /var/log/apache2/domains/adsactlyhits.com.log combined;
        access_log     /var/log/apache2/domains/adsactlyhits.com.bytes bytes;
        expires        max;
        try_files      $uri @fallback;
    }
}

location /error/ {
    alias   /home/adsactly/web/adsactlyhits.com/document_errors/;
}

location @fallback {
    proxy_pass      http://192.227.210.138:8080;
}
location ~ /\.svn/  {return 404;}
location ~ /\.git/  {return 404;}
location ~ /\.hg/   {return 404;}
location ~ /\.bzr/  {return 404;}

include /home/adsactly/conf/web/nginx.adsactlyhits.com.conf*;
}

snginx.conf

server {
listen      192.227.210.138:443;
server_name adsactlyhits.com www.adsactlyhits.com;
ssl         on;
ssl_certificate      /home/adsactly/conf/web/ssl.adsactlyhits.com.pem;
ssl_certificate_key  /home/adsactly/conf/web/ssl.adsactlyhits.com.key;
error_log  /var/log/apache2/domains/adsactlyhits.com.error.log error;

location / {
    if ($uri = '/'){
        rewrite / /fp/ break;
    }

    proxy_pass      http://192.227.210.138:8080;
    proxy_cache cache;
    proxy_cache_valid 15m;
    proxy_cache_valid 404 1m;
    proxy_no_cache $no_cache;
    proxy_cache_bypass $no_cache;
    proxy_cache_bypass $cookie_session $http_x_update;

    location ~* ^.+\.(jpeg|jpg|png|gif|bmp|ico|svg|tif|tiff|css|js|ttf|otf|webp|woff|txt|csv|rtf|doc|docx|xls|xlsx|ppt|pptx|odf|odp|ods|odt|pdf|psd|ai|eot|eps|ps|zip|tar|tgz|gz|rar|bz2|7z|aac|m4a|mp3|mp4|ogg|wav|wma|3gp|avi|flv|m4v|mkv|mov|mpeg|mpg|wmv|exe|iso|dmg|swf)$ {
        proxy_cache    off;
        root           /home/adsactly/web/adsactlyhits.com/public_html;
        access_log     /var/log/apache2/domains/adsactlyhits.com.log combined;
        access_log     /var/log/apache2/domains/adsactlyhits.com.bytes bytes;
        expires        max;
        try_files      $uri @fallback;
    }
}

location /error/ {
    alias   /home/adsactly/web/adsactlyhits.com/document_errors/;
}

location @fallback {
    proxy_pass      http://192.227.210.138:8080;
}

location ~ /\.ht    {return 404;}
location ~ /\.svn/  {return 404;}
location ~ /\.git/  {return 404;}
location ~ /\.hg/   {return 404;}
location ~ /\.bzr/  {return 404;}

include /home/adsactly/conf/web/nginx.adsactlyhits.com.conf*;
}

http://theurl.com/test.php

<?php echo $_SERVER['REQUEST_SCHEME']; ?>

returns: http

https://theurl.com/test.php

<?php echo $_SERVER['REQUEST_SCHEME']; ?>

returns: http

Best Answer

So for starters, how can I get the http to redirect to https only on the login.php page

The key is different server blocks for http and https. If you serve from a single server block you have more limited control. Something like this should work.

server {
  server_name example.com;
  listen 80; 

  location = login.php {
    return 302 https://example.com/login.php;
  }
}

server {
  server_name example.com;
  listen 443 ssl;

  # define any locations required
}

Bigger picture, you should just serve your entire site over https to avoid these problems, unless there's a very good reason you must use http. Your application might have to be aware of the site being segmented across http and https to support this setup.

Also, Nginx and Apache together is usually unnecessary. Nginx can do most things Apache can do, and using both adds to complexity.

Any time you find yourself needing to use "if" in Nginx you should think about the Nginx "if is evil" article. I do use if, but only to set variables for control caching directives, not for anything critical or flow related. You should avoid using "if" wherever possible.

Update

This article shows you how to pass headers such as protocol on to the next layer so it knows the original protocol. You'd be better off getting rid of Apache entirely and having Nginx call PHP using php-fpm.

location / {
  proxy_set_header HOST $host;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

  proxy_pass http://example.com/new/prefix;
}

Removing that If redirect

Instead of this

location / {
  if ($uri = '/'){
    rewrite / /fp/ break;
  }
  // etc
}

You could try something like this. The equals operator is an exact match operator. This will give better performance (slightly) and more reliable operation.

location = / {
    rewrite / /fp/ break;
}

location / {
  // etc
}

I haven't used rewrite myself so I don't know if that's the best way to do whatever it is you're trying to do.