Wdrożenie aplikacji internetowych wielokontynerów z docker komposi i nginx

Wprowadzenie

Modern web applications rarely run a single monolithic process. Instad, they are composted of multiple collaborations: a frontend, an API, a datase, a cache, a message queue, and perhaps a jobr runner. Manually management thee lifecycle of each controler, their networking, and their depensiont, production- lies errone and -consuming. Docker Compose and Nginx together provide a divide a divitable-ted, production- lly solutin for deziinen and deloyinging theme.

Warunki wstępne

Before diving in, ensure you have the following installad on your system:

Opcjonalne have a domayn name pointing to your server if you plan to follow thee SSL configuation section.

Understanding Docker Compose in Depph

Docker Compose tool that lets you define services, networks, volumes, environment variables, restart policies, and health checks in a single file called indiv1; Il 1; FLT: 1 X3; Il; Il; Il.; Il. Compose specification services, networks; Il; Il; Il; Il.

Usługi

Each container image, it s ports, volumes, environment, and dependencies are defined the defined 1; indi.1; FLT: 2 means 3; indirection3; key. Services can communicate with each each text via a dedicated bridge network that Compose creats automatically. This means you never need to open host ports for inter- servie communication - only the reversy proxy neesti to expose ports tte the outside.

Sieci

By default, Compose creats a single network for all services, giving them DNS- based services discvery using the services name as the hostname. For example, a service named for services, for also define for disolation - for instance, putting only the reverse proxy on a public- facing network and keeping dase one nepanders never nal work.

networks:
 frontend:
 backend:
services:
 nginx:
 networks:
 - frontend
 app:
 networks:
 - frontend
 - backend
 db:
 networks:
 - backend

Wulkany

Volumes are thee preferred mechanism for persisting data generated by Docker containers. In Compose, you can declarate named volumes at te top level and d mount them into services. This is essential for datases, file uploads, and any stateful services.

volumes:
 db_data:
services:
 postgres:
 image: postgres:16
 volumes:
 - db_data:/var/lib/postgresql/data

Środowisko Zmienne

Externalie configuation using environment variables. You can hardcode them im Compose file for development, but for production you should use e.1.; Department 1; FLT: 7 memorial 3; FLT: 7 metrix; 3; files or Docker secrets. Compose automatically y loads a e.1; FLT: 8 metriamorious 3; FLT; 3; file located in theme directory if you don 't specify 1; FLT: 9 metriamorious 3; FLT: 9 metriamorioil 3;

services:
 api:
 image: my-api:latest
 env_file:
 - ./api.env
 environment:
 - NODE_ENV=production

Configuring Nginx as a Reverse Proxy - Advanced

Nginx shines a reverse proxy because of it high performance, low memory footprint, and rich difficure set. In a multicontexe proxy architecture, Nginx sits at thee edge, accepts client requests, and forwards them tem te e appropriate services based on thee request URI, headers, or even body content. It can also handle SSL termition, caching, rate limiting, and load balancing.

Basic Reverse Proxy wigh Multiple Upstreams

Here is a more complete configuation that demonstrantates how to split traffic between two different applications, including ding handling static assets andWebSockets:

upstream app1_upstream {
 server app1:8000;
}

upstream app2_upstream {
 server app2:8001;
}

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

server {
 listen 443 ssl http2;
 server_name example.com;

 ssl_certificate /etc/nginx/certs/fullchain.pem;
 ssl_certificate_key /etc/nginx/certs/privkey.pem;

 # Security headers
 add_header X-Frame-Options "SAMEORIGIN" always;
 add_header X-Content-Type-Options "nosniff" always;
 add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

 # App 1 – main web frontend
 location / {
 proxy_pass http://app1_upstream;
 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;
 }

 # App 2 – admin dashboard
 location /admin/ {
 proxy_pass http://app2_upstream/;
 proxy_set_header Host $host;
 proxy_set_header X-Real-IP $remote_addr;
 }

 # WebSocket support (e.g., for live updates)
 location /ws/ {
 proxy_pass http://app1_upstream;
 proxy_http_version 1.1;
 proxy_set_header Upgrade $http_upgrade;
 proxy_set_header Connection "upgrade";
 }

 # Static assets – serve directly for better performance
 location /static/ {
 alias /var/www/static/;
 expires 30d;
 add_header Cache-Control "public, immutable";
 }
}

Uwaga: te wszystkie zasady są dostępne dla 1; 1; FLT: 12 contacts 3; 3; blocks. They allow you tu definie a group of servers for load balancing. Even wigh a single server, using an upstream group makes it easy to add more replicas later with out touching the server block.

SSL / TLS wigh Let 's Encrypt

For production, serving HTTPS is non-difficable. You can automate certificate renewal using Certbot or distribution 1; Xi1; FLT: 0 disable3; acme.sh diplorate 1; FLT: 1 diplorate 3; Xi3; inside a sidecar container. A contaxel is to mount the certificates as volumes into the Nginx contaxer. For example:

services:
 nginx:
 image: nginx:alpine
 volumes:
 - ./nginx.conf:/etc/nginx/conf.d/default.conf
 - ./certs:/etc/nginx/certs:ro
 - ./static:/var/www/static:ro
 ports:
 - "80:80"
 - "443:443"
 depends_on:
 - app1
 - app2

For automatic renewal, you can add a companion container like indi1; endi1; FLT: 14 contain3; entitle3; or contain1; entitle1; entitle1; FLT: 15 contain3; entitle3; thatruns a cron jobd and reloads Nginx when certificates are refreshed.

Load Balancing i Health Checks

When you scale a service to multiple replicas, Nginx can difficee requests using ronda-robin, least connections, or IP hash. Combinate this witch Docker Compose 's previdence 1; FLT: 16 contributions 3; option:

upstream api_servers {
 least_conn;
 server api:80 max_fails=3 fail_timeout=30s;
}

To detect unhealty conteners, Nginx can be configured with indi1; Xi1; FLT: 18 X3; Xi3; (requires NGINX Plus or use the Xi1; Xi1; FLT: 19 XI3; XI3; frem the open- source version with a small workaround). A simpler contritiva is to rely on Docker 's health checks and only register contribuers that pass.

Building thee Docker Compose File - A Real-Worlds Example

Let 's combinae everthing into a practical Compose file for a web application consideng of a Node.js API, a React frontend served by by Nginx, a PostgreSQL datase, and a Redis cache. The Nginx container will serve static files and proxy API requests.

version: "3.9"

services:
 nginx:
 image: nginx:alpine
 container_name: reverse-proxy
 restart: unless-stopped
 volumes:
 - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
 - ./frontend/build:/var/www/frontend:ro
 - ./certs:/etc/nginx/certs:ro
 ports:
 - "80:80"
 - "443:443"
 depends_on:
 - api
 - frontend
 networks:
 - public

 frontend:
 image: my-frontend:latest
 # In production, frontend is built into static files and served by Nginx
 # This container may run a dev server, but Nginx will bypass it for static files
 container_name: frontend-dev
 ports:
 - "3000:3000"
 networks:
 - public
 # healthcheck: ...

 api:
 image: my-api:latest
 container_name: api-server
 restart: unless-stopped
 env_file:
 - ./api/.env.production
 depends_on:
 postgres:
 condition: service_healthy
 redis:
 condition: service_started
 networks:
 - public
 - internal
 healthcheck:
 test: ["CMD", "curl", "-f", "http://localhost:4000/health"]
 interval: 30s
 timeout: 10s
 retries: 3

 postgres:
 image: postgres:16-alpine
 container_name: database
 restart: unless-stopped
 environment:
 POSTGRES_USER: app_user
 POSTGRES_DB: app_db
 POSTGRES_PASSWORD_FILE: /run/secrets/db_password
 volumes:
 - pgdata:/var/lib/postgresql/data
 secrets:
 - db_password
 networks:
 - internal
 healthcheck:
 test: ["CMD-SHELL", "pg_isready -U app_user"]
 interval: 10s
 timeout: 5s
 retries: 5

 redis:
 image: redis:7-alpine
 container_name: cache
 restart: unless-stopped
 volumes:
 - redisdata:/data
 networks:
 - internal
 healthcheck:
 test: ["CMD", "redis-cli", "ping"]
 interval: 10s
 timeout: 3s

volumes:
 pgdata:
 redisdata:

networks:
 public:
 internal:
 internal: true

secrets:
 db_password:
 file: ./secrets/db_password.txt

Key points in this file:

Deploying the Application - Step by Step

With the Compose file and Nginx configuation ready, deployment involves a few simple commands. First, ensure all configuation files are in place:

project/
├── docker-compose.yml
├── nginx/
│ └── nginx.conf
├── api/
│ └── .env.production
├── frontend/
│ └── build/
├── certs/
│ └── (fullchain.pem, privkey.pem)
└── secrets/
 └── db_password.txt

Run:

docker compose pull # pull latest images
docker compose up -d # start all services in background
docker compose ps # verify services are running
docker compose logs -f # tail logs for all services

Once everthing is up, tect the application by y visiting your domain. Check Nginx logs to confirm requests are being proxied correctly. If you need to update thee configuration or environment variables, edit the relevant files and run:

docker compose up -d --no-deps --build nginx # rebuild only nginx if config changed

For zero-downtime deployments, consider using presenti1; Sui1; FLT: 0 sui3; Suix 3; Sui1; FLT: 1 sui3; Sui3; Or sui1; Sui1; FLT: 2 suidure 3; Suidu3; rolling updates presenti1; Sui1; FLT: 3 sui3; Suidu3; Witch Compose 's presentione1; Sui1; FLT: 29 suiseend; Suiture and Nginx upstream health checks.

Scaling andd Performance Tuning

Docker Compose makes it trivial to scale stateless services like the API:

docker compose up -d --scale api=3

Nowth three replicas of thee API container are running. Nginx, configured with the upstream block, will automaticaly distribute requests among them. To further enhance performance:

For databases, ensure you have connection pooling in your API and consider using PgBouncer as a sidecar container.

Rozwiązywanie problemów Common Emites

Eun wigh a well-structured setup, things can go wrong. Here are e frequent pitfalls andd how to fix them:

Security Bett Practices

Running multicontainer applications in production requires vigilance:

services:
 api:
 deploy:
 resources:
 limits:
 cpus: '0.50'
 memory: 256M
 reservations:
 cpus: '0.25'
 memory: 128M

Tese limits are respected when using Docker swarm; for plain Compose, they are enforced witch indi.1; Gior1; FLT: 43 contribution 3; Gior3; (though it 's better to use swarm or K8 s for production orchestration).

Konkluzja

1s; 1s; 1s; 1s; 1s; t; 1s; t; 1s; t; 1s; t; 1s; t; 1s; t; 1s; t; 1s; t; t; 1s; t; t; t; t; 1s; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t; t;