Ось готовий урок, створений спеціально для тебе у стилі David Malan. Вмикаймо уяву, відкриваймо термінал і поїхали! 🚀
🎓 Урок: Proxy_pass та магія передачі заголовків
Привіт, друзі! Радий бачити вас на цій лекції. 👋
Сьогодні ми зазирнемо під капот того, як веб-сервери спілкуються між собою. Ми розберемося з директивою proxy_pass в Nginx і зрозуміємо, чому іноді ваш бекенд "втрачає пам'ять" про користувача і як це виправити за допомогою заголовків.
Готові? Тоді вперед!
1. 🔥 Вступ: проблема та мотивація
Уявіть ситуацію. Ви написали крутий додаток на Python (Django/FastAPI) або Node.js. Він працює на порту :8000. Але ви не виставляєте цей порт у світ. Ви ставите перед ним Nginx як охоронця (reverse proxy).
Користувач заходить на ваш сайт, Nginx приймає запит і пересилає його вашому додатку. Все працює? Ніби так.
Але тут ви дивитесь у логи свого Python-додатку і бачите дивну річ:
"Користувач із IP 127.0.0.1 намагався увійти..." "Користувач із IP 127.0.0.1 купив товар..."
Чекайте... Всі ваші користувачі раптом стали "localhost"? 🤨
А якщо вам треба заблокувати зловмисника по IP? Ви заблокуєте 127.0.0.1 і покладете свій власний сервер.
Чому це відбувається? Тому що для вашого бекенду (Python/Node) запит прийшов не від Олега з Києва, а від Nginx, який живе на тій самій машині.
Без розуміння proxy_pass та передачі заголовків ви:
1. Не зможете аналізувати географію користувачів.
2. Не зможете захиститися від DDOS.
3. Зламаєте логіку редіректів у своєму додатку.
Сьогодні ми навчимо Nginx не просто перекидати запити, а робити це розумно.
2. 🧠 Теоретична база (без сухої академічності)
Давайте розберемо це на аналогії.
Уявіть, що Бекенд — це Геніальний Шеф-кухар, який сидить у закритій кухні й готує страви. Він ніколи не бачить відвідувачів. Nginx — це Офіціант.
- Гість (Клієнт) каже Офіціанту: "Я хочу борщ. У мене алергія на часник".
- Офіціант йде на кухню і каже Шефу: "Один борщ".
⛔️ СТОП! Офіціант забув передати важливу деталь ("алергія на часник"). Шеф приготує звичайний борщ, і Гість постраждає.
У світі серверів:
* proxy_pass — це дія "Офіціант йде на кухню". Це команда Nginx переслати запит далі.
* Заголовки (Headers) — це ті самі "записки", які Офіціант має передати Шефу разом із замовленням: "Це замовлення від столика №5, у них алергія".
Що відбувається "під капотом"?
Коли Nginx робить proxy_pass, він створює новий HTTP-запит від себе до бекенду. За замовчуванням він не копіює інформацію про оригінального клієнта. Він просто каже: "Дай мені сторінку".
Щоб бекенд знав правду, ми використовуємо директиву proxy_set_header. Ми примусово клеїмо "стікери" на запит:
Host: Який домен запитував користувач? (важливо, якщо на бекенді кілька сайтів).X-Real-IP: Яка справжня IP-адреса клієнта?X-Forwarded-For: Весь ланцюжок IP-адрес, через які пройшов запит (якщо проксі серверів було кілька).
💡 Запам'ятайте головне:
proxy_passпересилає запит, але "стирає" особистість клієнта.proxy_set_headerвідновлює цю особистість, передаючи метадані.
3. 🧪 Приклади (від простого до реального)
Приклад 1: "Амнезія" (Базовий проксі)
Ось найпростіша конфігурація.
location / {
proxy_pass http://localhost:8000;
}
Що ви очікуєте? Сайт працює.
Що бачить бекенд?
Host: localhost:8000
Remote Address: 127.0.0.1
Ваш додаток думає, що до нього звертається локальний скрипт, а не жива людина з Інтернету. Якщо додаток згенерує посилання на самого себе, він може створити посилання типу http://localhost:8000/image.jpg, яке у користувача не відкриється.
Приклад 2: "Паспортний контроль" (Правильний проксі)
Виправляємо ситуацію. Додаємо передачу особистості.
location / {
proxy_pass http://localhost:8000;
# Передаємо оригінальний домен (наприклад, my-shop.com), а не localhost
proxy_set_header Host $host;
# Передаємо справжній IP користувача
proxy_set_header X-Real-IP $remote_addr;
# Передаємо історію IP (для сумісності з фреймворками)
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Чому це круто?
1. $host — змінна Nginx, що містить ім'я домену з запиту клієнта.
2. $remote_addr — IP клієнта.
3. Тепер ваш бекенд у логах бачить: Remote Address: 192.168.1.50 (реальний IP).
Приклад 3: "Проблема Слеша" (Класика жанру)
Подивіться уважно на ці два рядки. Як думаєте, є різниця?
proxy_pass http://localhost:8000;proxy_pass http://localhost:8000/;(зі слешем у кінці)
Це змінює все! 🤯
- Варіант 1 (без слеша): Nginx передає шлях "як є".
Якщо запит
/api/users, на бекенд полетить/api/users. - Варіант 2 (зі слешем): Nginx замінює частину шляху, яка співпала в
location, на те, що після слеша (тобто на корінь). Якщоlocation /api/, а запит/api/users, то на бекенд полетить просто/users.
Це найчастіша помилка новачків, через яку "відвалюються" API.
4. 🛠 Практична частина
Час забруднити руки кодом! Виконайте ці завдання, щоб закріпити матеріал.
Задача 1: Налаштування детектива 🕵️♂️
Налаштуйте Nginx так, щоб він проксував запити з порту 80 на порт 3000 (умовний Node.js).
* Вимога: Бекенд повинен знати, що запит прийшов з браузера Chrome (передайте заголовок User-Agent). Підказка: Nginx передає його автоматично, але переконайтеся в цьому.
Задача 2: Підміна особистості 🎭
Використовуючи proxy_set_header, створіть конфіг, де ви "брешете" бекенду.
* Зробіть так, щоб незалежно від того, хто заходить на сайт, бекенд думав, що це заходить користувач із заголовком My-Custom-Header: Hello-CS50.
Задача 3: Вирішення конфлікту шляхів 🛣
У вас є бекенд, який очікує запити на адресу /v1/status.
Але на сайті ви хочете, щоб це було доступно за адресою /server-health.
* Напишіть location і proxy_pass (зі слешем чи без?), щоб /server-health перетворювалось у /v1/status на бекенді.
Задача 4: Міні-кейс 💼
Ви розробляєте чат. Вам потрібно, щоб Nginx підтримував WebSocket з'єднання (які потребують особливих заголовків Upgrade та Connection). Знайдіть інформацію або здогадайтеся, які proxy_set_header треба додати, щоб канал зв'язку не обривався.
5. 💡 Мислення як у розробника
Як думає Senior DevOps або досвідчений Backend-розробник, коли налаштовує проксі?
-
"Don't Repeat Yourself" (DRY): Замість того, щоб копіювати
proxy_set_headerу кожнийlocation, вони створюють окремий файл (наприклад,proxy_params) і просто підключають його:nginx location / { proxy_pass http://localhost:8000; include proxy_params; # Краса! 😍 } -
Безпека насамперед: Вони знають, що заголовок
Hostкритично важливий для захисту від атак типу HTTP Host Header attacks. Вони ніколи не забувають його передавати. -
Зналагодження (Debugging): Якщо щось не працює, вони не вгадують. Вони дивляться:
access.logNginx.- Логи програми.
- Використовують
curl -v, щоб бачити заголовки відповіді.
Типова помилка новачка:
Думати, що proxy_pass — це магія. Ні, це просто HTTP-запит всередині HTTP-запиту. Якщо ви це зрозумієте, ви зможете дебажити будь-яку проблему.
6. 🧩 Підсумок
Отже, що ми сьогодні розібрали?
- Nginx — це посередник. Він як перекладач, який може або передати ваші слова точно, або спотворити їх.
proxy_pass— це механізм пересилання запиту на інший сервер (або порт).- Без
proxy_set_headerваш бекенд сліпий. Він не знає реального IP користувача і реального хоста. - Слеш має значення.
/у кінціproxy_passзмінює URL, відсутність — залишає як є.
Що ви тепер вмієте?
Ви можете "подружити" будь-який бекенд (Python, Go, Node.js) з Nginx так, щоб додаток отримував коректні дані про користувачів. Ви більше не боїтеся, що всі клієнти стануть 127.0.0.1.
🔮 У наступній серії... Ми навчимося керувати трафіком як боги. Що, якщо у вас не один бекенд, а три? Як розподілити навантаження між ними, щоб жоден не впав? Готуйтесь, тема наступного уроку: Load Balancing (Балансування навантаження).
А поки що — практикуйтесь і не забувайте перевіряти логи! Це був CS50... тобто, ваш урок з Nginx. 😉
Успіхів у коді!