Installing using Docker Compose and Portainer

I am trying to install OJS on an Ubuntu VM using Portainer and docker compose. I am using the instructions found at

I have populated portainer with the env variables required.

I have the following questions:

  1. I always use persistent volumes. What directory format (tree) should I create prior to running the docker container? From the compose file linked to above, it appears I need to create the following folders within a main ojs folder:
  • db
  • logs/db
  • logs/app
  • config
  • migration
  • public
  • private

Is that correct?

  1. I am able to get the software to get to the installation page, but I am confused about the database section. In the compose file, there is a mariadb db set up, so I am unsure why the installation instructions state the db in square brackets won’t work. What should I be entering in the database section of the installation page?

  2. I do not have a /etc/localtime folder on my Ubuntu VM. Should I create one?

  3. In the compose file, there is a statement “# WARNING: You can only enable file-volumes if file exists in the container.” Should I have a already or is one written during installation? If the latter, where is it created? In the /config folder that I mapped in the step above?

[Similar questions for the apache.htaccess and php.custom.ini files referred to in the compose file.]

  1. In the installation section called " File Settings | Directory for uploads", is the default /var/www/files folder correct for a docker compose install? Or, should I be pointing the installer to the ./volumes/private folder which, as per the compose file, is mapped to the /var/www/files location?

Any assistance is much appreciated. Thanks.

1 Like

Sorry for the delay. I’m on vacations here.

Lots of questions :slight_smile: but long story short, better try with the github project we updated in last Hannover meeting:

In short:

  • The gitLab repo is what I use to generate the official images before pushing to dockerHub.
  • The gitHub repo is the project uses the official images, simplifies the installation, and include a more clear documentation.

So thanks a lot for the advice. I will add a warning in the gitLab README to avoid further confusions.

About you questions:

You have all usual volumes described in the easyOJS project

But you don’t need to create them manually if you clone the gitHub/docker-ojs installation process.

If you follow the installation process, you should use “db” (without quotes).

This is explained in step 5 of the easyOJS installation process.

Long story short, with docker-compose you can name each service in your stack.
In containerization, the database service (mariadb, mysql, postgres or whatever option you like) is usually called db.

So, once named, you can simply refer it as"db, without been worried about what DB engine you used.

No, you didn’t.

/etc/localtime is a file in Unix and Linux-based systems that stores information about the system’s timezone. It is used by the operating system to determine the local time and adjust it according to the configured timezone. When you set the timezone on your system, the symbolic link or the /etc/localtime file itself is updated to point to the corresponding timezone file in the /usr/share/zoneinfo or /usr/share/zoneinfo/posix directory (depending on the distribution).

If this file does not exist, it means your system in not full configurated.
You can check and change the timezone configuration on Ubuntu using the timedatectl command, which automatically updates the symbolic link /etc/localtime.

file-volumes are kind of tricky.
When the container is created a file is created in your behalf.
If you “map” it in your host as a volume, docker-compose will overwrite it with the file you include outside your container. And the same applies for apache virtualhosts, php.ini, etc.

If you follow the easyOJS installation process, you don’t need to worry about crating config files.

You have the usual file-volumes described in the “Special Volumes” section.

Not necesarily. Using /var/www/private for private files is a quite common practice to keep all the apache stuff confined in a single place.

On debian based systems apache public folder is /var/www/html so if virutalhost is properly set (and hopefully in the docker images I keep they are), former folder is safe.

So this is why by default in docker-compose.yml I defined the subfolder ./volumes/private to be mapped into the /var/www/files folder and in the installation you need to refer this folder.

But if you don’t like this approach, you can map it whatver you like. The only condition is to refer it properly during the installation process.

Hope this helps.

If you have any further questions, do not hesitate to ask them. Your questions are very useful for me to understand the needs of the community, to see what has not been explained correctly and, at the same time, for others to find answers to their questions in this forum.



Thank you for these precise and detailed explanations. I ended up using your detailed guide for easyOJS.

I have now got the software running and even configured two journals. I am doing mock-ups currently so that I understand the software well before deploying production journals.

I am now trying to use certbot to generate SSL certificates, but the certbot software will not do so, as it states The apache plugin is not working; there may be problems with your existing configuration. The error was: NoInstallationError('Cannot find Apache executable apache2ctl')

I have tried to find where apache is actually located but have not found it.

I am hoping to get further instructions as to how to install an SSL cert, ideally from certbot so I can automatically keep it updated, within the docker installation. I have read the part about apache from your easyOJS installation guide, but I was still unsure how to do so.

I greatly appreciate the help!

1 Like

Sorry for the delay. Your questions aren’t easy, and I needed time to answer.

Thanks for asking about certificates, because I think it’s not explained anywhere and it’s not obvious.
Probably it’s something we should include in some documentation at some point, but till somebody find time to document it properly, I hope these pointers will help you.

The thing is… the docker image already creates a “self-signed certificate” so you can access to the site via httpS. Knowing this, you have three possibilities:

  1. Map the autogenerated pem and crt files as file-volumes to overwrite the image ones.
  2. Modify the ojs virtual-host to use the certificates you like.
  3. Delegate to your reverse proxy the management of the certificate for the frontend (and maintain the image with that self-signed certificate).

I’ll make a quick summary of each option, so you could decide what you want to use and if you run into trouble, we can look together how to solve it.

Solution 1: Map the autogenerated pem and crt files as file-volumes

As we have said, the image creates (and use) self-signed certificates that are stored in server.pem and server.key files.

If you have your own pem/crt, you can modify your docker-compose.yml to overwrite those files with the ones (yours stored on the host to give them persistence). So, assuming you copy your files to ./volumes/config/certificates/*, it would be enough to add these volume-files:


Note the detail of the “:ro” (read-only) after the certificate to ensure that the container can NOT modify these files.

Solution 2: Mapping the virtual host

The image also includes a virtual host file for the ojs site.

You can create a copy of the container’s ojs.conf on your host, edit that file with the new certificates (use a different name than server.*) and map the file as follows:

- ./volumes/config/apache.ojs.conf:/etc/apache2/conf.d/ojs.conf

This is useful if you have a chain, or encrypted certificates instead of a pem/crt couple.
You will also need to map your certificate files and the chain.

This way, when you restart your docker-compose, it will use the new virtual host and the certificates you specify.

Solution 3: Delegating to the reverse proxy

If you use containers, they almost certainly also have a reverse proxy and almost all of them (traefik, caddy, NPM…) are smart enough to generate the certificates and forward the traffic to the container you specify.

So, a more common practice than we all recognize is to have httpS in the proxy-reverse and then allow the container to run with self-signed certificates or even in http (although I warn you that the latter can be a drama because of the “mixed-content”, but with the right combinations of virtual-host, and a little patching… OJS may work).

There are some other possibilities, but this is getting too long, so take your pick, give it a try… and if you have problems, contact us here.

By the way, we try to keep the forum orderly as a collective knowledge base, so the good practice would be to create a new post if the topic changes. If you like, let’s continue here to finish talking about the certificates, but if other topics arise, please open a new thread and mention me to continue talking there.

Best regards,

1 Like

Once again a very helpful post. Thank you!

I understand re: new threads. My apologies.

For those who may come after me, using Marc’s instructions above, and deploying my site using Cloudflare, I chose option number 3.

On the server side, in I set force_ssl = On.

For Cloudflare, I did the following in the tunnel I had set up pointing to my site:

  • ensured the tunnel used https, not http
  • Under Additional application settings under TLS,
    • enabled No TLS verify
    • enabled HTTPS2 connection

The Cloudflare changes were as recommended by their official docs found here.

Everything seems to work fine.

I greatly appreciate the help!

1 Like

So happy it helps. :ok_hand:

And great you shared your tips with Cloudfare.
It will help a lot others following your same path.

Any trouble you find with docker/containers, you can mention me directly.