OJS 3.5 and complex web server rewrite / redirect rules

I’d like to revisit the not-so-trivial topic of web server configuration. I firmly believe that it is not out of scope of this forum because (a) obviously, OJS doesn’t work without a web server and (b) in order for some of the OJS core features, such as multi-tenancy and RESTful URLs, to work properly the web server must be configured in a certain way.

Besides, until OJS stops serving the articles from one context’s (journal’s) domain name under the other context’s domain name, we need even more rewrites and redirects. This particular issue is described here Multisite OJS with multiple domain - crossed accessible/indexed articles and unless addressed properly it can easily create a mess in the search engine indexing results.

Finally, new multilingual routing introduced in OJS 3.5 may break some older recommendations.

So I think we all need some Ultimate Rewrite Recommendations that will address/support the following issues/features:

  • www.* should be redirected to non-www, “naked” (sub)domains
  • API should work
  • RESTful URLs should work - no index.php in the address bar
  • multi-tenant (multi-context, multi-journal) installations should be supported
  • multilingual installations, where some journals support only one language and some - several languages, should be possible
  • new routing style (post-OJS 3.5) for multilingual journals should not break anything or result in infinite redirect loops
  • it should be possible to set up separate domains for separate contexts
  • no cross-accessible articles should be possible (see Multisite OJS with multiple domain - crossed accessible/indexed articles )

As Apache is (sort of) recommended, let’s try setting it up. I’ve spent quite some time attempting to create an example that would account for all of this, but I haven’t quite succeeded. As of now, I came up with this sample two-journal config:

base_url[index] = "https://journals.example.com"
base_url[journalone] = "https://journal1.example.com"
base_url[journaltwo] = "https://journal2.example.com"

; Generate RESTful URLs using mod_rewrite. This requires the
; rewrite directive to be enabled in your .htaccess or httpd.conf.
; See FAQ for more details.
restful_urls = On

in config.inc.php, and

RewriteEngine On
RewriteBase /

Options -MultiViews
AcceptPathInfo On

# WWW redirects

RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

#
# RESTful URL Rewrites
#

# API Access

RewriteCond %{SERVER_NAME} ^journals\.example\.com$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} api/v1/
RewriteRule ^api/v1(.*)$ index.php/index/api/v1$1 [R=307,L]

RewriteCond %{SERVER_NAME} ^journal1\.example\.com$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} api/v1/
RewriteRule ^api/v1(.*)$ index.php/journalone/api/v1$1 [R=307,L]

RewriteCond %{SERVER_NAME} ^journal2\.example\.com$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} api/v1/
RewriteRule ^api/v1(.*)$ index.php/journaltwo/api/v1$1 [R=307,L]

# index.php go away! (also, solves the wrong journal problem)

RewriteCond %{THE_REQUEST} /index\.php/index [NC]
RewriteCond %{REQUEST_URI} !api/v1/ [NC]
RewriteRule ^index\.php/index(.*)$ https://journals.example.com$1 [NC,R=301,L]

RewriteCond %{THE_REQUEST} /index\.php/journalone [NC]
RewriteCond %{REQUEST_URI} !api/v1/ [NC]
RewriteRule ^index\.php/journalone(.*)$ https://journal1.example.com$1 [NC,R=301,L]

RewriteCond %{THE_REQUEST} /index\.php/journaltwo [NC]
RewriteCond %{REQUEST_URI} !api/v1/ [NC]
RewriteRule ^index\.php/journaltwo(.*)$ https://journal2.example.com$1 [NC,R=301,L]

# Fixing the OJS Locale URLs

RewriteCond %{SERVER_NAME} ^journals\.example\.com$
RewriteCond %{THE_REQUEST} \s/+index/ [NC]
RewriteRule ^index/(.*)$ https://journals.example.com/$1 [R=301,L]

RewriteCond %{SERVER_NAME} ^journal1\.example\.com$
RewriteCond %{THE_REQUEST} \s/+journalone/ [NC]
RewriteRule ^journalone/(.*)$ https://journal1.example.com/$1 [R=301,L]

RewriteCond %{SERVER_NAME} ^journal2\.example\.com$
RewriteCond %{THE_REQUEST} \s/+journaltwo/ [NC]
RewriteRule ^journaltwo/(.*)$ https://journal2.example.com/$1 [R=301,L]

# Making the Regular Pages Work

RewriteCond %{SERVER_NAME} ^journals\.example\.com$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/*(index/)?(.*)$ /index.php/index/$2 [QSA,L]

RewriteCond %{SERVER_NAME} ^journal1\.example\.com$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/*(journalone/)?(.*)$ /index.php/journalone/$2 [QSA,L]

RewriteCond %{SERVER_NAME} ^journal2\.example\.com$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^/*(journaltwo/)?(.*)$ /index.php/journaltwo/$2 [QSA,L]

in .htaccess or the vhost config. This particular beauty is ugly as hell, probably excessive, and often results in a few sequential redirects. However, believe it or not, nothing less was sufficient. It mostly works as intended, BUT results in cyclic redirects between pages such as https://journals.example.com/en/management and https://journals.example.com/login?source=/en/management . It also doesn’t fix this OJS 3.5.0-1 site admin cannot edit journals with separate domains but it may not be easily “fixable”.

My obvious sources of inspiration were https://docs.pkp.sfu.ca/admin-guide/en/deploy-multi-tenant#domain-names , Each journal with its own domain name , and API redirect problems in RESTful URL configuration (api.404.endpointNotFound) . This topic [SOLVED] Infinite redirect loop (ERR_TOO_MANY_REDIRECTS) on secondary locales with restful_urls enabled also mentions some problems with multilingual routing in OJS 3.5.

I’d greatly appreciate any further suggestions or examples to try, because… just you look at that .htaccess, it’s easy to see that I’m totally discombobulated.

1 Like