ฉันมีหน้าลงทะเบียนในโดเมนย่อยเช่น: https://signup.example.com

ควรเข้าถึงได้ผ่าน HTTPS เท่านั้น แต่ฉันกังวลว่าผู้คนอาจสะดุดผ่าน HTTP และรับ 404

html/server block ของฉันใน nginx มีลักษณะดังนี้:

html {
  server {
    listen 443;
    server_name signup.example.com;

    ssl                        on;
    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

    ssl_session_timeout 30m;

    location / {
      root /path/to/my/rails/app/public;
      index index.html;
        passenger_enabled on;
    }
  }
}

ฉันจะเพิ่มอะไรได้บ้างเพื่อให้คนที่ไปhttp://signup.example.comถูกเปลี่ยนเส้นทางไปที่https://signup.example.com? (สำหรับข้อมูล ฉันรู้ว่ามีปลั๊กอิน Rails ที่สามารถบังคับได้SSLแต่หวังว่าจะหลีกเลี่ยงได้)

answer

ตามข้อผิดพลาดของ nginxเป็นการดีกว่าเล็กน้อยที่จะละเว้นการจับภาพที่ไม่จำเป็นโดยใช้$request_uriแทน ในกรณีนั้น ให้ผนวกเครื่องหมายคำถามเพื่อป้องกันไม่ให้ nginx เพิ่ม args ของข้อความค้นหาเป็นสองเท่า

server {
    listen      80;
    server_name signup.mysite.com;
    rewrite     ^   https://$server_name$request_uri? permanent;
}

วิธีที่ดีที่สุดตามที่อธิบายไว้ในวิธีการอย่างเป็นทางการคือการใช้returnคำสั่ง:

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

นี่เป็นวิธีที่ถูกต้องและมีประสิทธิภาพมากที่สุด หากคุณต้องการเก็บทุกอย่างไว้ในบล็อกเซิร์ฟเวอร์เดียว:

server {
    listen   80;
    listen   [::]:80;
    listen   443 default_server ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

    if ($scheme = http) {
        return 301 https://$server_name$request_uri;
    }
}

อย่างอื่นข้างต้น การใช้ "rewrite" หรือ "if ssl_protocol" ฯลฯ จะช้าลงและแย่ลง

นี่ก็เหมือนกัน แต่มีประสิทธิภาพมากกว่า เพียงรันการเขียนซ้ำบนโปรโตคอล http เท่านั้น เพื่อหลีกเลี่ยงไม่ให้ต้องตรวจสอบตัวแปร $scheme ในทุกคำขอ แต่อย่างจริงจัง มันเป็นเรื่องเล็กน้อยที่คุณไม่จำเป็นต้องแยกจากกัน

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

    server_name www.example.com;

    return 301 https://$server_name$request_uri;
}
server {
    listen   443 default_server ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;
}

หากคุณกำลังใช้นิยามเซิร์ฟเวอร์ HTTP และ HTTPS คู่ใหม่ คุณสามารถใช้สิ่งต่อไปนี้:

server {
    listen   80;
    listen   [::]:80;
    listen   443 default ssl;

    server_name www.example.com;

    ssl_certificate        /path/to/my/cert;
    ssl_certificate_key  /path/to/my/key;

    if ($ssl_protocol = "") {
       rewrite ^   https://$server_name$request_uri? permanent;
    }
}

ดูเหมือนว่าจะใช้ได้สำหรับฉันและไม่ทำให้เกิดการวนซ้ำของการเปลี่ยนเส้นทาง

แก้ไข:

แทนที่:

rewrite ^/(.*) https://$server_name/$1 permanent;

กับแนวรีไรท์ของแพรติก

อีกตัวแปรหนึ่งที่รักษา Host: ขอส่วนหัวและทำตามตัวอย่าง "GOOD" ในข้อผิดพลาด nginx :

server {
    listen   10.0.0.134:80 default_server;

    server_name  site1;
    server_name  site2;
    server_name  10.0.0.134;

    return 301 https://$host$request_uri;
}

นี่คือผลลัพธ์ โปรดทราบว่าการใช้$server_nameแทน$hostจะเปลี่ยนเส้นทางไปที่https://site1.

# curl -Is http://site1/ | grep Location
Location: https://site1/

# curl -Is http://site2/ | grep Location
Location: https://site2/


# curl -Is http://site1/foo/bar | grep Location
Location: https://site1/foo/bar

# curl -Is http://site1/foo/bar?baz=qux | grep Location
Location: https://site1/foo/bar?baz=qux
server {
    listen x.x.x.x:80;

    server_name domain.tld;
    server_name www.domian.tld;
    server_name ipv4.domain.tld;

    rewrite     ^   https://$server_name$request_uri? permanent;
}

มันใช้งานได้ดีกว่าฉันคิดว่า xxxx หมายถึง IP ของเซิร์ฟเวอร์ของคุณ หากคุณกำลังทำงานกับ Plesk 12 คุณสามารถทำได้โดยเปลี่ยนไฟล์ "nginx.conf" ในไดเร็กทอรี "/var/www/vhosts/system/domain.tld/conf" สำหรับโดเมนใดก็ได้ที่คุณต้องการ อย่าลืมรีสตาร์ทบริการ nginx หลังจากที่คุณบันทึกการกำหนดค่า

ฉันคิดว่านี่เป็นวิธีแก้ปัญหาที่ง่ายที่สุด บังคับทั้งทราฟฟิกที่ไม่ใช่ HTTPS และไม่ใช่ WWW ไปยัง HTTPS และ www เท่านั้น

server {
    listen 80;
    listen 443 ssl;

    server_name domain.tld www.domain.tld;

    # global HTTP handler
    if ($scheme = http) {
        return 301 https://www.domain.tld$request_uri;
    }

    # global non-WWW HTTPS handler
    if ($http_host = domain.tld) {
        return 303 https://www.domain.tld$request_uri;
    }
}

แก้ไข - เม.ย. 2018: โซลูชันที่ไม่มี IF สามารถพบได้ในโพสต์ของฉันที่นี่: https://stackoverflow.com/a/36777526/6076984