PhuongTT
PhuongTT

Reputation: 355

Docker Nginx + Multiple domains + multiple wordpress on their own directories in 1 vps

Currently, I want to run multiple wordpress sites with multiple domains in 1 vps. I hope I can separate each wordpress in separated sub folders.

I tried with many different ways but I always got 404 error at the first time I visit to setup wordpress.

Here is my error log in nginx error.log

*6 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 192.168.63.1, server: site1.com, request: "GET / HTTP/1.0", upstream: "fastcgi://172.21.0.4:9000", host: "192.168.63.130"

Could anyone explain to me what I'm doing wrong? Thank you!

docker-compose.yml

version: '3.6'
services:
  nginx:
    image: nginx:1.15.7-alpine
    container_name: nginx
    ports:
      - '80:80'
      - '443:443'
    volumes:
      - ./nginx:/etc/nginx
      - ./logs/nginx:/var/log/nginx
      - ./wordpress:/var/www/html
      - ./certs:/etc/letsencrypt
      - ./certs-data:/data/letsencrypt
    links:
      - site1
      - site2
    restart: always

  mysql:
    image: mariadb
    container_name: mysql
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password
    restart: always

  site1:
    image: wordpress:php7.2-fpm-alpine
    container_name: site1
    volumes:
      - ./wordpress/site1:/var/www/html/
      - ./php/conf.d/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    environment:
      - WORDPRESS_DB_NAME=site1
      - WORDPRESS_TABLE_PREFIX=wp_
      - WORDPRESS_DB_HOST=mysql
      - WORDPRESS_DB_PASSWORD=password
    links:
      - mysql
    restart: always

  site2:
    image: wordpress:php7.2-fpm-alpine
    container_name: site2
    volumes:
      - ./wordpress/site2:/var/www/html/
      - ./php/conf.d/uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
    environment:
      - WORDPRESS_DB_NAME=site2
      - WORDPRESS_TABLE_PREFIX=wp_
      - WORDPRESS_DB_HOST=mysql
      - WORDPRESS_DB_PASSWORD=password
    links:
      - mysql
    restart: always

/nginx/sites-enabled/site1 (site2 is the same with replace site1 to site2

fastcgi_cache_path /var/cache/nginx/site1 levels=1:2 keys_zone=site1:100m inactive=60m;

server {
        # Ports to listen on
        listen 80;
        listen [::]:80;

        # Server name to listen for
        server_name site1.com;

        # Path to document root
        root /var/www/html/site1;

        # File to be used as index
        index index.php;

        # Overrides logs defined in nginx.conf, allows per site logs.
        access_log /var/log/nginx/site1.access.log;
        error_log /var/log/nginx/site1.error.log crit;

        # Default server block rules
        include global/server/defaults.conf;

        # Fastcgi cache rules
        include global/server/fastcgi-cache.conf;

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

        location ~ \.php$ {
                try_files $uri =404;
                include global/fastcgi-params.conf;

                fastcgi_pass   site1:9000;

                # Skip cache based on rules in global/server/fastcgi-cache.conf.
                fastcgi_cache_bypass $skip_cache;
                fastcgi_no_cache $skip_cache;

                # Define memory zone for caching. Should match key_zone in fastcgi_cache_path above.
                fastcgi_cache site1;

                # Define caching time.
                fastcgi_cache_valid 60m;
        }

        # Rewrite robots.txt
        rewrite ^/robots.txt$ /index.php last;

        # Uncomment if using the fastcgi_cache_purge module and Nginx Helper plugin (https://wordpress.org/plugins/nginx-helper/)
        # location ~ /purge(/.*) {
        #       fastcgi_cache_purge fastcgi-cache.com "$scheme$request_method$host$1";
        # }
}

# Redirect www to non-www
server {
        listen 80;
        listen [::]:80;
        server_name www.site1.com;

        return 301 $scheme://site1.com$request_uri;
}

Upvotes: 1

Views: 4954

Answers (3)

user2641832
user2641832

Reputation: 1

Uros Majeric's answer helped me (not enough reputation to comment)

However, I had to change each of the Docker volume in the Wordpress container to exactly match the nginx, ie.

  wordpress1:
  ###
    volumes:
      - wordpress1:/var/www/domain1.com

  wordpress2:
  ###
    volumes:
      - wordpress2:/var/www/domain2.com

Upvotes: 0

Uros Majeric
Uros Majeric

Reputation: 456

Maybe it will help someone. I successfully deployed multiple (domains) WordPress docker containers with single Nginx docker.

docker-compose.yml:

version: '3'

services:
  db:
    image: mysql:8.0
    container_name: db
    restart: unless-stopped
    env_file: .env
    environment:
      - MYSQL_DATABASE=wordpress
    volumes:
      - dbdata:/var/lib/mysql
      - ./mysql:/docker-entrypoint-initdb.d
    command: '--default-authentication-plugin=mysql_native_password'
    networks:
      - app-network

  wordpress1:
    depends_on:
      - db
    image: wordpress:6.0.1-fpm-alpine
    container_name: wordpress1
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress1
    volumes:
      - wordpress1:/var/www/html
    networks:
      - app-network

  wordpress2:
    depends_on:
      - db
    image: wordpress:6.0.1-fpm-alpine
    container_name: wordpress2
    restart: unless-stopped
    env_file: .env
    environment:
      - WORDPRESS_DB_HOST=db:3306
      - WORDPRESS_DB_USER=$MYSQL_USER
      - WORDPRESS_DB_PASSWORD=$MYSQL_PASSWORD
      - WORDPRESS_DB_NAME=wordpress2
    volumes:
      - wordpress2:/var/www/html
    networks:
      - app-network

  webserver:
    depends_on:
      - wordpress1
      - wordpress2
    image: nginx:1.15.12-alpine
    container_name: webserver
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - wordpress1:/var/www/domain1.com
      - wordpress2:/var/www/domain2.com
      - ./nginx-conf:/etc/nginx/conf.d
      - certbot-etc:/etc/letsencrypt
    networks:
      - app-network

  certbot:
    depends_on:
      - webserver
    image: certbot/dns-cloudflare
    container_name: certbot
    volumes:
      - certbot-etc:/etc/letsencrypt
      - ./certbot:/etc/letsencrypt-conf
    command: certonly -v --cert-name domain1.com --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt-conf/cloudflareapi.cfg --agree-tos --email [email protected] --no-eff-email --non-interactive --server https://acme-v02.api.letsencrypt.org/directory -d "*.domain1.com" -d domain1.com

#  certbot2:
#  ...

volumes:
  certbot-etc:
  wordpress1:
  wordpress2:
  dbdata:

networks:
  app-network:
    driver: bridge

nginx-conf/domain1.com.conf (wordpress2 site nginx config is pretty much the same - just replace domain1 with domain2)

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

    server_name domain1.com www.domain1.com;

    location ~ /.well-known/acme-challenge {
        allow all;
        root /var/www/domain1.com;
    }

    if ($host = www.domain1.com) {
        return 301 https://$host$request_uri;
    }
    if ($host = domain1.com) {
        return 301 https://$host$request_uri;
    }

    return 404;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl  http2 ipv6only=on;

    server_name domain1.com www.domain1.com;

    root /var/www/domain1.com;
    index index.php index.html index.htm;

    server_tokens off;

    ssl_certificate /etc/letsencrypt/live/domain1.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domain1.com/privkey.pem;
    include /etc/nginx/conf.d/options-ssl-nginx.conf;

    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;
    add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
    # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    # enable strict transport security only if you understand the implications

    location / {
            try_files $uri $uri/ /index.php$is_args$args;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass wordpress:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }

    location ~ /\.ht {
        deny all;
    }

    location = /favicon.ico {
        log_not_found off; access_log off;
    }
    location = /robots.txt {
        log_not_found off; access_log off; allow all;
    }
    location ~* \.(css|gif|ico|jpeg|jpg|js|png)$ {
        expires max;
        log_not_found off;
    }
}

I spent hours if not days to figure out I need to change:

fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

to

fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;

Hope I will spare some extra hours to anyone.

Upvotes: 7

Paco Chavez
Paco Chavez

Reputation: 36

I add a Dockerfile site1_build/Dockerfile:

FROM  wordpress:php7.2-fpm
WORKDIR /var/www/html/site1

In the docker-compose.yml file:

 site1:
    build: ./site1_build
    container_name: site1
    volumes:
      - ./wordpress/site1:/var/www/html/site1

Upvotes: 2

Related Questions