Nginx में, मैं सब-डोमेन को बनाए रखते हुए https के सभी http अनुरोधों को फिर से कैसे लिख सकता हूं?


508

मैं अपने वेब सर्वर पर http अनुरोधों के लिए सभी http अनुरोधों को फिर से लिखना चाहता हूं, मैंने निम्नलिखित के साथ शुरू किया:

सर्वर {
    80 सुनो;

    स्थान / {
      rewrite ^ (? *) https: //mysite.com$1 स्थायी;
    }
...


एक समस्या यह है कि यह किसी भी उपडोमेन जानकारी (उदाहरण के लिए, nd1.mysite.com/folder) को हटा देता है, मैं उपरोक्त सब को फिर से कैसे लिख सकता हूं ताकि सबकुछ को फिर से शुरू किया जा सके और सब-डोमेन को बनाए रखा जा सके?


2
कृपया 'स्वीकृत उत्तर' को serverfault.com/a/171238/90758 पर ले जाने पर विचार करें । यह सही है।
olafure

हार्डकोडेड mysite.com के बजाय बस $ server_name का उपयोग करें
Fedir RYKHTIK

जवाबों:


748

नगीनक्स के नए संस्करणों में सही तरीका

इस सवाल का मेरा पहला जवाब निश्चित समय पर सही था, लेकिन यह एक और नुकसान में बदल गया - तारीख तक रहने के लिए कृपया कर को फिर से लिखें

मुझे कई एसई उपयोगकर्ताओं द्वारा ठीक किया गया है, इसलिए इसका श्रेय उन्हें जाता है, लेकिन इससे भी महत्वपूर्ण बात यह है कि यहां सही कोड है:

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; 

       [....]
}

3
आपको ऐसा डोमेन के आधार पर डोमेन के आधार पर करना होगा - नहीं? यदि आप इसे अपने सर्वर पर हर डोमेन पर लागू करना चाहते हैं तो क्या होगा?
JM4

30
@ JM4: यदि आप सर्वर_नाम के बजाय पुनर्लेखन में $ $ होस्ट का उपयोग करते हैं और सुनने के निर्देश में default_server जोड़ते हैं तो यह आपके सर्वर पर प्रत्येक डोमेन के लिए काम करेगा।
कालस वैन स्केलेनवेन

5
यह उल्लेख करना महत्वपूर्ण है कि 301 आपके स्थानीय कैश में एक्सपायरी डेट के बिना संग्रहीत है। बहुत उपयोगी नहीं है जब विन्यास बदलता है
ट्रेफेक्स

9
@ हर कोई POST सामग्री को संरक्षित करने के लिए एक 307 पुनर्निर्देशित का उपयोग करें।
महमूद अल-कुद्सी

10
ध्यान दें कि आप का उपयोग करना चाहिए $hostबजाय $server_nameआप उप डोमेन उपयोग कर रहे हैं।
कैटफिश

276

नोट: ऐसा करने का सबसे अच्छा तरीका https://serverfault.com/a/401632/3641 द्वारा प्रदान किया गया था - लेकिन यहां दोहराया गया है:

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

सबसे सरल स्थिति में आपके होस्ट को आपकी सेवा के रूप में तय किया जाएगा जिसे आप उन्हें भेजना चाहते हैं - यह ब्राउज़र को 301 रीडायरेक्ट करेगा और ब्राउज़र URL तदनुसार अपडेट करेगा।

नीचे पिछले उत्तर है, जो रेगेक्स के कारण अक्षम है, एक सरल 301 @kmindi द्वारा दिखाया गया है

मैं nginx 0.8.39 और इसके बाद के संस्करण का उपयोग कर रहा हूं, और निम्नलिखित का उपयोग किया है:

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

क्लाइंट के लिए एक स्थायी रीडायरेक्ट भेजता है।


15
मुझे लगता है कि यह 80 होना चाहिए - क्योंकि यह http के लिए सुन रहा है और फिर क्लाइंट को https (443) के रूप में वापस आने के लिए कह रहा है।
माइकल निएले

3
यह शीर्ष उत्तर होना चाहिए!
नाथन

3
यह सबसे कर जवाब है।
केस

1
यह सबसे आसान है, लेकिन कम से कम सुरक्षित है - इस तरह से आप अपने सर्वर को किसी भी पृष्ठ पर किसी भी पृष्ठ पर किसी उपयोगकर्ता को पुनर्निर्देशित करने की अनुमति देते हैं, अगर यह आपके सर्वर पर उपयोग करने की अनुमति है या नहीं। यदि आपका सर्वर mydomain.co पर कार्य करता है, तो दुर्भावनापूर्ण उपयोगकर्ता अभी भी आपके सर्वर का उपयोग अन्य डोमेन जैसे mydomain.co, जैसे google.com पर कर सकते हैं।
फ्राइडकिवी

10
@ cab0lt यहाँ कोई सुरक्षा समस्या नहीं है। पुनर्निर्देशन परोसने से सुरक्षा जोखिम नहीं होता है। यदि एक्सेस कंट्रोल आवश्यकताएं हैं, तो उन बिंदुओं पर जांच की जानी चाहिए जहां ब्राउज़र नए URL का अनुरोध करता है। ब्राउज़र केवल रीडायरेक्ट के आधार पर पहुँच प्राप्त नहीं करेगा, और न ही उन्हें नए URL का अनुरोध करने के लिए रीडायरेक्ट की आवश्यकता होगी।
mc0e

125

मुझे लगता है कि सबसे अच्छा और एक ही तरीका है एक का उपयोग करना चाहिए HTTP 301 स्थायी रूप से स्थानांतरित इस तरह अनुप्रेषित:

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

HTTP 301 स्थायी रूप से स्थानांतरित अनुप्रेषित भी सबसे कारगर नहीं regex मूल्यांकन किया जाना है, क्योंकि, पहले ही उल्लेख के अनुसार है pitfails


नया HTTP 308 मूव्ड स्थायी रूप से अनुरोध विधि को संरक्षित रखता है और इसे प्रमुख ब्राउज़रों द्वारा समर्थित किया जाता है । उदाहरण के लिए, का उपयोग कर 308रोकता से अनुरोध विधि में बदलाव करने से ब्राउज़र POSTको GETपुन: निर्देशन अनुरोध के लिए।


यदि आप hostname को संरक्षित करना चाहते हैं और यह उप डोमेन है।

अगर आपके पास DNS नहीं है तो भी यह काम करता है , क्योंकि मैं भी इसका स्थानीय स्तर पर उपयोग कर रहा हूं। मैं उदाहरण के लिए अनुरोध कर रहा हूं http://192.168.0.100/index.phpऔर वास्तव में पुनर्निर्देशित कर दूंगा https://192.168.0.100/index.php

मैं listen [::]:80अपने होस्ट पर उपयोग करता हूं क्योंकि मैंने bindv6onlyसेट किया है false, इसलिए यह आईपीवी 4 सॉकेट से भी बांधता है। listen 80अगर आप IPv6 नहीं चाहते या इसे कहीं और बांधना चाहते हैं तो इसे बदल दें ।

सैफ बिचेन से समाधान का उपयोग करता है server_nameजो मेरे मामले में लोकलहोस्ट है, लेकिन यह एक नेटवर्क पर उपलब्ध नहीं है।

माइकल नेले से समाधान अच्छा है, लेकिन पिटफेल के अनुसार, पुनर्निर्देशित 301 के साथ बेहतर समाधान है;)


अच्छा आप इसे उद्धृत करने का प्रयास करते हैं, लेकिन 301 HTTPS पर काम नहीं करता है।
केस

5
क्या काम नहीं करता है? उल्लिखित सर्वर अनुभाग गैर-एन्क्रिप्टेड http (बिना s) ट्रैफ़िक के है जो कि एन्क्रिप्टेड सर्वर पर स्थायी रूप से पुनर्निर्देशित किया जा सकता है (वह खंड जो 443 (https) को सुनता है) सूचीबद्ध नहीं है
kmindi

मैंने https और सब कुछ के साथ यह बहुत अच्छा काम किया है - @kmindi मैंने अपना उत्तर आपके संदर्भ में अपडेट किया है - जैसा कि मुझे लगता है कि यह सही तरीका है और यह पॉप अप करता रहता है! अच्छा काम।
माइकल नेयले

डोमेन (गैर-आईपी) अनुरोध का उपयोग करते समय, जब तक मैं '[::]: 80' को '80' में परिवर्तित नहीं करता, तब तक काम नहीं करता है।
जोसेफ वासना

यह अपेक्षित व्यवहार हो सकता है: trac.nginx.org/nginx/ticket/345 । मैंने सुनने के विकल्प का वर्णन करने के लिए उत्तर को अपडेट किया।
किमीहिंदी

20

सर्वर ब्लॉक के भीतर आप निम्न कार्य भी कर सकते हैं:

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

2
इस कॉन्फ़िगरेशन के कारण मेरा सर्वर एक अनुप्रेषित लूप का उत्पादन करने लगा
कॉर्कस्क्रूव ऑक्ट

हो सकता है कि आपकी साइट में कोई दूसरा रीडायरेक्ट हो या https आपकी साइट / ऐप में सक्षम न हो
Oriol

1
इस एक को छोड़कर अन्य कोई भी काम नहीं कर रहा था।
Nginx

https: // $ host $ uri के लिए upvoted
AMB

4
यदि आप एक भारोत्तोलक के पीछे हैं तो जाने का यह तरीका है!
एंटवान

17

हर समय नए उप-डोमेन के साथ उपर्युक्त कार्य नहीं किया गया। उदा। 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
# ...
}

धन्यवाद! nginx या तो वापस आ जाएगा या 301 https://*/अन्य उत्तरों में समय से पहले अनुरोध को रद्द कर देगा। server_name _;के साथ $hostजवाब था कि चाल है। +1
zamnuts

1
यह एक इष्टतम है! हालाँकि, मैं कुछ के लिए _वास्तविक डोमेन के साथ बदलने की सलाह देता हूं , उदाहरण के लिए .domain.comमेरे पास दो सर्वर थे, और nginx गलती से अपने एक सर्वर को डिफ़ॉल्ट सर्वर पर निर्देशित कर रहा था।
जूल

1
यह एकमात्र उत्तर है जिसने मेरे लिए काम किया, धन्यवाद!
स्नोमैन

बहुत बहुत धन्यवाद दोस्त .. मैं कई समाधान की कोशिश की है, लेकिन काम नहीं किया। यह समाधान बहुत बढ़िया है और इसने मेरे लिए काम किया। सर्वर का नाम _; इसका मतलब क्या है .. मुझे समझ में नहीं आया। कृपया मुझे यह समझाएं।
पवन कुमार

6

मैंने एक सही उत्तर पर एक टिप्पणी बहुत पहले, बहुत समय पहले एक बहुत ही महत्वपूर्ण सुधार के साथ पोस्ट की थी, लेकिन मुझे लगता है कि इस सुधार को अपने स्वयं के उत्तर में उजागर करना आवश्यक है। पिछले उत्तरों में से कोई भी उपयोग करने के लिए सुरक्षित नहीं है यदि किसी भी बिंदु पर आपके पास असुरक्षित HTTP सेट अप था और उपयोगकर्ता सामग्री की अपेक्षा करता है, तो आपके साइट से बात करने के लिए किसी भी वेबसाइट, उपकरण, एप्लिकेशन, या उपयोगिता को कॉन्फ़िगर करने या किसी भी वेबसाइट को कॉन्फ़िगर करने की आवश्यकता है।

समस्या तब होती है जब POSTआपके सर्वर से अनुरोध किया जाता है। यदि एक सादे 30xरीडायरेक्ट के साथ सर्वर की प्रतिक्रिया POST सामग्री खो जाएगी। क्या होता है कि ब्राउज़र / क्लाइंट अनुरोध को SSL में अपग्रेड करेगा लेकिन अनुरोध को डाउनग्रेड कर सकता POSTहै GETPOSTपैरामीटर गुम हो जाएंगे और गलत अनुरोध अपने सर्वर पर किया जाएगा।

समाधान सरल है। आपको एक 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"; 

       [....]
}

4

मैं इसे इस तरह करने में कामयाब रहा:

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


अपडेट किया गया संस्करण, w / o IF: paste.debian.net/plain/899679
स्टैमस्टर

4

मैं AWS ELB के पीछे ngnix चला रहा हूं। ELB http पर ngnix से बात कर रहा है। चूंकि एलएलबी के पास ग्राहकों को रीडायरेक्ट भेजने का कोई तरीका नहीं है, इसलिए मैं एक्स-फॉरवर्डेड-प्रोटो हेडर और रीडायरेक्ट की जांच करता हूं:

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

1

यदि आप 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ब्लॉक मैच को अपने किसी भी वैध डोमेन से नहीं बना सकते हैं और कुछ आक्रामक सेवा कर सकते हैं। । । ।

[१] तकनीकी रूप से "प्रॉक्सी" गलत शब्द है, क्योंकि आपका सर्वर बाहर नहीं जा रहा है और ग्राहकों के लिए अनुरोधों को पूरा कर रहा है, सिर्फ एक रीडायरेक्ट भेज रहा है, लेकिन मुझे यकीन नहीं है कि सही शब्द क्या होगा। मुझे यह भी पता नहीं है कि लक्ष्य क्या है, लेकिन यह आपके लॉग को शोर से भरता है और आपके सीपीयू और बैंडविड्थ का उपभोग करता है, इसलिए आप इसे रोक सकते हैं।


0

ऐसा लगता है कि वास्तव में किसी को भी यह 100% सही नहीं लगा। पोर्ट 80 अनुरोधों को पूरे वेबसर्वर के लिए उनके 443 समकक्षों पर जाने के लिए, आपको सुनने के निर्देश का उपयोग करने की आवश्यकता है , न कि कैच-ऑल नाम निर्दिष्ट करने के लिए server_name निर्देश काHttps://nginx.org/en/docs/http/request_processing.html भी देखें

सर्वर {
    80 डिफ़ॉल्ट सुनो;
    सुनो [::]: 80 डिफ़ॉल्ट;
      वापसी 307 https: // $ मेजबान $ request_uri;
}
  • $ मेजबान उपडोमेन नामों को पकड़ता है।
  • 307 और 308 में POST और GET अनुरोध दोनों URI शामिल हैं।
  • 307 अस्थायी है, पूरी तरह से परीक्षण के बाद स्थायी 308 में परिवर्तन:

और यह सुनिश्चित कर लें कि आप पहले से ही /etc/nginx/conf.d/ में क्या देख रहे हैं, क्योंकि अधिक बार मेरे पास ऐसे मुद्दे नहीं थे जहां default.conf ने कुछ मौजूदा vhost लौटाए। Nginx मुद्दों के साथ काम करने का मेरा क्रम हमेशा डिफ़ॉल्ट फ़ाइल को स्थानांतरित करने से शुरू होता है, इसे वापस लाइन पर टिप्पणी करते हुए यह देखने के लिए कि यह कहाँ गलत है।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.