OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openproject/docs/installation-and-operations/installation/docker/README.md

526 lines
18 KiB

---
sidebar_navigation:
5 years ago
title: Docker
priority: 300
---
# Install OpenProject with Docker
5 years ago
[Docker](https://www.docker.com/) is a way to distribute self-contained applications easily. We
provide a Docker image for the Community Edition that you can very easily
install and upgrade on your servers. However, contrary to the manual or
package-based installation, your machine needs to have the Docker Engine
installed first, which usually requires a recent operating system. Please see
5 years ago
the [Docker Engine installation page](https://docs.docker.com/install) if you don't have Docker
installed.
OpenProject with Docker can be launched in two ways:
1. Multiple containers (recommended), each with a single process inside, using a Compose file. Allows to easily choose which services you want to run, and simplifies scaling and monitoring aspects.
2. One container with all the processes inside. Easy but not recommended for production. This is the legacy behaviour.
## One container per process (recommended)
### Quick Start
First, you must clone the OpenProject repository:
```bash
git clone --depth=1 --branch=stable/10 https://github.com/opf/openproject
```
Then, go into the OpenProject folder and you can launch all the services required by OpenProject with docker-compose:
```bash
docker-compose up -d
```
After some time, you will be able to access OpenProject on http://localhost:8080. The default username and password is login: `admin`, and password: `admin`.
Note that the official `docker-compose.yml` file present in the repository can be adjusted to your convenience. For instance you could mount specific configuration files, override environment variables, or switch off services you don't need. Please refer to the official docker-compose documentation for more details.
You can stop the Compose stack by running:
```
docker-compose down
```
## All-in-one container
### Quick Start
The fastest way to get an OpenProject instance up and running is to run the
following command:
```bash
docker run -it -p 8080:80 -e SECRET_KEY_BASE=secret openproject/community:10
```
This will take a bit of time the first time you launch it, but after a few
minutes you should see a success message indicating the default administration
password (login: `admin`, password: `admin`).
You can then launch a browser and access your new OpenProject installation at
<http://localhost:8080>. Easy!
To stop the container, simply hit CTRL-C.
Note that the above command will not daemonize the container and will display
the logs to your terminal, which helps with debugging if anything goes wrong.
For normal usage you probably want to start it in the background, which can be
achieved with the `-d` flag:
```bash
docker run -d -p 8080:80 -e SECRET_KEY_BASE=secret openproject/community:10
```
### Recommended usage
The one-liner above is great to get started quickly, but if you want to run
OpenProject in production you will likely want to ensure that your data is not
lost if you restart the container.
To achieve this, we recommend that you create a directory on your host system
where the Docker Engine is installed (for instance: `/var/lib/openproject`)
where all this data will be stored.
You can use the following commands to create the local directories where the
data will be stored across container restarts, and start the container with
those directories mounted:
```bash
sudo mkdir -p /var/lib/openproject/{pgdata,assets}
docker run -d -p 8080:80 --name openproject -e SECRET_KEY_BASE=secret \
-v /var/lib/openproject/pgdata:/var/openproject/pgdata \
-v /var/lib/openproject/assets:/var/openproject/assets \
openproject/community:10
```
**Note**: Make sure to replace `secret` with a random string. One way to generate one is to run `head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32 ; echo ''` if you are on Linux.
Since we named the container, you can now stop it by running:
```bash
docker stop openproject
```
And start it again:
```bash
docker start openproject
```
If you want to destroy the container, run the following commands
```bash
docker stop openproject
docker rm openproject
```
### Initial configuration
OpenProject is usually configured through a YAML file, but with the Docker
image you need to pass all configuration through environment variables. You can
overwrite any of the values usually found in the standard YAML file by using
[environment variables](../../configuration/environment).
Environment variables can be either passed directly on the command-line to the
Docker Engine, or via an environment file:
```bash
docker run -d -e KEY1=VALUE1 -e KEY2=VALUE2 ...
# or
docker run -d --env-file path/to/file ...
```
5 years ago
For more advanced configuration, please have a look at the [Advanced configuration](../../configuration) section.
### Apache Reverse Proxy Setup
Often there will be an existing web server through which you want to make OpenProject acccessible.
There are two ways to run OpenProject. We'll cover each configuration in a separate of the following sections.
For both configurations the following Apache mods are required:
* proxy
* proxy_http
* rewrite
* ssl (optional)
In each case you will create a file `/usr/local/apache2/conf/sites/openproject.conf`
with the contents as described in the respective sections.
Both configuration examples are based on the following assumptions:
* the site is accessed via https
* certificate and key are located under `/etc/ssl/crt/server.{crt, key}`
* the OpenProject docker container's port 80 is mapped to the docker host's port 8080
*Important:* Once OpenProject is running make sure to also set the host name and protocol
accordingly under Administration -> System Settings.
#### 1) Virtual host root
The default scenario is to have OpenProject serve the whole virtual host.
This requires no further configuration for the docker container beyond what is
described above.
Assuming the desired *server name* is `openproject.example.com` the configuration
will look like this:
```
<VirtualHost *:80>
ServerName openproject.example.com
RewriteEngine on
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*)$ https://%{SERVER_NAME}/$1 [R,L]
</VirtualHost>
<VirtualHost *:443>
ServerName openproject.example.com
SSLEngine on
SSLCertificateFile /etc/ssl/crt/server.crt
SSLCertificateKeyFile /etc/ssl/crt//server.key
RewriteEngine on
RewriteRule "^$" "/" [R,L]
ProxyRequests off
<Location "/">
RequestHeader set X-Forwarded-Proto 'https'
ProxyPreserveHost On
ProxyPass http://127.0.0.1:8080/
ProxyPassReverse http://127.0.0.1:8080/
</Location>
</VirtualHost>
```
#### 2) Location (subdirectory)
Let's assume you want OpenProject to run on your host with the *server name* `example.com`
under the *subdirectory* `/openproject`.
If you want to run OpenProject in a subdirectory on your server, first you will
need to configure OpenProject accordingly by adding the following options to the `docker run` call:
```
-e OPENPROJECT_RAILS__RELATIVE__URL__ROOT=/openproject \
-e OPENPROJECT_RAILS__FORCE__SSL=true \
```
The `force ssl` option can be left out if you are not using HTTPS.
The apache configuration for this configuration then looks like this:
```
<VirtualHost *:80>
ServerName example.com
RewriteEngine on
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(openproject.*)$ https://%{SERVER_NAME}/$1 [R,L]
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/crt/server.crt
SSLCertificateKeyFile /etc/ssl/crt/server.key
RewriteEngine on
RewriteRule "^/openproject$" "/openproject/" [R,L]
ProxyRequests off
<Location "/openproject/">
RequestHeader set X-Forwarded-Proto 'https'
ProxyPreserveHost On
ProxyPass http://127.0.0.1:8080/openproject/
ProxyPassReverse http://127.0.0.1:8080/openproject/
</Location>
</VirtualHost>
```
### OpenProject plugins
The docker image itself does not support plugins. But you can create your own docker image to include plugins.
**1. Create a new folder** with any name, for instance `custom-openproject`. Change into that folder.
**2. Create the file `Gemfile.plugins`** in that folder. In the file you declare the plugins you want to install.
For instance:
```
group :opf_plugins do
gem "openproject-slack", git: "https://github.com/opf/openproject-slack.git", branch: "release/10.0"
end
```
**3. Create the `Dockerfile`** in the same folder. The contents have to look like this:
```
FROM openproject/community:10
COPY Gemfile.plugins /app/
RUN bundle config unset deployment && bundle install && bundle config set deployment 'true'
RUN bash docker/precompile-assets.sh
```
The file is based on the normal OpenProject docker image.
All the Dockerfile does is copy your custom plugins gemfile into the image, install the gems and precompile any new assets.
**4. Build the image**
To actually build the docker image run:
```
docker build -t openproject-with-slack .
```
The `-t` option is the tag for your image. You can choose what ever you want.
**5. Run the image**
You can run the image just like the normal OpenProject image (as shown earlier).
You just have to use your chosen tag instead of `openproject/community:10`.
To just give it a quick try you can run this:
```
docker run -p 8080:80 --rm -it openproject-with-slack
```
After which you can access OpenProject under http://localhost:8080.
## Docker Swarm
If you need to serve a very large number of users it's time to scale up horizontally.
One way to do that is to use your orchestration tool of choice such as [Kubernetes](../kubernetes/) or [Swarm](https://docs.docker.com/engine/swarm/).
Here we'll cover how to scale up using the latter.
### 1) Setup Swarm
Here will go through a simple setup of a Swarm with a single manager.
For more advanced setups and more information please consult the [docker swarm documentation](https://docs.docker.com/engine/swarm/swarm-tutorial/create-swarm/).
First [initialize your swarm](https://docs.docker.com/get-started/swarm-deploy/) on the host you wish to be the swarm manager(s).
```bash
docker swarm init
# You may need or want to specify the advertise address.
# Say your node manager host's IP is 10.0.2.77:
#
# docker swarm init --advertise-addr=10.0.2.77
```
The host will automatically also join the swarm as a node to host containers.
**Add nodes**
To add worker nodes run `docker swarm join-token worker`.
This will print the necessary command (which includes the join token) which you need to run
on the host you wish to add as a worker. For instance:
```
docker swarm join --token SWMTKN-1-2wnvro17w7w2u7878yflajyjfa93e8b2x58g9c04lavcee93eb-abig91iqb6e5vmupfvq2f33ni 10.0.2.77:2377
```
Where `10.0.2.77` is your swarm manager's (advertise) IP address.
### 2) Setup shared storage
**Note:** This is only relevant if you have more than 1 node in your swarm.
If your containers run distributed on multiple nodes you will need a shared network storage to store OpenProject's attachments.
The easiest way for this would be to setup an NFS drive that is shared among all nodes and mounted to the same path on each of them.
Say `/mnt/openproject/files`.
Alternatively, if using S3 is an option, you can use S3 attachments instead.
We will show both possibilities later in the configuration.
### 3) Create stack
To create a stack you need a stack file. The easiest way is to just copy OpenProject's [docker-compose.yml](https://github.com/opf/openproject/blob/release/10.6/docker-compose.yml). Just download it and save it as, say, `openproject-stack.yml`.
#### Configuring storage
**Note:** This is only necessary if your swarm runs on multiple nodes.
##### Attachments
**NFS**
If you are using NFS to share attachments use a mounted docker volume to share the attachments folder.
Per default the YAML file will start with the following section:
```
version: "3.7"
networks:
frontend:
backend:
volumes:
pgdata:
opdata:
```
Adjust this so that the previously created, mounted NFS drive is used.
```
version: "3.7"
networks:
frontend:
backend:
volumes:
pgdata:
opdata:/mnt/openproject/files
```
**S3**
If you want to use S3 you will have to add the respective configuration to the `stack.yml`'s environment section for the `app`.
```
x-op-app: &app
<<: *image
<<: *restart_policy
environment:
- "RAILS_CACHE_STORE=memcache"
- "OPENPROJECT_CACHE__MEMCACHE__SERVER=cache:11211"
- "OPENPROJECT_RAILS__RELATIVE__URL__ROOT=${OPENPROJECT_RAILS__RELATIVE__URL__ROOT:-}"
- "DATABASE_URL=postgres://postgres:p4ssw0rd@db/openproject"
- "USE_PUMA=true"
# set to true to enable the email receiving feature. See ./docker/cron for more options
- "IMAP_ENABLED=false"
# ADD THIS FOR S3 attachments substituting the respecive credentials:
- "OPENPROJECT_ATTACHMENTS__STORAGE=fog"
- "OPENPROJECT_FOG_DIRECTORY="<bucket-name>"
- "OPENPROJECT_FOG_CREDENTIALS_PROVIDER=AWS"
- "OPENPROJECT_FOG_CREDENTIALS_AWS__ACCESS__KEY__ID=<access-key-id>"
- "OPENPROJECT_FOG_CREDENTIALS_AWS__SECRET__ACCESS__KEY=<secret-access-key>"
- "OPENPROJECT_FOG_CREDENTIALS_REGION=us-east-1"
```
##### Database
The database's data directory should also be shared so that the database service can be moved to another node
in case the original node fails. The easiest way to do this would again be a shared NFS mount present on each node.
This is also the easiest way to persist the database data so it remains even if you shutdown the whole stack.
You could either use a new mounted NFS folder or use a sub-folder in the one we will use for attachments.
Along the same lines as attachments you could adjust the volume in the `openproject-stack.yml` so it would look something like this:
```
version: "3.7"
networks:
frontend:
backend:
volumes:
pgdata:/mnt/openproject/files/database
opdata:/mnt/openproject/files
```
**Disclaimer**: This may not be the best possible solution, but it is the most straight-forward one.
#### Launching
Once you made any necessary adjustments to the `openproject-stack.yml` you are ready to launch the stack.
```
docker stack deploy -c openproject-stack.yaml openproject
```
Once this has finished you should see something like this when running `docker service ls`:
```
docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
kpdoc86ggema openproject_cache replicated 1/1 memcached:latest
qrd8rx6ybg90 openproject_cron replicated 1/1 openproject/community:10
cvgd4c4at61i openproject_db replicated 1/1 postgres:10
uvtfnc9dnlbn openproject_proxy replicated 1/1 openproject/community:10 *:8080->80/tcp
g8e3lannlpb8 openproject_seeder replicated 0/1 openproject/community:10
canb3m7ilkjn openproject_web replicated 1/1 openproject/community:10
7ovn0sbu8a7w openproject_worker replicated 1/1 openproject/community:10
```
You can now access OpenProject under [http://0.0.0.0:8080](http://0.0.0.0:8080).
This endpoint then can be used in a apache reverse proxy setup as shown further up, for instance.
#### Scaling
Now the whole reason we are using swarm is to be able to scale.
This is now easily done using the `docker service scale` command.
We'll keep the database and memcached at 1 which should be sufficient for any but huge amounts of users (several tens of thousands of users)
assuming that the docker hosts (swarm nodes) are powerful enough.
Even with the database's data directory shared via NFS **you cannot scale up the database** in this setup.
Scaling the database horizontally adds another level of complexity which we won't cover here.
What we can scale is both the proxy and most importantly the web service.
For a couple of thousand users we may want to use 6 web services:
```
docker service scale openproject_proxy=2 openproject_web=6
```
This will take a moment to converge. Once done you should see something like the following when listing the services using `docker service ls`:
```
docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
kpdoc86ggema openproject_cache replicated 1/1 memcached:latest
qrd8rx6ybg90 openproject_cron replicated 1/1 openproject/community:10
cvgd4c4at61i openproject_db replicated 1/1 postgres:10
uvtfnc9dnlbn openproject_proxy replicated 2/2 openproject/community:10 *:8080->80/tcp
g8e3lannlpb8 openproject_seeder replicated 0/1 openproject/community:10
canb3m7ilkjn openproject_web replicated 6/6 openproject/community:10
7ovn0sbu8a7w openproject_worker replicated 1/1 openproject/community:10
```
Docker swarm handles the networking necessary to distribute the load among the nodes.
The application will still be accessible as before simply under `http://0.0.0.0:8080` on each node, e.g. `http://10.0.2.77:8080`, the manager node's IP.
#### Load balancer setup
Now as mentioned earlier you can simply use the manager node's endpoint in a reverse proxy setup and the load will be balanced among the nodes.
But that will be a single point of failure if the manager node goes down.
To make this more redundant you can use the load balancer directive in your proxy configuration.
For instance for apache this could look like this:
```
<Proxy balancer://swarm>
BalancerMember http://10.0.2.77:8080 # swarm node 1 (manager)
BalancerMember http://10.0.2.78:8080 # swarm node 2
BalancerMember http://10.0.2.79:8080 # swarm node 3
BalancerMember http://10.0.2.80:8080 # swarm node 4
BalancerMember http://10.0.2.81:8080 # swarm node 5
BalancerMember http://10.0.2.82:8080 # swarm node 6
ProxySet lbmethod=bytraffic
</Proxy>
# ...
ProxyPass "/" "balancer://swarm/"
ProxyPassReverse "/" "balancer://swarm/"
# instead of
# ProxyPass http://127.0.0.1:8080/
# ProxyPassReverse http://127.0.0.1:8080/
# shown in the reverse proxy configuration example further up
```