nginx language redirection with wordpress

The problem

Lets go through this simple story of one of development' day problems.
Imagine you have a working service on example.com. The service has also multiple language support, so for each language it has a separated subdomain, like this:

en.example.com
fr.example.com
pl.example.com

Great! Nginx configuration looks pretty simple and you spend your days playing table tenis and swimming in the pool. But the idyll will not last longer, sadly. It finally comes out that you have to setup a blogging platform for each language version and it has to be pointed via *.example.com/blog. The probem seems to be very easy to solve if you want to serve the blog on the same machine - but one does not simply install a buggy blog platform (such as wordpress) on the same machine with a high-traffic application with SSL and security in mind.

Solutions

Obviously the first thing that comes into our minds is to setup the blogging platform on a separated small server where it will not cause any problems to our 'mother-application'.
Great! Lets do it then :)

For ease of reading lets say we will call mother-app server as motherapp and blog server as bugblog.

Configuration:
motherapp:

  • nginx
  • php
  • ssl

bugblog:

  • apache
  • php

On bugblog:

$ wget https://wordpress.org/latest.tar.gz
[...]
$ tar -xvf latest.tar.gz
[...]
$ rm latest.tar.gz
$ ls
./ ../ wordpress/
$ mv wordpress/ blog/

I will omit wordpress instalation for obvious reasons.


To not have problems with changing domain after wordpress installation we can configure the proxypass immediately, so on motherapp:

server {
  listen 443 ssl;
  server_name www.motherapp.com ~^\w+\.motherapp\.com$;
  
  # ssl certificates here
      
  root /var/www/motherapp;

  # -- our main interest --
  location ~* ^/blog {
    proxy_set_header Host $host;
    # ip of the bugblog machine here
    proxy_pass http://bugblogIP:8001;
  }

  # the rest for motherapp configuration
  location / {
    # [...]
  }
}

From now all links like those below should match and proxy to our bugblog server.

In most of documentations over the internet you will find this line which has to be added to nginx proxypass config:

rewrite ^/blog(/.*)$ $1 break;

but be careful - it will redirect each request to higher level and for example wordpress will see it as on / path and will do all the wierd redirections one level up in the URL structure. Instead of this you can put your apache configuration to point bugblogIP:8001 to one level higher than the blog installation directory, like this:

/var/www/
|-- blog_network/ <- here points the vHost
    `-- blog/ <- same as the routing directory (/blog/)
        |-- index.php
        |-- wp-config.php
        `-- [...]

This solution can help you to omit the bug with proxypassing between nginx and apache with the rewrite.

Sample apache config:

<VirtualHost *:8001>
  # hostname will be passed as Host from nginx proxy
  ServerName www.motherapp.com

  DocumentRoot /var/www/blog_network

  <Directory /var/www/blog_network>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Order allow,deny
    allow from all
  </Directory>
  [...]
</VirtualHost>

Remember to restart both nginx and apache on both servers.

Now you should be able to enter the wordpress configuration by going to https://motherapp.com/blog

If you are using HTTPS assets will probably not load so you will see sample HTML forms and buttons - don't worry - go through the installation anyway. After installation edit the wp-config.php file and add those lines:

define('FORCE_SSL_ADMIN', true);
$_SERVER['HTTPS']='on';

to be able to enter wp-admin without redirection to HTTP (from HTTPS).

In wordpress general settings remember to check if the protocol is set correctly (HTTPS) for siteURL and homeURL if not assets will not be loaded due to CORS.

Final wordpress configuration

If previous steps went without any problems you should be able to enable wordpress network which allows you to manage multiple wordpress instances as a network (for example install plugins for all separate language blog instances like fr, pl). This is very helpful if you want to keep updates and plugins across all languages but separate content between them (e.g. posts in different languages, different editors).

To enable wordpress network add this line to wp-config.php

define( 'WP_ALLOW_MULTISITE', true );

and then refresh the admin panel. Try to follow network configuration steps - #3 Installing network point.

After that it's very important to add again to wp-config.php this line (near other ones generated via wordpres):

define('SUBDOMAIN_INSTALL', true);

which will allow you to use subdomain-based wordpress instances.

After that, last step is to update the .htaccess file with new config:

RewriteEngine On
RewriteBase /blog/
RewriteRule ^index\.php$ - [L]

# add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]

RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
RewriteRule . index.php [L]

Now its just the matter of adding new network sites in wordpress admin.
Network Admin -> Sites -> New Site

adding wordpress network site

Now each url will match different blog instance which still can be managed by one admin and use shared themes / plugins / settings.

Examples:

https://www.motherapp.com/blog -> main blog (English)
https://fr.motherapp.com/blog -> French blog
https://pl.motherapp.com/blog -> Polish blog

If you have any questions don't hesitate to write comments or contact via email!