การจัดการกับ nginx 400 ข้อผิดพลาด“ คำขอ HTTP ธรรมดาถูกส่งไปยังพอร์ต HTTPS”


115

ฉันใช้งานแอป Sinatra หลังผู้โดยสาร / nginx ฉันกำลังพยายามทำให้มันตอบสนองต่อการโทรทั้ง http และ https ปัญหาคือเมื่อกำหนดทั้งสองอย่างในการโทร https บล็อกเซิร์ฟเวอร์จะได้รับการตอบสนองตามปกติ แต่ http ให้ข้อผิดพลาด 400 "คำขอ HTTP ธรรมดาถูกส่งไปยังพอร์ต HTTPS" นี่คือหน้าคงที่ดังนั้นฉันเดาว่าซินาตร้าไม่เกี่ยวข้องกับสิ่งนี้ มีแนวคิดในการแก้ไขปัญหานี้อย่างไร

นี่คือบล็อกเซิร์ฟเวอร์:

server {
        listen 80;
        listen 443  ssl;
        server_name localhost;
        root /home/myhome/app/public;
        passenger_enabled on;

        ssl on;
        ssl_certificate      /opt/nginx/ssl_keys/ssl.crt;
        ssl_certificate_key  /opt/nginx/ssl_keys/ssl.key;
        ssl_protocols        SSLv3 TLSv1;
        ssl_ciphers          HIGH:!aNULL:!MD5;

        location /static {
            root  /home/myhome/app/public;
            index  index.html index.htm index.php;
        }

        error_page 404 /404.html;

        # redirect server error pages to the static page /50x.html
        error_page 500 /500.html;

        access_log /home/myhome/app/logs/access.log;
        error_log /home/myhome/app/logs/error.log;
}

ในกรณีของฉันคือ url ในเบราว์เซอร์: my.example.com:443ไม่ทำงาน เปลี่ยนสิ่งนั้นแทนให้https://my.example.comได้ผล แปลกไม่เคยมีปัญหากับ apache นี้
Sebastian

1
ssl on;บอก NGINX ไปยังเซิร์ฟเวอร์เนื้อหาใด ๆผ่าน SSL ใช้แฟล็ก "ssl" ต่อท้ายlisten 443;เช่นlisten 443 ssl;หากเซิร์ฟเวอร์ของคุณส่งทั้งการรับส่งข้อมูล http และ https และลบssl on;คำสั่ง
Stphane

คำตอบ:


195

ฉันพบปัญหาที่คล้ายกัน ทำงานบนเซิร์ฟเวอร์เดียวและไม่ได้อยู่บนเซิร์ฟเวอร์อื่นที่มีการกำหนดค่า Nginx เดียวกัน พบวิธีแก้ปัญหาที่ Igor ตอบที่นี่http://forum.nginx.org/read.php?2,1612,1627#msg-1627

ใช่. หรือคุณอาจรวมเซิร์ฟเวอร์ SSL / ไม่ใช่ SSL ไว้ในเซิร์ฟเวอร์เดียว:

server {
  listen 80;
  listen 443 default ssl;

  # ssl on   - remember to comment this out

}

ตามสิ่งที่ rapam iosif พูดอย่าลืมใส่ด้วยssl off;
aceofspades

20
คุณจะต้องลบบรรทัดเท่านั้นssl on;(ไม่จำเป็นต้องเพิ่ม ssl ปิด) นอกจากนี้ตั้งแต่ผมจำไม่ได้ว่ารุ่น Nginx, มีความจำเป็นมากขึ้นในการใช้งานdefaultบนlisten 443บรรทัด ดังนั้นการกำหนดค่า OP ก็โอเคจำเป็นต้องลบเท่านั้นssl onและควรใช้งานได้
laurent

@bobojam อย่าลังเลที่จะรวมคำอธิบายจากคำตอบของฉันเพื่อที่คุณจะได้สมบูรณ์ยิ่งขึ้น ฉันขอให้ผู้เขียน OP ยอมรับคำตอบของคุณ
Alexander Azarov

2
มันไม่แก้วัตถุประสงค์ SSL ssl onโดยการแสดงความคิดเห็น @ MichaelJ.Evans คำตอบด้านล่างเป็นทางออกที่ดีกว่ามาก
Neel

1
ดูเหมือนจะไม่ทำงานกับไฟล์ conf หลายไฟล์ กล่าวว่ามีค่าเริ่มต้นที่ซ้ำกัน 2 ค่า ใช้วิธีแก้ปัญหาของ Alexander
Ryall

39

คำตอบข้างต้นไม่ถูกต้องเนื่องจากการทดสอบ "คือการเชื่อมต่อ HTTPS" มากเกินไปเพื่ออนุญาตให้แสดงหน้าเว็บผ่าน http โดยไม่คำนึงถึงความปลอดภัยของการเชื่อมต่อ

คำตอบที่ปลอดภัยโดยใช้หน้าแสดงข้อผิดพลาดบนรหัสข้อผิดพลาด http 4xx เฉพาะของ NGINX เพื่อเปลี่ยนเส้นทางไคลเอ็นต์เพื่อลองคำขอเดียวกันกับ https อีกครั้ง (ตามที่อธิบายไว้ที่นี่/server/338700/redirect-http-mydomain-com12345-to-https-mydomain-com12345-in-nginx )

OP ควรใช้:

server {
  listen        12345;
  server_name   php.myadmin.com;

  root         /var/www/php;

  ssl           on;

  # If they come here using HTTP, bounce them to the correct scheme
  error_page 497 https://$host:$server_port$request_uri;

  [....]
}

1
คุณอาจต้องการ $ server_name แทนที่จะเป็น $ host เซิร์ฟเวอร์_nameน่าจะถูกตั้งค่าเป็น CN ที่ใบรับรอง SSL รับรองความถูกต้อง ด้วยวิธีนี้ผู้ใช้จะไม่ได้รับหน้าจอที่น่ากลัวหากเข้ามาทาง IP หรือ localhost
George

ฉันพยายามใช้สิ่งนี้กับการติดตั้งGitLabในเครื่องของฉันแต่ใช้การแทรกการตั้งค่า NGINX ที่กำหนดเองลงในวิธีการบล็อกเซิร์ฟเวอร์ GitLabจึงnginx['custom_gitlab_server_config'] = "error_page 497 https://$host:$server_port$request_uri;"เป็นเคล็ดลับ
Aaron C

17

ข้อผิดพลาดบอกว่าทั้งหมดเป็นจริง การกำหนดค่าของคุณบอกให้ Nginx ฟังบนพอร์ต 80 (HTTP) และใช้ SSL เมื่อคุณชี้เบราว์เซอร์ไปที่เบราว์เซอร์จะhttp://localhostพยายามเชื่อมต่อผ่าน HTTP เนื่องจาก Nginx ต้องการ SSL จึงบ่นพร้อมกับข้อผิดพลาด

วิธีแก้ปัญหานั้นง่ายมาก คุณต้องมีสองserverส่วน:

server {
  listen 80;

  // other directives...
}

server {
  listen 443;

  ssl on;
  // SSL directives...

  // other directives...
}

7
คุณไม่จำเป็นต้องมีเซิร์ฟเวอร์สองส่วน ลบบรรทัด "ssl on" และเปลี่ยนสายการฟังตามคำตอบของ @bobojam
toxaq

12

ฉันมีปัญหาเดียวกันแน่นอนฉันมีการกำหนดค่าแบบเดียวกับตัวอย่างของคุณและฉันทำให้มันใช้งานได้โดยลบบรรทัด:

ssl on;

ในการอ้างอิงเอกสาร:

หากเซิร์ฟเวอร์ HTTP และ HTTPS เท่ากันเซิร์ฟเวอร์เดียวที่จัดการทั้งคำขอ HTTP และ HTTPS อาจได้รับการกำหนดค่าโดยการลบคำสั่ง“ ssl on” และเพิ่มพารามิเตอร์ ssl สำหรับพอร์ต *: 443


1
มีโอกาสที่คุณจะมีลิงค์ไปยัง doc หรือไม่?
Adam Parkin

12

ตามที่บทความวิกิพีเดียเกี่ยวกับรหัสสถานะ Nginx มีรหัสข้อผิดพลาดที่กำหนดเองเมื่อการรับส่งข้อมูล http ถูกส่งไปยังพอร์ต https (รหัสข้อผิดพลาด 497)

และตามเอกสาร nginx ใน error_pageคุณสามารถกำหนด URI ที่จะแสดงสำหรับข้อผิดพลาดเฉพาะ
ดังนั้นเราสามารถสร้าง uri ที่ลูกค้าจะถูกส่งไปเมื่อรหัสข้อผิดพลาด 497 ถูกยกขึ้น

nginx.conf

#lets assume your IP address is 89.89.89.89 and also 
#that you want nginx to listen on port 7000 and your app is running on port 3000

server {
    listen 7000 ssl;
 
    ssl_certificate /path/to/ssl_certificate.cer;
    ssl_certificate_key /path/to/ssl_certificate_key.key;
    ssl_client_certificate /path/to/ssl_client_certificate.cer;

    error_page 497 301 =307 https://89.89.89.89:7000$request_uri;

    location / {
        proxy_pass http://89.89.89.89:3000/;

        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
    }
}

อย่างไรก็ตามหากลูกค้าทำการร้องขอด้วยวิธีการอื่นใดยกเว้น GET คำขอนั้นจะกลายเป็น GET ดังนั้นเพื่อรักษาวิธีการร้องขอที่ลูกค้าเข้ามาทาง; เราใช้ข้อผิดพลาดในการประมวลผลการเปลี่ยนเส้นทางดังที่แสดงในเอกสาร nginx บน error_page

และนั่นคือเหตุผลที่เราใช้การ301 =307เปลี่ยนเส้นทาง

การใช้ไฟล์ nginx.conf ที่แสดงที่นี่เราสามารถรับฟัง http และ https บนพอร์ตเดียวกันได้


สิ่งนี้ใช้ได้กับฉัน - error_page 497 301 = 307 89.89.89.89:7000$request_uri ;
ugali soft

7

นี่คือตัวอย่างการกำหนดค่าHTTPและHTTPSในบล็อกการกำหนดค่าเดียวกันที่รองรับipv6 การกำหนดค่าได้รับการทดสอบในUbuntu ServerและNGINX / 1.4.6แต่ควรใช้ได้กับเซิร์ฟเวอร์ทั้งหมด

server {
    # support http and ipv6
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    # support https and ipv6
    listen 443 default_server ssl;
    listen [::]:443 ipv6only=on default_server ssl;

    # path to web directory
    root /path/to/example.com;
    index index.html index.htm;

    # domain or subdomain
    server_name example.com www.example.com;

    # ssl certificate
    ssl_certificate /path/to/certs/example_com-bundle.crt;
    ssl_certificate_key /path/to/certs/example_com.key;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
    ssl_prefer_server_ciphers on;
}

อย่ารวมssl onสิ่งที่อาจทำให้เกิด400ข้อผิดพลาด การกำหนดค่าด้านบนควรใช้งานได้

http://example.com

http://www.example.com

https://example.com

https://www.example.com

หวังว่านี่จะช่วยได้!



4

จริงๆแล้วคุณสามารถทำได้ด้วย:

ssl off; 

สิ่งนี้ช่วยแก้ปัญหาของฉันในการใช้ nginxvhosts; ตอนนี้ฉันสามารถใช้ทั้ง SSL และ HTTP ธรรมดา ใช้งานได้แม้กับพอร์ตรวม


ใช้ได้กับฉันบน nginx / 1.6.3 :)
djthoms
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.