Documentation

Workbench Containerized Application Deployment Guide

Table of Contents

Introduction

This guide explains how to deploy FossID Workbench in a containerized environment using Docker, Podman, or Docker Compose. It covers prerequisites, configuration, deployment, upgrading, troubleshooting, and best practices.

Application Overview

  • Registry Location: quay.io/fossid
  • Base Image: workbench
  • Exposed Ports: 80 (map 443 as well when serving HTTPS from the container; see Custom CA certificates and HTTPS)
  • Required Environment Variables: multiple
  • Storage Requirements:
    • fossid.conf
    • version.lock
    • backup
    • intake
    • logs
    • uploads
    • scan-path
    • ssh-keys (for scanning Git repositories)
  • Network Configuration: bridge

Quick Start (TL;DR)

Get FossID Workbench running in 5 minutes. For detailed configuration options, see the sections below. Important: the default container deployment is not secured for production. Pay special attention to the Caution section below.

Step 1: Authenticate with Quay.io

sudo docker login quay.io
# Use credentials from the Delivery portal

Step 2: Create Required Files and Directories

Caution: Replace all default passwords and update the webapp_base_url variable before deploying, as this configuration assumes a localhost environment. Pay special attention to setting the correct host and token (cli_server_host and cli_token in fossid.conf, or the corresponding environment variables); they can be set in different files and are easy to miss.

# Create directories
mkdir -p backup intake logs uploads scan-path ssh-keys db/db-persist

# Create version.lock (empty for fresh install)
touch version.lock

# Create minimal fossid.conf
cat > fossid.conf << 'EOF'
[CLI]
cli_server_host = fossid-scan-server
cli_strip_tags = .html

[WebApp]
webapp_db_server = db
webapp_db_database = fossid_db
webapp_db_username = fossiduser
webapp_db_password = fossidpassword
webapp_db_port = 3306
webapp_timezone = Europe/Berlin
webapp_intake_repository = /fossid/intake/
webapp_backups = /fossid/backup/
webapp_base_url = http://localhost:8080/index.php
EOF

# Create .env file
cat > .env << 'EOF'
RELEASE=25.1.0
MYSQL_ROOT_PASSWORD=root123
MYSQL_USER=fossiduser
MYSQL_PASSWORD=fossidpassword
MYSQL_HOST=db
FOSSID_MYSQL_DATABASE=fossid_db
HTTP_PORT=8080
FOSSID_INITIAL_PASSWORD=fossidlogin
FOSSID_SHINOBI_JAVA_ARGS="-Xms8g -Xmx8g -XX:NewSize=5g -XX:MaxNewSize=5g -XX:SurvivorRatio=8"
FOSSID_SHINOBI_ARGS="-threads 8 -timeout 275 -socket 127.0.0.1:9900"
FOSSID_CLI_TOKEN=replace-with-token-from-vault
FOSSID_TOKEN=replace-with-token-from-vault
EOF

# Create MySQL custom config
cat > mysql-custom.cnf << 'EOF'
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
max_allowed_packet = 64M
EOF

# Create docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    platform: linux/amd64
    mem_reservation: 9g
    container_name: fossid-workbench
    restart: unless-stopped
    ports:
      - "${HTTP_PORT}:80"
    tty: true
    env_file:
      - .env
    depends_on:
      fossid-mysql:
        condition: service_healthy
    healthcheck:
      test: curl --silent --fail localhost:80/health-check
      interval: 5s
      timeout: 5s
      retries: 60
    volumes:
      - ./fossid.conf:/fossid/etc/fossid.conf:Z
      - ./version.lock:/fossid/version.lock:Z
      - ./backup:/fossid/backup:Z
      - ./intake:/fossid/intake:Z
      - ./logs:/fossid/logs:Z
      - ./uploads:/fossid/uploads:Z
      - ./scan-path:/fossid/scan-path:Z
      - ./ssh-keys:/tmp/ssh-keys:ro,Z
    networks:
      - wb-network
    cap_add:
      - CAP_AUDIT_WRITE

  fossid-mysql:
    image: docker.io/library/mysql:8.0
    platform: linux/amd64
    container_name: db
    env_file:
      - .env
    restart: unless-stopped
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --max-allowed-packet=64M
    healthcheck:
      test: mysqladmin -u"$$MYSQL_USER" -p"$$MYSQL_PASSWORD" -h127.0.0.1 ping
      interval: 5s
      timeout: 5s
      retries: 60
    networks:
      - wb-network
    volumes:
      - ./db/db-persist:/var/lib/mysql
      - ./mysql-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro

networks:
  wb-network:
    driver: bridge
EOF

Step 3: Deploy

sudo docker compose up -d

Step 4: Access FossID Workbench

Open http://localhost:8080 and log in with:

  • Username: fossid
  • Password: fossidlogin (or your FOSSID_INITIAL_PASSWORD value)

Important: This quick start uses default passwords suitable for testing only. For production deployments, change all passwords and review the Production Deployment section.

System Requirements

FossID Workbench container images are built for the linux/amd64 platform. When running on other architectures (e.g., Apple Silicon), use the --platform linux/amd64 flag.

Before deploying FossID Workbench, ensure your system meets the following requirements.

Hardware Requirements

Component Minimum Recommended Notes
CPU 4 cores 8+ cores More cores improve scan performance
RAM 8 GB 16+ GB Required for Shinobi scanning engine
Disk Space 50 GB 200+ GB Depends on scan volume and backup retention

Software Requirements

To deploy FossID Workbench as a container, use one of the following runtimes. Ensure the software is installed and up to date.

Software Minimum Version Verification Command
Docker 20.10+ sudo docker --version
Docker Compose 2.0+ sudo docker compose version
Podman (alternative) 4.0+ podman --version

Docker and Docker Compose commands in this guide use sudo so they work when the Docker daemon requires root. If your user is in the docker group, you can omit sudo. Podman commands are left without sudo.

Network Requirements

Requirement Details
Outbound HTTPS Access to quay.io for pulling container images
Outbound SSH Port 22 for Git repository scanning (optional)
Inbound HTTP/HTTPS Port 80/443 for web interface access
Internal Network Container-to-container communication (bridge network)

Authentication

Use the credentials from the Delivery portal to authenticate with the FossID repository at Quay.io.

sudo docker login quay.io

Pre-Deployment Checklist

Before starting the deployment, verify that you have completed the following steps:

Environment Setup

  • Docker, Podman, or Docker Compose is installed and running
  • Authenticated with Quay.io registry (sudo docker login quay.io)
  • System meets minimum requirements (8GB+ RAM, 50GB+ disk)

Required Files

  • Created .env file with database credentials and release version
  • Created fossid.conf with database connection settings
  • Created version.lock file (empty for fresh install, or preserved from previous version)
  • Created mysql-custom.cnf for MySQL configuration

Required Directories

  • Created backup/ directory
  • Created intake/ directory
  • Created logs/ directory
  • Created uploads/ directory
  • Created scan-path/ directory
  • Created db/db-persist/ directory for MySQL data
  • Created ssh-keys/ directory (if scanning Git repositories)

Network and Security

  • Configured SSH keys for Git repository access (if needed)
  • Verified outbound connectivity to quay.io
  • Verified outbound SSH access to Git servers (if needed)
  • Reviewed and changed default passwords in .env file

Pre-Upgrade Only

  • Reviewed release notes for the target version
  • Created backup of existing data and database
  • Documented current version for rollback purposes

Tip: Use the Quick Start section for a streamlined setup, or refer to Configuration Reference for full configuration file examples.

Configuration Management

MySQL/MariaDB Configuration

Set the following MySQL/MariaDB parameters when deploying the database container for compatibility and performance.

Database Compatibility:

FossID Workbench is compatible with both MySQL and MariaDB. Both database systems use the same configuration parameters and connection methods. MariaDB is a drop-in replacement for MySQL and offers enhanced features and performance in many scenarios. You can use either docker.io/library/mysql:8.0 or a specific supported MariaDB image tag such as docker.io/library/mariadb:10.6 (pinning to a specific version rather than using latest is recommended) based on your preference and requirements.

Required Database Parameters

The following parameters must be configured in the MySQL/MariaDB server configuration. These can be set through:

  • Custom MySQL configuration file mounted as a volume
  • Environment variables (for Docker/Podman deployments)
  • Command-line parameters in the container startup command

Character Set and Collation:

It is strongly recommended to explicitly set these values for character set and collation:

[mysqld]
character-set-server     = utf8mb4
collation-server         = utf8mb4_general_ci

Packet Size Configuration:

A minimum value of 64M must be set for max_allowed_packet:

[mysqld]
max_allowed_packet = 64M

MySQL Replication (if applicable):

When using MySQL Replication, particularly when replicating from MySQL 5.7 (or earlier) to MySQL 8.x, the parameter default_collation_for_utf8mb4 should be set to utf8mb4_general_ci on both the source and replica servers to ensure compatibility.

Important: The default_collation_for_utf8mb4 variable cannot be set in my.cnf or as a command-line startup option. It must be set at runtime using SQL commands after the MySQL server has started.

Method 1: Using SET PERSIST (Recommended for persistence across restarts)

Connect to MySQL and execute:

SET PERSIST default_collation_for_utf8mb4="utf8mb4_general_ci";

This will persist the setting across server restarts. Note that some MySQL versions (8.0.35+) may show deprecation warnings, but the setting will still work.

Method 2: Using SET GLOBAL (Temporary, lost on restart)

SET GLOBAL default_collation_for_utf8mb4="utf8mb4_general_ci";

Method 3: Using init_connect (for non-privileged users)

Add to your MySQL configuration file:

[mysqld]
init_connect='SET default_collation_for_utf8mb4="utf8mb4_general_ci"'

Note: init_connect does not apply to users with SUPER or CONNECTION_ADMIN privileges. The standard fossiduser created with GRANT ALL PRIVILEGES ON fossid_db.* does not have these global privileges, so init_connect will work correctly for the application user. However, if SUPER or CONNECTION_ADMIN privileges are granted to the database user, init_connect will be bypassed for that user and you should use Method 1 or Method 2 instead.

When is this parameter necessary:

  • Replicating from MySQL 5.7 or earlier (which used utf8mb4_general_ci as the default) to MySQL 8.x (which uses utf8mb4_0900_ai_ci as the default)
  • You need backward compatibility with older MySQL versions

For new MySQL 8.x deployments without replication from older versions, this parameter is not required as MySQL 8.x uses utf8mb4_0900_ai_ci by default, which is compatible with utf8mb4_general_ci for most use cases.

More details: https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_default_collation_for_utf8mb4

Database Creation

When creating the FossID database, ensure the correct character set and collation are specified:

CREATE DATABASE fossid_db CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;

Use the same database name everywhere (FOSSID_MYSQL_DATABASE, FOSSID_WEBAPP_DB_DATABASE, and webapp_db_database in fossid.conf).

Implementation Methods

Method 1: Custom MySQL Configuration File

Create a custom MySQL configuration file on the host:

# Create custom MySQL config
cat > ./mysql-custom.cnf << 'EOF'
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
max_allowed_packet = 64M
EOF

Mount it in your Docker Compose configuration:

services:
  fossid-mysql:
    image: docker.io/library/mysql:8.0
    # ... other configuration ...
    volumes:
      - ./db/db-persist:/var/lib/mysql
      - ./mysql-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro

Or in Docker run command:

sudo docker run -d \
  --name db \
  -v ./mysql-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro \
  -v ./db/db-persist:/var/lib/mysql \
  # ... other options ...
  docker.io/library/mysql:8.0

Method 2: MySQL Command-Line Parameters

Add MySQL parameters directly to the container command:

services:
  fossid-mysql:
    image: docker.io/library/mysql:8.0
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --max-allowed-packet=64M
    # ... other configuration ...

Method 3: MariaDB Configuration

MariaDB uses the same configuration approach as MySQL. You can use MariaDB by replacing the MySQL image with a MariaDB image:

MariaDB with Custom Configuration File:

# Create custom MariaDB config (same format as MySQL)
cat > ./mariadb-custom.cnf << 'EOF'
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci
max_allowed_packet = 64M
EOF

Docker Compose with MariaDB:

services:
  fossid-mysql:
    image: docker.io/library/mariadb:10.6
    # ... other configuration ...
    volumes:
      - ./db/db-persist:/var/lib/mysql
      - ./mariadb-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro

Docker run with MariaDB:

docker run -d \
  --name db \
  -v ./mariadb-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro \
  -v ./db/db-persist:/var/lib/mysql \
  # ... other options ...
  docker.io/library/mariadb:10.6 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_general_ci \
  --max-allowed-packet=64M

MariaDB Command-Line Parameters:

services:
  fossid-mysql:
    image: docker.io/library/mariadb:10.6
    command: 
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --max-allowed-packet=64M
    # ... other configuration ...

Note: For MariaDB server configuration, use the [mysqld], [mariadbd], or [server] section headers. The [mariadb] group applies to client programs and is not equivalent to the server groups, so server settings placed there may be ignored.

Verification

After starting the MySQL or MariaDB container, verify the configuration:

# Check character set and collation
sudo docker exec db mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "SHOW VARIABLES LIKE 'character_set%';"
sudo docker exec db mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "SHOW VARIABLES LIKE 'collation%';"

# Check max_allowed_packet
sudo docker exec db mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "SHOW VARIABLES LIKE 'max_allowed_packet';"

# Verify database character set
sudo docker exec db mysql -u root -p"$MYSQL_ROOT_PASSWORD" -e "SELECT SCHEMA_NAME, DEFAULT_CHARACTER_SET_NAME, DEFAULT_COLLATION_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='fossid_db';"

# For MariaDB, you can also use mariadb command (if available in the container)
sudo docker exec db mariadb -u root -p"$MYSQL_ROOT_PASSWORD" -e "SHOW VARIABLES LIKE 'version%';"

Expected output should show:

  • character_set_server: utf8mb4
  • collation_server: utf8mb4_general_ci
  • max_allowed_packet: 67108864 (64M in bytes)
  • For MariaDB, version will show MariaDB version information

Environment Variables

Use .env files for local development. For production, use a secret manager (e.g., HashiCorp Vault, AWS Secrets Manager).

Example .env file:

PROJECT_NAME=deployment

# FOSSID Release configuration
# RELEASE=25.1.0
# Replace FOSSID_VERSION with the image tag you deploy (e.g. 25.2.0), matching quay.io/fossid/workbench:<tag>
RELEASE=FOSSID_VERSION

# Database server environment configuration
MYSQL_ROOT_PASSWORD=root123
MYSQL_USER=fossiduser
MYSQL_PASSWORD=fossidpassword
MYSQL_HOST=db
FOSSID_MYSQL_DATABASE=fossid_db

# Web Server Configuration
# change only if default HTTP is modified or HTTPS is configured
# HTTPS_PORT=
HTTP_PORT=8080

# FossID Shinobi service configuration
FOSSID_SHINOBI_JAVA_ARGS="-Xms8g -Xmx8g -XX:NewSize=5g -XX:MaxNewSize=5g -XX:SurvivorRatio=8"
FOSSID_SHINOBI_ARGS="-threads 8 -timeout 275 -socket 127.0.0.1:9900"

# FossID Workbench
# The initial password for the `fossid` user.
FOSSID_INITIAL_PASSWORD=fossidlogin

FossID Workbench Configuration

FossID Workbench is configured via the fossid.conf file. The image includes a sample file at /fossid/etc/fossid.conf.dist. To extract it: sudo docker cp <container_id>:/fossid/etc/fossid.conf.dist /path/on/host/fossid.conf.dist.

The minimal configuration required is:

Replace every placeholder below with real values from your environment (hostnames, secrets, URLs). Names such as FOSSID_HOST, MYSQL_USER, and FOSSID_MYSQL_PASSWORD are not valid literals—substitute the actual CLI host, database user, and password. The database name must match MySQL (see Database Creation; examples use fossid_db). You can instead set the equivalent FOSSID_WEBAPP_* and CLI environment variables, which override fossid.conf when both are present.

[CLI]
cli_server_host = FOSSID_HOST
cli_token = FOSSID_TOKEN
cli_strip_tags = .html

[WebApp]
webapp_db_server = MYSQL_HOST
webapp_db_database = fossid_db
webapp_db_username = MYSQL_USER
webapp_db_password = FOSSID_MYSQL_PASSWORD
webapp_db_port = 3306
webapp_server_name = fossid-workbench
webapp_timezone = Europe/Berlin
webapp_intake_repository = /fossid/intake/
webapp_backups = /fossid/backup/

webapp_base_url = https://fossid.example.com/index.php

The file can be mounted in the container by adding the following option to the docker or podman command, for example:

  --volume ./fossid.conf:/fossid/etc/fossid.conf:Z

or add it as a volume in the compose.yaml file, for example:

...
  fossid-workbench-service:
  ...
    volumes:
      - ./fossid.conf:/fossid/etc/fossid.conf:Z
...

Configuration via Environment Variables

As an alternative to using the fossid.conf file, configuration values can be injected directly through environment variables. This approach is particularly useful in containerized environments where configuration management through environment variables is preferred.

Important: When both fossid.conf and environment variables are present, environment variables take precedence over the values defined in fossid.conf.

Configuration Quick Reference

The following table provides a quick reference for the most commonly used configuration options, organized by category:

Database Configuration (Required)

Purpose fossid.conf Environment Variable Default
Database host webapp_db_server FOSSID_WEBAPP_DB_SERVER -
Database name webapp_db_database FOSSID_WEBAPP_DB_DATABASE -
Database user webapp_db_username FOSSID_WEBAPP_DB_USERNAME -
Database password webapp_db_password FOSSID_WEBAPP_DB_PASSWORD -
Database port webapp_db_port FOSSID_WEBAPP_DB_PORT 3306

Web Application Settings (Required)

Purpose fossid.conf Environment Variable Default
Base URL webapp_base_url FOSSID_WEBAPP_BASE_URL -
Timezone webapp_timezone - UTC
Intake directory webapp_intake_repository - /fossid/intake/
Backup directory webapp_backups - /fossid/backup/

Email Configuration (Optional)

Purpose fossid.conf Environment Variable Default
Enable email webapp_enable_email_sending FOSSID_WEBAPP_ENABLE_EMAIL_SENDING false
Mail transport webapp_mailer_transport FOSSID_WEBAPP_MAILER_TRANSPORT smtp
SMTP host webapp_mailer_host FOSSID_WEBAPP_MAILER_HOST -
SMTP port webapp_mailer_port FOSSID_WEBAPP_MAILER_PORT 25
Encryption webapp_mailer_encryption FOSSID_WEBAPP_MAILER_ENCRYPTION -
Sender address webapp_mailer_sender_address FOSSID_WEBAPP_MAILER_SENDER_ADDRESS -

LDAP Authentication (Optional)

Purpose fossid.conf Environment Variable Default
Enable LDAP webapp_use_ldap_auth FOSSID_WEBAPP_USE_LDAP_AUTH false
LDAP server webapp_ldap_connection FOSSID_WEBAPP_LDAP_CONNECTION -
LDAP port webapp_ldap_port FOSSID_WEBAPP_LDAP_PORT 389
Fallback to local webapp_fallback_local_login FOSSID_WEBAPP_FALLBACK_LOCAL_LOGIN true

OAuth2 Authentication (Optional)

Purpose fossid.conf Environment Variable Default
Enable OAuth2 webapp_oauth2_login FOSSID_WEBAPP_OAUTH2_LOGIN false
Provider webapp_oauth2_provider FOSSID_WEBAPP_OAUTH2_PROVIDER -
Client ID webapp_oauth2_client_id FOSSID_WEBAPP_OAUTH2_CLIENT_ID -
Client secret webapp_oauth2_secret FOSSID_WEBAPP_OAUTH2_SECRET -
Redirect URI webapp_oauth2_redirect_uri FOSSID_WEBAPP_OAUTH2_REDIRECT_URI -

Proxy Settings (Optional)

Purpose fossid.conf Environment Variable Default
CLI proxy host cli_proxy_host FOSSID_CLI_PROXY_HOST -
CLI proxy port cli_proxy_port FOSSID_CLI_PROXY_PORT -
JIRA proxy host webapp_jira_proxy_host FOSSID_WEBAPP_JIRA_PROXY_HOST -
JIRA proxy port webapp_jira_proxy_port FOSSID_WEBAPP_JIRA_PROXY_PORT -

How Environment Variables Work in Containers

In the FossID Workbench container, environment variables are automatically processed by the container’s startup script. The script reads the environment variables you provide (via --env, env_file, or environment in Docker Compose) and injects them into the application configuration during container initialization.

Note: This is handled automatically by the container - no manual PHP-FPM configuration or additional setup is required. The PHP-FPM pool configuration maintains its default setting (clear_env = yes), and the startup script takes care of making environment variables available to the application.

Available Environment Variables

The following table lists all available environment variables and their corresponding fossid.conf parameters:

Environment Variable fossid.conf Parameter
FOSSID_WEBAPP_DB_SERVER webapp_db_server
FOSSID_WEBAPP_DB_DATABASE webapp_db_database
FOSSID_WEBAPP_DB_USERNAME webapp_db_username
FOSSID_WEBAPP_DB_PASSWORD webapp_db_password
FOSSID_WEBAPP_DB_PORT webapp_db_port
FOSSID_WEBAPP_ENABLE_EMAIL_SENDING webapp_enable_email_sending
FOSSID_WEBAPP_MAILER_TRANSPORT webapp_mailer_transport
FOSSID_WEBAPP_MAILER_HOST webapp_mailer_host
FOSSID_WEBAPP_MAILER_PORT webapp_mailer_port
FOSSID_WEBAPP_MAILER_USERNAME webapp_mailer_username
FOSSID_WEBAPP_MAILER_PASSWORD webapp_mailer_password
FOSSID_WEBAPP_MAILER_ENCRYPTION webapp_mailer_encryption
FOSSID_WEBAPP_MAILER_AUTH_MODE webapp_mailer_auth_mode
FOSSID_WEBAPP_MAILER_SENDER_ADDRESS webapp_mailer_sender_address
FOSSID_WEBAPP_MAILER_SENDER_DISPLAY_NAME webapp_mailer_sender_display_name
FOSSID_WEBAPP_MAILER_SENDMAIL_COMMAND webapp_mailer_sendmail_command
FOSSID_WEBAPP_BASE_URL webapp_base_url
FOSSID_WEBAPP_MAILER_EMAIL_SIGNATURE webapp_mailer_email_signature
FOSSID_WEBAPP_OAUTH2_LOGIN webapp_oauth2_login
FOSSID_WEBAPP_OAUTH2_PROVIDER webapp_oauth2_provider
FOSSID_WEBAPP_OAUTH2_DISPLAYED_TEXT webapp_oauth2_displayed_text
FOSSID_WEBAPP_OAUTH2_CLIENT_ID webapp_oauth2_client_id
FOSSID_WEBAPP_OAUTH2_SECRET webapp_oauth2_secret
FOSSID_WEBAPP_OAUTH2_TENANT webapp_oauth2_tenant
FOSSID_WEBAPP_OAUTH2_DOMAIN webapp_oauth2_domain
FOSSID_WEBAPP_OAUTH2_REDIRECT_URI webapp_oauth2_redirect_uri
FOSSID_WEBAPP_OAUTH2_FALLBACK_LOCAL_LOGIN webapp_oauth2_fallback_local_login
FOSSID_WEBAPP_OAUTH2_FALLBACK_LOCAL_LOGIN_TEXT webapp_oauth2_fallback_local_login_text
FOSSID_WEBAPP_USE_LDAP_AUTH webapp_use_ldap_auth
FOSSID_WEBAPP_FALLBACK_LOCAL_LOGIN webapp_fallback_local_login
FOSSID_WEBAPP_LDAP_CONNECTION webapp_ldap_connection
FOSSID_WEBAPP_LDAP_PORT webapp_ldap_port
FOSSID_WEBAPP_LDAP_DN_UKEY webapp_ldap_dn_ukey
FOSSID_WEBAPP_LDAP_DN webapp_ldap_dn
FOSSID_WEBAPP_LDAP_MANAGER_DN webapp_ldap_manager_dn
FOSSID_WEBAPP_LDAP_MANAGER_PASSWORD webapp_ldap_manager_password
FOSSID_WEBAPP_LDAP_SEARCH_BASE webapp_ldap_search_base
FOSSID_WEBAPP_LDAP_SEARCH_FILTER webapp_ldap_search_filter
FOSSID_WEBAPP_LDAP_SEARCH_FIELD_FROM_RESULT webapp_ldap_search_field_from_result
FOSSID_WEBAPP_LDAP_OPT_NETWORK_TIMEOUT webapp_ldap_opt_network_timeout
FOSSID_WEBAPP_JIRA webapp_jira
FOSSID_WEBAPP_JIRA_PROXY_HOST webapp_jira_proxy_host
FOSSID_WEBAPP_JIRA_PROXY_PORT webapp_jira_proxy_port
FOSSID_CLI_PROXY_HOST cli_proxy_host
FOSSID_CLI_PROXY_PORT cli_proxy_port
FOSSID_CLI_PROXY_USER cli_proxy_user
FOSSID_CLI_PROXY_PASS cli_proxy_pass
FOSSID_WEBAPP_ALTERNATIVE_SERVER_HOSTS webapp_alternative_server_hosts
FOSSID_WEBAPP_PM_PIDFILE_DIRECTORY webapp_pm_pidfile_directory
FOSSID_WEBAPP_HOST_ID_LOGGING webapp_host_id_logging

Usage Examples

Docker run with environment variables:

sudo docker run -d \
  --name fossid-workbench \
  --env FOSSID_WEBAPP_DB_SERVER=db \
  --env FOSSID_WEBAPP_DB_DATABASE=fossid_db \
  --env FOSSID_WEBAPP_DB_USERNAME=fossiduser \
  --env FOSSID_WEBAPP_DB_PASSWORD=secretpassword \
  --env FOSSID_WEBAPP_BASE_URL=https://fossid.example.com/index.php \
  # ... other options ...
  quay.io/fossid/workbench:latest

Docker Compose with environment variables:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    environment:
      - FOSSID_WEBAPP_DB_SERVER=db
      - FOSSID_WEBAPP_DB_DATABASE=fossid_db
      - FOSSID_WEBAPP_DB_USERNAME=fossiduser
      - FOSSID_WEBAPP_DB_PASSWORD=${FOSSID_DB_PASSWORD}
      - FOSSID_WEBAPP_BASE_URL=https://fossid.example.com/index.php
    # ... other configuration ...

Using .env file (recommended):

# .env file
FOSSID_WEBAPP_DB_SERVER=db
FOSSID_WEBAPP_DB_DATABASE=fossid_db
FOSSID_WEBAPP_DB_USERNAME=fossiduser
FOSSID_WEBAPP_DB_PASSWORD=secretpassword
FOSSID_WEBAPP_BASE_URL=https://fossid.example.com/index.php

Then reference it in Docker Compose:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    env_file:
      - .env
    # ... other configuration ...

Best Practices

  1. Secret Management: Use external secret management solutions (HashiCorp Vault, AWS Secrets Manager, Kubernetes Secrets) for sensitive values like passwords and tokens
  2. Hybrid Approach: You can use fossid.conf for static configuration and environment variables for dynamic or sensitive values
  3. Priority Understanding: Remember that environment variables override fossid.conf values when both are present
  4. Documentation: Document which configuration method is used in your deployment for maintenance purposes

Version Lock File

FossID Workbench uses a version.lock file to manage version upgrades and migrations between releases. This file must exist before starting the container and its content depends on your installation scenario.

Purpose

The version.lock file:

  • Controls the database migration process during version upgrades
  • Ensures safe transitions between FossID Workbench versions
  • Is automatically managed by the container after initial setup

File Location

The file should be created on the host and mounted into the container at:

/fossid/version.lock

Initial Setup Scenarios

Scenario 1: Fresh Installation (First Time Setup)

For a new FossID Workbench installation, create an empty version.lock file:

# Create empty version.lock file
touch version.lock

Scenario 2: Migration from Version < 25.2.0

If you’re upgrading from a version prior to 25.2.0 where the version.lock file didn’t exist, create the file with content:

# Create version.lock for migration
echo 1 > version.lock

Scenario 3: Upgrade from Version ≥ 25.2.0

If you already have a version.lock file from a previous deployment:

  • Do not modify the existing file
  • The container will automatically manage version transitions

Mounting the File

Add the version.lock file as a volume when running the container:

Docker run:

sudo docker run -d \
  --name fossid-workbench \
  # ... other options ...
  -v ./version.lock:/fossid/version.lock:Z \
  quay.io/fossid/workbench:latest

Docker Compose:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    # ... other configuration ...
    volumes:
      - ./fossid.conf:/fossid/etc/fossid.conf:Z
      - ./version.lock:/fossid/version.lock:Z
      - ./backup:/fossid/backup:Z
      # ... other volumes ...

Podman:

podman run -d \
  --name fossid-workbench \
  # ... other options ...
  -v ./version.lock:/fossid/version.lock:Z \
  quay.io/fossid/workbench:latest

Important Notes

Critical Considerations:

  • Must exist before first start: Create the file before running the container for the first time
  • Do not delete: Once created and mounted, never delete this file
  • Do not manually edit: After initial setup, the container manages this file automatically
  • Backup recommended: Include version.lock in your backup strategy
  • Version-specific behavior: The file content is managed differently depending on the version

Verification

After container startup, verify the file is correctly mounted:

# Check if file exists in container
sudo docker exec fossid-workbench ls -l /fossid/version.lock

# View file content (for debugging)
sudo docker exec fossid-workbench cat /fossid/version.lock

Troubleshooting

Container fails to start with version.lock error:

  • Ensure the file exists on the host before starting the container
  • Verify the file is correctly mounted (check volume mapping)
  • Check file permissions: Should be readable by the container user

Migration issues after upgrade:

  • If upgrading from < 25.2.0, ensure version.lock contains 1
  • Check container logs for migration-related errors: sudo docker logs fossid-workbench
  • Do not modify the file during container runtime

Lost version.lock file:

  • Stop the container immediately
  • Restore from backup if available
  • Contact support if you’re unsure about the correct content for your version

Port Mapping

The application listens on port 80 inside the container. In Docker Compose, map it to a host port:

ports:
  - "80:80"

Volume Management

The following directories can be configured as volumes or as bind-mounts for data persistence outside the container:

# Create volumes
sudo docker volume create fossid-wb-backup
sudo docker volume create fossid-wb-intake
sudo docker volume create fossid-wb-logs
sudo docker volume create fossid-wb-uploads

# Inspect volumes
sudo docker volume inspect fossid-wb-backup
sudo docker volume inspect fossid-wb-intake
sudo docker volume inspect fossid-wb-logs
sudo docker volume inspect fossid-wb-uploads

For using the target path option in FossID Workbench it is recommended to use a bind mounted volume. You can use either the --volume flag or the --mount flag with Docker or Podman. Here are some examples:

# Create directory on the host
mkdir /path/to/target-path-directory

and use one of the options:

--volume /path/to/target-path-directory:/target-path:rw,Z

or

--mount type=bind,source=/path/to/target-path-directory,target=/target-path

For custom CA certificates and an optional custom Nginx main configuration, you can bind-mount additional paths—see Custom CA certificates and HTTPS.

SSH Client Configuration

FossID Workbench requires SSH access to clone and scan repositories from Git servers (GitHub, GitLab, Bitbucket, etc.). This section describes how to configure SSH keys and the SSH client within the container.

SSH Directory Structure

Mount your SSH directory into the container at /tmp/ssh-keys/. At runtime the container may copy keys to /var/www/.ssh/ for the web user; use that path when verifying from inside the container.

Required files in the mounted directory:

  • id_rsa or id_ed25519 - Private SSH key
  • id_rsa.pub or id_ed25519.pub - Public SSH key (optional)
  • known_hosts - Known hosts file for SSH host verification
  • config - SSH client configuration (optional)

Preparing SSH Keys on Host

Create a dedicated SSH directory on your host machine:

# Create SSH directory
mkdir -p ./ssh-keys

# Set proper permissions
chmod 700 ./ssh-keys

# Generate SSH key pair (if you don't have one)
ssh-keygen -t ed25519 -C "fossid@your-domain.com" -f ./ssh-keys/id_ed25519 -N ""

# Or use existing keys
cp ~/.ssh/id_ed25519 ./ssh-keys/
cp ~/.ssh/id_ed25519.pub ./ssh-keys/

Adding Git Servers to known_hosts

Pre-populate the known_hosts file to avoid SSH host verification prompts:

# For GitHub
ssh-keyscan github.com >> ./ssh-keys/known_hosts

# For GitLab
ssh-keyscan gitlab.com >> ./ssh-keys/known_hosts

# For custom Git server
ssh-keyscan company-git-server.com >> ./ssh-keys/known_hosts

Create an SSH config file for advanced configuration:

cat > ./ssh-keys/config << 'EOF'
Host github.com
    HostName github.com
    User git
    IdentityFile /var/www/.ssh/id_ed25519
    StrictHostKeyChecking yes

Host gitlab.com
    HostName gitlab.com
    User git
    IdentityFile /var/www/.ssh/id_ed25519
    StrictHostKeyChecking yes

Host custom-git-server
    HostName git.company-git-server.com
    User git
    Port 2222
    IdentityFile /var/www/.ssh/id_ed25519
    StrictHostKeyChecking yes
EOF

Mounting SSH Keys in the container

Add the SSH directory as a volume when running the container:

Docker run:

sudo docker run -d \
  --name fossid-workbench \
  # ... other options ...
  -v ./ssh-keys:/tmp/ssh-keys:ro,Z \
  quay.io/fossid/workbench:latest

Docker Compose:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    # ... other configuration ...
    volumes:
      - ./fossid.conf:/fossid/etc/fossid.conf:Z
      - ./backup:/fossid/backup:Z
      - ./intake:/fossid/intake:Z
      - ./logs:/fossid/logs:Z
      - ./uploads:/fossid/uploads:Z
      - ./scan-path:/fossid/scan-path:Z
      - ./ssh-keys:/tmp/ssh-keys:ro,Z  # SSH keys mounted read-only

Podman:

podman run -d \
  --name fossid-workbench \
  # ... other options ...
  -v ./ssh-keys:/tmp/ssh-keys:ro,Z \
  quay.io/fossid/workbench:latest

Security Best Practices

Important Security Considerations:

  • Use read-only mount (:ro flag) to prevent the container from modifying SSH keys
  • Use dedicated SSH keys for FossID Workbench, don’t reuse personal keys
  • Never commit SSH keys to version control (add ssh-keys/ to .gitignore)
  • Restrict key permissions to 600 for private keys, 644 for public keys. The container copies them with the correct permissions at runtime.
  • Use passphrase-protected keys when possible (requires additional configuration)
  • Rotate keys regularly and remove access when no longer needed
  • Use deploy keys on Git platforms with read-only access when possible

Verifying SSH Configuration

After deployment, verify SSH connectivity from within the container:

# Access container shell
sudo docker exec -it fossid-workbench /bin/sh

# Test SSH connection to GitHub
sudo -u www-data ssh -T git@github.com

# Test SSH connection to GitLab
sudo -u www-data ssh -T git@gitlab.com

# Check SSH key permissions
ls -la /var/www/.ssh/

# Verify known_hosts
cat /var/www/.ssh/known_hosts

Expected output for GitHub:

Hi username! You've successfully authenticated, but GitHub does not provide shell access.

Troubleshooting SSH Issues

Permission denied (publickey):

  • Verify private key exists in the correct directory: sudo docker exec -it fossid-workbench ls -la /var/www/.ssh/
  • Check key permissions: Should be 400 for private key
  • Verify the public key is added to your Git server (GitHub/GitLab/etc.)
  • Check SSH key format (RSA, ED25519, etc.)

Host key verification failed:

  • Add the Git server to known_hosts file
  • Or set StrictHostKeyChecking no in SSH config (not recommended for production)

Could not resolve hostname:

  • Check network connectivity from container
  • Verify DNS resolution: sudo docker exec -it fossid-workbench curl -v github.com

Connection timeout:

  • Check firewall rules
  • Verify outbound SSH traffic (port 22) is allowed
  • Test from host first: ssh -T git@github.com

Custom CA certificates and HTTPS

Custom CA certificates (system trust store)

For outbound HTTPS to services that use certificates signed by private or corporate certificate authorities, you can supply additional CA certificates when the container starts.

Mount: Bind-mount a host directory or named volume to /tmp/certs in the container (for example, a host directory such as tmp-ca).

Startup behavior: On startup, the container scans /tmp/certs for .crt and .pem files. If any are found, they are copied to /usr/local/share/ca-certificates so the system trust store can be updated accordingly.

HTTPS inside the container (Nginx)

This is separate from the custom CA workflow above: here you configure inbound TLS for the web interface by enabling SSL in Nginx.

Nginx reads its live configuration from /etc/nginx/nginx.conf. The image includes a template (nginx.conf.dist) with commented instructions. A typical approach is to copy that template on the host, follow the steps under Enabling SSL using the template, save the result as nginx.conf, and bind-mount that file into the container at /etc/nginx/nginx.conf. Changing configuration only inside an ephemeral container layer is discouraged because those changes are lost when the container is recreated.

Optional bind-mount example:

-v ./nginx.conf:/etc/nginx/nginx.conf:ro

Use a read-only mount (:ro) when the container must not modify the configuration file.

Port mapping: When serving HTTPS from the container, map host port 443 to container 443 in addition to 80 where applicable:

ports:
  - "80:80"
  - "443:443"
-p 80:80 -p 443:443

Enabling SSL using the template

The following comments are taken from nginx.conf.dist and describe how to enable SSL:

        # How to enable ssl:
        #   1. Comment the line above
        #   2. generate a ssl certificate
        #   3. Uncomment the following 4 lines
        #   4. Update the paths for your .crt and .key file below
        #   5. Update the server_name to match your servers domain name below
        # ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
        # ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
        # listen 443 default_server ssl; # replace 'ssl' with 'http2' for a performance boost
        # server_name fossid.yourdomain.com;

After you prepare nginx.conf on the host, mount it to /etc/nginx/nginx.conf as described above. You can instead supply a complete custom nginx.conf without using the template (advanced).

Important: /tmp/certs (the tmp-ca mount) is for outbound trust only — it is scanned at startup to update the system trust store and is not read by Nginx for inbound TLS. The server certificate and private key referenced from nginx.conf (default template paths: /etc/ssl/certs/nginx-selfsigned.crt and /etc/ssl/private/nginx-selfsigned.key) must be bind-mounted from the host (or supplied through another mechanism such as a secrets store). Pick the mounting scenario below that matches your goal.

Mounting examples

The examples below cover three independent scenarios. Pick the one that matches your goal; do not assume tmp-ca alone is sufficient for inbound HTTPS.

Scenario A — Inbound HTTPS in Nginx only

Use this scenario when you only need to serve the web interface over HTTPS. Mount nginx.conf and the server certificate and private key into the paths referenced by the template, and map port 443.

Docker run:

docker run -d \
  --name fossid-workbench \
  # ... other options ...
  -p 80:80 -p 443:443 \
  -v ./nginx.conf:/etc/nginx/nginx.conf:ro,Z \
  -v ./nginx-selfsigned.crt:/etc/ssl/certs/nginx-selfsigned.crt:ro,Z \
  -v ./nginx-selfsigned.key:/etc/ssl/private/nginx-selfsigned.key:ro,Z \
  quay.io/fossid/workbench:${RELEASE}

Docker Compose:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    # ... other configuration ...
    ports:
      - "80:80"
      - "443:443"
    volumes:
      # ... other volumes ...
      - ./nginx.conf:/etc/nginx/nginx.conf:ro,Z
      - ./nginx-selfsigned.crt:/etc/ssl/certs/nginx-selfsigned.crt:ro,Z
      - ./nginx-selfsigned.key:/etc/ssl/private/nginx-selfsigned.key:ro,Z

Podman:

podman run -d \
  --name fossid-workbench \
  # ... other options ...
  -p 80:80 -p 443:443 \
  -v ./nginx.conf:/etc/nginx/nginx.conf:ro,Z \
  -v ./nginx-selfsigned.crt:/etc/ssl/certs/nginx-selfsigned.crt:ro,Z \
  -v ./nginx-selfsigned.key:/etc/ssl/private/nginx-selfsigned.key:ro,Z \
  quay.io/fossid/workbench:${RELEASE}

If you change the ssl_certificate or ssl_certificate_key paths in your nginx.conf, adjust the container-side mount paths to match.

Scenario B — Custom CA trust only (outbound)

Use this scenario when the Workbench needs to trust certificates issued by a private or corporate CA for outbound connections (for example, internal Git or proxy servers). Inbound HTTPS in Nginx is not affected; do not map port 443 unless you also configure inbound TLS as in Scenario A or C.

Docker run:

docker run -d \
  --name fossid-workbench \
  # ... other options ...
  -p 80:80 \
  -v ./tmp-ca:/tmp/certs:ro,Z \
  quay.io/fossid/workbench:${RELEASE}

Docker Compose:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    # ... other configuration ...
    ports:
      - "80:80"
    volumes:
      # ... other volumes ...
      - ./tmp-ca:/tmp/certs:ro,Z

Podman:

podman run -d \
  --name fossid-workbench \
  # ... other options ...
  -p 80:80 \
  -v ./tmp-ca:/tmp/certs:ro,Z \
  quay.io/fossid/workbench:${RELEASE}

The container scans /tmp/certs for .crt and .pem files at startup and copies them into the system trust store as described in Custom CA certificates (system trust store).

Scenario C — Both inbound HTTPS and custom CA trust

Use this scenario when you need both inbound HTTPS in Nginx and custom CA trust for outbound connections. Combine the mounts from Scenarios A and B.

Docker run:

docker run -d \
  --name fossid-workbench \
  # ... other options ...
  -p 80:80 -p 443:443 \
  -v ./tmp-ca:/tmp/certs:ro,Z \
  -v ./nginx.conf:/etc/nginx/nginx.conf:ro,Z \
  -v ./nginx-selfsigned.crt:/etc/ssl/certs/nginx-selfsigned.crt:ro,Z \
  -v ./nginx-selfsigned.key:/etc/ssl/private/nginx-selfsigned.key:ro,Z \
  quay.io/fossid/workbench:${RELEASE}

Docker Compose:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    # ... other configuration ...
    ports:
      - "80:80"
      - "443:443"
    volumes:
      # ... other volumes ...
      - ./tmp-ca:/tmp/certs:ro,Z
      - ./nginx.conf:/etc/nginx/nginx.conf:ro,Z
      - ./nginx-selfsigned.crt:/etc/ssl/certs/nginx-selfsigned.crt:ro,Z
      - ./nginx-selfsigned.key:/etc/ssl/private/nginx-selfsigned.key:ro,Z

Podman:

podman run -d \
  --name fossid-workbench \
  # ... other options ...
  -p 80:80 -p 443:443 \
  -v ./tmp-ca:/tmp/certs:ro,Z \
  -v ./nginx.conf:/etc/nginx/nginx.conf:ro,Z \
  -v ./nginx-selfsigned.crt:/etc/ssl/certs/nginx-selfsigned.crt:ro,Z \
  -v ./nginx-selfsigned.key:/etc/ssl/private/nginx-selfsigned.key:ro,Z \
  quay.io/fossid/workbench:${RELEASE}

The mounts from each scenario are independent: use Scenario A for inbound HTTPS only, Scenario B for outbound CA trust only, or Scenario C when you need both.

Verification

# Confirm mounts
docker exec fossid-workbench ls -la /tmp/certs
docker exec fossid-workbench ls -la /etc/nginx/nginx.conf
docker exec fossid-workbench ls -la /etc/ssl/certs/nginx-selfsigned.crt
docker exec fossid-workbench ls -la /etc/ssl/private/nginx-selfsigned.key

# Validate Nginx configuration (if supported in the image)
docker exec fossid-workbench nginx -t

# Test HTTPS (adjust host and port as needed)
curl -vk https://localhost:443/

If you changed the ssl_certificate or ssl_certificate_key paths in your nginx.conf, replace the ls paths above with the paths your configuration uses.

Security notes

  • Prefer read-only mounts for certificate material and Nginx configuration when possible.
  • Restrict private key permissions on the host.
  • Many deployments terminate TLS on an external reverse proxy instead of, or in addition to, Nginx inside the container—see Reverse proxy setup (Nginx).

Image Management

Pulling the Image

Pull the image from the FossID private repository quay.io.

sudo docker pull quay.io/fossid/workbench:latest

Or a specific version

sudo docker pull quay.io/fossid/workbench:25.1.0

Using specific platform (if needed)

sudo docker pull --platform linux/amd64 quay.io/fossid/workbench:latest

Image Verification

# Verify image presence
sudo docker images | grep workbench

# Inspect image details
sudo docker inspect --format='{{.RepoDigests}}' quay.io/fossid/workbench:25.1.0

Deployment

This section provides step-by-step instructions for deploying FossID Workbench using different container runtimes. Choose the deployment method that best fits your infrastructure and requirements.

Choosing a Deployment Method

Use the following table to select the deployment method that best fits your needs:

Method Best For Pros Cons
Docker Compose Most deployments Declarative configuration, easy to manage, version controlled Requires Docker Compose installation
Docker (standalone) Simple setups, CI/CD pipelines Direct control, no additional tools needed Manual network and volume management
Podman Rootless/Enterprise environments Daemonless, better security, drop-in Docker replacement Slightly different syntax in some cases

Recommendation: Use Docker Compose for most deployments. It provides the best balance of simplicity, maintainability, and reproducibility.

For Kubernetes deployments, refer to the Kubernetes Deployment Guide.

Basic Docker Deployment

Using MySQL:

sudo docker network create --driver=bridge wb-network

sudo docker run -d \
  --name db \
  --platform linux/amd64 \
  --env-file .env \
  --health-cmd 'mysqladmin -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -h127.0.0.1 ping' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  --network wb-network \
  -v ./db/db-persist:/var/lib/mysql \
  -v ./mysql-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro \
  docker.io/library/mysql:8.0 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_general_ci \
  --max-allowed-packet=64M

sudo docker run -d \
  --name fossid-workbench \
  --platform linux/amd64 \
  --memory-reservation 8g \
  --tty \
  --env-file .env \
  --cap-add=CAP_AUDIT_WRITE \
  --health-cmd 'curl --silent --fail localhost:80/health-check' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  --network wb-network \
  -p 8080:80 \
  -v ./fossid.conf:/fossid/etc/fossid.conf:Z \
  -v ./version.lock:/fossid/version.lock:Z \
  -v ./backup:/fossid/backup:Z \
  -v ./intake:/fossid/intake:Z \
  -v ./logs:/fossid/logs:Z \
  -v ./uploads:/fossid/uploads:Z \
  -v ./scan-path:/fossid/scan-path:Z \
  -v ./ssh-keys:/tmp/ssh-keys:ro,Z \
  --restart unless-stopped \
  quay.io/fossid/workbench:${RELEASE}

Alternative: Using MariaDB:

docker network create --driver=bridge wb-network

docker run -d \
  --name db \
  --platform linux/amd64 \
  --env-file .env \
  --health-cmd 'mysqladmin -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -h127.0.0.1 ping' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  --network wb-network \
  -v ./db/db-persist:/var/lib/mysql \
  -v ./mariadb-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro \
  docker.io/library/mariadb:10.6 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_general_ci \
  --max-allowed-packet=64M

docker run -d \
  --name fossid-workbench \
  --platform linux/amd64 \
  --memory-reservation 8g \
  --tty \
  --env-file .env \
  --cap-add=CAP_AUDIT_WRITE \
  --health-cmd 'curl --silent --fail localhost:80/health-check' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  --network wb-network \
  -p 8080:80 \
  -v ./fossid.conf:/fossid/etc/fossid.conf:Z \
  -v ./version.lock:/fossid/version.lock:Z \
  -v ./backup:/fossid/backup:Z \
  -v ./intake:/fossid/intake:Z \
  -v ./logs:/fossid/logs:Z \
  -v ./uploads:/fossid/uploads:Z \
  -v ./scan-path:/fossid/scan-path:Z \
  -v ./ssh-keys:/var/www/.ssh:ro,Z \
  --restart unless-stopped \
  quay.io/fossid/workbench:${RELEASE}

Note: Both MySQL and MariaDB use the same environment variables and connection methods. The only difference is the container image used (mysql:8.0 vs mariadb:10.6).

Docker Compose Deployment

Create a compose.yaml:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    platform: linux/amd64
    mem_reservation: 9g
    container_name: fossid-workbench
    restart: unless-stopped
    ports:
      - "8080:80"
    tty: true
    env_file:
      - .env
    depends_on:
      fossid-mysql:
        condition: service_healthy
    healthcheck:
      test: curl --silent --fail localhost:80/health-check
      interval: 5s
      timeout: 5s
      retries: 60
    volumes:
      - ./fossid.conf:/fossid/etc/fossid.conf:Z
      - ./version.lock:/fossid/version.lock:Z
      - ./backup:/fossid/backup:Z
      - ./intake:/fossid/intake:Z
      - ./logs:/fossid/logs:Z
      - ./uploads:/fossid/uploads:Z
      - ./scan-path:/fossid/scan-path:Z
      - ./ssh-keys:/tmp/ssh-keys:ro,Z
    networks:
      - wb-network
    cap_add:
      - CAP_AUDIT_WRITE

  fossid-mysql:
    image: docker.io/library/mysql:8.0
    platform: linux/amd64
    container_name: db
    env_file:
      - .env
    restart: unless-stopped
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --max-allowed-packet=64M
    healthcheck:
      test: mysqladmin -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -h127.0.0.1 ping
      interval: 5s
      timeout: 5s
      retries: 60
    networks:
      - wb-network
    volumes:
      - ./db/db-persist:/var/lib/mysql
      - ./mysql-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro

networks:
  wb-network:
    driver: bridge

Deploy with:

sudo docker compose up -d

Alternative: Docker Compose with MariaDB

To use MariaDB instead of MySQL, replace the fossid-mysql service in your docker-compose.yml:

services:
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    platform: linux/amd64
    mem_reservation: 8g
    container_name: fossid-workbench
    restart: unless-stopped
    ports:
      - "8081:80"
    tty: true
    env_file:
      - .env
    depends_on:
      - fossid-mysql
    healthcheck:
      test: curl --silent --fail localhost:80/health-check
      interval: 5s
      timeout: 5s
      retries: 60
    volumes:
      - ./fossid.conf:/fossid/etc/fossid.conf:Z
      - ./version.lock:/fossid/version.lock:Z
      - ./backup:/fossid/backup:Z
      - ./intake:/fossid/intake:Z
      - ./logs:/fossid/logs:Z
      - ./uploads:/fossid/uploads:Z
      - ./scan-path:/fossid/scan-path:Z
      - ./ssh-keys:/var/www/.ssh:ro,Z
    networks:
      - wb-network
    cap_add:
      - CAP_AUDIT_WRITE

  fossid-mysql:
    image: docker.io/library/mariadb:10.6
    platform: linux/amd64
    container_name: db
    env_file:
      - .env
    restart: unless-stopped
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --max-allowed-packet=64M
    healthcheck:
      test: mysqladmin -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -h127.0.0.1 ping
      interval: 5s
      timeout: 5s
      retries: 60
    networks:
      - wb-network
    volumes:
      - ./db/db-persist:/var/lib/mysql
      - ./mariadb-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro

networks:
  wb-network:
    driver: bridge

Note: The environment variables (MYSQL_ROOT_PASSWORD, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE) work identically with MariaDB. MariaDB maintains full compatibility with MySQL client protocols and environment variable naming conventions.

Podman Pod Deployment

Map the HTTP port on the pod (podman pod create --publish ...). Containers joined to that pod should not publish the same host port again.

Using MySQL:

podman network create --driver=bridge wb-network

podman pod create --name fossid-workbench-pod --publish 8080:80 --network wb-network

podman run -d \
  --name db \
  --platform linux/amd64 \
  --pod fossid-workbench-pod \
  --env-file .env \
  --health-cmd 'mysqladmin -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -h127.0.0.1 ping' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  -v ./db/db-persist:/var/lib/mysql \
  -v ./mysql-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro \
  docker.io/library/mysql:8.0 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_general_ci \
  --max-allowed-packet=64M

podman run -d \
  --name fossid-workbench \
  --platform linux/amd64 \
  --pod fossid-workbench-pod \
  --memory-reservation 8g \
  --tty \
  --env-file .env \
  --cap-add=CAP_AUDIT_WRITE \
  --health-cmd 'curl --silent --fail localhost:80/health-check' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  -v ./fossid.conf:/fossid/etc/fossid.conf:Z \
  -v ./version.lock:/fossid/version.lock:Z \
  -v ./backup:/fossid/backup:Z \
  -v ./intake:/fossid/intake:Z \
  -v ./logs:/fossid/logs:Z \
  -v ./uploads:/fossid/uploads:Z \
  -v ./scan-path:/fossid/scan-path:Z \
  -v ./ssh-keys:/tmp/ssh-keys:ro,Z \
  --restart unless-stopped \
  quay.io/fossid/workbench:latest

Alternative: Using MariaDB:

# Skip network creation if already created above
podman network exists wb-network || podman network create --driver=bridge wb-network

podman pod create --name fossid-workbench-pod --publish 8080:80 --network wb-network

podman run -d \
  --name db \
  --platform linux/amd64 \
  --pod fossid-workbench-pod \
  --env-file .env \
  --health-cmd 'mysqladmin -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -h127.0.0.1 ping' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  -v ./db/db-persist:/var/lib/mysql \
  -v ./mariadb-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro \
  docker.io/library/mariadb:10.6 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_general_ci \
  --max-allowed-packet=64M

podman run -d \
  --name fossid-workbench \
  --platform linux/amd64 \
  --pod fossid-workbench-pod \
  --memory-reservation 8g \
  --tty \
  --env-file .env \
  --cap-add=CAP_AUDIT_WRITE \
  --health-cmd 'curl --silent --fail localhost:80/health-check' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  -v ./fossid.conf:/fossid/etc/fossid.conf:Z \
  -v ./version.lock:/fossid/version.lock:Z \
  -v ./backup:/fossid/backup:Z \
  -v ./intake:/fossid/intake:Z \
  -v ./logs:/fossid/logs:Z \
  -v ./uploads:/fossid/uploads:Z \
  -v ./scan-path:/fossid/scan-path:Z \
  -v ./ssh-keys:/tmp/ssh-keys:ro,Z \
  --restart unless-stopped \
  quay.io/fossid/workbench:latest

Upgrading FossID Workbench

This section describes the process for upgrading FossID Workbench to a new version. Follow these steps carefully to ensure a smooth upgrade process.

Pre-Upgrade Checklist

Before starting the upgrade process, complete the following tasks:

  1. Review Release Notes: Check the release notes for the target version for any breaking changes or special upgrade instructions
  2. Document Current Version: Note your current version for rollback purposes
  3. Plan Maintenance Window: Schedule the upgrade during a maintenance window to minimize disruption
  4. Test in Non-Production: If possible, test the upgrade process in a staging environment first
  5. Prepare Backup Strategy: Ensure you have sufficient disk space for backups (backups will be created after stopping containers)

Important: Backups should be created after stopping the containers to ensure data consistency. See Step 2 of the upgrade procedure.

Check Current Version:

# Check the currently running image version
sudo docker inspect fossid-workbench --format='{{.Config.Image}}'

# Or for Docker Compose
sudo docker compose ps fossid-workbench

Upgrade Procedure

Step 1: Stop the Current Container

For Docker Compose:

# Stop all services
sudo docker compose down

# Verify containers are stopped
sudo docker compose ps

For Standalone Docker:

# Stop the FossID Workbench container
sudo docker stop fossid-workbench

# Stop the database container (if upgrading both)
sudo docker stop db

# Verify containers are stopped
sudo docker ps -a | grep fossid

For Podman:

# Stop the pod
podman pod stop fossid-workbench-pod

# Verify pod is stopped
podman pod ps

Step 2: Create Backups

Critical: Now that containers are stopped, create backups to ensure data consistency.

Backup Persistent Volumes:

# Backup all persistent data directories
tar -czf fossid-backup-$(date +%Y%m%d-%H%M%S).tar.gz \
  ./fossid.conf \
  ./version.lock \
  ./backup \
  ./intake \
  ./logs \
  ./uploads \
  ./scan-path \
  ./ssh-keys \
  ./db

Archives that include ./ssh-keys contain private key material. Treat them as highly sensitive: encrypt at rest, restrict file permissions and storage location, or omit ./ssh-keys from this archive if you back up keys through a dedicated secret or key-management process (understanding that you must still be able to restore Git/SSH access when needed).

Backup Database:

After docker compose down, containers are removed; recreate only the database service, wait until MySQL is ready (for example sudo docker compose ps until fossid-mysql is healthy), then run the dump:

# Start database container temporarily for backup
# For Docker Compose
sudo docker compose up -d fossid-mysql
# Wait for MySQL to accept connections (healthcheck or several seconds)
sudo docker compose exec fossid-mysql mysqldump \
  -u"$MYSQL_USER" \
  -p"$MYSQL_PASSWORD" \
  "$FOSSID_MYSQL_DATABASE" > fossid-db-backup-$(date +%Y%m%d-%H%M%S).sql
sudo docker compose stop fossid-mysql

# For standalone Docker
sudo docker start db
sudo docker exec db mysqldump \
  -u"$MYSQL_USER" \
  -p"$MYSQL_PASSWORD" \
  "$FOSSID_MYSQL_DATABASE" > fossid-db-backup-$(date +%Y%m%d-%H%M%S).sql
sudo docker stop db

# Alternative: Backup database files directly (if MySQL container is stopped)
# Ensure database is properly shut down before using this method
tar -czf mysql-data-backup-$(date +%Y%m%d-%H%M%S).tar.gz ./db/db-persist

Verify Backups:

# Check backup file was created
ls -lh fossid-backup-*.tar.gz

# Verify database backup
ls -lh fossid-db-backup-*.sql
# or
ls -lh mysql-data-backup-*.tar.gz

Step 3: Pull the New Image

# Pull the new version
sudo docker pull quay.io/fossid/workbench:<TARGET_VERSION>

# Or pull the latest version
sudo docker pull quay.io/fossid/workbench:latest

# Verify the new image
sudo docker images | grep workbench

Step 4: Update Configuration (if needed)

Update your .env file or compose.yaml to reference the new version:

# Edit .env file
RELEASE=<TARGET_VERSION>

Important: Review the Version Lock File section to understand how the version.lock file is managed during upgrades. The file will be automatically updated by the container during the upgrade process.

Critical: Do not modify or delete the version.lock file manually during the upgrade process.

Step 5: Start with the New Version

For Docker Compose:

# Start services with the new image
sudo docker compose up -d

# Follow the startup logs
sudo docker compose logs -f fossid-workbench

For Standalone Docker:

# Remove the old container (data is preserved in volumes)
sudo docker rm fossid-workbench

# Start with the new image using the same run command
sudo docker run -d \
  --name fossid-workbench \
  --platform linux/amd64 \
  --memory-reservation 8g \
  --tty \
  --env-file .env \
  --cap-add=CAP_AUDIT_WRITE \
  --health-cmd 'curl --silent --fail localhost:80/health-check' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  --network wb-network \
  -p 8080:80 \
  -v ./fossid.conf:/fossid/etc/fossid.conf:Z \
  -v ./version.lock:/fossid/version.lock:Z \
  -v ./backup:/fossid/backup:Z \
  -v ./intake:/fossid/intake:Z \
  -v ./logs:/fossid/logs:Z \
  -v ./uploads:/fossid/uploads:Z \
  -v ./scan-path:/fossid/scan-path:Z \
  -v ./ssh-keys:/tmp/ssh-keys:ro,Z \
  --restart unless-stopped \
  quay.io/fossid/workbench:<TARGET_VERSION>
# Follow the startup logs
sudo docker logs -f fossid-workbench

For Podman:

# Remove old containers from pod
podman rm fossid-workbench

# Start with the new image
podman run -d \
  --name fossid-workbench \
  --platform linux/amd64 \
  --pod fossid-workbench-pod \
  --memory-reservation 8g \
  --tty \
  --env-file .env \
  --cap-add=CAP_AUDIT_WRITE \
  --health-cmd 'curl --silent --fail localhost:80/health-check' \
  --health-interval 5s \
  --health-timeout 5s \
  --health-retries 60 \
  -v ./fossid.conf:/fossid/etc/fossid.conf:Z \
  -v ./version.lock:/fossid/version.lock:Z \
  -v ./backup:/fossid/backup:Z \
  -v ./intake:/fossid/intake:Z \
  -v ./logs:/fossid/logs:Z \
  -v ./uploads:/fossid/uploads:Z \
  -v ./scan-path:/fossid/scan-path:Z \
  -v ./ssh-keys:/tmp/ssh-keys:ro,Z \
  --restart unless-stopped \
  quay.io/fossid/workbench:<TARGET_VERSION>

# Start the pod
podman pod start fossid-workbench-pod

Step 6: Verify the Upgrade

After starting the container, verify that the upgrade was successful:

# Check container health status
sudo docker ps

# Verify health check is passing
sudo docker inspect --format='{{.State.Health.Status}}' fossid-workbench

# Check application logs for errors
sudo docker logs fossid-workbench | tail -50

# Verify version.lock file was updated
sudo docker exec fossid-workbench cat /fossid/version.lock

# Access the application
curl http://localhost:8080/health-check

Functional Verification:

  1. Log in to the FossID Workbench web interface
  2. Verify that existing projects and scans are accessible
  3. Check that all configuration settings are preserved
  4. Test creating a new scan to ensure functionality
  5. Verify database migrations completed successfully (check logs)

Post-Upgrade Tasks

After successful upgrade:

  1. Monitor Application: Monitor logs and performance for the first few hours
  2. Update Documentation: Document the new version number in your environment documentation
  3. Clean Up Old Images: Remove old container images to free up disk space
  4. Verify Backups: Ensure your backup process is still working correctly
  5. Test Integrations: Verify that any external integrations (CI/CD, APIs) are working
# Remove old images (optional)
sudo docker images | grep workbench
sudo docker rmi quay.io/fossid/workbench:<old-version>

# Clean up unused images (removes unused images across the host, not only FossID)
sudo docker image prune -a

Warning: docker image prune -a can delete many unrelated images. When rolling back a single release, prefer sudo docker rmi quay.io/fossid/workbench:<old-version> first, and use prune only if you intend a broader cleanup.

Rollback Procedure

If you encounter issues after upgrading, you can roll back to the previous version:

Step 1: Stop the New Container

# For Docker Compose
sudo docker compose down

# For standalone Docker
sudo docker stop fossid-workbench && sudo docker rm fossid-workbench

# For Podman
podman pod stop fossid-workbench-pod

Step 2: Restore Backups

Important: Restoring from backup will overwrite current data. Any changes made after the backup was taken will be lost.

Extract the File-System Backup:

First, extract the version.lock and any other files you need from the backup archive:

# List contents of the backup to see what's included
tar -tzf fossid-backup-YYYYMMDD-HHMMSS.tar.gz

# Extract specific files (version.lock is required for rollback)
tar -xzf fossid-backup-YYYYMMDD-HHMMSS.tar.gz ./version.lock

# Optional: Extract all files if you need to restore the complete state
# WARNING: This will overwrite existing directories
# tar -xzf fossid-backup-YYYYMMDD-HHMMSS.tar.gz

Restore Database from SQL Dump:

# Start database container first
# For Docker Compose (after `docker compose down`, use up -d to recreate the service)
sudo docker compose up -d fossid-mysql

# For standalone Docker
sudo docker start db

# Wait for database to be ready (use compose health / ps, or allow a short delay)
sleep 10

# Drop and recreate database to ensure clean restore (optional but recommended)
sudo docker exec db mysql \
  -u root \
  -p"$MYSQL_ROOT_PASSWORD" \
  -e "DROP DATABASE IF EXISTS $FOSSID_MYSQL_DATABASE; CREATE DATABASE $FOSSID_MYSQL_DATABASE CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;"

# Restore database backup
# For Docker Compose
sudo docker compose exec -T fossid-mysql mysql \
  -u"$MYSQL_USER" \
  -p"$MYSQL_PASSWORD" \
  "$FOSSID_MYSQL_DATABASE" < fossid-db-backup-YYYYMMDD-HHMMSS.sql

# For standalone Docker
sudo docker exec -i db mysql \
  -u"$MYSQL_USER" \
  -p"$MYSQL_PASSWORD" \
  "$FOSSID_MYSQL_DATABASE" < fossid-db-backup-YYYYMMDD-HHMMSS.sql

# Stop database container
# For Docker Compose
sudo docker compose stop fossid-mysql

# For standalone Docker
sudo docker stop db

Alternative: Restore Database from Data Files:

If you backed up MySQL data files directly instead of using SQL dump:

Warning: The following permanently deletes the current MySQL data directory on the host. Confirm you have a valid backup and that the path ./db/db-persist is correct for your deployment before running rm -rf.

# Ensure database container is stopped
sudo docker stop db

# Remove existing database files and restore from backup
rm -rf ./db/db-persist/*
tar -xzf mysql-data-backup-YYYYMMDD-HHMMSS.tar.gz

# Start database container
sudo docker start db

Verify Backup Restoration:

# Verify version.lock was restored
cat ./version.lock

# Verify database files are in place (if using data files restore)
ls -la ./db/db-persist/

Step 3: Start with Previous Version

Update your .env or compose.yaml to reference the previous version and restart:

# Update .env
RELEASE=<PREVIOUS_VERSION>

# Start with previous version
sudo docker compose up -d

Step 4: Verify Rollback

Verify that the application is running correctly with the previous version:

sudo docker logs fossid-workbench
curl http://localhost:8080/health-check

Troubleshooting Upgrade Issues

Database Migration Fails:

  • Check container logs: sudo docker logs fossid-workbench
  • Verify database connectivity
  • Ensure sufficient disk space
  • Review version.lock file content
  • Contact support with migration error details

Container Won’t Start After Upgrade:

  • Verify all volumes are correctly mounted
  • Check for configuration changes in release notes
  • Review environment variables
  • Check container logs for specific errors

Performance Issues After Upgrade:

  • Review new Java/Shinobi arguments in release notes
  • Check memory allocation settings
  • Monitor container resource usage: sudo docker stats
  • Verify database performance

version.lock File Issues:

  • Never manually edit or delete version.lock during upgrade
  • See the Version Lock File section for detailed information
  • If you suspect corruption, restore from backup before retrying upgrade

Troubleshooting

Quick Diagnostics

Run these commands first to gather diagnostic information:

# Check container status
sudo docker ps -a | grep fossid

# View recent logs
sudo docker logs --tail 100 fossid-workbench

# Check health status
sudo docker inspect --format='{{.State.Health.Status}}' fossid-workbench

# Check resource usage
sudo docker stats --no-stream fossid-workbench db

Database Connection Issues

Symptom: “Connection refused” or “Access denied” errors in logs

Diagnostic Steps:

# 1. Verify database container is running
sudo docker ps | grep db

# 2. Check database logs
sudo docker logs db

# 3. Test MySQL connection from workbench (checks network and auth)
sudo docker exec fossid-workbench mysql -h db -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SELECT 1;"

# 4. Test MySQL from database container
sudo docker exec db mysql -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" -e "SELECT 1;"

Common Causes and Solutions:

Cause Solution
Password mismatch Ensure passwords match across all config files (see below)
Database not ready Wait for database health check to pass before starting workbench
Network isolation Verify both containers are on the same Docker network
Wrong hostname Use container name db (not localhost) in fossid.conf

Important: The database password must be identical in all three locations:

# In .env file
MYSQL_PASSWORD=your_password

# In .env file (if using environment variable configuration)
FOSSID_WEBAPP_DB_PASSWORD=your_password

# In fossid.conf
webapp_db_password = your_password

Container Fails to Start

Symptom: Container exits immediately after starting

Diagnostic Steps:

# 1. Check exit code
sudo docker inspect fossid-workbench --format='{{.State.ExitCode}}'

# 2. View full logs
sudo docker logs fossid-workbench

# 3. Check if required files exist
ls -la fossid.conf version.lock

# 4. Verify file permissions
ls -la backup intake logs uploads scan-path

Common Causes and Solutions:

Exit Code Cause Solution
1 Configuration error Check fossid.conf syntax and required parameters
126 Permission denied Fix file/directory permissions
127 Command not found Image may be corrupted; re-pull the image
137 Out of memory (OOM) Increase container memory limit
139 Segmentation fault Check logs; may need to re-pull image

Out of Memory (OOM) Issues

Symptom: Container killed unexpectedly, sudo docker inspect shows OOMKilled: true

Diagnostic Steps:

# Check if container was OOM killed
sudo docker inspect fossid-workbench --format='{{.State.OOMKilled}}'

# Check system memory
free -h

# Check container memory usage
sudo docker stats --no-stream fossid-workbench

Solutions:

  1. Increase container memory:
    # In docker-compose.yml
    services:
      fossid-workbench:
        mem_reservation: 12g
        mem_limit: 16g
    
  2. Adjust Java heap settings in .env:
    # Reduce heap size if system has limited memory
    FOSSID_SHINOBI_JAVA_ARGS="-Xms4g -Xmx4g -XX:NewSize=2g -XX:MaxNewSize=2g -XX:SurvivorRatio=8"
    
  3. Check for memory leaks: Monitor memory over time with sudo docker stats

Health Check Failures

Symptom: Container shows as “unhealthy” in sudo docker ps

Diagnostic Steps:

# Check health check logs
sudo docker inspect fossid-workbench --format='{{range .State.Health.Log}}{{.Output}}{{end}}'

# Test health endpoint manually
sudo docker exec fossid-workbench curl -s localhost:80/health-check

# Check if web server is running
sudo docker exec fossid-workbench ps aux | grep -E 'nginx|php'

Common Causes and Solutions:

Cause Solution
Services still starting Wait for start_period to complete (default 30s)
Database connection failed Fix database connectivity (see above)
PHP-FPM not running Check logs for PHP errors
Port conflict Ensure port 80 is not in use inside container

Volume Mounting Issues

Symptom: Files not visible in container, permission denied errors

Diagnostic Steps:

# Verify mount points
sudo docker inspect fossid-workbench --format='{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'

# Check permissions inside container
sudo docker exec fossid-workbench ls -la /fossid/

# Check SELinux context (if applicable)
ls -laZ fossid.conf backup intake logs

Solutions:

  1. Fix ownership (on host):
    # Create directories with correct permissions
    mkdir -p backup intake logs uploads scan-path
    chmod 755 backup intake logs uploads scan-path
    
  2. SELinux issues (RHEL/CentOS):
    # Add :Z flag to volume mounts (already in examples)
    # Or disable SELinux enforcement temporarily for testing
    sudo setenforce 0
    
  3. Verify files exist before mounting:
    # Ensure fossid.conf exists
    test -f fossid.conf || echo "ERROR: fossid.conf not found"
    

Network Connectivity Issues

Symptom: Containers cannot communicate with each other

Diagnostic Steps:

# List networks
sudo docker network ls

# Inspect the network
sudo docker network inspect wb-network

# Check container network settings
sudo docker inspect fossid-workbench --format='{{.NetworkSettings.Networks}}'

Solutions:

  1. Ensure containers are on the same network:
    # Connect container to network manually if needed
    sudo docker network connect wb-network fossid-workbench
    
  2. Recreate the network:
    sudo docker compose down
    sudo docker network rm wb-network
    sudo docker compose up -d
    

SSH/Git Repository Issues

Symptom: Cannot clone repositories, “Permission denied (publickey)” errors

Diagnostic Steps:

# Check if SSH keys are mounted
sudo docker exec fossid-workbench ls -la /var/www/.ssh/

# Test SSH connection
sudo docker exec fossid-workbench sudo -u www-data ssh -T git@github.com

# Check known_hosts
sudo docker exec fossid-workbench cat /var/www/.ssh/known_hosts

Solutions:

See the SSH Client Configuration section for detailed setup instructions.

Certificate or HTTPS issues (custom CA or in-container Nginx):

  • Confirm /tmp/certs and /etc/nginx/nginx.conf are mounted as expected: docker inspect -f '{{ .Mounts }}' [CONTAINER_ID]
  • Confirm certificate files use .crt or .pem extensions where required for the startup behavior described in Custom CA certificates and HTTPS
  • Validate Nginx syntax: docker exec [CONTAINER_ID] nginx -t (if available in the image)
  • Review container logs: docker logs [CONTAINER_ID]

Debugging Commands Reference

# Container shell access
sudo docker exec -it fossid-workbench /bin/sh

# View real-time logs
sudo docker logs -f fossid-workbench

# Process list in container
sudo docker exec fossid-workbench ps aux

# Check disk usage
sudo docker exec fossid-workbench df -h

# Network information
sudo docker network inspect wb-network

# Full container inspection
sudo docker inspect fossid-workbench

Production Deployment

Security Best Practices

Image Security:

# Scan for vulnerabilities (example: Trivy — install from https://github.com/aquasecurity/trivy)
trivy image quay.io/fossid/workbench:latest

# Use specific tags instead of 'latest'
sudo docker pull quay.io/fossid/workbench@sha256:[DIGEST]

Use a scanner your organization approves (for example Trivy, Grype, or a registry-integrated tool). Always reference the full image name (quay.io/fossid/workbench:<tag>), not an unqualified short name.

For HTTPS, many environments terminate TLS on a reverse proxy in front of the Workbench container. Alternatively, you can serve HTTPS inside the container with a custom nginx.conf, the server certificate and private key bind-mounted from the host, optional custom CA trust for outbound connections, and port 443 mapping—see Custom CA certificates and HTTPS.

Reverse Proxy Setup (Nginx)

The example below configures an external Nginx that terminates TLS and forwards traffic to the application over HTTP. If you enable HTTPS inside the Workbench container instead, mount nginx.conf together with the SSL certificate and key files, and map port 443, as described in Custom CA certificates and HTTPS.

Example Nginx configuration:

server {
    listen 80;
    client_max_body_size 50M;
    location / {
        proxy_pass http://[APP_NAME]:[PORT];
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 10m;
        proxy_buffering off;
        proxy_request_buffering off;
        proxy_redirect http:// $scheme://;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

Configuration Reference

This section provides a copy-paste ready configuration files for FossID Workbench deployment. Customize the values according to your environment.

.env File

# =============================================================================
# FossID Workbench Environment Configuration
# =============================================================================

# -----------------------------------------------------------------------------
# Release Version
# -----------------------------------------------------------------------------
# Specify the FossID Workbench version to deploy
RELEASE=25.1.0

# -----------------------------------------------------------------------------
# Database Configuration
# -----------------------------------------------------------------------------
MYSQL_ROOT_PASSWORD=your_secure_root_password
MYSQL_USER=fossiduser
MYSQL_PASSWORD=your_secure_password
MYSQL_HOST=db
FOSSID_MYSQL_DATABASE=fossid_db

# -----------------------------------------------------------------------------
# Web Server Configuration
# -----------------------------------------------------------------------------
# HTTP port for accessing FossID Workbench
HTTP_PORT=8080

# Uncomment and set if using HTTPS
# HTTPS_PORT=8443

# -----------------------------------------------------------------------------
# FossID Initial Setup
# -----------------------------------------------------------------------------
# Initial password for the 'fossid' admin user (first-time setup only)
FOSSID_INITIAL_PASSWORD=your_initial_password

# -----------------------------------------------------------------------------
# Shinobi Engine Configuration
# -----------------------------------------------------------------------------
# Java heap settings for the scanning engine
# Adjust based on available memory (recommended: 50-75% of container memory)
FOSSID_SHINOBI_JAVA_ARGS="-Xms8g -Xmx8g -XX:NewSize=5g -XX:MaxNewSize=5g -XX:SurvivorRatio=8"

# Shinobi process settings
# -threads: Number of parallel scanning threads (adjust based on CPU cores)
# -timeout: Scan timeout in seconds
# -socket: Internal socket for process communication
FOSSID_SHINOBI_ARGS="-threads 8 -timeout 275 -socket 127.0.0.1:9900"

fossid.conf File

# =============================================================================
# FossID Workbench Configuration File
# =============================================================================
# Location: /fossid/etc/fossid.conf (inside container)
# Mount as: ./fossid.conf:/fossid/etc/fossid.conf:Z

[CLI]
# -----------------------------------------------------------------------------
# CLI Configuration
# -----------------------------------------------------------------------------
cli_server_host = fossid-scan-server
cli_token =
cli_strip_tags = .html

# Proxy settings for CLI (optional)
# cli_proxy_host = proxy.example.com
# cli_proxy_port = 8080
# cli_proxy_user =
# cli_proxy_pass =

[WebApp]
# -----------------------------------------------------------------------------
# Database Configuration
# -----------------------------------------------------------------------------
webapp_db_server = db
webapp_db_database = fossid_db
webapp_db_username = fossiduser
webapp_db_password = your_secure_password
webapp_db_port = 3306

# -----------------------------------------------------------------------------
# Server Configuration
# -----------------------------------------------------------------------------
webapp_server_name = fossid-workbench
webapp_timezone = Europe/Berlin
webapp_base_url = https://fossid.example.com/index.php

# -----------------------------------------------------------------------------
# Storage Paths
# -----------------------------------------------------------------------------
webapp_intake_repository = /fossid/intake/
webapp_backups = /fossid/backup/

# -----------------------------------------------------------------------------
# Email Configuration (optional)
# -----------------------------------------------------------------------------
# webapp_enable_email_sending = true
# webapp_mailer_transport = smtp
# webapp_mailer_host = smtp.example.com
# webapp_mailer_port = 587
# webapp_mailer_username =
# webapp_mailer_password =
# webapp_mailer_encryption = tls
# webapp_mailer_sender_address = fossid@example.com
# webapp_mailer_sender_display_name = FossID Workbench

# -----------------------------------------------------------------------------
# LDAP Configuration (optional)
# -----------------------------------------------------------------------------
# webapp_use_ldap_auth = true
# webapp_fallback_local_login = true
# webapp_ldap_connection = ldap://ldap.example.com
# webapp_ldap_port = 389
# webapp_ldap_dn = uid=%s,ou=users,dc=example,dc=com
# webapp_ldap_manager_dn = cn=admin,dc=example,dc=com
# webapp_ldap_manager_password =
# webapp_ldap_search_base = ou=users,dc=example,dc=com

# -----------------------------------------------------------------------------
# OAuth2 Configuration (optional)
# -----------------------------------------------------------------------------
# webapp_oauth2_login = true
# webapp_oauth2_provider = azure
# webapp_oauth2_client_id =
# webapp_oauth2_secret =
# webapp_oauth2_tenant =
# webapp_oauth2_redirect_uri = https://fossid.example.com/oauth2/callback
# webapp_oauth2_fallback_local_login = true

# -----------------------------------------------------------------------------
# JIRA Integration (optional)
# -----------------------------------------------------------------------------
# webapp_jira = true
# webapp_jira_proxy_host =
# webapp_jira_proxy_port =

docker-compose.yml File

# =============================================================================
# FossID Workbench Docker Compose Configuration
# =============================================================================
# Usage: sudo docker compose up -d

services:
  # ---------------------------------------------------------------------------
  # FossID Workbench Application
  # ---------------------------------------------------------------------------
  fossid-workbench:
    image: quay.io/fossid/workbench:${RELEASE}
    platform: linux/amd64
    container_name: fossid-workbench
    hostname: fossid-workbench
    restart: unless-stopped

    # Resource allocation
    mem_reservation: 9g
    # mem_limit: 16g  # Uncomment to set hard memory limit

    # Terminal allocation for proper signal handling
    tty: true

    # Port mapping
    ports:
      - "${HTTP_PORT:-8080}:80"
      # - "${HTTPS_PORT:-8443}:443"  # Uncomment for HTTPS

    # Environment configuration
    env_file:
      - .env

    # Service dependencies
    depends_on:
      fossid-mysql:
        condition: service_healthy

    # Health monitoring
    healthcheck:
      test: curl --silent --fail localhost:80/health-check
      interval: 5s
      timeout: 5s
      retries: 60
      start_period: 30s

    # Volume mounts
    volumes:
      # Configuration files
      - ./fossid.conf:/fossid/etc/fossid.conf:Z
      - ./version.lock:/fossid/version.lock:Z

      # Data directories
      - ./backup:/fossid/backup:Z
      - ./intake:/fossid/intake:Z
      - ./logs:/fossid/logs:Z
      - ./uploads:/fossid/uploads:Z
      - ./scan-path:/fossid/scan-path:Z

      # SSH keys for Git repository access (read-only)
      - ./ssh-keys:/tmp/ssh-keys:ro,Z

    # Network configuration
    networks:
      - wb-network

    # Required capabilities
    cap_add:
      - CAP_AUDIT_WRITE

  # ---------------------------------------------------------------------------
  # MySQL Database Server
  # ---------------------------------------------------------------------------
  fossid-mysql:
    image: docker.io/library/mysql:8.0
    platform: linux/amd64
    container_name: db
    hostname: db
    restart: unless-stopped

    # Environment configuration
    env_file:
      - .env

    # MySQL server configuration
    command:
      - --character-set-server=utf8mb4
      - --collation-server=utf8mb4_general_ci
      - --max-allowed-packet=64M

    # Health monitoring
    healthcheck:
      test: mysqladmin -u"$$MYSQL_USER" -p"$$MYSQL_PASSWORD" -h127.0.0.1 ping
      interval: 5s
      timeout: 5s
      retries: 60
      start_period: 30s

    # Volume mounts
    volumes:
      # Persistent database storage
      - ./db/db-persist:/var/lib/mysql

      # Custom MySQL configuration (optional)
      - ./mysql-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro

    # Network configuration
    networks:
      - wb-network

# =============================================================================
# Network Configuration
# =============================================================================
networks:
  wb-network:
    driver: bridge
    name: wb-network

mysql-custom.cnf File

# =============================================================================
# MySQL Custom Configuration for FossID Workbench
# =============================================================================
# Location: Mount as ./mysql-custom.cnf:/etc/mysql/conf.d/custom.cnf:ro

[mysqld]
# -----------------------------------------------------------------------------
# Character Set Configuration (required)
# -----------------------------------------------------------------------------
character-set-server = utf8mb4
collation-server = utf8mb4_general_ci

# -----------------------------------------------------------------------------
# Packet Size Configuration (required)
# -----------------------------------------------------------------------------
# Minimum 64M required for FossID Workbench
max_allowed_packet = 64M

# -----------------------------------------------------------------------------
# Performance Tuning (optional, adjust based on available resources)
# -----------------------------------------------------------------------------
# InnoDB buffer pool size (recommended: 50-70% of available RAM for DB)
# innodb_buffer_pool_size = 4G

# InnoDB log file size
# innodb_log_file_size = 256M

# Maximum connections
# max_connections = 200

# -----------------------------------------------------------------------------
# MySQL Replication (if applicable)
# -----------------------------------------------------------------------------
# Required for MySQL 8.0 replication compatibility
# default_collation_for_utf8mb4 = utf8mb4_general_ci

Additional Resources