שאלה ב Nginx, איך אני יכול לשכתב את כל בקשות http ל- https תוך שמירה על תת תחום?


אני רוצה לשכתב את כל בקשות http בשרת האינטרנט שלי להיות בקשות https, התחלתי עם הפעולות הבאות:

שרת {
    תקשיב 80;

    מקום / {
      rewrite ^ (. *) https: //mysite.com$1 קבע;
    }
...


בעיה אחת היא שמפשיט כל מידע תת-דומיין (למשל node1.mysite.com/folder), כיצד אוכל לשכתב את הנ"ל כדי לנתב מחדש את הכל ל- https ולשמור על תת-הדומיין?


495
2017-09-21 14:04




אנא שקול להעביר את 'התשובה המקובלת' ל serverfault.com/a/171238/90758. זה נכון. - olafure
פשוט להשתמש $ server_name במקום hardcoded mysite.com - Fedir RYKHTIK


תשובות:


תקן את הדרך בגרסאות חדשות של nginx

התברר שהתשובה הראשונה שלי לשאלה זו היתה נכונה בזמן מסוים, אבל זה הפך להיות מכשול נוסף - להישאר מעודכן בבקשה לבדוק מיסוי לשכתב pitfalls

אני כבר תיקן על ידי משתמשים רבים SE, כך האשראי הולך אליהם, אבל חשוב יותר, הנה הקוד הנכון:

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

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000" always; 

       [....]
}

737
2017-12-05 20:43



אתה צריך לעשות את זה על בסיס דומיין לפי בסיס עם זאת - לא? מה אם אתה רוצה להחיל אותו על כל תחום בשרת שלך? - JM4
@ JM4: אם אתה משתמש $ host $ ב rewrite במקום server_name ולהוסיף default_server להנחיית האזנה זה יעבוד עבור כל תחום בשרת שלך. - Klaas van Schelven
חשוב לציין כי 301 מאוחסן במטמון המקומי שלך ללא תאריך תפוגה. לא מאוד שימושי כאשר השינויים config - Trefex
@everyone השתמש בהפניה מחדש של 307 כדי לשמור על תוכן POST. - Mahmoud Al-Qudsi
שים לב שעליך להשתמש $host במקום $server_name אם אתה משתמש בתת-דומיינים. - Catfish


הערה: הדרך הטובה ביותר לעשות זאת מסופקת על ידי https://serverfault.com/a/401632/3641 - אבל הוא חזר על עצמו כאן:

server {
    listen         80;
    return 301 https://$host$request_uri;
}

במקרה הפשוט המארח שלך יהיה קבוע להיות השירות שלך אתה רוצה לשלוח אותם - זה יעשה הפניה 301 לדפדפן ואת כתובת האתר של הדפדפן יעדכן בהתאם.

להלן התשובה הקודמת, אשר אינו יעיל בשל regex, פשוט 301 הוא נהדר כפי שמוצג על ידי @kmindi

אני משתמש nginx 0.8.39 ומעלה, ושימש את הפעולות הבאות:

 server {
       listen 80;
       rewrite ^(.*) https://$host$1 permanent;
 }

שולח הפניה קבועה ללקוח.


270
2017-08-17 03:07



אני חושב שזה צריך להיות 80 - כמו זה מקשיב http ולאחר מכן אומר הלקוח לחזור כמו https (443). - Michael Neale
זו צריכה להיות התשובה הטובה ביותר! - Nathan
זוהי התשובה הכי מסים. - Case
זה הכי קל, אבל הכי פחות מאובטח - בדרך זו אתה מאפשר לשרת שלך להפנות משתמש לדף כלשהו, ​​מבלי לבדוק אם זה מותר אפילו להשתמש בשרת שלך. אם השרת שלך משרת את mydomain.co, משתמשים זדוניים עדיין יכולים להשתמש בשרת שלך כדי להפנות משתמשים לדומיינים אחרים כגון mydomain.co, כגון google.com. - friedkiwi
@ cab0lt אין בעיית אבטחה כאן. הצגת כתובת אתר להפניה מחדש אינה מהווה סיכון אבטחה. אם יש דרישות בקרת גישה, יש לבדוק אותן בנקודה שבה הדפדפן מבקש את כתובת האתר החדשה. הדפדפן לא יקבל גישה פשוט על סמך ההפניה מחדש, וגם לא צריך את כתובת האתר להפניה מחדש כדי לבקש את כתובת האתר החדשה. - mc0e


אני חושב שהדרך הטובה ביותר והיחידה צריכה להיות באמצעות HTTP 301 הועבר לצמיתות להפנות מחדש כך:

server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

ה HTTP 301 הועבר לצמיתות הפניה היא גם היעילה ביותר, כי אין regex להיות מוערך, על פי שכבר הוזכר פיגורים.


החדש HTTP 308 הועבר לצמיתות משמר את שיטת הבקשה והוא נתמך על ידי דפדפנים עיקריים. לדוגמה, באמצעות 308 מונע מהדפדפנים לשנות את שיטת הבקשה POST ל GET עבור הבקשה להפניה מחדש.


אם אתה רוצה שמור על שם המארח ותת-הדומיין זו הדרך.

זה עדיין עובד אם אין לך DNS, כפי שאני גם משתמש בו באופן מקומי. אני מבקש למשל עם http://192.168.0.100/index.php ו יופנה מחדש בדיוק https://192.168.0.100/index.php.

אני משתמש listen [::]:80 על המארח שלי כי יש לי bindv6only מכוון ל false, אז זה גם נקשר לשקע ipv4. לשנות את זה listen 80 אם אתה לא רוצה IPv6 או רוצה לקשור במקום אחר.

הפתרון של סייף Bechan משתמש server_name אשר במקרה שלי הוא localhost אבל זה לא נגיש על פני הרשת.

הפתרון מייקל ניל הוא טוב, אבל על פי pitfails, יש פתרון טוב יותר עם הפניה 301;)


121
2018-06-23 17:19



נחמד אתה מנסה לצטט אותו, אבל 301 לא עובד על HTTPS. - Case
מה לא עובד? הקטע שרת כאמור הוא עבור HTTP לא מוצפן (ללא s) התנועה להיות מנותב לצמיתות לשרת מוצפן (כי סעיף מאזין על 443 (https) אינו מופיע) - kmindi
בדקתי את זה עובד נהדר עם https והכל - @kmindi אני מעודכן את התשובה שלי עם התייחסות שלך - כפי שאני חושב שזה הדרך הנכונה ואת זה שומר popping up! עבודה נחמדה. - Michael Neale
בעת שימוש בבקשת דומיין (לא IP), לא עובד אלא אם כן אני משנה את '[::]: 80' ל -80 '. - Joseph Lust
זה יכול להיות ההתנהגות הצפויה: trac.nginx.org/nginx/ticket/345. עדכנו את התשובה לתיאור אפשרות ההאזנה. - kmindi


האמור לעיל לא עובד עם עם subdomains חדשים נוצרים כל הזמן. למשל AAA.example.com BBB.example.com עבור כ -30 תת-דומיינים.

לבסוף יש הגדרה עובד עם הבאות:

server {
  listen 80;
  server_name _;
  rewrite ^ https://$host$request_uri? permanent;
}
server {
  listen  443;
  server_name example.com;
  ssl on;
  ssl_certificate /etc/ssl/certs/myssl.crt;
  ssl_certificate_key /etc/ssl/private/myssl.key;
  ssl_prefer_server_ciphers       on;
# ...
# rest of config here
# ...
}

17
2018-06-25 04:29



תודה! nginx יחזור 301 https://*/ או לבטל את הבקשה בטרם עת בתשובות אחרות כאן. server_name _; עם $host היתה התשובה שעשתה את הטריק. +1 - zamnuts
זה אחד אופטימלי! עם זאת, אני ממליץ עבור חלק להחליף _ עם הדומיין עצמו, למשל. .domain.com היו לי שני שרתים, ו nginx היה בטעות מכוון אחד השרתים שלי לשרת ברירת המחדל. - zzz
זו התשובה היחידה שעבדה בשבילי, תודה! - Snowman
תודה רבה חבר .. ניסיתי רבות של פתרונות אבל did not עבד. פתרונות זה מדהים וזה עבד בשבילי. שם שרת _; מה זה אומר .. אני לא מבין. בבקשה תסבירי לי את זה. - Pavan Kumar


בתוך בלוק השרת ניתן גם לבצע את הפעולות הבאות:

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
}

16
2017-07-31 19:50



תצורה זו גרמה לשרת שלי לייצר לולאה להפניה מחדש - Corkscreewe
אולי הסיבה לכך היא שיש כתובת אתר אחרת להפניה מחדש או ש- https אינה מופעלת באתר / באפליקציה שלך - Oriol
נראה שאיש מן האחרים לא עבד מלבד זה. שימוש בגירסת nginx: nginx / 1.10.0 (אובונטו) - ThatGuy343
upvoted עבור https: // $ host $ uri - AMB
זוהי הדרך ללכת אם אתה מאחורי loadbalancer! - Antwan


פרסמתי תגובה על התשובה הנכונה לפני זמן רב, עם תיקון חשוב מאוד, אבל אני מרגיש צורך להדגיש תיקון זה בתשובתו. אף אחת מהתשובות הקודמות בטוחה לשימוש אם בשלב כלשהו הגדרת HTTP לא מאובטחת וציפית לתוכן המשתמש, יש לך טפסים, לארח ממשק API או שהגדרת כל אתר, כלי, יישום או כלי שירות כדי לדבר עם האתר שלך.

הבעיה מתרחשת כאשר a POST הבקשה מתבצעת לשרת שלך. אם תגובת השרת עם רגיל 30x הפניה מחדש התוכן POST יאבדו. מה שקורה הוא שהדפדפן / הלקוח ישדרג את הבקשה ל- SSL אבל שדרג לאחור ה POST כדי GET בקשה. ה POST הפרמטרים יאבדו ובקשה לא נכונה תבוצע לשרת שלך.

הפתרון הוא פשוט. אתה צריך להשתמש HTTP 1.1 307 הפניה מחדש. זה מפורט ב RFC 7231 S6.4.7:

  Note: This status code is similar to 302 (Found), except that it
  does not allow changing the request method from POST to GET.  This
  specification defines no equivalent counterpart for 301 (Moved
  Permanently) ([RFC7238], however, defines the status code 308
  (Permanent Redirect) for this purpose).

הפתרון, מותאם מהפתרון המקובל, הוא להשתמש 307 בקוד ההפניה שלך:

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

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000"; 

       [....]
}

6
2018-03-19 20:24



מאוד, מאוד מאוד הפקודה. תודה! - Denis Matafonov


הצלחתי לעשות זאת כך:

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;
}
}

https://stackoverflow.com/a/36777526/6076984


4
2018-04-21 18:27



גרסה מעודכנת, w / o IF: - מדריך - stamster


אני מפעיל ngnix מאחורי AWS ELB. ELB מדבר ngnix מעל http. מאז ELB אין שום דרך לשלוח הפניות ללקוחות, אני בודק את הכותרת X-Forwarded-Proto ולהפנות מחדש:

if ($http_x_forwarded_proto != 'https') {
    return 301 "https://www.exampl.com";
}

3
2018-01-04 17:09





אם אתה return 301 https://$host$request_uri; כתגובת ברירת המחדל ביציאה 80, השרת שלך עשוי להופיע במוקדם או במאוחר ברשימה של פרוקסי פתוח [1] ולהתחיל להתעלל בהם כדי לשלוח תנועה למקום אחר באינטרנט. אם היומנים שלך מתמלאים עם הודעות כמו זו, אז אתה יודע שזה קרה לך:

42.232.104.114 - - [25/Mar/2018:04:50:49 +0000] "GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1" 301 185 "http://www.ioffer.com/" "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Hotbar 4.1.8.0; RogueCleaner; Alexa Toolbar)"

הבעיה היא $host יהיה הד בחזרה מה הדפדפן שולח ב Host כותרת או אפילו שם המארח משורת הפתיחה של HTTP, כמו זו:

GET http://www.ioffer.com/i/new-fashion-fine-gold-bracelet-versaec-bracelet-641175733 HTTP/1.1

בגלל בעיה זו, כמה תשובות אחרות כאן ממליצים להשתמש $server_name במקום $host. $server_name תמיד מעריך למה אתה לשים את server_name הצהרה. אבל אם יש לך תת תחומי מרובים שם או להשתמש בתווים כלליים, זה לא יעבוד, כי $server_name רק משתמש ראשון כניסה לאחר server_name ההצהרה, וחשוב יותר יהיה רק ​​הד חזרה תו כללי (לא להרחיב אותו).

אז איך לתמוך תחומים מרובים תוך שמירה על אבטחה? במערכות שלי טיפלתי בדילמה הזאת ראשון רישום א default_server בלוק שאינו בשימוש $host, ולאחר מכן רישום בלוק כלליים שעושה:

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

(תוכל גם לרשום יותר מדומיין אחד בבלוק השני).

עם שילוב זה, תחומים שאין כמוהם ינותבו מחדש במקום כלשהו עם קוד מקור (תמיד example.com), וכן תחומים התואמים משלך ילך למקום הנכון. השרת שלך לא יהיה שימושי כפרוקס פתוח, כך שלא תמשוך בעיות.

אם אתה מרגיש אורנרי, אני מניח שאתה יכול גם לעשות את default_server בלוק התאמה אף אחד של תחומים לגיטימיים שלך לשרת משהו פוגע. . . .

[1] מבחינה טכנית "proxy" היא מילה שגויה, כי השרת שלך לא יוצא וממלא בקשות עבור הלקוחות, רק שולח הפניה, אבל אני לא בטוח מה המילה הנכונה יהיה. אני גם לא בטוח מה המטרה, אבל זה ממלא את היומנים שלך עם רעש וצורכת את המעבד ואת רוחב הפס, אז אתה יכול גם לשים את זה להפסיק.


0
2018-03-25 05:58





rewrite ^!https https://$host$request_uri permanent;

-1
2018-06-29 04:33