Docker software deployment

Introduction

This post includes instructions on how to deploy self-hosted software via Docker containers

Careful with web domains!

In this examples, we are using example.com as our web domain. Change it to your own domain where the applications are accessed from.

Software categories

Communication

NextCloud

Installation

Follow the Docker deployment installation guide for a quick nextCloud deployment. After that, create the required configurations to ensure persistence.

For a quick test, just run:

docker run -d -p 8081:80 nextcloud:stable-apache

Connect to http://<nextcloud-server>:8081 and follow the instructions. Install the recommended apps to try the Online Office feature.

Data is not persistent!

Be aware that if no volume binding has been made, when stopping the containers the volumes become dandling, not reattached to the next started container. Make sure to define pertinent volume attachments when deploying to production.

Enabling NextCloud office features

NextCloud can make use of a built-in document server named Collabora, based on LibreOffice that allows to modify several types of documents online.

On a testing environment, if documents aren’t opened online, try to go to the Administration Parameters –> Administration –> Office. Even though the second option is selected, the built-in CODE isn’t accessible due to using an insecure protocol (HTTP) (just try to click again on the button and the verification will fail). As a workaround, click on the first option Use your own server and just tick the Disable certificate verification checkbox; Now the notification regarding Collabora Online accessibility should be OK.

Some features are unavailable without an SSL certificate

Features like video conferences in Talk are disabled. When using a service like Cloudflare that creates an HTTPS tunnel towards the application, then this problem is solved.

OnlyOffice + NextCloud integration

As an alternative to the built-in Collabora/CODE document server, if you want to easily deploy both the OnlyOffice Document Server and the NextCloud at the same time, follow this installation guide. It contains a docker-compose.yml file for the deployment.

Configuration

Try to create a docker-compose.yml file to ease the nextCloud deployment, the steps are defined in the installation guide. You’ll also have to provide secrets for both the nextcloud and postgres admin credentials:

docker-compose.yml
version: '3.2'
name: nextcloud
services:
  db:
    image: postgres
    #container_name: nextcloud_db
    hostname: nextcloud_db
    restart: always
    ports:
      - 5432:5432
    volumes:
      - db:/var/lib/postgresql/data
    environment:
      - TZ=Europe/Madrid
      - POSTGRES_DB_FILE=/run/secrets/postgres_db
      - POSTGRES_USER_FILE=/run/secrets/postgres_user
      - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
    secrets:
      - postgres_db
      - postgres_password
      - postgres_user

  app:
    image: nextcloud:stable-apache
    #container_name: nextcloud_app
    restart: always
    ports:
      - 8081:80
    volumes:
      - data:/var/www/html
    environment:
      - TZ=Europe/Madrid
      - POSTGRES_HOST=nextcloud_db
      - POSTGRES_DB_FILE=/run/secrets/postgres_db
      - POSTGRES_USER_FILE=/run/secrets/postgres_user
      - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password
      - NEXTCLOUD_ADMIN_PASSWORD_FILE=/run/secrets/nextcloud_admin_password
      - NEXTCLOUD_ADMIN_USER_FILE=/run/secrets/nextcloud_admin_user
      - NEXTCLOUD_TRUSTED_DOMAINS=<nextcloud.server.ip> nextcloud.example.com localhost
      # Required fields for Cloudflare HTTPS access
      - OVERWRITEPROTOCOL=https
      #- APACHE_DISABLE_REWRITE_IP=1
      #- TRUSTED_PROXIES=nextcloud.example.com
      # Additional memory increase for both clients and uploads
      #- PHP_MEMORY_LIMIT=1024M
      #- PHP_UPLOAD_LIMIT=1024M
    depends_on:
      - db
    secrets:
      - nextcloud_admin_password
      - nextcloud_admin_user
      - postgres_db
      - postgres_password
      - postgres_user

volumes:
  db:
  data:

secrets:
  nextcloud_admin_password:
    file: $PWD/secrets/nextcloud_admin_password.txt # put admin password in this file
  nextcloud_admin_user:
    file: $PWD/secrets/nextcloud_admin_user.txt # put admin username in this file
  postgres_db:
    file: $PWD/secrets/postgres_db.txt # put postgresql db name in this file
  postgres_password:
    file: $PWD/secrets/postgres_password.txt # put postgresql password in this file
  postgres_user:
    file: $PWD/secrets/postgres_user.txt # put postgresql username in this file

Collaborative tools

Productivity tools

OpenProject

OpenProject is a project management suite. It has the required tools to manage Scrum projects.

Installation

OpenProject can be deployed as docker containers. Follow the installation guide to do it. They have a GitHub repository with the docker-compose configuration to easily deploy it.

Be patient with the OpenProject initialization

It takes some time for the OpenProject Web GUI to be available, just wait at least 5 minutes. If something goes wrong, check logs. From the same docker-compose.yml dir:

docker compose logs

Once up, access the Web GUI at http://<openproject-ip>:8080

Configuration

Things to consider configuring:

  • User creation activation: by default, the admin user is responsible of manually activate any new account. This can be changed to automatically activate accounts either instantly or by sending an e-mail
    • The e-mail option requires OpenProject to have an SMTP server available to send mails
  • Use a docker-compose.override.yml file to replace values of docker-compose.yml, don’t modify it:
docker-compose.override.yml
version: "3.7"

services:
  web:
    environment:
      #OPENPROJECT_HTTPS: "false"
      OPENPROJECT_HOST__NAME: "openproject.example.com"
      OPENPROJECT_LDAP__USERS__SYNC__STATUS: true

User database and authentication

OpenLDAP + phpLDAPadmin + Self-Service-Password

We’ll be using a bitnami/openldap docker image as it runs as non-privileged user, providing an additional layer of security. You’ll need to provide the following files:

  • A conf/config.inc.local.php to override default openldap config
  • A secrets/ldap_admin_password.txt file containing the ldap admin user password (just the password in plain text, no key-value format)
  • A .env file containing key-value fields for the SSP_KEYPHRASE and the LDAP_BIND_PASSWORD required for the Self-Service-Password docker image. LDAP_BIND_PASSWORD must match the ldap admin password of OpenLDAP
docker-compose.yml
version: '2'
name: ldap-service
services:
  # LDAP server
  openldap:
    image: docker.io/bitnami/openldap:2.6
    container_name: openldap
    hostname: openldap
    restart: always
    ports:
      - '1389:1389'
      - '1636:1636'
    environment:
      # Default LDAP_ROOT: dc=example,dc=org
      - LDAP_ROOT=dc=cifojava,dc=local
      - LDAP_ADMIN_PASSWORD_FILE=/run/secrets/ldap_admin_password
      - LDAP_USERS=
      - LDAP_PASSWORDS=
      - LDAP_ENABLE_TLS=no
    volumes:
      - 'openldap_data:/bitnami/openldap'
    networks:
      - network
    secrets:
      - ldap_admin_password

  # LDAP administrator via web interface
  phpldapadmin:
    image: osixia/phpldapadmin:latest
    container_name: phpldapadmin
    restart: always
    # Don't know why this link attribute started to fail
    #link:
    #  openldap: ldap-server
    environment:
      # bitnami/openldap uses non-privileged port as default
      PHPLDAPADMIN_LDAP_HOSTS: "#PYTHON2BASH:[{'openldap': [{'server': [{ 'port': 1389 }]}]}]"
      #PHPLDAPADMIN_LDAP_HOSTS: ldap-host
      PHPLDAPADMIN_HTTPS: "false"
      PHPLDAPADMIN_LDAP_CLIENT_TLS: "false"
    networks:
      - network
    ports:
      - "8080:80"
    depends_on:
      - openldap

  # Simple web service for password restart
  self-service-password:
    image: ltbproject/self-service-password:latest
    container_name: self-service-password
    environment:
      LDAP_BIND_PASSWORD: ${LDAP_BIND_PASSWORD}
      SSP_KEYPHRASE: ${SSP_KEYPHRASE}
    volumes:
      - '$PWD/conf/config.inc.local.php:/var/www/conf/config.inc.local.php'
    ports:
      - "8081:80"
    networks:
      - network
    depends_on:
      - openldap

networks:
  network:
    driver: bridge

volumes:
  openldap_data:
    driver: local

secrets:
  ldap_admin_password:
    file: secrets/ldap_admin_password.txt

FreeIPA

Follow this tutorial:

Code analysis

SonarQube

  • Use the following docker-compose.yml as a starting point.

  • Sonarqube uses ElasticSearch, and it requires some system params changes, we have to change it inside the docker container. We’ll use an init container for that:

    • Add the following code snippet as a service inside the docker-compose.yml:
    docker-compose.yml
    service:
        [...]
        # Init container for system parameter changes
        init:
            image: bash
            privileged: true
            user: root
            volumes:
            - ./scripts/init.sh:/mnt/init.sh
            command: ["sh", "-e", "/mnt/init.sh"]
    • Create a scripts/init.sh file that changes some limits:
    scripts/init.sh
    sysctl -w vm.max_map_count=524288
    sysctl -w fs.file-max=131072
  • If we want SonarQube to use LDAP authentication, we need to add custom config properties:

    • We must edit its properties file $SONARQUBE_HOME/conf/sonar.properties (change the values according to your LDAP server):
    $SONARQUBE_HOME/conf/sonar.properties
    # LDAP configuration
    
    # General Configuration
    sonar.security.realm=LDAP
    ldap.url=ldap://myserver.mycompany.com:[port]
    ldap.bindDn=my_bind_dn # i.e: cn=admin,dc=mycompany,dc=com
    ldap.bindPassword=my_bind_password
    
    # User Configuration
    ldap.user.baseDn=ou=Users,dc=mycompany,dc=com
    ldap.user.request=(&(objectClass=inetOrgPerson)(uid={login}))
    ldap.user.realNameAttribute=displayName
    ldap.user.emailAttribute=mail
    
    # Group Configuration
    ldap.group.baseDn=ou=Groups,dc=sonarsource,dc=com
    ldap.group.request=(&(objectClass=groupOfUniqueNames)(uniqueMember={dn}))
    • Add both a conf volume and the sonar.properties inside the SonarQube docker-compose file:
    $PWD/docker-compose.yml
    services:
        sonarqube:
            [...]
            volumes:
            - sonarqube_conf:/opt/sonarqube/conf
            - $PWD/conf/sonar.properties:/opt/sonarqube/conf/sonar.properties
    
    volumes:
        [...]
        sonarqube_conf:
TODO

Obfuscate LDAP credentials somehow!