Docker на Windows 11 за допомогою підсистеми Linux в Windows (WSL): тестове вебсередовище з Nginx, PHP і Python
Коли потрібно швидко перевірити PHP, Python або Nginx, не хочеться щоразу встановлювати їх у Windows, редагувати системні змінні й потім згадувати, що саме було змінено. Docker дає просте тестове середовище: усі компоненти описані файлами проєкту, запускаються однією командою і видаляються без сліду в системі.
У цьому мануалі зберемо локальний вебстенд для Windows 11 на диску D:. Зовні буде доступний лише Nginx на http://localhost:8080; Nginx передаватиме PHP-файли у PHP-FPM, а PHP-сторінка звертатиметься до Python/Flask по внутрішній мережі Docker. Це хороший мінімальний фундамент для тестової веброзробки.
Що буде в результаті
- Nginx приймає запити браузера на порту
8080; - PHP-FPM виконує
index.php; - Python + Flask відповідає на внутрішній URL
http://python:8000/health; - код і конфігурація лежать у
D:\web-lab; - стенд запускається через
docker compose up --build -dі вимикається черезdocker compose down.
1. Підготовка Windows 11
Для Linux-контейнерів у Windows 11 рекомендую Docker Desktop з WSL 2 backend. Відкрийте PowerShell від імені адміністратора та, якщо WSL ще не встановлений, виконайте:
wsl --install
wsl --update
wsl --version
Після перезавантаження встановіть Docker Desktop for Windows. Під час першого запуску залиште увімкненим WSL 2 backend і дочекайтеся статусу Engine running. Compose уже входить до Docker Desktop, окремо його ставити не потрібно.
Перевірка в PowerShell:
docker version
docker compose version
2. Структура проєкту на диску D:
Створіть каталоги:
New-Item -ItemType Directory -Force -Path "D:\web-lab", "D:\web-lab\nginx", "D:\web-lab\php\public", "D:\web-lab\python" | Out-Null
У результаті має бути така структура:
D:\web-lab
├── docker-compose.yml
├── nginx
│ └── default.conf
├── php
│ ├── Dockerfile
│ └── public
│ └── index.php
└── python
├── Dockerfile
├── app.py
└── requirements.txt
3. Docker Compose: три сервіси
Створіть D:\web-lab\docker-compose.yml. Compose автоматично створює приватну мережу: контейнер PHP бачить Python за ім’ям сервісу python, але порт Flask не відкритий у Windows.
services:
nginx:
image: nginx:alpine
ports:
- "8080:80"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./php/public:/var/www/html:ro
depends_on:
- php
php:
build:
context: ./php
volumes:
- ./php/public:/var/www/html:ro
python:
build:
context: ./python
volumes:
- ./python:/app
command: python app.py
4. Конфігурація Nginx
Створіть D:\web-lab\nginx\default.conf:
server {
listen 80;
server_name _;
root /var/www/html;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass php:9000;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
}
location ~ /\. {
deny all;
}
}
Ключовий рядок тут – fastcgi_pass php:9000. Ім’я php не є IP-адресою: це назва сервісу з docker-compose.yml, яку Docker сам знаходить у своїй мережі.
5. PHP-FPM
Створіть D:\web-lab\php\Dockerfile:
FROM php:8.3-fpm-alpine
WORKDIR /var/www/html
Створіть D:\web-lab\php\public\index.php. Ця сторінка виконується PHP-FPM і робить внутрішній HTTP-запит до Flask.
<?php
declare(strict_types=1);
$pythonUrl = 'http://python:8000/health';
$response = @file_get_contents($pythonUrl);
$payload = $response !== false ? json_decode($response, true) : null;
$pythonIsReady = is_array($payload) && ($payload['status'] ?? '') === 'ok';
$message = $pythonIsReady
? $payload['message']
: 'Python-сервіс поки недоступний. Перевірте docker compose logs python.';
?>
<!doctype html>
<html lang="uk">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Docker web lab</title>
<style>
body { font-family: system-ui, sans-serif; max-width: 760px; margin: 64px auto; padding: 0 22px; }
.status { padding: 20px; border-radius: 10px; background: #f4f4f4; }
.ok { color: #087443; }
.error { color: #aa2635; }
code { background: #eee; padding: 2px 6px; border-radius: 4px; }
</style>
</head>
<body>
<h1>Docker test web server</h1>
<p>Nginx передав цей запит у PHP-FPM. Далі PHP звернувся до Python Flask по внутрішній Docker-мережі.</p>
<div class="status">
<h2 class="<?= $pythonIsReady ? 'ok' : 'error' ?>">
<?= $pythonIsReady ? 'Python працює' : 'Python недоступний' ?>
</h2>
<p><?= htmlspecialchars((string) $message, ENT_QUOTES, 'UTF-8') ?></p>
<p>Внутрішній URL: <code><?= htmlspecialchars($pythonUrl, ENT_QUOTES, 'UTF-8') ?></code></p>
</div>
</body>
</html>
6. Python і Flask
Створіть D:\web-lab\python\requirements.txt:
Flask==3.1.1
Створіть D:\web-lab\python\Dockerfile:
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
І нарешті D:\web-lab\python\app.py:
from flask import Flask, jsonify
app = Flask(__name__)
@app.get("/health")
def health():
return jsonify(
status="ok",
service="python-flask",
message="Python Flask відповідає коректно."
)
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)
7. Збірка та запуск
У PowerShell перейдіть у корінь проєкту та запустіть стек:
Set-Location D:\web-lab
docker compose up --build -d
docker compose ps
Відкрийте http://localhost:8080. Правильний результат – сторінка з повідомленням «Python працює» та текстом Python Flask відповідає коректно.
Те саме можна перевірити без браузера:
Invoke-WebRequest http://localhost:8080 | Select-Object -ExpandProperty Content
8. Діагностика та зупинка
- Переглянути всі логи:
docker compose logs -f - Логи лише Python:
docker compose logs -f python - Перезібрати після зміни
Dockerfileабоrequirements.txt:docker compose up --build -d - Зупинити й видалити контейнери:
docker compose down - Видалити також дані named volumes, якщо вони з’являться пізніше:
docker compose down -v
PHP- і Python-код змонтовані з диска D:. Це означає, що зміну index.php видно після оновлення браузера, а зміну app.py у цьому простому варіанті зручно застосувати перезапуском: docker compose restart python.
Що далі
Це середовище свідомо просте й призначене для локального тестування. Наступні логічні кроки: додати базу даних MariaDB або PostgreSQL, окремий .env для налаштувань, Xdebug для PHP, автоматичні тести та Git. Але навіть у такому вигляді проєкт уже демонструє головну ідею Docker: вебстенд можна відтворити на іншому комп’ютері з тих самих файлів, без ручного налаштування Nginx, PHP і Python у Windows.