You are reading the documentation for an outdated Corteza release. 2023.9 is the latest stable Corteza release.

DevOps Guide

The DevOps guide covers the process of setting up, configuring, and maintaining your Corteza instance.

This page attempts to provide simple instructions to setup an instance that should be used for most cases. More complex use cases and advanced readers should refer to additional DevOps guide sub pages.

Corteza is compiled, developed, and tested for modern browsers. If you need to support older browsers, such as InternetExplorer, you need to build your images. Refer to System Requirements for more details.

Prerequisites

Docker

To use our pre-built Docker images, you must have Docker setup and running on every system you wish to set up Corteza. You can follow the official documentation to get it setup.

Alternatively, you can download prebuilt sources from our releases page or you can build your own.

Docker Compose

Docker Compose makes your life easier when running multiple Docker images where each can be arbitrarily configured. You can follow the official documentation to get it setup.

When using .env files, you need to explicitly specify this inside the docker-compose.yaml file, for example:

version: '3.5'

services:
  server:
    image: cortezaproject/corteza:${VERSION}
    restart: always
    env_file: [ .env ] # <- see here
    depends_on: [ db ]
    ports: [ "127.0.0.1:18084:80" ]

  # ...

Architecture and Repository Overview

Corteza Architecture

The diagram outlines different {PRODUCT_NAME} parts, their relation, and how they interact.
Figure 1. The diagram outlines different Corteza parts, their relation, and how they interact.

The web applications communicate with the server over the REST API and authenticate via the authentication server.

Corteza Discovery additionally communicates with corteza-server-discovery.

The server interacts with all internal auxiliary services such as the database, object storage, error and log tracking, automation runners, …​

Some of the auxiliary services include:
  • data federation,

  • data storage,

  • logger,

  • email sender.

Corteza Repositories and Their Relation

build pipelines
Figure 2. The diagram outlines Corteza repositories and their relation in regards to the build pipeline.
Corteza core repositories:
  1. corteza: The monorepo containing the codebase for core Corteza features.

  2. corteza-server-corredor: Corredor automation runner.

  3. corteza-docs: Corteza documentation.

System Configuration Files

Corteza is configured via the environment (.env) file. It allows you to quickly deploy and configure how Corteza should behave on another system.

Our examples are configured to work as is, but feel free to tweak the server and the Corredor server as you see fit.

The .env file is at the root of the project folder. In the context of Docker Compose, it is next to the docker-compose.yaml file.

The .env file performs implicit Docker Compose configuration, variable substitution for Docker configurations, and service configurations.

You can use variables defined in the .env file inside your docker-compose.yaml files using ${VARIABLE_HERE}.

Offline Deployment

Offline deployments run all services on the same network where the ports are bound to the host’s network.

Offline deployments are suitable only for local development and demos (environments that are not accessible from the outside).

This section provides a minimum setup with PostgreSQL as the persistent database storage. See Offline Deployment Examples for example offline deployment configurations.

Setting up Your File Structure

Your file structure should look like this:
📁 my-corteza
  📄 .env
  📄 docker-compose.yaml
  📁 data (1)
    📁 server (2)
    📁 db (3)
1 Make sure to change the owner to the Docker container (you can use chown 1001:1001 data/db and chown 4242:4242 data/server). Omit if you won’t use persistent storage.
2 Here is where all of the server data is stored, for example uploaded attachments.
3 Here is where the database data is stored.

Configure docker-compose.yaml

Your configuration should look like this:
version: '3.5'

services:
  server:
    image: cortezaproject/corteza:${VERSION}
    restart: always
    env_file: [ .env ]
    depends_on: [ db ]
    ports: [ "127.0.0.1:18080:80" ]

  db:
    # PostgreSQL Database
    # See https://hub.docker.com/_/postgres for details
    # Support for postgres 13, 14 and 15 is available in the latest version of Corteza
    image: postgres:15
      #    networks: [ internal ]
    restart: always
    healthcheck: { test: ["CMD-SHELL", "pg_isready -U corteza"], interval: 10s, timeout: 5s, retries: 5 }
    volumes:
      - "dbdata:/var/lib/postgresql/data"
    environment:
      # Warning: these are values that are only used on 1st start
      #          if you want to change it later, you need to do that
      #          manually inside db container
      POSTGRES_USER:     corteza
      POSTGRES_PASSWORD: corteza

volumes:
  dbdata:

Supported PostgreSQL versions 13, 14, 15

Configure .env

Your configuration should look like this:
########################################################################################################################
# docker-compose supports environment variable interpolation/substitution in compose configuration file
# (more info: https://docs.docker.com/compose/environment-variables)

########################################################################################################################
# General settings
DOMAIN=localhost:18080
VERSION=2023.3

########################################################################################################################
# Database connection
DB_DSN=postgres://corteza:corteza@db:5432/corteza?sslmode=disable

########################################################################################################################
# Server settings

# Running all-in-one and serving web applications directly from server container
HTTP_WEBAPP_ENABLED=true

# Disabled, we do not need detailed persistent logging of actions in local env
ACTIONLOG_ENABLED=false

########################################################################################################################
# SMTP (mail sending) settings

# Point this to your local or external SMTP server if you want to send emails.
# In most cases, Corteza can detect that SMTP is disabled and skips over sending emails without an error
#SMTP_HOST=smtp-server.example.tld:587
#SMTP_USER=postmaster@smtp-server.example.tld
#SMTP_PASS=this-is-your-smtp-password
#SMTP_FROM='"Demo" <info@your-demo.example.tld>'

Running the Services

In the root of your project (next to your docker-compose.yaml and .env files), run the docker compose (the execution can take a few seconds). The command (downloads and) runs all of the services configured in your docker-compose.yaml file.

docker-compose up -d

Check if everything started correctly by running docker-compose ps. The output should look like this:

      Name                    Command                   State                      Ports
-------------------------------------------------------------------------------------------------------
demo_pgsql_db_1         /docker-entrypoint.sh psql       Up (healthy)     5432/tcp
demo_pgsql_server_1     bin/server serve-api             Up (healthy)     127.0.0.1:18080->80/tcp

See Troubleshooting if something went wrong or failed to start.

Testing the Deploy

  1. Direct your browser to http://localhost:18080 (change the port if you used a different port). You should be redirected to the authentication page (/auth).

  2. Create your account through the sign-up form (the first created account is an administrator by default).

  3. Check the server version http://localhost:18080/version.

  4. Check the server’s health http://localhost:18080/healthcheck.

  5. Check the API documentation http://localhost:18080/api/docs/.

If you did not configure your SMTP settings, all sign-ups are marked as confirmed.

Online Deployment

If you’re using Nginx and the WebSocket connection is failing, refer to Maintenance  Troubleshooting.

Online setups separate your services into two networks; internal and proxy. The internal network hides most of the system from the internet. This section provides a minimum setup with PostgreSQL as the persistent database storage with Corredor server enabled.

You can use the same steps to configure multiple online deployments, for example a staging and a production environment.

See Online Deployment Examples for example online deployment configurations.

Setting up Your File Structure

Your file structure should look like this:
📁 my-proxy (1)
  📄 docker-compose.yaml
  📄 custom.conf (2)
📁 my-corteza
  📄 .env
  📄 docker-compose.yaml
  📁 data (3)
    📁 server (4)
    📁 db (5)
1 Omit this if you’re not planning on using Nginx reverse proxy or if it’s already setup.
2 custom.conf must be placed next to the docker-compose.yaml file.
3 Make sure to change the owner to the Docker container (you can use chown 1001:1001 data/db and chown 4242:4242 data/server). Omit if you won’t use persistent storage.
4 Here is where all of the server data is stored, such as uploaded attachments.
5 Here is where the database can store the data.

Setting up Your Nginx Reverse Proxy

⚠️ We are inside the my-proxy directory.

This part automates the creation and renewal of Let’s Encrypt TLS certificates, forward traffic to Docker containers and simplifies complicated firewall configurations.

The following instructions assume that you don’t have anything similar setup in your current environment.

If you are using other means of providing traffic forwarding or SSL certificate handling, proceed with caution.

We will be using Nginx Proxy and LetsEncrypt Nginx Proxy Companion. If you wish to use or are using something else, feel free to skip this section.

Your docker-compose.yaml should look like this:
version: '3.5'

services:
  nginx-proxy:
    image: nginxproxy/nginx-proxy
    container_name: nginx-proxy
    restart: always
    networks:
      - proxy
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./certs:/etc/nginx/certs
      - ./htpasswd:/etc/nginx/htpasswd
      - ./vhost.d:/etc/nginx/vhost.d
      - ./html:/usr/share/nginx/html
      - ./custom.conf:/etc/nginx/conf.d/custom.conf:ro
      - /var/run/docker.sock:/tmp/docker.sock:ro

  nginx-letsencrypt:
    image: nginxproxy/acme-companion
    container_name: nginx-letsencrypt
    restart: always
    depends_on:
      - nginx-proxy
    volumes_from:
      - nginx-proxy:rw
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - acme:/etc/acme.sh

# Create network if it does not exist
networks:
  proxy:
    external: true

volumes:
  acme:

Supported PostgreSQL versions 13, 14, 15

Your custom.conf should look like this:
client_max_body_size 1g;
# allows nginx to support larger file uploads

proxy_read_timeout 86400s;
# support longer running requests as opposed to the default 60s

client_header_buffer_size 64k;
# increase the size of the client header buffer to support larger headers, as sometimes cookie data can get large

large_client_header_buffers 4 64k;
# increase the number of buffers to support larger headers

proxy_ignore_client_abort  on;
# close connection immidiately when client aborts

proxy_buffer_size          128k;
# increase the size of the buffer used for reading the response from the proxied server

proxy_buffers              4 256k;
# size of the buffers for a single connection

proxy_busy_buffers_size    256k;
# size of buffers during sending to proxied server and buffering the response

Inside your my-proxy directory, run docker-compose up -d (the execution can take a few seconds) to start the reverse proxy.

Check if everything started correctly by running docker-compose ps. The output should look like this:

      Name                     Command               State                    Ports
-----------------------------------------------------------------------------------------------------
nginx-letsencrypt   /bin/bash /app/entrypoint. ...   Up
nginx-proxy         /app/docker-entrypoint.sh  ...   Up      0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp

Configuring docker-compose.yaml

⚠️ We are inside the my-corteza directory.

Containers must be on the same network as nginx-proxy (in the examples, we’re using a network named proxy).

Your configuration should look like this:
version: '3.5'

services:
  server:
    image: cortezaproject/corteza:${VERSION}
    networks: [ proxy, internal ]
    restart: always
    env_file: [ .env ]
    depends_on: [ db ]
    volumes: [ "./data/server:/data" ]
    environment:
      # VIRTUAL_HOST helps NginX proxy route traffic for specific virtual host to
      # this container
      # This value is also picked up by initial boot auto-configuration procedure
      # If this is changed, make sure you change settings accordingly
      VIRTUAL_HOST: ${DOMAIN}
      # This is needed only if you are using NginX Lets-Encrypt companion
      # (see docs.cortezaproject.org for details)
      LETSENCRYPT_HOST: ${DOMAIN}

  db:
    # PostgreSQL Database
    # See https://hub.docker.com/_/postgres for details
    # Support for postgres 13, 14 and 15 is available in the latest version of Corteza
    image: postgres:15
    networks: [ internal ]
    restart: always
    healthcheck: { test: ["CMD-SHELL", "pg_isready -U corteza"], interval: 10s, timeout: 5s, retries: 5 }
    environment:
      # Warning: these are values that are only used on 1st start
      #          if you want to change it later, you need to do that
      #          manually inside db container
      POSTGRES_USER:     corteza
      POSTGRES_PASSWORD: corteza

networks:
  internal: {}
  proxy: { external: true }

Configure .env

⚠️ We are inside the my-corteza directory.

Your configuration should look like this:
########################################################################################################################
# docker-compose supports environment variable interpolation/substitution in compose configuration file
# (more info: https://docs.docker.com/compose/environment-variables)

########################################################################################################################
# General settings
DOMAIN=your-demo.example.tld
VERSION=2023.3

########################################################################################################################
# Database connection

DB_DSN=postgres://corteza:corteza@db:5432/corteza?sslmode=disable

########################################################################################################################
# Server settings

# Serve Corteza webapps alongside API
HTTP_WEBAPP_ENABLED=true

# Send action log to container logs as well
# ACTIONLOG_DEBUG=true

# Uncomment for extra debug info if something goes wrong
# LOG_LEVEL=debug

# Use nicer and colorful log instead of JSON
# LOG_DEBUG=true

########################################################################################################################
# Authentication

# Secret to use for JWT token
# Make sure you change it (>30 random characters) if
# you expose your deployment to outside traffic
# AUTH_JWT_SECRET=this-is-only-for-demo-purpose--make-sure-you-change-it-for-production

########################################################################################################################
# SMTP (mail sending) settings

# Point this to your local or external SMTP server if you want to send emails.
# In most cases, Corteza can detect that SMTP is disabled and skips over sending emails without an error
#SMTP_HOST=smtp-server.example.tld:587
#SMTP_USER=postmaster@smtp-server.example.tld
#SMTP_PASS=this-is-your-smtp-password
#SMTP_FROM='"Demo" <info@your-demo.example.tld>'

Running the Services

Inside your my-corteza directory (next to your docker-compose.yaml and .env files), run the docker compose (the execution can take a few seconds). The command (downloads and) runs all of the services configured in your docker-compose.yaml file.

docker-compose up -d

Check whether everything started correctly by running docker-compose ps. The output should look like this:

        Name                                Command                  State              Ports
----------------------------------------------------------------------------------------------------
my_production_demo_db_1         docker-entrypoint.sh postgres    Up (healthy)   3306/tcp, 33060/tcp
my_production_demo_server_1     /bin/corteza-server serve-api    Up (healthy)   80/tcp

See Troubleshooting if something went wrong or failed to start.

Testing the Deployment

  1. Direct your browser to http://your-demo.example.tld. You will be redirected to the authentication page (/auth).

  2. Create your account through the sign-up form (the first created account is an administrator by default).

  3. Check the server version http://your-demo.example.tld/version

  4. Check the server’s health http://your-demo.example.tld/healthcheck

  5. Check the API documentation http://your-demo.example.tld/api/docs/

Useful Commands

Table 1. A list of useful Docker commands:

Run commands inside a container (started)

docker exec -it <container name> help

Run commands inside a container (not started)

docker run -it --rm <container name> help

Table 2. A list of useful Docker Compose commands:

Stop and remove containers along with their volumes without confirmation

docker-compose rm --force --stop -v

View logs for all running containers

docker-compose logs --follow --tail 20

View logs for a specific container

docker-compose logs --follow --tail 20 <service name>

Execute with Docker Compose

docker-compose exec <service name> help

Access bash in the container at WORKDIR

docker-compose exec <service name> bash

Where to next

The sub-sections under menu:DevOps guide go into more details regarding specific topics, such as: