Nginx wordpress website loading on /blog domain but files not loading - wordpress

Im trying to containerize my Wordpress installation.
Although Wordpress is installed in the root directory, I need to server it on www.example.com/blog domain.
Setup:
Following is my docker-compose file (I'm loading variables using an .env file):
version: '3.9'
services:
wordpress:
# default port 9000 (FastCGI)
image: wordpress:6.1.1-fpm
container_name: wp-wordpress
env_file:
- .env
restart: unless-stopped
networks:
- wordpress
depends_on:
- database
volumes:
- ${WORDPRESS_LOCAL_HOME}:/var/www/html
- ${WORDPRESS_UPLOADS_CONFIG}:/usr/local/etc/php/conf.d/uploads.ini
environment:
- WORDPRESS_DB_HOST=${WORDPRESS_DB_HOST}
- WORDPRESS_DB_NAME=${WORDPRESS_DB_NAME}
- WORDPRESS_DB_USER=${WORDPRESS_DB_USER}
- WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD}
database:
# default port 3306
image: mysql:8
container_name: wp-database
ports:
- 3306:3306
env_file:
- .env
restart: unless-stopped
networks:
- wordpress
environment:
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
volumes:
- ${MYSQL_LOCAL_HOME}:/var/lib/mysql
command:
- '--default-authentication-plugin=mysql_native_password'
nginx:
# default ports 80, 443 - expose mapping as needed to host
image: nginx:1
container_name: wp-nginx
env_file:
- .env
restart: unless-stopped
networks:
- wordpress
depends_on:
- wordpress
ports:
- "8080:80" # http
- "443:443" # https
volumes:
- ${WORDPRESS_LOCAL_HOME}:/var/www/html
- ${NGINX_CONF}:/etc/nginx/conf.d/default.conf
- ${NGINX_SSL_CERTS}:/etc/ssl:ro
- ${NGINX_LOGS}:/var/log/nginx
networks:
wordpress:
name: wp-wordpress
driver: bridge
Following is my nginx config:
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name www.example.com;
index index.php index.html index.htm;
root /var/www/html;
server_tokens off;
client_max_body_size 75M;
# update ssl files as required by your deployment
ssl_certificate /etc/ssl/fullchain.pem;
ssl_certificate_key /etc/ssl/privkey.pem;
# logging
access_log /var/log/nginx/wordpress.access.log;
error_log /var/log/nginx/wordpress.error.log;
# some security headers ( optional )
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;
location /blog {
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 $document_root$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 = /favicon.svg {
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;
}
}
What is working:
The blog is accessible on https://www.example.com/blog
What is not working:
The blog tries to load files at https://www.example.com/blog/wp-content/themes/my-theme/images/sprite.webp
This returns as 404
The file is accessible on the url without /blog (https://www.example.com/wp-content/themes/my-theme/images/sprite.webp)
I think it should only be a tweek in nginx conf to get the files to load, but Im unable to figure that out.

Related

Failed to open stream when fetching URL in docker container

I have local docker setup with nginx as reverse proxy, self-signed SSL certs, mariadb, and wordpress.
Everything works well except when fetching resources on the local domain.
Let's say the domain name is myapp.local. I have added this in the /etc/hosts and the site is loading on this domain over https.
Problem occurs when php functions like file_get_contents() or simplexml_load_file() are fetching local assets.
For an example: file_get_contents('https://myapp.local/icon.svg');
Then I get a warning:
Failed to open stream: Connection refused
Here is my docker-compose file:
${DOMAIN} is set to myapp.local in .env file.
version: '3.6'
services:
nginx:
container_name: myapp-nginx
image: nginx:latest
ports:
- 80:80
- 443:443
volumes:
- ./config/nginx.conf:/tmp/default.template
- ./certs:/etc/certs
- wp_data:/var/www/html:rw,cached
- ./www:/var/www/html/wp-content
depends_on:
- wordpress
restart: always
entrypoint: /bin/bash -c 'cat /tmp/default.template | sed "s/\\\$$domain/${DOMAIN}/g" > /etc/nginx/conf.d/default.conf && nginx -g "daemon off;"'
networks:
webnet:
aliases:
- myapp.local
mysql:
container_name: myapp-mysql
image: mariadb:latest
volumes:
- ./db_data:/var/lib/mysql
- ./config/db.cnf:/etc/mysql/conf.d/db.cnf
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_USER: root
MYSQL_PASSWORD: root
MYSQL_DATABASE: myapp
restart: always
ports:
- 3306:3306
networks:
- webnet
wordpress:
container_name: myapp-wordpress
image: wordpress:php8.0-fpm
volumes:
- ./config/php.ini:/usr/local/etc/php/conf.d/php.ini
- wp_data:/var/www/html:rw,cached
- ./www:/var/www/html/wp-content
depends_on:
- mysql
restart: always
environment:
WORDPRESS_DB_NAME: myapp
WORDPRESS_TABLE_PREFIX: wp_
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_USER: root
WORDPRESS_DB_PASSWORD: root
WORDPRESS_DEBUG: 1
networks:
- webnet
extra_hosts:
- "myapp.local:127.0.0.1"
networks:
webnet:
external: true
driver: bridge
volumes:
db_data: {}
wp_data: {}
nginx conf:
server {
listen 80;
listen [::]:80;
server_name $domain;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name $domain www.$domain;
ssl_certificate /etc/certs/$domain.pem;
ssl_certificate_key /etc/certs/$domain-key.pem;
add_header Strict-Transport-Security "max-age=31536000" always;
ssl_session_cache shared:SSL:20m;
ssl_session_timeout 10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDH+AESGCM:ECDH+AES256:ECDH+AES128:!ADH:!AECDH:!MD5;";
root /var/www/html;
index index.php;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_min_length 0;
gzip_types text/plain application/javascript text/css text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype;
client_max_body_size 100M;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
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 $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_read_timeout 300;
}
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'm struggling with this for weeks. I've tried numerous options and I'm stuck. What am I missing here? Any help is appreciated.
p.s.: rewriting/swapping functions isn't an option since these are coming from third-party plugins.

wordpress page, post url on nginx inside docker container automatically redirect to root domain with 301 status

I have successfully setup a wordpress site running on a dockerized nginx. When the wordpress site is up and running, I can go to the home page: https://my_domain.com or any links or at after wp-admin/... without any problem.
But when I go to https://my_domain.com/sample-page or https://my_domain.com/post-id it immediately redirects to the root domain http://my_domain.com
wordpress nginx post, page url automatically redirects to root domain
with exception route /wp-admin/ when accessed redirects correctly to https://my_domain.com/wp-admin/login.php if not logged in and to https://my_domain.com/wp-admin/ if logged in
Here is my nginx config at /nginx/default.conf:
server {
listen 80;
listen [::]:80;
server_name my_domain.com www.my_domain.com;
location / {
return 301 https://my_domain.com$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name my_domain.com www.my_domain.com;
index index.php index.html index.htm;
root /var/www/html/wordpress;
ssl on;
server_tokens off;
ssl_certificate /etc/nginx/ssl/live/my_domain.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/my_domain.com/privkey.pem;
ssl_dhparam /etc/nginx/dhparam/dhparam-2048.pem;
ssl_buffer_size 8k;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
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;
proxy_pass http://wordpress_host:80;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
proxy_pass http://wordpress_host:80;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
}
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 also config at wp-config.php:
define('FORCE_SSL_ADMIN', true);
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
$_SERVER['HTTPS']='on';
define('WP_SITEURL', 'https://www.my_domain.com/');
define('WP_HOME', 'https://www.my_domain.com/');
Update:
Here the docker compose file:
version: '3';
services:
nginx:
image: nginx:stable-alpine
ports:
- "80:80" # nginx listen on 80
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./wordpress/app:/var/www/html/wordpress
db:
image: mysql:8.0
container_name: db-example
restart: unless-stopped
env_file: ./wordpress/app/.env
environment:
- MYSQL_DATABASE=example
volumes:
- ./wordpress/dbdata:/var/lib/mysql
#- ./wordpress/db/db.sql:/docker-entrypoint-initdb.d/install_wordpress.sql #if you have db.sql of project input here
command: '--default-authentication-plugin=mysql_native_password'
wordpress_host:
depends_on:
- db
image: wordpress
container_name: wordpress_host
ports:
- "8080:80"
restart: unless-stopped
env_file: ./wordpress/app/.env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_PASSWORD=root
- WORDPRESS_DB_NAME=example
volumes:
- ./wordpress/app:/var/www/html/wordpress
volumes:
wordpress-host:
dbdata
:
.env file:
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=example
MYSQL_PASSWORD=password

dockerized nginx try_files causes dockerized wordpress url(except /wp-admin) to 500 Internal Server Error or auto redirect to root domain

I have successfully setup a wordpress site running on a dockerized nginx. When the wordpress site is up and running, I can go to the home page: https://my_domain.com or any links or at after wp-admin/... without any problem.
But when I go to https://my_domain.com/sample-page or https://my_domain.com/post-id or any route except after \wp-admin it then:
immediately redirects to the root domain http://my_domain.com if I set:
try_files $uri $uri/ /index.php$is_args$args;
or dont auto redirect to root domain but return 500 Internal Server Error if I set(add a / after index.php):
try_files $uri $uri/ /index.php/$is_args$args;
with exception route /wp-admin/ when accessed redirects correctly to https://my_domain.com/wp-admin/login.php if not logged in and to https://my_domain.com/wp-admin/ if logged in, in all 2 of try_files cases above.
Here is my nginx config at /nginx/default.conf:
server {
listen 80;
listen [::]:80;
server_name my_domain.com www.my_domain.com;
location / {
return 301 https://my_domain.com$request_uri;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name my_domain.com www.my_domain.com;
index index.php index.html index.htm;
root /var/www/html/wordpress;
ssl on;
server_tokens off;
ssl_certificate /etc/nginx/ssl/live/my_domain.com/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/live/my_domain.com/privkey.pem;
ssl_dhparam /etc/nginx/dhparam/dhparam-2048.pem;
ssl_buffer_size 8k;
ssl_protocols TLSv1.2 TLSv1.1 TLSv1;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:!ADH:!AECDH:!MD5;
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;
proxy_pass http://wordpress_host:80;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
proxy_pass http://wordpress_host:80;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
}
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 also config at wp-config.php:
define('FORCE_SSL_ADMIN', true);
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
$_SERVER['HTTPS']='on';
define('WP_SITEURL', 'https://www.my_domain.com/');
define('WP_HOME', 'https://www.my_domain.com/');
Update:
Here the docker compose file:
version: '3';
services:
nginx:
image: nginx:stable-alpine
ports:
- "80:80" # nginx listen on 80
- "443:443"
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./wordpress/app:/var/www/html/wordpress
db:
image: mysql:8.0
container_name: db-example
restart: unless-stopped
env_file: ./wordpress/app/.env
environment:
- MYSQL_DATABASE=example
volumes:
- ./wordpress/dbdata:/var/lib/mysql
#- ./wordpress/db/db.sql:/docker-entrypoint-initdb.d/install_wordpress.sql #if you have db.sql of project input here
command: '--default-authentication-plugin=mysql_native_password'
wordpress_host:
depends_on:
- db
image: wordpress
container_name: wordpress_host
ports:
- "8080:80"
restart: unless-stopped
env_file: ./wordpress/app/.env
environment:
- WORDPRESS_DB_HOST=db:3306
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_PASSWORD=root
- WORDPRESS_DB_NAME=example
volumes:
- ./wordpress/app:/var/www/html/wordpress
volumes:
wordpress-host:
dbdata
:
.env file:
MYSQL_ROOT_PASSWORD=root
MYSQL_USER=example
MYSQL_PASSWORD=password

Error to set up wordpress with Let's encrypt, Nginx on Docker

on the secure shell there was no error shown and It seems fine to be connected.
but I can not connect to my website (http://mrtrobotics.com)
I've got 502 bad gate way. would it be affected by nginx ???
I have no idea what to do. could anyone help me out please ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
Name Command State Ports
------------------------------------------------------------------------------
certbot certbot certonly --webroot ... Exit 0
mrtrobotics_db_1 docker-entrypoint.sh mysqld Up 3306/tcp, 33060/tcp
mrtrobotics_phpmyadmin_1 /docker-entrypoint.sh apac ... Up 0.0.0.0:3333->80/tcp
mrtrobotics_wordpress_1 docker-entrypoint.sh apach ... Up 80/tcp, 0.0.0.0:9000->9000/tcp
webserver nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
docker-compose.yml
version: '3.3'
services:
db:
image: mysql:5.7
volumes:
- ./db_data:/var/lib/mysql
restart: unless-stopped
env_file: .env
environment:
MYSQL_DATABASE: wordpress
networks:
- app-network
wordpress:
depends_on:
- db
image: wordpress:latest
restart: unless-stopped
ports:
- "9000:9000"
env_file: .env
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: $MYSQL_USER
WORDPRESS_DB_PASSWORD: $MYSQL_PASSWORD
WORDPRESS_DB_NAME: wordpress
volumes:
- ./wordpress/:/var/www/html/
networks:
- app-network
phpmyadmin:
image: phpmyadmin/phpmyadmin:latest
ports:
- "3333:80"
webserver:
depends_on:
- wordpress
image: nginx:1.15.12-alpine
container_name: webserver
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./wordpress/:/var/www/html/
- ./nginx-conf/:/etc/nginx/conf.d
- ./certbot-etc/:/etc/letsencrypt/
networks:
- app-network
certbot:
depends_on:
- webserver
image: certbot/certbot
container_name: certbot
volumes:
- ./certbot-etc/:/etc/letsencrypt/
- ./wordpress/:/var/www/html/
command: certonly --webroot --webroot-path=/var/www/html --email elearning#wemakerobot.com --agree-tos --no-eff-email --force-renewal -d mrtrobotics.com -d www.mrtrobotics.com
volumes:
certbot-etc:
wordpress:
db_data:
networks:
app-network:
driver: bridge
nginx.conf
server {
listen 80;
listen [::]:80;
server_name mrtrobotics.com www.mrtrobotics.com;
location ~ /.well-known/acme-challenge {
allow all;
root /var/www/html;
}
location / {
rewrite ^ https://$host$request_uri? permanent;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name mrtrobotics.com www.mrtrobotics.com;
index index.php index.html index.htm;
root /var/www/html;
server_tokens off;
ssl_certificate /etc/letsencrypt/live/mrtrobotics.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mrtrobotics.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 $document_root$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;
}
}

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;
}
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
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 my#domain1.com --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.
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

Resources