Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nginx redirect Http to Https - what's wrong here?

I have an Nginx server which should redirect all requests from http://www.domain.com and http://domain.com and https://domain.com to https://www.domain.com

So with or without www and with or without ssl I want the user to always get to https://www.domain.com.

After reading the nginx documentation and researching on google this is my current nginx configuration:

server {
  listen 80;
  server_name .domain.com;
  return 301 https://www.domain.com$request_uri;
}

server {
  listen                       443 ssl;
  server_name                  .domain.com;
  ssl_certificate              /etc/ssl/private/[pem file];
  ssl_certificate_key          /etc/ssl/private/[key file];
  ssl_session_timeout          5m;
  ssl_protocols                SSLv3 TLSv1;
  ssl_ciphers                  HIGH:!ADH:!MD5;
  ssl_prefer_server_ciphers    on;
  keepalive_timeout            70;
  ###
  ### Deny known crawlers.
  ###
  if ($is_crawler) {
    return 403;
  }
  location / {
    proxy_pass                 http://nginx_http;
    proxy_redirect             off;
    proxy_set_header           Host              $host;
    proxy_set_header           X-Real-IP         $remote_addr;
    proxy_set_header           X-Forwarded-By    $server_addr:$server_port;
    proxy_set_header           X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header           X-Local-Proxy     $scheme;
    proxy_set_header           X-Forwarded-Proto $scheme;
    proxy_pass_header          Set-Cookie;
    proxy_pass_header          Cookie;
    proxy_pass_header          X-Accel-Expires;
    proxy_pass_header          X-Accel-Redirect;
    proxy_pass_header          X-This-Proto;
    proxy_connect_timeout      300;
    proxy_send_timeout         300;
    proxy_read_timeout         300;
    proxy_buffer_size          4k;
    proxy_buffers              4 32k;
    proxy_busy_buffers_size    64k;
    proxy_temp_file_write_size 64k;
    access_log                 off;
    log_not_found              off;
  }
 50 }

What happens is that requests to http://domain.com get correctly redirected to https://www.domain.com but requests to http://www.domain.com are not being redirected (and the website is delivered without ssl).

UPDATE:

As this is part of a server set up by BOA (Barracuda Octopus Aegir) there are several config files in use. This is the nginx.conf which is loaded as well:

# Aegir web server main configuration file

#######################################################
###  nginx.conf main
#######################################################

 ## FastCGI params
  fastcgi_param  SCRIPT_FILENAME     $document_root$fastcgi_script_name;
  fastcgi_param  QUERY_STRING        $query_string;
  fastcgi_param  REQUEST_METHOD      $request_method;
  fastcgi_param  CONTENT_TYPE        $content_type;
  fastcgi_param  CONTENT_LENGTH      $content_length;
  fastcgi_param  SCRIPT_NAME         $fastcgi_script_name;
  fastcgi_param  REQUEST_URI         $request_uri;
  fastcgi_param  DOCUMENT_URI        $document_uri;
  fastcgi_param  DOCUMENT_ROOT       $document_root;
  fastcgi_param  SERVER_PROTOCOL     $server_protocol;
  fastcgi_param  GATEWAY_INTERFACE   CGI/1.1;
  fastcgi_param  SERVER_SOFTWARE     ApacheSolaris/$nginx_version;
  fastcgi_param  REMOTE_ADDR         $remote_addr;
  fastcgi_param  REMOTE_PORT         $remote_port;
  fastcgi_param  SERVER_ADDR         $server_addr;
  fastcgi_param  SERVER_PORT         $server_port;
  fastcgi_param  SERVER_NAME         $server_name;
  fastcgi_param  USER_DEVICE         $device;
  fastcgi_param  GEOIP_COUNTRY_CODE  $geoip_country_code;
  fastcgi_param  GEOIP_COUNTRY_CODE3 $geoip_country_code3;
  fastcgi_param  GEOIP_COUNTRY_NAME  $geoip_country_name;
  fastcgi_param  REDIRECT_STATUS     200;
  fastcgi_index  index.php;

 ## Default index files
  index         index.php index.html;

 ## Size Limits
  client_body_buffer_size        64k;
  client_header_buffer_size      32k;
  client_max_body_size          100m;
  large_client_header_buffers 32 32k;
  connection_pool_size           256;
  request_pool_size               4k;
  server_names_hash_bucket_size  512;
  server_names_hash_max_size    8192;
  types_hash_bucket_size         512;
  map_hash_bucket_size           192;
  fastcgi_buffer_size           128k;
  fastcgi_buffers             256 4k;
  fastcgi_busy_buffers_size     256k;
  fastcgi_temp_file_write_size  256k;

 ## Timeouts
  client_body_timeout             60;
  client_header_timeout           60;
  send_timeout                    60;
  lingering_time                  30;
  lingering_timeout                5;
  fastcgi_connect_timeout         60;
  fastcgi_send_timeout           300;
  fastcgi_read_timeout           300;

 ## Open File Performance
  open_file_cache max=8000 inactive=30s;
  open_file_cache_valid          60s;
  open_file_cache_min_uses         3;
  open_file_cache_errors          on;

 ## FastCGI Caching
  fastcgi_cache_path /var/lib/nginx/speed
                     levels=2:2:2
                     keys_zone=speed:10m
                     inactive=15m
                     max_size=3g;

 ## General Options
  ignore_invalid_headers          on;
  limit_conn_zone $binary_remote_addr zone=gulag:10m;
  recursive_error_pages           on;
  reset_timedout_connection       on;
  fastcgi_intercept_errors        on;
  server_tokens                  off;
  fastcgi_hide_header         'Link';
  fastcgi_hide_header  'X-Generator';
  fastcgi_hide_header 'X-Powered-By';
  fastcgi_hide_header 'X-Drupal-Cache';

 ## TCP options moved to /etc/nginx/nginx.conf

 ## SSL performance
  ssl_session_cache   shared:SSL:10m;
  ssl_session_timeout            10m;

 ## GeoIP support
  geoip_country /usr/share/GeoIP/GeoIP.dat;

 ## Compression
  gzip_buffers      16 8k;
  gzip_comp_level   5;
  gzip_http_version 1.0;
  gzip_min_length   10;
  gzip_types        text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
  gzip_vary         on;
  gzip_proxied      any;
  add_header Vary "Accept-Encoding";
  gzip_static       on;
  upload_progress uploads 1m;

 ## Log Format
  log_format        main '"$proxy_add_x_forwarded_for" $host [$time_local] '
                         '"$request" $status $body_bytes_sent '
                         '$request_length $bytes_sent "$http_referer" '
                         '"$http_user_agent" $request_time "$gzip_ratio"';

  client_body_temp_path  /var/lib/nginx/body 1 2;
  access_log             /var/log/nginx/access.log main;
  error_log              /var/log/nginx/error.log crit;

# Extra configuration from modules:
#######################################################
###  nginx default maps
#######################################################

###
### Support separate Boost and Speed Booster caches for various mobile devices.
###
map $http_user_agent $device {
  default                                                                normal;
  ~*Nokia|BlackBerry.+MIDP|240x|320x|Palm|NetFront|Symbian|SonyEricsson  mobile-other;
  ~*iPhone|iPod|Android|BlackBerry.+AppleWebKit                          mobile-smart;
  ~*iPad|Tablet                                                          mobile-tablet;
}

###
### Set a cache_uid variable for authenticated users (by @brianmercer and @perusio, fixed by @omega8cc).
###
map $http_cookie $cache_uid {
  default  '';
  ~SESS[[:alnum:]]+=(?<session_id>[[:graph:]]+)  $session_id;
}

###
### Live switch of $key_uri for Speed Booster cache depending on $args.
###
map $request_uri $key_uri {
  default                                                                            $request_uri;
  ~(?<no_args_uri>[[:graph:]]+)\?(.*)(utm_|__utm|_campaign|gclid|source=|adv=|req=)  $no_args_uri;
}

###
### Set cache expiration depending on the Drupal core version.
###
map $sent_http_x_purge_level $will_expire_in {
  default   on-demand;
  ~*5|none  5m;
}

###
### Deny crawlers.
###
map $http_user_agent $is_crawler {
  default  '';
  ~*HTTrack|BrokenLinkCheck|2009042316.*Firefox.*3\.0\.10|MJ12|HTMLParser|libwww|PECL|Automatic|Click|SiteBot|BuzzTrack|Sistrix|Offline|Screaming|Nutch|Mireo|SWEB|Morfeus|GSLFbot  is_crawler;
}

###
### Deny all known bots on some URIs.
###
map $http_user_agent $is_bot {
  default  '';
  ~*crawl|goog|yahoo|yandex|spider|bot|tracker|click|parser  is_bot;
}

###
### Deny almost all crawlers under high load.
###
map $http_user_agent $deny_on_high_load {
  default  '';
  ~*crawl|goog|yahoo|yandex|baidu|bing|spider|tracker|click|parser  deny_on_high_load;
}

###
### Deny listed requests for security reasons.
###
map $args $is_denied {
  default  '';
  ~*delete.+from|insert.+into|select.+from|union.+select|onload|\.php.+src|system\(.+|document\.cookie|\;|\.\.  is_denied;
}

#######################################################
###  nginx default server
#######################################################

server {
  limit_conn   gulag 32; # like mod_evasive - this allows max 32 simultaneous connections from one IP address
  listen       *:80;
  server_name  _;
  location / {
     root   /var/www/nginx-default;
     index  index.html index.htm;
  }
}

#######################################################
###  nginx virtual domains
#######################################################

# virtual hosts
include /var/aegir/config/server_master/nginx/pre.d/*;
include /var/aegir/config/server_master/nginx/platform.d/*;
include /var/aegir/config/server_master/nginx/vhost.d/*;
include /var/aegir/config/server_master/nginx/post.d/*;

In the included directories at the end are some servers defined which listen to specific subdomains (set up by aegir). I think these don't affect us here.

UPDATE 2:

Thanks davismwfl and Melvyn for you input. Now it's getting interesting:

server {
  listen 80;
  server_name www.domain.com;
  return 301 https://www.domain.com$request_uri;
}

When I create a server which should only redirect http://www.domain.com to https://www.domain.com requests get redirected to https://.. and then stuck in a redirect loop.

If I understand this right for some reason the server which shall listen to port 80 also listens to https requests and tries again to redirect requests.

Do you guy know why?

Any ideas what the problem might be or why it does what it does?

Thanks a lot, Martin

like image 575
witti Avatar asked Mar 25 '23 08:03

witti


1 Answers

So, I do this the reverse way. I literally had this issue the other day. One thing is the order was found to be important, and I really should have changed the "rewrite" rules to "return 301 ..." but I got lazy and didn't do that yet as I was in a bit of a hurry.

Here is a snippet of my config

#
# Rewrite any http requests for domain.com to https.
#
server {
   listen       80;
   server_name domain.com;
   return 301 https://domain.com$request_uri;
}
#
# Rewrite any http requests for www.domain.com to domain.com
# using SSL
#
server {
   listen 80;
   server_name www.domain.com;
   rewrite ^/(.*) https://domain.com/$1 permanent;
}

#
# The domain.com website
#
server {
   listen       443 ssl;
    server_name  domain.com;

    ssl_certificate /etc/nginx/conf.d/[crt];
    ssl_certificate_key /etc/nginx/conf.d/[key];
    ... Bunches of more stuff goes here. 
}

#
# Rewrite any https requests for www.domain.com to domain.com
# Note that this must be after the domain.com declaration.
#
server {
   listen 443;
   server_name www.domain.com;
   rewrite ^/(.*) https://domain.com/$1 permanent;
}
like image 52
davismwfl Avatar answered Apr 01 '23 02:04

davismwfl