Search code examples
phpdockernginxdocker-compose

Is it possible to publish multiple sites on port 80 on a single server in Docker?


First of all, I should mention that I am not good at docker. And thank you in advance for your help.

A Laravel project is currently running on Docker on a VPS server (this site will be called a.com)

For a.com I am sharing below docker-compose-production.yaml and nginx.conf

docker-compose-production.yml:

networks:
    default:
        driver: bridge

services:
  a.com:
    restart: always
    build: .docker/prod/php
    container_name: acom_php
    networks:
      - default
    volumes:
      - .:/var/www
  nginx:
    restart: always
    image: nginx:stable
    container_name: a_nginx
    networks:
      - default
    links:
      - a.com
    ports:
      - 80:80
      - 443:443
    volumes:
      - .:/var/www
      - .docker/prod/nginx/default.conf:/etc/nginx/conf.d/default.conf
      - .docker/prod/nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./certbot/www:/var/www/certbot/
      - ./certbot/conf/:/etc/nginx/ssl/
    depends_on:
      - a.com
      - mysql
  certbot:
    image: certbot/certbot
    volumes:
      - ./certbot/www/:/var/www/certbot/
      - ./certbot/conf/:/etc/letsencrypt/
    depends_on:
      - nginx
  mysql:
    restart: unless-stopped
    platform: linux/amd64
    image: mysql:8.0
    container_name: acom_db
    networks:
      - default
    ports:
      - 1300:3306
    volumes:
      - .docker/prod/db/data:/var/lib/mysql
      - .docker/prod/logs:/var/log/mysql
      - .docker/prod/db/my.cnf:/etc/mysql/conf.d/my.cnf
      - .docker/prod/db/sql:/docker-entrypoint-initdb.d
    environment:
      MYSQL_ROOT_PASSWORD: acom_password
      MYSQL_DATABASE: acom
      MYSQL_USER: acom_laravel
      MYSQL_PASSWORD: acom_secret
  phpmyadmin:
    restart: unless-stopped
    platform: linux/amd64
    image: phpmyadmin/phpmyadmin
    container_name: acom_phpmyadmin
    networks:
      - default
    ports:
      - 8080:80
    links:
      - mysql
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      UPLOAD_LIMIT: 300M
      PHP_MEMORY_LIMIT: 2048M
    depends_on:
      - mysql
    volumes:
      - .docker/prod/phpmyadmin/sessions:/sessions

nginx.conf:

server {
    listen 80;
    listen [::]:80;

    server_name a.com a.com;
    server_tokens off;

    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
    }

    location / {
        return 301 https://a.com$request_uri;
    }
}

server {
  listen 443 ssl;
  server_name a.com;
  return 301 https://a.com$request_uri;

  ssl_certificate /etc/nginx/ssl/live/a.com/fullchain.pem;
  ssl_certificate_key /etc/nginx/ssl/live/a.com/privkey.pem;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  http2 on;
  server_name a.com a.com;
  index index.php index.html;
  root /var/www/public;

  ssl_certificate /etc/nginx/ssl/live/a.com/fullchain.pem;
  ssl_certificate_key /etc/nginx/ssl/live/a.com/privkey.pem;

  client_max_body_size 300M; # 413 Request Entity Too Large
 
  index index.php;
 
  charset utf-8;

  location / {
    try_files $uri $uri/ /index.php?$query_string;
  }

  location = /favicon.ico { access_log off; log_not_found off; }
  location = /robots.txt  { access_log off; log_not_found off; }

  error_page 404 /index.php;

  location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass a_php:9000;
    fastcgi_read_timeout 3600;
    fastcgi_index index.php;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    send_timeout 3600;
    proxy_connect_timeout 3600;
    proxy_read_timeout    3600;
    proxy_send_timeout    3600;
  }
}

With the above settings, a.com works fine without any problems.

My main problem is when I want to use the same settings for b.com Laravel project: Bind for 0.0.0.0.0:80 failed: port is already allocated error. I understand the cause of this error and set the ports in docker-compose-production.yaml for b.com to be different and docker starts working.

Assume I am using the following ports for the b.com site.

  • ports
    • 8001:80 # nginx 80
    • 8002:443 # nginx 443
    • 1301:3306 # mysql 3306
    • 8081:80 # phpmyadmin

nginx.conf: (for testing purposes)

server {
    listen 80;
    listen [::]:80;

    server_name b.com www.b.com;
    root /var/www/public;
    server_tokens off;

    client_max_body_size 300M; # 413 Request Entity Too Large
  
    index index.php;
  
    charset utf-8;

    location / {
      try_files $uri $uri/ /index.php?$query_string;
    }

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

    location ~ \.php$ {
      try_files $uri =404;
      fastcgi_split_path_info ^(.+\.php)(/.+)$;
      fastcgi_pass bcom_php:9000;
      fastcgi_read_timeout 3600;
      fastcgi_index index.php;
      include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
      send_timeout 3600;
      proxy_connect_timeout 3600;
      proxy_read_timeout    3600;
      proxy_send_timeout    3600;
    }
}
  • I run each project with docker compose up -d --build command

With these settings, when Docker runs and I visit b.com, it automatically redirects me to a.com. I can't figure out what I'm doing wrong, I think it automatically redirects me to a.com because port 80 is currently on the other Docker container.

I would be very grateful if you can help me.


Solution

  • You are using root /var/www/public for both a.com and b.com and in your docker-compose file you have in a.com volumes mapping - .:/var/www You need to either find a way to map your two projects to separate directories in your nginx container or in case your Laravel project is a standalone project you could use nginx as a reverse proxy and use something like proxy_pass: b.com:port for your b.com configuration in nginx.