Skip to content

Installation Guide

Docker Installation Guide

www.tine-groupware.de | docker-compose.yml | Dockerfile

Quickstart

This is an easy way to try out tine-groupware. You need Docker and Docker Compose (https://docs.docker.com/compose/).

First, create a folder. Docker Compose uses the folder names as an identifier.

mkdir tine
cd tine
Then you need to download the current docker-compose.yml. And save it in the folder just created.
wget https://tine-docu.s3web.rz1.metaways.net/de/operators/docker/docker-compose.yml
Now you can start the docker-compose.


Note

Depending on your docker compose installation, you need to use this command: docker compose or this docker-compose.


docker compose up

Wait for the database to become available. If it is, the web container will log web_1 | DB available. Now open another terminal and start the tine installer. There you need to accept the tine-license and Privacy policy and you will be able to set the initial admin password.

docker compose exec web tine20_install

Your tine-groupware is now reachable at http://127.0.0.1:4000.

setup.php UI

The setup.php browser interface can be accessed here: http://127.0.0.1:4000/setup.php. The site is protected by HTTP basic auth. Username and password hash can be configured with the ENV Variable TINE20_SETUP_HTPASSWD (example: "setup:$apr1$JhCtViTh$k15DH.HvNR5hZ66Ew5aTH/" #setup:setuppw). The hash can be generated with htpasswd: 1. htpasswd -c setup.htpasswd setup. 2. Enter the password. 3. Copy username and password form the file setup.htpasswd.

Note: When using docker-compose, $ needs to be escaped as follows: $$.

Cleanup

Use the following to stop and delete all containers, networks and volumes created by this compose.

docker compose down --volumes

Image

This image contains the tine code, PHP-FPM, and Nginx. Additionally, a database e.g MariaDB is required. In production, this image should be utilized with a reverse proxy handling all the custom configuration and ssl termination.

Paths

Path Description
/etc/tine20/config.inc.php tine main config file.
/etc/tine20/conf.d/* tine auto include config files.
/var/lib/tine20/files Stores user data. Files like in tine Filemanager
/var/lib/tine20/tmp Temporary file storage
/var/lib/tine20/caching Used for caching if TINE20_CACHING_BACKEND == 'File'
/var/lib/tine20/sessions Used as session store if TINE20_SESSION_BACKEND == 'File'

Update

Use 'docker compose up' to fetch the latest docker image.

Use this command to update tine:

docker exec --user tine20 tine-docker_web_1 sh -c "php /usr/share/tine20/setup.php --config=/etc/tine20 --update"

If you see this error during the update:

"Tinebase_Exception -> waited for Action Queue to become empty for more than 300 sec"

You should check why there are still jobs in the ActionQueue and/or run the update with skipQueueCheck=1.

SSL / Reverse Proxy

NGINX

Example NGINX VHOST conf:

server {
    listen 80;
    listen 443 ssl;

    ssl_certificate /etc/letsencrypt/live/MYDOMAIN.de/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/MYDOMAIN.de/privkey.pem;

    server_name tine.MYDOMAIN.de autodiscover.MYDOMAIN.de;

    if ($ssl_protocol = "" ) {
        rewrite        ^ https://$server_name$request_uri? permanent;
    }

    access_log /var/www/MYDOMAIN/logs/nginx-access.log;
    error_log /var/www/MYDOMAIN/logs/nginx-error.log;

    client_max_body_size 2G; # set maximum upload size

    location /.well-known { }

    location / {
        proxy_pass http://127.0.0.1:4000;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

TRAEFIK

  traefik:
    image: "traefik:v2.6"
    restart: always
    container_name: "traefik"
    command:
      - "--providers.docker=true"
      - "--providers.docker.exposedbydefault=false"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
      - "--entrypoints.websecure.address=:443"
      - "--certificatesresolvers.http01.acme.httpchallenge=true"
      - "--certificatesresolvers.http01.acme.httpchallenge.entrypoint=web"
      - "--certificatesresolvers.http01.acme.storage=/letsencrypt/acme.json"
    ports:
      - "80:80"
      - "443:443"
      - "8080:8080"
    volumes:
      - "./letsencrypt:/letsencrypt"
      - "/var/run/docker.sock:/var/run/docker.sock:ro"

  web:
    image: tinegroupware/tine:2021.11
    #[...]
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.tile-server.rule=Host(`MYDOMAIN.de`)"
      - "traefik.http.routers.tile-server.entrypoints=websecure"
      - "traefik.http.routers.tile-server.tls.certresolver=http01"
      - "traefik.http.services.tile-server.loadbalancer.server.port=80"

Migration

To migrate from an old tine installation, you can try to just mount the database as a volume (you have to know the root password of the existing database and you should ideally use the same db version):

  db:
    image: mariadb:10.6
    volumes:
      - "/var/lib/mysql:/var/lib/mysql"
    #[...]

  web:
    image: tinegroupware/tine:2021.11
    volumes:
      - "/var/lib/tine20/files:/var/lib/tine20/files"
    #[...]

If this does not work or your existing tine database is on another server, it is recommended to use the tine CLI functions --backup and --restore for migration. Please note that the tine container needs to access the backup/dump files, so it might be necessary to copy the files into the container.

Custom Configuration

  web:
    image: tinegroupware/tine:2021.11
    volumes:
      - "conf.d:/etc/tine20/conf.d"
    #[...]

docker-compose.yml

docker-compose.yml
version: '2'
services:
  db:
    image: mariadb:10.9.8
    command: --max-allowed-packet=209715210
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: &MYSQL_DATABASE tine
      MYSQL_USER: &MYSQL_USER tine
      MYSQL_PASSWORD: &MYSQL_PASSWORD tine
      MARIADB_AUTO_UPGRADE: 1
    ### use volume for persistent DB
    volumes:
      - "tine_db:/var/lib/mysql"
    ### OR
#      - "./data/tine_mysql:/var/lib/mysql"
    networks:
      - internal_network

  web:
    image: tinegroupware/tine:2023
    restart: always
    depends_on:
      - db
      - cache
    environment:
      TINE20_DATABASE_HOST: db
      TINE20_DATABASE_DBNAME: *MYSQL_DATABASE
      TINE20_DATABASE_USERNAME: *MYSQL_USER
      TINE20_DATABASE_PASSWORD: *MYSQL_PASSWORD
      TINE20_DATABASE_TABLEPREFIX: tine_
      TINE20_CACHING_BACKEND: Redis
      TINE20_CACHING_REDIS_HOST: cache
      TINE20_ACTIONQUEUE_HOST: cache
      TINE20_SESSION_BACKEND: Redis
      TINE20_SESSION_HOST: cache
      TINE20_CREDENTIALCACHESHAREDKEY: change_me
      TINE20_SETUPUSER_USERNAME: tinesetup
      TINE20_SETUPUSER_PASSWORD: tinesetup
      TINE20_SETUP_HTPASSWD: "setup:$$apr1$$JhCtViTh$$k15DH.HvNR5hZ66Ew5aTH/" #setup:setuppw
      TINE20_ACTIONQUEUE: "true"
      BROADCASTHUB_URL: http://broadcasthub
      # TINE20_LOGGER_PRIORITY: "7"
      ### the url of you tine installation (should be adjusted)
      # TINE20_URL: http://localhost:4000
      ### install+update tine automatically
      # TINE20_INSTALL: "true"
      ### needed for auto-install
      # TINE20_ACCEPTED_TERMS_VERSION: 10000
      # TINE20_LOGIN_USERNAME: admin
      # TINE20_LOGIN_PASSWORD: change_me
      ### apps to install - if omitted, all available apps are installed
      # TINE20_APPLICATION_TO_INSTALL: "Addressbook,Felamimail,Calendar,Filemanager"

    volumes:
      - "tine_files:/var/lib/tine20/files"
      # use this for custom configuration files (like logger.inc.php)
      - "./conf.d:/etc/tine20/conf.d"
    ### OR
      # NOTE: you need to make sure that the folder has the correct file permissions
#      - "./data/tine_files:/var/lib/tine20/files"
    networks:
      - external_network
      - internal_network
    ports:
      - "127.0.0.1:4000:80"
    ### for traefik support (see https://doc.traefik.io/traefik/providers/docker/)
#    labels:
#      - "traefik.enable=true"
#      - "traefik.http.routers.web.rule=Host(`MYDOMAIN.de`)"
#      - "traefik.http.routers.web.entrypoints=websecure"
#      - "traefik.http.routers.web.tls.certresolver=http01"
#      - "traefik.http.services.web.loadbalancer.server.port=80"

  cache:
    image: redis:6.0.16
    restart: always
    networks:
      - internal_network

  broadcasthub:
    image: tinegroupware/broadcasthub:0.7
    restart: always
    networks:
      - external_network
      - internal_network
    ports:
      - "5001:80"
    environment:
      REDIS_URL: redis://cache:6379
      REDIS_CHANNEL: broadcasthub
      TINE20_JSON_API_URL: http://localhost
      AUTH_TIMEOUT: 5000
      WS_PORT: 80
      DEBUG: '*'
      DEBUG_DEFAULT_LOGGING: "on"
      DEBUG_LOG_TO_FILE: "off"
      DEBUG_LOG_FILE: ../../stdout.log

### other optional services

############################################################################
# docservice
############
# to use this in tine, you need to add the following to your config:
#
# 'filesystem' => [
#   'createPreviews' => true,
#   'previewServiceUrl' => 'http://docservice/v2/documentPreviewService',
#   'previewServiceVersion' => 2,
#   [...]
# ],
############################################################################
#  docservice:
#    image: tinegroupware/document-preview-service:2.1
#    restart: always
#    networks:
#      - internal_network

############################################################################
#  documentserver
############################################################################
#
# to use this in tine, you need to add the following to your config:
#
# return [
#    'OnlyOfficeIntegrator' => [
#        'onlyOfficePublicUrl' => 'http://localhost:4020/',
#        'onlyOfficeServerUrl' => 'http://documentserver/',
#        'tine20ServerUrl' => 'http://web/',
#        'jwtEnabled' => true,
#        'jwtSecret' => 'change_me_also_define_in_tine_cfg',
#    ],
#
############################################################################
#  documentserver:
#    image: onlyoffice/documentserver:latest
#    restart: always
#    ports:
#      - "4020:80"
#    environment:
#      JWT_ENABLED: "true"
#      JWT_SECRET: "change_me_also_define_in_tine_cfg"
#    networks:
#      - external_network
#      - internal_network

#  clamav:
#    image: tiredofit/clamav
#    restart: always
#    container_name: clamav
#    environment:
#      - ZABBIX_HOSTNAME=clamav
#    # need to be created on the host
#    volumes:
#      - "clamav_files:/data"
#    networks:
#      - internal_network

#  traefik:
#    image: "traefik:v2.6"
#    restart: always
#    container_name: "traefik"
#    command:
#      - "--providers.docker=true"
#      - "--providers.docker.exposedbydefault=false"
#      - "--entrypoints.web.address=:80"
#      - "--entrypoints.web.http.redirections.entryPoint.to=websecure"
#      - "--entrypoints.web.http.redirections.entryPoint.scheme=https"
#      - "--entrypoints.web.http.redirections.entrypoint.permanent=true"
#      - "--entrypoints.websecure.address=:443"
#      - "--certificatesresolvers.http01.acme.httpchallenge=true"
#      - "--certificatesresolvers.http01.acme.httpchallenge.entrypoint=web"
#      - "--certificatesresolvers.http01.acme.storage=/letsencrypt/acme.json"
#    ports:
#      - "80:80"
#      - "443:443"
#      - "8080:8080"
#    volumes:
#      - "./letsencrypt:/letsencrypt"
#      - "/var/run/docker.sock:/var/run/docker.sock:ro"

### if you use directory mounts, you might no need that
volumes:
  tine_files:
  tine_db:
#  clamav_files:

networks:
  external_network:
  internal_network:
    internal: true

Ansible Role For Deployments

https://github.com/tine-groupware/tine/tree/main/scripts/ansible/roles/tinedockercompose