เปลี่ยนเส้นทางไม่ใช่ www ไปยัง www ผ่าน SSL ด้วย Nginx


25

ฉันมีข้อผิดพลาดเมื่อพยายามที่จะเปลี่ยนเส้นทางhttps://example.comเพื่อhttps://www.example.com

เมื่อฉันไปที่https://example.comจะไม่เปลี่ยนเส้นทางและส่งคืนสถานะหน้า / 200

ฉันไม่ต้องการที่นี้ผมต้องการให้เปลี่ยนเส้นทางไปยังhttps://www.example.com

เมื่อฉันไปที่http://example.comมันจะเปลี่ยนเส้นทางไปที่https://www.example.com

ใครสามารถบอกฉันได้ว่าฉันกำลังทำผิดอยู่ที่ไหน?

นี่คือไฟล์คอนฟิกูเรชันดีฟอลต์และ default-ssl ของฉัน:

default.conf

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

เริ่มต้น ssl.conf

upstream app_server_ssl {
    server unix:/tmp/unicorn.sock fail_timeout=0;
}

server {
    server_name example.com;
    return 301 https://www.example.com$request_uri
}
server {
    server_name www.example.com;

    listen 443;
    root /home/app/myproject/current/public;
    index index.html index.htm;

    error_log /srv/www/example.com/logs/error.log info;
    access_log /srv/www/example.com/logs/access.log combined;

    ssl on;
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_certificate /srv/www/example.com/keys/ssl.crt;
    ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
    ssl_ciphers AES128-SHA:RC4-MD5:ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5:AES128-SHA;
    ssl_prefer_server_ciphers on;

    client_max_body_size 20M;


    try_files $uri/index.html $uri.html $uri @app;


    # CVE-2013-2028 http://mailman.nginx.org/pipermail/nginx-announce/2013/000112.html
    if ($http_transfer_encoding ~* chunked) {
            return 444;
        }

    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server_ssl;
    }

    error_page 500 502 503 504 /500.html;

    location = /500.html {
        root /home/app/example/current/public;
    }
}

1
จุดประสงค์ในการสร้างไฟล์ 2 conf คืออะไร?
Sandip Subedi

การแยกข้อกังวลการกำหนดค่าที่ไม่ใช่ SSL มีขนาดเล็กมากจนดูดีที่สุดที่จะแยกมันออกจากการกำหนดค่า SSL เท่านั้น
Thomas V.

คำตอบ:


34

คุณจะหายไปสั่งในไฟล์listen default-ssl.confเพิ่มlisten 443;ในคำสั่งนี้

server {
    server_name example.com;
    return 301 https://www.example.com$request_uri;
}

ตามค่าเริ่มต้นหากคุณไม่ใช้คำสั่งนี้ nginx จะถือว่าคุณต้องการฟังพอร์ต 80 นี่คือเอกสารของพฤติกรรมเริ่มต้นนี้


แก้ไข: ขอบคุณสำหรับความคิดเห็นจาก @TeroKilkanen

นี่คือการกำหนดค่าที่สมบูรณ์สำหรับ default-ssl.conf ของคุณ

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /srv/www/example.com/keys/ssl.crt;
    ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
    return 301 https://www.example.com$request_uri;
}

Sidenote : คุณสามารถแทนที่ssl on;คำสั่งด้วยlisten 443 ssl;เป็นคำแนะนำจากเอกสารคู่มือnginx


4
คุณต้องตั้งค่าssl_certificateและssl_certificate_keyสั่งการในบล็อกนี้และใช้listen 443 ssl;เพื่อเป็น SSL vhost
Tero Kilkanen

default-ssl.confกรุณาโพสต์เนื้อหาของปัจจุบัน อาจมีปัญหาการพิมพ์ผิดหรือสั่งซื้อใหม่เกิดขึ้นได้
masegaloeh

นี่เป็นเรื่องที่น่าอาย: \ ผู้ร้ายคือการกำหนดค่า nginx ที่ซ้ำกันใน / etc / nginx / sites-enabled, /etc/nginx/sites-enabled/default-ssl.backup มีการแทรกแซงการเปลี่ยนเส้นทางใด ๆ ใน default-ssl ข้อผิดพลาดโง่
โทมัส V.

ดังนั้นฉันจึงต้องออก 2 certs: สำหรับ www-domain และสำหรับ non-www one
vladkras

วิธีนี้สามารถทำได้ในพูดพอร์ต 5007: example.com:5007เพื่อ example.com:5007
CP3O

5

เพียงแค่ใส่คำสั่ง if และคุณควรจะไป ฉันตรวจสอบผลลัพธ์ใน curl.exe -I และทุกกรณีนอกเหนือจากhttps://www.example.comรับการรักษาเป็น 301 SSL นั้นค่อนข้างยุ่งยากเพราะจะได้รับการตรวจสอบก่อนที่คุณจะได้รับการเปลี่ยนเส้นทาง 301 URL ดังนั้นคุณจะได้รับข้อผิดพลาดของใบรับรอง

โดยส่วนตัวฉันชอบลบ www จากโดเมน แต่ฉันเขียนรหัสด้านล่างเพื่อตอบคำถามของคุณ

server {
listen 443 ssl;
listen [::]:443 ssl; # IPV6

server_name example.com www.example.com; # List all variations here

# If the domain is https://example.com, lets fix it!

if ($host = 'example.com') {
  return 301 https://www.example.com$request_uri;
}

# If the domain is https://www.example.com, it's OK! No changes necessary!

... # SSL .pem stuff
...
}

server {
listen 80;
listen [::]:80;

# If the domain is http://example.com or https://www.example.com, let's change it to https!

server_name example.com www.example.com;
return 310 https://www.example.com$request_uri;
}

3

วิธีที่ฉันทำคือการใช้คำสั่ง if ในบล็อกเซิร์ฟเวอร์ ssl ซึ่งเปลี่ยนเส้นทางไปที่ https ของ www

ssl_certificate /srv/www/example.com/keys/ssl.crt;
ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:RC4-MD5:ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5:AES128-SHA;
ssl_prefer_server_ciphers on;
client_max_body_size 20M;

upstream app_server_ssl {
    server unix:/tmp/unicorn.sock fail_timeout=0;
}

server {
    server_name example.com;
    return 301 https://www.example.com$request_uri
}

server {
    listen 443 default_server ssl;
    server_name www.example.com;

    # redirect https://example.com to https://www.example.com
    # mainly for SEO purposes etc
    #we will use a variable to do that
    set $redirect_var 0;

    if ($host = 'example.com') {
      set $redirect_var 1;
    }
    if ($host = 'www.example.com') {
      set $redirect_var 1;
    }

    if ($redirect_var = 1) {
      return 301 https://www.example.com$request_uri;
    } 

    try_files $uri/index.html $uri.html $uri @app;

    # CVE-2013-2028 http://mailman.nginx.org/pipermail/nginx-announce/2013/000112.html
    if ($http_transfer_encoding ~* chunked) {
            return 444;
        }

    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server_ssl;
    }

    error_page 500 502 503 504 /500.html;

    location = /500.html {
        root /home/app/example/current/public;
    }
}

แน่นอนทุกครั้งที่คุณต้องการใช้คำสั่ง if ในไฟล์ nginx config; คุณควรอ่าน: https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/


เงื่อนไขif ($host = 'www.example.com')ไม่จำเป็น
Karl.S

2

ตอนนี้มันเป็นปี 2018 และฉันคิดว่าจะให้สิ่งนี้กับการยิงใหม่ในกรณีที่บางคนกำลังมองหาทางออกที่ง่าย

สิ่งที่ฉันทำในฐานะผู้มาใหม่ค่อนข้างจะทำสิ่งที่ง่ายที่สุดเท่าที่จะทำได้ โดยทั่วไปคุณต้องการเปลี่ยนเส้นทางทั้งhttp://example.comและhttps://example.comเป็นhttps : // www .example.com และคุณประสบความสำเร็จในการเปลี่ยนเส้นทางhttp://example.com เท่านั้น

นี่เป็นการดำเนินการที่ค่อนข้างตรงไปตรงมาซึ่งต้องการเซิร์ฟเวอร์บล็อกเพียงสองบล็อกเท่านั้น (ฉันจะแสดงให้เห็นสั้น ๆ นี้ในไฟล์ config เดียว)

# 1. Server block to redirect all non-www and/or non-https to https://www
server {
    # listen to the standard http port 80
    listen 80; 

    # Now, since you want to route https://example.com to http://www.example.com....
    # you need to get this block to listen on https port 443 as well
    # alternative to defining 'ssl on' is to put it with listen 443
    listen 443 ssl; 

    # define server_name
    server_name example.com *.example.com; 

    # DO NOT (!) forget your ssl certificate and key
    ssl_certificate PATH_TO_YOUR_CRT_FILE;
    ssl_certificate_key PATH_TO_YOUR_KEY_FILE; 

    # permanent redirect
    return 301 https://www.example.com$request_uri;  
    # hard coded example.com for legibility 
}
# end of server block 1. nearly there....

# 2. Server block for the www (primary) domain
# note that this is the block that will ultimately deliver content
server {
    # define your server name
    server_name www.example.com; 

    # this block only cares about https port 443
    listen 443 ssl;

    # DO NOT (!) forget your ssl certificate and key
    ssl_certificate PATH_TO_YOUR_CRT_FILE;
    ssl_certificate_key PATH_TO_YOUR_KEY_FILE; 

    # define your logging .. access , error , and the usual 

    # and of course define your config that actually points to your service
    # i.e. location / { include proxy_params; proxy_pass PATH_TO_SOME_SOCKET; }
}
# End of block 2.
# voilà! 

ตอนนี้ทั้งสองhttp://example.comและhttps://example.comควรเปลี่ยนเส้นทางไปยังhttps://www.example.com โดยทั่วไปการตั้งค่านี้เปลี่ยนเส้นทางทุกอย่างที่ไม่ใช่ www และ / หรือไม่ https เพื่อhttps: // www


-1

หากต้องการเปลี่ยนเส้นทางคำขอทั้งหมดไปที่ https://www.example

สร้างบล็อกเซิร์ฟเวอร์สำหรับการเปลี่ยนเส้นทางและโดเมนหลักบนพอร์ต SSL ของคุณ (โดยทั่วไปคือ 443) รวมถึง http พอร์ตเริ่มต้น 80

# non-www to ssl www redirect
server {
  listen 80; 
  listen 443 ssl;
  server_name example.com;
  return 301 https://www.example.com$request_uri;
  # ... ssl certs
}

# ssl setup for www (primary) domain
server {
  listen 80;
  listen 443 ssl;
  server_name www.example.com;
  if ($scheme = http) {
    return 301 https://www.example.com$request_uri;
  }
  # ... the rest of your config + ssl certs
}

บันทึกและติดตามด้วย sudo nginx -s reload

สิ่งนี้จะเปลี่ยนเส้นทาง

http://example      301 -> https://www.example
https://example     301 -> https://www.example
http://www.example  301 -> https://www.example
https://www.example 200

คุณกำลังขาด a ;ในเซิร์ฟเวอร์บล็อกที่สองใน if clause มันควรจะเป็นreturn 301 https://www.example.com$request_uri;
Lukas Oppermann

1
อย่างไรก็ตามมันจะใช้งานได้หรือไม่ ก็สามารถฟังhttpได้ที่443?
Lukas Oppermann

คุณพูดถูกฉันฟัง 80, ive เพิ่มเข้าไป
lfender6445
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.