So I'm setting up an nginx server and installed wordpress and SSL.
The site is working perfectly on both http and https but when I try to redirect http to https via nginx's server block, both http and https results in a endless redirect loop.
Here's my server block
server {
listen 80;
return 301 $server_name$request_uri;
listen 443 ssl spdy;
root /var/www/wordpress;
index index.php index.html index.htm;
server_name www.example.com;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 10m;
spdy_headers_comp 6;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_certificate /etc/ssl/certs/www.example.com.certchain.crt;
ssl_certificate_key /etc/ssl/private/www.example.com.key;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
add_header Alternate-Protocol 443:npn-spdy/2;
proxy_set_header X-Forwarded-Proto https;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
location / {
proxy_set_header X-Forwarded-Proto $scheme;
# try_files $uri $uri/ =404;
try_files $uri $uri/ /index.php?q=$uri&$args;
if ($http_referer ~* (buttons-for-website.com)) { return 444; }
if ($http_referer ~* (semalt.com)) { return 444; }
}
location ~ \.(hh|php)$ {
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
fastcgi_keep_conn on;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache microcache;
fastcgi_cache_valid 200 60m;
}
location ~ \.php$ {
location @fallback {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache microcache; fastcgi_cache_valid 200 60m;
}
# Cache Static Files For As Long As Possible
location ~*
\.(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|$
{
access_log off;
log_not_found off;
expires max;
}
# Security Settings For Better Privacy Deny Hidden Files
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# Return 403 Forbidden For readme.(txt|html) or license.(txt|html)
if ($request_uri ~* "^.+(readme|license)\.(txt|html)$") {
return 403;
}
# Disallow PHP In Upload Folder
location /wp-content/uploads/ {
location ~ \.php$ {
deny all;
}
}
}
I'd really appreciate anyone's help. I commented out that "return 301" in 3rd line and google indexed both http and https version of the same page and deindexed most of my pages and dropped rankings for several keywords.
Thanks a bunch in advance!
Best Answer
When Nginx processes a request, it first identifies the server block that will handle the request. This means that it will match the server_name and listen directives.
In your case, the single server block you have contains :
This will listen on both port 80 and 443. The fact that you have a return directive between the two does not matter as the return directive is not processed at this point.
Once the server block is matched, Nginx will move on to process other directives. In the case of the rewrite directives (e.g. return), they are processed in the order listed. In the case of location directives, they are processed based on specificity of match (the exact rules are listed here).
In order to implement your redirect, you should separate out your rewrite directive into a separate server block:
Note that you need to specify that you are returning the HTTPS version and not the same (HTTP) version of the page. In some cases it may be preferable to hard-code the server name (e.g. if you want to redirect www and non-www traffic to the same HTTPS page).
Edit: To address your comment:
You want content served from
https://www.example.com
and you want the following redirects:http://(www.)?example.com
redirects tohttps://www.example.com
https://example.com
redirects tohttps://www.example.com
To do this, you need 3 server blocks:
A few important points of mention:
Your SSL certificate should list both www.example.com and example.com as subject alternative names. Even though you are redirecting away from example.com, an SSL connection is still established before the redirect. Without a valid certificate for example.com the user will get an invalid certificate warning and the redirect will not occur. (This also implies that you must include the certificate in the https://example.com block)
Since having a redirect requires multiple SSL server blocks, it is preferable to move some of your SSL configuration outside the server block (into the http block). These include:
ssl_session_timeout
,ssl_session_cache
,ssl_protocols
,ssl_ciphers
,ssl_prefer_server_ciphers
,ssl_stapling
,ssl_stapling_verify
,ssl_trusted_certificate
,ssl_dhparam
, and your HSTS header. (As an aside, I highly recommend looking over Mozilla's Server Side TLS page)