SSD Nodes Learn 🎉 VPS dari $5.50/bln
Panduan Matt ConnorOleh Matt Connor

Cara Konfigurasi Nginx Reverse Proxy Langkah Demi Langkah

Ketahui cara membina blok server nginx reverse proxy yang lengkap. Panduan ini merangkumi tetapan proxy_pass, header penting, sokongan websocket, dan pengurusan fail muat naik.

Fungsi konfigurasi reverse proxy nginx

Reverse proxy nginx menerima permintaan yang sampai pada port 80 dan port 443, kemudian menyerahkan setiap permintaan kepada aplikasi yang sedang mendengar pada port tempatan, seterusnya mengembalikan jawapan aplikasi tersebut kepada pelayar. Konfigurasi ini merupakan satu blok server, dan blok tersebut adalah ringkas. Hampir semua kesukaran terletak pada lima atau enam baris yang memberitahu aplikasi anda siapa pelanggan sebenar dan protokol apa yang digunakan oleh pelanggan tersebut.

Segala yang berikut dibina dari awal pada Ubuntu 24.04, menggunakan pakej nginx daripada pengedaran tersebut. Titik permulaannya ialah aplikasi yang sudah menjawab pada 127.0.0.1:3000. Jika anda belum membuat keputusan mengenai proxy, perbandingan nginx dengan Caddy dan Traefik adalah perbandingan yang perlu dibaca terlebih dahulu. Apa yang berikut ialah rupa jawapan nginx, baris demi baris.

Jalankan konfigurasi ini pada pelayan anda sendiri. Uji setiap perubahan dengan sudo nginx -t sebelum anda memuat semula, dan baca apa yang dipaparkannya.

Lokasi konfigurasi nginx pada Ubuntu

sudo apt update
sudo apt install -y nginx
ls -l /etc/nginx/sites-enabled/

Fail utama ialah /etc/nginx/nginx.conf. Ia menetapkan pilihan global di dalam blok http { } dan kemudian memanggil dua direktori: /etc/nginx/conf.d/*.conf dan /etc/nginx/sites-enabled/*. Pada Ubuntu dan Debian, anda menulis satu fail bagi setiap tapak dalam /etc/nginx/sites-available/ dan mengaktifkannya dengan symlink ke dalam /etc/nginx/sites-enabled/. Memadam symlink tersebut akan menyahaktifkan tapak berkenaan dan mengekalkan fail tersebut.

Dua direktif yang digunakan kemudian hanya berfungsi dalam konteks http, bukan di dalam blok server: map dan upstream. Letakkannya dalam fail sendiri di bawah /etc/nginx/conf.d/, kerana direktori tersebut disertakan pada tahap http.

Pakej ini membekalkan satu tapak yang diaktifkan bernama default. Ia ditandakan sebagai default_server, yang bermaksud ia menjawab sebarang permintaan yang pengepala Host-nya tidak sepadan dengan mana-mana server_name dalam konfigurasi anda. Selagi ia kekal aktif, permintaan yang tidak sepadan dengan nama anda akan dihalakan ke situ dan bukannya ke aplikasi anda. Buang symlink tersebut sebaik sahaja tapak anda sendiri berfungsi.

sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

Blok pelayan paling kecil yang memproksi satu aplikasi

server {
    listen 80;
    listen [::]:80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
    }
}

Simpan sebagai /etc/nginx/sites-available/app.example.com, kemudian aktifkan dan muatkan ia.

sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
curl -sI -H 'Host: app.example.com' http://127.0.0.1/

listen 80; mengikat IPv4 dan listen [::]:80; mengikat IPv6. Jika baris kedua ditinggalkan, pelawat yang carian DNS (domain name system) pelayan anda menghasilkan rekod AAAA akan menerima sambungan yang ditolak, manakala pengguna IPv4 melihat tapak yang berfungsi. Laporan pepijat yang anda terima akan menyatakan "ia berfungsi bagi saya".

server_name dipadankan dengan pengepala Host yang dihantar oleh pelayar. Beberapa nama boleh disenaraikan, dipisahkan dengan ruang. Jika tiada blok yang sepadan, nginx menggunakan blok yang ditetapkan sebagai default_server, itulah sebabnya tapak yang dipakejkan perlu dibuang.

location / ialah padanan awalan pada laluan permintaan, dan / memadankan setiap laluan. proxy_pass ialah alamat yang nginx buka untuk sambungan. Pastikan aplikasi terikat pada 127.0.0.1 supaya satu-satunya laluan masuk adalah melalui nginx. Jika aplikasi berjalan dalam kontena, terbitkan ia sebagai 127.0.0.1:3000:3000 dan bukan sebagai 3000:3000, kerana Docker menulis peraturannya sendiri dan menerbitkan port terus melepasi ufw, jadi port yang diterbitkan secara terus boleh dicapai dari internet tanpa mengira tetapan firewall anda.

Baris curl menghantar pengepala Host yang betul daripada pelayan itu sendiri, supaya anda boleh menguji blok tersebut sebelum DNS menghala ke mana-mana.

Perkara yang dihantar oleh nginx ke upstream apabila tiada konfigurasi tambahan

proxy_pass secara lalai menyembunyikan empat perkara daripada aplikasi anda.

nginx menggunakan HTTP/1.0 untuk berkomunikasi dengan backend secara lalai dan menghantar Connection: close, menyebabkan setiap permintaan membuka sambungan upstream baharu dan menafikan sebarang peningkatan protokol.

Header Host ditulis semula kepada nilai dalam proxy_pass, iaitu 127.0.0.1:3000. Aplikasi yang membina pautan mutlak daripada Host kini menghasilkan pautan yang tidak boleh dibuka oleh sesiapa di luar pelayan.

Sambungan yang sampai ke aplikasi datang daripada nginx, jadi aplikasi melihat alamat klien sebagai 127.0.0.1. Setiap baris log dan setiap had kadar (rate limit) di dalam aplikasi kemudiannya merekodkan proksi tersebut dan bukannya pelawat sebenar.

Aplikasi tidak dapat mengetahui bahawa pelayar menggunakan HTTPS, kerana sambungan yang diterima adalah HTTP biasa pada alamat loopback.

Empat baris konfigurasi akan menyelesaikan semua masalah tersebut.

Empat pengepala yang perlu ditetapkan, dan perkara yang dapat dilihat oleh backend

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

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

Host membawa nama yang ditaip oleh pelawat. $host ialah nama daripada permintaan tersebut, dengan port dibuang dan huruf ditukarkan kepada huruf kecil. Tetapkan pengepala ini supaya aplikasi anda membina URL mutlak yang betul: seperti ubah hala selepas log masuk, atau pautan di dalam e-mel tetapan semula kata laluan. Jika ditinggalkan, URL tersebut akan menghala ke 127.0.0.1:3000, menyebabkan log masuk menghantar pelayar ke alamat yang menolak sambungan. Jika aplikasi anda memerlukan port juga, kerana anda menghidangkannya pada 8080, gunakan $http_host, iaitu pengepala yang sama seperti yang dihantar oleh klien.

X-Real-IP membawa satu nilai: $remote_addr, iaitu alamat yang diterima oleh nginx untuk sambungan tersebut. Aplikasi membaca nilai ini untuk log akses dan pengehadan kadar (rate limiting) mereka sendiri.

X-Forwarded-For membawa satu senarai. $proxy_add_x_forwarded_for menambah $remote_addr kepada apa sahaja yang telah diletakkan oleh klien dalam pengepala tersebut, jadi nilainya dipisahkan dengan koma dan entri yang ditambah oleh nginx anda adalah yang terakhir. Perincian ini menentukan sama ada pengepala tersebut boleh dipercayai: klien boleh menghantar sebarang X-Forwarded-For yang disukainya, jadi aplikasi yang membaca entri pertama boleh ditipu dengan sebarang alamat. Apabila nginx menjadi pelayan pinggir (edge server), tulis $remote_addr sebaliknya dan buang versi klien. Apabila CDN atau proksi lain berada di hadapan, gunakan set_real_ip_from dan real_ip_header daripada modul realip, supaya $remote_addr itu sendiri menjadi alamat klien yang sebenar.

X-Forwarded-Proto membawa http atau https. Rangka kerja (framework) membaca nilai ini untuk menentukan sama ada perlu menandakan kuki sebagai Secure dan sama ada perlu memaksa ubah hala ke HTTPS. Jika ditinggalkan pada tapak TLS, aplikasi yang dikonfigurasikan untuk memaksa HTTPS akan melihat http, menjawab dengan ubah hala ke alamat HTTPS, menerima permintaan seterusnya melalui nginx, masih melihat http, dan mengubah hala sekali lagi. Pelayar akan berhenti dan memaparkan ERR_TOO_MANY_REDIRECTS.

Mengulang empat baris tersebut dalam setiap lokasi adalah punca ia menjadi tidak selaras. Letakkannya dalam satu fail dan sertakan fail tersebut.

# /etc/nginx/snippets/proxy-headers.conf
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;
location / {
    include snippets/proxy-headers.conf;
    proxy_pass http://127.0.0.1:3000;
}

Warisan (inheritance) di sini mempunyai perangkap. Sesuatu lokasi mewarisi arahan proxy_set_header daripada blok pelayannya hanya jika lokasi tersebut tidak mentakrifkan arahannya sendiri. Tambahkan satu proxy_set_header di dalam lokasi dan setiap pengepala yang ditakrifkan pada peringkat pelayan akan digugurkan untuk lokasi tersebut. Oleh itu, kekalkan kesemuanya pada satu peringkat, atau include coretan (snippet) tersebut dalam setiap lokasi yang melakukan proksi.

Mengapa aplikasi WebSocket saya bersambung kemudian terputus?

Kerana tetapan lalai melarang naik taraf (upgrade), dan had masa baca (read timeout) lalai akan menutup terowong terbiar selepas 60 saat. WebSocket bermula sebagai permintaan HTTP yang membawa Upgrade: websocket dan Connection: Upgrade. Ini adalah header hop-by-hop, yang bermaksud proksi dijangka menggunakannya dan bukannya melalukannya, dan HTTP/1.0 tidak mempunyai mekanisme naik taraf langsung. Kedua-duanya perlu diletakkan semula secara manual.

Peta (map) diletakkan dalam konteks http, di dalam failnya sendiri.

# /etc/nginx/conf.d/websocket.conf
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

Kemudian lokasi tersebut.

location / {
    include snippets/proxy-headers.conf;
    proxy_pass http://127.0.0.1:3000;

    proxy_http_version 1.1;
    proxy_set_header Upgrade    $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}

Peta ini wujud supaya satu lokasi boleh melayani kedua-dua jenis trafik. Pada permintaan biasa $http_upgrade adalah kosong, jadi $connection_upgrade menjadi close. Pada permintaan naik taraf ia memegang websocket, jadi header yang dihantar ke hulu (upstream) adalah Connection: upgrade. Mengekod proxy_set_header Connection "upgrade"; secara terus akan menghantar header tersebut pada setiap permintaan halaman biasa juga, dan sesetengah backend menjawab permintaan sedemikian dengan ralat 400.

proxy_read_timeout adalah punca laporan "ia dimuatkan, kemudian berhenti mengemas kini". Ia ditetapkan kepada 60 saat secara lalai, dan ia mengukur jurang antara dua bacaan daripada backend, bukan jangka hayat sambungan. WebSocket yang senyap selama 60 saat akan ditutup oleh nginx, dan konsol pelayar menunjukkan soket ditutup dengan kod 1006. Aplikasi yang menghantar degupan jantung (heartbeat) sendiri lebih kerap daripada sekali seminit tidak akan mengalami masalah ini. Aplikasi yang tidak berbuat demikian akan terputus pada minit tersebut. Editor langsung dan papan pemuka adalah tempat masalah ini muncul dahulu, dengan instans n8n yang dihoskan sendiri di sebalik HTTPS sebagai contoh biasa.

Mengapa garis miring (trailing slash) dalam proxy_pass mengubah URL saya?

Peraturannya adalah satu ayat. Jika proxy_pass berakhir dengan URI (uniform resource identifier), walaupun hanya satu /, nginx akan membuang bahagian laluan permintaan yang sepadan dengan awalan location dan menggantikannya dengan URI tersebut. Jika proxy_pass berhenti pada host dan port, laluan permintaan akan dilalukan tanpa sebarang perubahan.

location /app/ {
    proxy_pass http://127.0.0.1:3000/;
}

Permintaan untuk /app/status sampai ke backend sebagai /status.

location /app/ {
    proxy_pass http://127.0.0.1:3000;
}

Permintaan untuk /app/status sampai ke backend sebagai /app/status.

Bentuk yang anda perlukan bergantung pada aplikasi tersebut. Aplikasi dengan tetapan base-path atau sub-folder memerlukan bentuk kedua, dengan tetapan yang dimaklumkan tentang /app. Aplikasi yang tidak mengetahui tentang awalan memerlukan bentuk pertama. Bentuk pertama mempunyai kesan yang anda akan lihat serta-merta: HTML yang dikembalikan oleh aplikasi tersebut masih mengandungi laluan mutlak seperti /static/main.css, pelayar akan memintanya daripada root tapak, tiada lokasi yang sepadan, dan halaman dipaparkan tanpa penggayaan. Tab rangkaian pelayar menunjukkan permintaan aset tersebut kembali sebagai 404. Penyelesaiannya adalah tetapan base-path aplikasi itu sendiri, atau location /static/ kedua yang menghala ke backend yang sama.

Lokasi regex tidak boleh membawa URI dalam proxy_pass. sudo nginx -t akan menolak konfigurasi tersebut dan menyatakan sebabnya: "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block.

Keseluruhan kelas masalah ini hilang apabila setiap aplikasi mempunyai nama sendiri, app.example.com, yang diproksi daripada location /. Sub-laluan hanya berbaloi jika anda tidak boleh menambah DNS record.

Bagaimanakah cara meletakkan lebih daripada satu backend di bawah satu nama?

Gunakan blok upstream. Ia tergolong dalam konteks http, jadi tuliskan ia di atas blok server dalam fail yang sama, atau di dalam /etc/nginx/conf.d/.

upstream app_backend {
    least_conn;
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
    server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
    keepalive 32;
}

Lokasi tersebut kemudian menamakannya: proxy_pass http://app_backend;.

Kaedah lalai ialah round robin. least_conn menghantar setiap permintaan kepada backend yang mempunyai sambungan aktif paling sedikit, yang sesuai untuk permintaan dengan tempoh masa yang tidak sekata. ip_hash mengikat satu alamat klien kepada satu backend. Anda memerlukan ip_hash apabila aplikasi menyimpan sesi dalam memorinya sendiri, kerana round robin merentasi dua backend sedemikian akan menyebabkan pengguna terkeluar (log out) secara rawak apabila permintaan mereka sampai ke instans yang tidak mempunyai data sesi tersebut. Memindahkan sesi ke storan kongsi adalah penyelesaian yang lebih baik.

max_fails=3 fail_timeout=30s bermaksud tiga percubaan gagal dalam tempoh 30 saat akan mengeluarkan pelayan tersebut selama 30 saat. Apabila setiap pelayan dalam blok berada dalam keadaan tersebut, klien akan menerima 502 dan log ralat akan memaparkan no live upstreams while connecting to upstream.

keepalive 32 mengekalkan sehingga 32 sambungan terbiar (idle) ke backend terbuka bagi setiap proses pekerja, yang membuang proses TCP handshake daripada kebanyakan permintaan. Ia hanya berfungsi dengan proxy_http_version 1.1 dan tanpa Connection: close yang menuju ke upstream. Jika lokasi yang sama turut menggunakan peta WebSocket, tukar kes kosong daripada close kepada rentetan kosong, supaya permintaan biasa tidak membawa pengepala Connection dan sambungan terkumpul (pooled connection) digunakan semula.

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      '';
}

Nama di dalam blok upstream diselesaikan (resolved) apabila nginx bermula. Jika backend anda ialah kontena yang menerima alamat baharu apabila ia dimulakan semula, nginx akan terus menggunakan alamat lama sehingga anda memuat semula (reload) konfigurasi. Di dalam rangkaian Docker, anda boleh memindahkan carian ke masa permintaan dengan menggunakan resolver terbenam.

resolver 127.0.0.11 valid=10s;
set $backend http://app:3000;
proxy_pass $backend;

Apabila kontena muncul dan hilang dengan kerap sehingga anda perlu menyunting nginx untuk mengikutinya, proksi yang membaca label kontena adalah alat yang lebih baik. Traefik di hadapan beberapa aplikasi Docker Compose membina laluan (routes) daripada kontena itu sendiri.

Mengapa muat naik gagal dengan ralat 413 Request Entity Too Large?

client_max_body_size ditetapkan secara lalai kepada 1 megabyte. Badan permintaan yang lebih besar akan ditolak oleh nginx sebelum aplikasi anda menerimanya, dan log ralat akan merekodkan client intended to send too large body. Tingkatkan nilai ini di dalam blok server, atau di lokasi di mana muat naik berlaku.

client_max_body_size 512m;

Nilai 0 akan mematikan semakan ini sepenuhnya. Aplikasi juga mempunyai hadnya sendiri, jadi ralat 413 yang masih berlaku selepas perubahan ini berpunca daripada backend, dan tetapan muat naik aplikasi tersebut adalah perkara seterusnya yang perlu diperiksa.

Secara lalai, nginx membaca keseluruhan badan permintaan sebelum ia membuka sambungan upstream, dengan menulis sebarang data besar ke fail sementara pada cakera terlebih dahulu. Ini melindungi aplikasi daripada klien yang perlahan, kerana backend menerima muat naik pada kelajuan tempatan yang penuh. Untuk muat naik yang sangat besar, anda boleh menggunakan penstriman (streaming).

proxy_request_buffering off;

Backend kemudian menerima badan permintaan tersebut semasa ia tiba dan perlu mampu mengendalikannya. nginx juga akan kehilangan keupayaan untuk mencuba semula permintaan terhadap upstream lain, kerana badan permintaan tersebut sudah tiada.

client_body_timeout, yang ditetapkan kepada 60 saat secara lalai, terpakai di antara dua bacaan berturutan bagi badan permintaan dan bukannya untuk keseluruhan muat naik. Muat naik yang perlahan tetapi stabil akan berjaya melaluinya. Muat naik yang terhenti akan digugurkan.

Penimbalan respons, dan tetapan yang mengganggu output langsung

proxy_buffering diaktifkan secara lalai dan ini biasanya merupakan tetapan yang disyorkan. nginx membaca respons daripada aplikasi anda sepantas yang mampu ditulis oleh aplikasi tersebut, menyimpannya, dan menyalurkannya kepada klien yang perlahan mengikut kelajuan klien itu sendiri. Pekerja aplikasi (app worker) selesai lebih awal dan tidak perlu kekal sibuk sepanjang tempoh muat turun yang perlahan.

Tetapan ini mengganggu respons penstriman. Server-sent events dan output log langsung tidak akan memaparkan apa-apa kepada pembaca sehingga penimbal (buffer) penuh. Matikan penimbalan hanya pada lokasi tersebut.

proxy_buffering off;

Jika anda mengawal aplikasi tersebut, langkah yang lebih baik adalah dengan menghantar header X-Accel-Buffering: no khusus pada respons penstriman sahaja. nginx membaca header tersebut bagi setiap respons dan melumpuhkan penimbalan hanya untuk respons itu, supaya halaman biasa tetap mendapat manfaatnya.

Apabila log ralat memaparkan upstream sent too big header while reading response header from upstream, header respons tidak muat dalam satu penimbal. proxy_buffer_size ditetapkan secara lalai kepada satu halaman memori, iaitu 4 atau 8 kilobait bergantung pada platform, dan kuki yang panjang atau header pengesahan yang besar akan menyebabkan limpahan. Tingkatkan kedua-dua nilai tersebut.

proxy_buffer_size 16k;
proxy_buffers 8 16k;

Di manakah kedudukan TLS dalam konfigurasi ini?

Di Nginx, di hadapan semua perkara di atas. TLS (transport layer security) ditamatkan pada proksi, dan sambungan daripada Nginx ke aplikasi kekal sebagai HTTP biasa melalui alamat loopback, di mana tiada peranti lain dalam rangkaian boleh membacanya. Aplikasi mengetahui bahawa pelawat menggunakan HTTPS daripada X-Forwarded-Proto, iaitu header keempat daripada empat header yang ada.

Jangan tulis laluan sijil secara manual. Halakan DNS record ke pelayan, buka firewall, dan biarkan Certbot menyunting blok pelayan yang sama ini: ia akan menambah baris listen 443 ssl dengan laluan ssl_certificate, serta pengalihan (redirect) daripada port 80. Mengeluarkan sijil Let's Encrypt untuk Nginx dengan Certbot merangkumi proses pengeluaran dan pemasa pembaharuan.

sudo ufw allow 'Nginx Full'
sudo ufw status

Nginx Full ialah profil aplikasi yang dipasang oleh pakej Nginx, dan ia membuka port 80 serta port 443 secara serentak. Port 80 perlu kekal terbuka untuk cabaran pembaharuan HTTP-01, walaupun selepas semua pelawat dialihkan ke HTTPS.

Uji konfigurasi, kemudian muat semula

sudo nginx -t
sudo systemctl reload nginx

nginx -t menghuraikan setiap fail yang disertakan dan sama ada melaporkan ujian sebagai berjaya atau mencetak fail serta baris tempat ia terhenti. Baca output tersebut sebelum anda memuat semula. Muat semula dengan konfigurasi yang rosak tidak akan digunakan: nginx terus melayani konfigurasi sebelumnya, jadi laman web kekal aktif sementara perubahan anda tidak memberi kesan secara senyap. systemctl restart berkelakuan berbeza dan lebih buruk, kerana mulakan semula (restart) akan mematikan pelayan yang sedang berjalan terlebih dahulu, jadi ralat konfigurasi akan menyebabkan nginx tidak berjalan langsung. Gunakan muat semula (reload) secara lalai, dan simpan mulakan semula untuk perubahan jarang yang memerlukannya.

sudo tail -f /var/log/nginx/error.log
sudo ss -lntp | grep -E ':(80|443|3000)'

Baris ss menunjukkan proses mana yang memegang setiap port, supaya anda boleh mengesahkan aplikasi tersebut benar-benar mendengar pada tempat yang ditunjukkan oleh proxy_pass.

Kegagalan yang akan anda temui

502 Bad Gateway, dengan connect() failed (111: Connection refused) while connecting to upstream dalam log ralat. Tiada apa-apa yang mendengar pada alamat dalam proxy_pass. Aplikasi telah dihentikan, atau terikat pada port lain, atau terikat pada alamat dalaman kontena yang tidak boleh dicapai oleh hos.

502 dengan no live upstreams while connecting to upstream. Setiap pelayan dalam blok upstream kini ditandakan sebagai gagal oleh max_fails. Baiki backend tersebut. nginx akan mencuba semula setelah fail_timeout tamat tempoh.

504 Gateway Time-out, dengan upstream timed out (110: Connection timed out) while reading response header from upstream. Backend menerima sambungan tersebut tetapi tidak menghantar apa-apa selama proxy_read_timeout saat. Meningkatkan had masa adalah tindakan yang betul untuk laporan yang benar-benar perlahan, namun salah bagi aplikasi yang tersangkut.

Setiap path mengembalikan 404 daripada aplikasi. Aturan trailing slash telah menulis semula path tersebut. Bandingkan path yang direkodkan oleh aplikasi dengan path yang anda minta.

Laman yang berbeza memberikan respons. server_name tidak sepadan dengan header Host, jadi permintaan tersebut jatuh ke blok default_server.

Laman dimuatkan, kemudian antaramuka terhenti selepas kira-kira seminit. Ini adalah kes WebSocket: pengendalian Upgrade tiada, atau proxy_read_timeout masih ditetapkan pada 60 saat.

FAQ

Mengapa nginx memaparkan 502 Bad Gateway selepas saya menambah proxy_pass?

nginx tidak dapat membuka sambungan ke alamat dalam proxy_pass. Log ralat di /var/log/nginx/error.log menyatakan puncanya: connect() failed (111: Connection refused) while connecting to upstream bermaksud tiada apa-apa yang mendengar pada port tersebut, dan no live upstreams bermaksud setiap pelayan dalam blok upstream telah ditandakan sebagai gagal. Jalankan sudo ss -lntp | grep 3000 untuk melihat proses mana yang memegang port tersebut dan alamat mana yang diikat kepadanya. Aplikasi yang diikat pada alamat dalaman kontena, atau pada port selain daripada yang anda tulis, akan memberikan ralat ini setiap kali.

Mengapa aplikasi saya terputus sambungan selepas kira-kira seminit di sebalik nginx?

Sambungan tersebut adalah WebSocket dan proxy_read_timeout masih pada nilai lalai 60 saat, yang mengukur jurang antara dua bacaan daripada backend. Soket yang senyap akan ditutup oleh nginx dan konsol pelayar akan melaporkan kod tutup 1006. Tetapkan proxy_http_version 1.1, hantar Upgrade dan Connection dengan map pada $http_upgrade, dan tingkatkan proxy_read_timeout kepada nilai seperti 3600s. Tanpa pengepala Upgrade, proses naik taraf (upgrade) tidak akan berlaku, menyebabkan aplikasi kembali kepada polling atau tidak memaparkan kemas kini secara langsung.

Adakah garis miring (trailing slash) dalam proxy_pass penting?

Ya, dan ia mengubah laluan yang diterima oleh backend anda. Dengan location /app/ dan proxy_pass http://127.0.0.1:3000/, permintaan untuk /app/status sampai ke backend sebagai /status, kerana sebarang URI selepas hos dan port akan menggantikan awalan lokasi yang dipadankan. Buang garis miring terakhir itu dan permintaan yang sama akan sampai sebagai /app/status. Membuang awalan sering menyebabkan pautan aset aplikasi rosak, yang kekal mutlak dan kemudian memberikan ralat 404 pada punca tapak, jadi aplikasi dengan tetapan laluan asas lebih baik dilayan dengan bentuk yang menghantar laluan tersebut secara terus.

Mengapa aplikasi saya merekodkan 127.0.0.1 sebagai alamat IP setiap pelawat?

Kerana sambungan yang diterima oleh aplikasi sebenarnya datang daripada nginx pada alamat loopback. Alamat pelawat hanya sampai ke aplikasi dalam pengepala yang anda tetapkan: proxy_set_header X-Real-IP $remote_addr; untuk nilai tunggal, dan proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; untuk rantaian yang ditambah. Aplikasi kemudian perlu dikonfigurasikan untuk mempercayai pengepala tersebut. Ingat bahawa klien boleh menghantar X-Forwarded-For mereka sendiri, jadi apabila nginx bertindak sebagai pelayan pinggir (edge server), tulis ganti dengan $remote_addr dan bukannya menambahkannya.

Adakah saya memerlukan TLS pada sambungan antara nginx dan aplikasi saya?

Tidak perlu apabila aplikasi berjalan pada pelayan yang sama dan diikat pada 127.0.0.1, kerana trafik tersebut tidak pernah keluar dari mesin. Tamatkan TLS di nginx, kekalkan proxy_pass pada HTTP biasa melalui loopback, dan hantar X-Forwarded-Proto $scheme supaya aplikasi tahu pelawat menggunakan HTTPS. Jika backend berada pada hos berbeza merentasi rangkaian yang tidak anda kawal, hop tersebut memerlukan perlindungannya sendiri, sama ada HTTPS ke backend atau terowong peribadi antara kedua-dua mesin tersebut.