ให้เข้ารหัสด้วยพร็อกซีย้อนกลับ nginx


45

บทนำ

ฉันมีเซิร์ฟเวอร์ dev (ปัจจุบันใช้งาน Ubuntu 14.04 LTS) ซึ่งฉันใช้มาระยะหนึ่งแล้วเพื่อใช้เป็นเครื่องมือในการพัฒนาบนพอร์ตต่างๆ เนื่องจากพอร์ตอาจจำยากฉันจึงตัดสินใจใช้พอร์ต 80 สำหรับบริการทั้งหมดของฉันและทำการส่งต่อพอร์ตภายในโดยใช้ชื่อโฮสต์

แทนที่จะเขียน domain.com:5432 ฉันสามารถเข้าถึงผ่าน sub.domain.com

ตัวอย่างเช่นแอ็พพลิเคชัน X ซึ่งใช้พอร์ต 7547 และกำลังรันบน sub.domain.com มีการกำหนดค่า nginx ต่อไปนี้:

upstream sub {
    server 127.0.0.1:7547;
}

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    access_log /var/log/nginx/sub.log combined;
    location / {
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://127.0.0.1:7547;
            proxy_set_header Authorization "";
    }
}

คำถาม

กำหนดโครงสร้างการกำหนดค่าปัจจุบันที่ฉันเลือกไว้เป็นไปได้ไหมที่จะใช้ allowencrypt และใช้บริการต่าง ๆ ภายใต้ https?


3
ฉันเขียนโพสต์บล็อกในหัวข้อนี้: tom.busby.ninja/letsecnrypt-nginx-reverse-proxy-no-downtime
Tom Busby

คำตอบ:


81

ใช่คุณสามารถมีคำขอพร็อกซี nginx ไปยังเซิร์ฟเวอร์ HTTP จากนั้นตอบสนองต่อลูกค้าผ่าน HTTPS เมื่อทำสิ่งนี้คุณจะต้องแน่ใจว่าการเชื่อมต่อพร็อกซี nginx <-> ไม่น่าจะถูกดมกลิ่นโดยใครก็ตามที่เป็นผู้โจมตีที่คุณคาดหวัง วิธีที่ปลอดภัยเพียงพออาจรวมถึง:

  • พร็อกซี่ไปยังโฮสต์เดียวกัน (เช่นคุณ)
  • พร็อกซี่ไปยังโฮสต์อื่น ๆ ที่อยู่เบื้องหลังไฟร์วอลล์ของคุณ

การส่งต่อไปยังโฮสต์อื่นบนอินเทอร์เน็ตสาธารณะนั้นไม่น่าปลอดภัยพอ

นี่คือคำแนะนำในการรับใบรับรอง Let's Encrypt โดยใช้เว็บเซิร์ฟเวอร์เดียวกับที่คุณใช้เป็นพร็อกซี

การขอใบรับรองเริ่มต้นจาก Let's Encrypt

แก้ไขserverอนุประโยคของคุณเพื่ออนุญาตให้ไดเรกทอรีย่อย.well-knownให้บริการจากไดเรกทอรีท้องถิ่นเช่น:

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    […]
    location /.well-known {
            alias /var/www/sub.domain.com/.well-known;
    }

    location / {
        # proxy commands go here
        […]
    }
}

http://sub.domain.com/.well-known เป็นที่ที่เซิร์ฟเวอร์ Let's Encrypt จะค้นหาคำตอบสำหรับความท้าทายที่เกิดขึ้น

จากนั้นคุณสามารถใช้ไคลเอนต์certbotเพื่อขอใบรับรองจาก Let's Encrypt โดยใช้ปลั๊กอินwebroot (เป็น root):

certbot certonly --webroot -w /var/www/sub.domain.com/ -d sub.domain.com -d www.sub.domain.com

ตอนนี้คีย์ใบรับรองและสายใบรับรองของคุณจะได้รับการติดตั้งแล้ว /etc/letsencrypt/live/sub.domain.com/

การกำหนดค่า nginx เพื่อใช้ใบรับรองของคุณ

ขั้นแรกให้สร้างเซิร์ฟเวอร์ใหม่ข้อดังนี้:

server {
    listen 443 ssl;

    # if you wish, you can use the below line for listen instead
    # which enables HTTP/2
    # requires nginx version >= 1.9.5
    # listen 443 ssl http2;

    server_name sub.domain.com www.sub.domain.com;

    ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem;

    # Turn on OCSP stapling as recommended at 
    # https://community.letsencrypt.org/t/integration-guide/13123 
    # requires nginx version >= 1.3.7
    ssl_stapling on;
    ssl_stapling_verify on;

    # Uncomment this line only after testing in browsers,
    # as it commits you to continuing to serve your site over HTTPS
    # in future
    # add_header Strict-Transport-Security "max-age=31536000";

    access_log /var/log/nginx/sub.log combined;

    # maintain the .well-known directory alias for renewals
    location /.well-known {
        alias /var/www/sub.domain.com/.well-known;
    }

    location / {
        # proxy commands go here as in your port 80 configuration
        […]
    }
}

โหลดซ้ำ nginx:

service nginx reload

ตรวจสอบว่าตอนนี้ HTTPS ทำงานได้โดยไปที่https://sub.domain.comและhttps://www.sub.domain.comในเบราว์เซอร์ของคุณ (และเบราว์เซอร์อื่น ๆ ที่คุณต้องการให้การสนับสนุนเป็นพิเศษ) และตรวจสอบว่าพวกเขาไม่รายงานข้อผิดพลาดของใบรับรอง

แนะนำ: นอกจากนี้ยังตรวจสอบraymii.org: แข็งแกร่งรักษาความปลอดภัย SSL บน Nginx และทดสอบการตั้งค่าของคุณในSSL Labs

(แนะนำ) เปลี่ยนเส้นทางคำขอ HTTP ไปยัง HTTPS

เมื่อคุณยืนยันว่าเว็บไซต์ของคุณทำงานกับhttps://เวอร์ชันของ URL ได้แทนที่จะให้ผู้ใช้บางรายแสดงเนื้อหาที่ไม่ปลอดภัยเพราะไปแล้วให้http://sub.domain.comเปลี่ยนเส้นทางไปยังเว็บไซต์รุ่น HTTPS

แทนที่ 80 พอร์ตทั้งหมดของคุณserverด้วย:

server {
    listen 80;
    server_name sub.domain.com www.sub.domain.com;
    rewrite     ^   https://$host$request_uri? permanent;
}

ตอนนี้คุณควรยกเลิกการใส่เครื่องหมายบรรทัดนี้ในการกำหนดค่าพอร์ต 443 เพื่อให้เบราว์เซอร์จำไม่ได้ว่าจะลองใช้เว็บไซต์ HTTP เวอร์ชัน:

add_header Strict-Transport-Security "max-age=31536000";

ต่ออายุใบรับรองของคุณโดยอัตโนมัติ

คุณสามารถใช้คำสั่งนี้ (เป็น root) เพื่อต่ออายุใบรับรองทั้งหมดที่รู้จักกับ certbot และโหลด nginx โดยใช้ใบรับรองใหม่ (ซึ่งจะมีเส้นทางเดียวกันกับใบรับรองที่มีอยู่ของคุณ):

certbot renew --renew-hook "service nginx reload"

certbot จะพยายามต่ออายุใบรับรองที่มีอายุมากกว่า 60 วันเท่านั้นดังนั้นจึงปลอดภัย (และแนะนำ!) ให้เรียกใช้คำสั่งนี้เป็นประจำอย่างสม่ำเสมอและโดยอัตโนมัติหากเป็นไปได้ทั้งหมด เช่นคุณสามารถใส่คำสั่งต่อไปนี้ใน/etc/crontab:

# at 4:47am/pm, renew all Let's Encrypt certificates over 60 days old
47 4,16   * * *   root   certbot renew --quiet --renew-hook "service nginx reload"

คุณสามารถทดสอบการต่ออายุด้วยการรันแบบแห้งซึ่งจะติดต่อ Let's Encrypt staging เซิร์ฟเวอร์เพื่อทำการทดสอบการติดต่อโดเมนของคุณ แต่จะไม่เก็บใบรับรองผลลัพธ์:

certbot --dry-run renew

หรือคุณสามารถบังคับให้ต่ออายุก่อนกำหนดได้ด้วย:

certbot renew --force-renew --renew-hook "service nginx reload"

หมายเหตุ: คุณสามารถแห้งวิ่งหลายครั้งตามที่คุณต้องการ แต่การต่ออายุจริงอาจมีการLet 's เข้ารหัสขีด จำกัด ของอัตรา


โซลูตรอนของคุณไม่ทำงานสำหรับฉัน ฉันมีการกำหนดค่าเดียวกันโดยทั่วไป ใช้งานได้กับ goopen.tk แต่ไม่ใช่ www.goopen.tk
Alko

3
@Alko คำแนะนำของคำตอบนั้นถูกต้องและครอบคลุมปัญหานี้ เมื่อใช้งานcertbotหรือเครื่องมืออื่น ๆ คุณไม่สามารถลืมระบุโดเมนของคุณในรูปแบบ www และ non-www ให้ทำงานได้
เปาโลโคกี

ภายใต้location /.well-knownคุณต้องออก.well-knownไปในเส้นทาง ใช้alias /var/www/sub.domain.comไม่ใช่alias /var/www/sub.domain.com/.well-known
gldraphael

1
ทุกคนสามารถอธิบายให้ฉันทำไมคุณต้องการใช้ "เขียนใหม่ ^ https: // $ host $ request_uri ถาวร"; ที่นี่แทน "คืน 301 https: // $ server_name $ request_uri;"
ZaxLofful

ฉันพบว่าฉันต้องการอัญประกาศรอบเส้นทางในตำแหน่งที่ตั้ง location '/.well-known' {. ไม่แน่ใจว่านี่เป็นสิ่งที่รุ่นหรือเพียงแค่การตั้งค่าของฉัน แต่ในกรณีที่คนอื่นติดอยู่
แฟรงก์วี

2

ใช่คุณสามารถใช้nginxเป็นจุดสิ้นสุดของ https และร่วมมือกับแบ็กเอนด์ผ่าน http ตัวอย่างเช่นการกำหนดค่าของฉัน:

server {
        server_name host;
        listen 443 ssl;
...
 location /svn/ {
            auth_ldap off;

            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;

            proxy_pass http://localhost:1080/svn/;
            proxy_redirect http://localhost:1080/ https://host/;
        }
...
}

แต่อย่างที่ฉันรู้กันแล้วด้วยการเข้ารหัสคุณจะต้องชี้โดเมนย่อยทั้งหมดเมื่อคุณได้รับใบรับรองและหากเป็นปัญหาคุณก็เลือก url https://host/serviceแทนhttps://service.host

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