如何用Docker Compose实现双域名指向同一项目并分连不同数据库?
Alright, let's break down how to get your two domains pointing to the same app instance but connecting to separate databases using Docker Compose. Here's a practical, step-by-step solution tailored to your setup:
The key is to use Nginx as a reverse proxy to route requests from each domain to your single app service, while passing the domain information to the app. Your app will then use that domain info to connect to the corresponding database. We'll also spin up two independent database containers for each domain.
We'll modify your existing docker-compose.yml to add two database services, keep your single app service, and add an Nginx proxy service. Here's the full config:
version: '3.8' services: # Shared app service (uses the same codebase) app: build: . # Assumes your Dockerfile is in the current directory environment: - APP_ENV=local # Add any shared env vars here volumes: - ./app:/app # Mount local code for development convenience depends_on: - db_xyz_com - db_xyz_net networks: - app_network # Database for xyz.com db_xyz_com: image: mysql:8.0 # Swap with your preferred DB (PostgreSQL, MongoDB, etc.) environment: - MYSQL_ROOT_PASSWORD=secure_root_pass_123 - MYSQL_DATABASE=xyz_com_db - MYSQL_USER=xyz_app_user - MYSQL_PASSWORD=secure_app_pass_456 volumes: - db_com_data:/var/lib/mysql # Isolated volume for xyz.com data networks: - app_network # Database for xyz.net db_xyz_net: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=secure_root_pass_123 - MYSQL_DATABASE=xyz_net_db - MYSQL_USER=xyz_app_user - MYSQL_PASSWORD=secure_app_pass_456 volumes: - db_net_data:/var/lib/mysql # Isolated volume for xyz.net data networks: - app_network # Nginx reverse proxy to handle domain routing nginx: image: nginx:alpine ports: - "80:80" # Map port 80 on your host to Nginx volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf # Mount custom Nginx config depends_on: - app networks: - app_network volumes: db_com_data: db_net_data: networks: app_network: driver: bridge
Create an nginx.conf file in the same directory as your docker-compose.yml. This config will route requests based on the incoming domain and pass the domain name to your app:
server { listen 80; server_name xyz.com www.xyz.com; location / { proxy_pass http://app:2000; # Forward to your app's internal port (matches your original localhost:2000) proxy_set_header Host $host; # Pass the original domain to the app proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } server { listen 80; server_name xyz.net www.xyz.net; location / { proxy_pass http://app:2000; proxy_set_header Host $host; # Critical for the app to identify the domain proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
This is the most important part—your app needs to detect the incoming domain and use the corresponding database connection. Here's an example using Python/Flask (the logic translates to any language):
from flask import Flask, request import mysql.connector app = Flask(__name__) # Define database configs for each domain DB_CONFIGS = { "xyz.com": { "host": "db_xyz_com", # Matches the DB service name in Docker Compose "user": "xyz_app_user", "password": "secure_app_pass_456", "database": "xyz_com_db" }, "xyz.net": { "host": "db_xyz_net", "user": "xyz_app_user", "password": "secure_app_pass_456", "database": "xyz_net_db" } } def get_db_connection(): # Extract the domain (strip www if present) raw_host = request.host.split(':')[0] domain = raw_host[4:] if raw_host.startswith('www.') else raw_host # Fallback to xyz.com if domain isn't recognized config = DB_CONFIGS.get(domain, DB_CONFIGS["xyz.com"]) return mysql.connector.connect(**config) @app.route('/') def home(): conn = get_db_connection() cursor = conn.cursor() cursor.execute("SELECT DATABASE()") current_db = cursor.fetchone()[0] return f"Welcome to {request.host}! Connected to database: {current_db}" if __name__ == '__main__': app.run(host='0.0.0.0', port=2000)
For other languages (Node.js/Express, PHP, etc.), the logic is identical:
- Grab the
Hostheader from the request - Map it to the corresponding database config
- Use that config to establish a connection
Since you're testing locally, add these lines to your system's hosts file to point the domains to your localhost:
- Windows:
C:\Windows\System32\drivers\etc\hosts - macOS/Linux:
/etc/hosts
127.0.0.1 xyz.com 127.0.0.1 xyz.net
Run this command to build and start all services:
docker-compose up -d --build
Now open your browser and visit:
http://xyz.com→ Should show it's connected toxyz_com_dbhttp://xyz.net→ Should show it's connected toxyz_net_db
- Database Initialization: If you need to seed each database with tables/data, mount an init script to each DB service. For example, add
- ./init_com.sql:/docker-entrypoint-initdb.d/init.sqltodb_xyz_comvolumes, and a correspondinginit_net.sqlfordb_xyz_net. - Production Considerations: For production, add SSL certificates (use Let's Encrypt with Nginx) and harden database security (avoid root users, use stronger passwords).
- Config Management: Instead of hardcoding DB configs in your app, use environment variables or external config files for easier updates.
内容的提问来源于stack exchange,提问作者Aayush Raj Joshi

