> ## Documentation Index
> Fetch the complete documentation index at: https://docs.minimus.io/llms.txt
> Use this file to discover all available pages before exploring further.

# CouchDB TLS Tutorial

> How to deploy a CouchDB server and establish a secure TLS connection with self-signed, locally issued certificates

Set up CouchDB using self-signed, locally issued certificates and test that it accepts TLS connections, enforces authentication, and allows secure read/write operations from a test client.

<Info>
  For production purposes, we recommend using publicly trusted certificates issued by a Certificate Authority (CA).
</Info>

## Components

* **CouchDB image built by Minimus**: CouchDB listens only on HTTPS (5984); HTTP is disabled.
* Dynamic certificate generation via OpenSSL:
  * **certgen.sh script**: Shell script that generates a custom CA, server, and client certificates using OpenSSL.
  * **minidebug image**: A Minimus dev toolkit that provides a shell, OpenSSL, and other utilities used to generate the certificates.

The test does not persist any certificates on the host machine.

## What this guide demonstrates

* TLS handshake validation
* Server/client certificate trust
* Basic auth and CouchDB operations

## Directory structure

```text theme={null}
.
├── certgen.sh              # Script to generate CA, server, and client certs
├── create-certs.yml        # Compose file to generate certs in a dedicated container
├── couchdb-local.ini       # CouchDB configuration with SSL and authentication
└── docker-compose.yml      # Compose file for CouchDB and test client
```

## Deploy CouchDB with self-signed TLS certificates

### Prerequisite: Authenticate to the Minimus Registry

Run the docker login command to authenticate to the Minimus registry:

```shellscript theme={null}
echo "{token}" | docker login reg.mini.dev -u minimus --password-stdin
```

### Step 1: Generate TLS certificates

<Steps>
  <Step title="Save script that generates TLS certificates">
    Save the following script to a file named `certgen.sh`. The script is used to generate the TLS certificates and store them in a `certs` folder on the host.

    ```powershell certgen.sh expandable theme={null}
    #!/bin/sh
    # Company: Minimus

    set -e
    cd /certs

    echo "[INFO] Generating OpenSSL config..."
    cat > openssl.cnf <<EOF
    [req]
    distinguished_name = req_distinguished_name
    req_extensions = v3_req
    prompt = no

    [req_distinguished_name]
    CN = couchdb

    [v3_req]
    keyUsage = keyEncipherment, dataEncipherment
    extendedKeyUsage = serverAuth, clientAuth
    subjectAltName = @alt_names

    [alt_names]
    DNS.1 = couchdb
    DNS.2 = localhost
    IP.1 = 127.0.0.1
    IP.2 = 192.168.80.0
    IP.3 = 192.168.80.2
    IP.4 = 192.168.80.3


    [v3_ca]
    subjectKeyIdentifier = hash
    authorityKeyIdentifier = keyid:always,issuer
    basicConstraints = critical, CA:true
    keyUsage = critical, keyCertSign, cRLSign
    EOF

    echo "[INFO] Creating CA cert..."
    openssl genrsa -out ca-key.pem 2048
    openssl req -x509 -new -nodes -key ca-key.pem -sha256 -days 365 \
      -out ca.pem -subj "/CN=CouchDB Test CA" \
      -extensions v3_ca -config openssl.cnf

    echo "[INFO] Creating server cert..."
    openssl genrsa -out server-key.pem 2048
    openssl req -new -key server-key.pem -out server.csr \
      -config openssl.cnf -extensions v3_req
    openssl x509 -req -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial \
      -out server-cert.pem -days 365 -sha256 \
      -extfile openssl.cnf -extensions v3_req
    cat server-cert.pem ca.pem > server.pem

    echo "[INFO] Creating client cert..."
    openssl genrsa -out client-key.pem 2048
    openssl req -new -key client-key.pem -out client.csr -subj "/CN=couchdb-client"
    openssl x509 -req -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial \
      -out client-cert.pem -days 365 -sha256 \
      -extfile openssl.cnf -extensions v3_req
    cat client-cert.pem client-key.pem > client.pem
    cat server-cert.pem ca.pem > server.pem

    echo "[INFO] Setting file ownership and permissions..."
    chown 1000:1000 /certs/*.pem || echo "[WARN] chown failed"
    chmod 600 /certs/*-key.pem
    chmod 644 /certs/*.pem

    echo "[SUCCESS] Certificates successfully created for CouchDB."
    ```
  </Step>

  <Step title="Save Docker Compose configuration">
    Save the following YAML configuration to a file named `create-certs.yml`. The configuration uses the [Minimus minidebug image](https://images.minimus.io/gallery/images/minidebug/quick-start) to generate the certificates with the `certgen.sh` shell script. Minidebug is a secure Minimus dev toolkit that provides a shell, OpenSSL, and other utilities.

    The certificates will be persisted in the `certs` volume on the host.

    ```yaml create-certs.yml theme={null}
    services:
      certgen:
        image: reg.mini.dev/minidebug:latest
        container_name: certgen
        volumes:
        - ./certs:/certs
        - ./certgen.sh:/certgen.sh:ro
        entrypoint:
        - /bin/sh
        - /certgen.sh
        network_mode: none
    ```
  </Step>

  <Step title="Generate certificates">
    Run the following to generate the certificates:

    <CodeGroup>
      ```shellscript Run command theme={null}
      docker compose -f create-certs.yml up
      ```

      ```shellscript Expected output theme={null}
       ✔ Image reg.mini.dev/minidebug:latest Pulled                                                           10.2s
         ✔ *********                         Pull complete                                                     7.9s
       ✔ Container certgen                   Created                                                           0.9s
      Attaching to certgen
      certgen  | [INFO] Generating OpenSSL config...
      certgen  | [INFO] Creating CA cert...
      certgen  | [INFO] Creating server cert...
      certgen  | Certificate request self-signature ok
      certgen  | subject=CN=couchdb
      certgen  | [INFO] Creating client cert...
      certgen  | Certificate request self-signature ok
      certgen  | subject=CN=couchdb-client
      certgen  | [INFO] Setting file ownership and permissions...
      certgen  | [SUCCESS] Certificates successfully created for CouchDB.
      ```
    </CodeGroup>
  </Step>
</Steps>

Congrats! You have just generated the following self-signed certificates:

* CA certificate (`ca.pem`)
* Server certificates (`server-cert.pem`, `server-key.pem`)
* Client certificates (`client.pem`, `client-key.pem`)

In the next steps, you will mount these certificates into the CouchDB container and configure them via `local.ini`.

### Step 2: Deploy CouchDB server

<Steps>
  <Step title="Save couchdb-local.ini">
    Save the following configuration to a file named `couchdb-local.ini`:

    ```bash couchdb-local.ini expandable theme={null}
    [couchdb] 
    single_node = true

    [cluster]
    n = 1
    q = 8

    [chttpd_auth_lockout]
    mode = off

    [chttpd]
    ; Disable plain HTTP completely by setting an invalid port
    port = 0
    bind_address = 0.0.0.0
    require_valid_user = true

    [daemons]
    ; Enable only HTTPS daemon
    httpsd = {couch_httpd, start_link, ["https"]}
    ; Optionally comment out httpd if not used:
    ; httpd = {couch_httpd, start_link, ["http"]}

    [ssl]
    ; Now safe to bind to 5984 since HTTP is disabled
    port = 5984
    enable = true
    cert_file = /certs/server-cert.pem
    key_file = /certs/server-key.pem
    cacert_file = /certs/ca.pem
    verify_ssl_certificates = true
    verify_ssl_peer = true
    fail_if_no_peer_cert = false

    [admins]
    admin = admin

    [authentication]
    authentication_handlers = {chttpd_auth, proxy_authentication_handler}, {chttpd_auth, default_authentication_handler}

    # Use TLS 1.2+
    tls_versions = tlsv1.2,tlsv1.3
    ```
  </Step>

  <Step title="Save Docker Compose script">
    Save the following Docker Compose script to `docker-compose.yml`. This compose file sets up CouchDB using TLS (HTTPS only), with authentication enabled, mounts the generated certificates, uses the configurations in the local INI file, and exposes CouchDB over [https://localhost:15984](https://localhost:15984).

    ```yaml docker-compose.yml expandable theme={null}
    services:
      couchdb:
        image: reg.mini.dev/couchdb:latest-dev
        container_name: couchdb-1
        environment:
          - COUCHDB_USER=admin
          - COUCHDB_PASSWORD=admin
          - NODENAME=couchdb
          - COUCHDB_CLUSTER_SIZE=1
        volumes:
          - ./certs:/certs
          - ./data:/opt/couchdb/data
          - ./couchdb-local.ini:/opt/couchdb/etc/local.ini
        ports:
          - "15984:5984"
    ```

    If you don't yet have the folder `./data` ready and waiting, create it and give it permissions:

    ```powershell theme={null}
    mkdir data
    sudo chmod -R 777 ./data
    ```
  </Step>

  <Step title="Run CouchDB">
    Start the CouchDB container:

    ```shellscript theme={null}
    docker compose -f docker-compose.yml up --build -d
    ```
  </Step>
</Steps>

### Step 3: Test your CouchDB server

Connect to your database and test its connectivity. For example, here are a few commands you can try out:

1. Check server health:
   ```bash theme={null}
   curl --cacert certs/ca.pem -u admin:admin https://localhost:15984/_up
   ```
   You should get the response `{"seeds":{},"status":"ok"}`.
2. Create and delete a database (for example `testdb`):

   <CodeGroup>
     ```bash Create database theme={null}
     curl --cacert certs/ca.pem \
          -u admin:admin \
          -X PUT \
          https://localhost:15984/testdb
     ```

     ```bash Delete database theme={null}
     curl --cacert certs/ca.pem \
          -u admin:admin \
          -X DELETE \
          https://localhost:15984/testdb
     ```
   </CodeGroup>
3. List all databases:

   <CodeGroup>
     ```bash List databases theme={null}
     curl --cacert certs/ca.pem -u admin:admin https://localhost:15984/_all_dbs
     ```

     ```bash Example response theme={null}
     ["_replicator","_users","testdb"]
     ```
   </CodeGroup>

   You can also pass the request for a JSON format. This option requires the [jq JSON processor](https://jqlang.org/download/).

   <CodeGroup>
     ```With List databases in JSON format theme={null}
     curl --cacert certs/ca.pem -u admin:admin https://localhost:15984/_all_dbs | jq .
     ```

     ```json Example response theme={null}
       % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                      Dload  Upload   Total   Spent    Left  Speed
     100    34    0    34    0     0   1019      0 --:--:-- --:--:-- --:--:--  1030
     [
       "_replicator",
       "_users",
       "testdb"
     ]
     ```
   </CodeGroup>
4. Check if a database exists:

   <CodeGroup>
     ```bash Check for database theme={null}
     curl --cacert certs/ca.pem \
     -u admin:admin https://localhost:15984/testdb
     ```

     ```bash Example response theme={null}
     {
       "instance_start_time": "1765789065",
       "db_name": "testdb",
       "purge_seq": "0-g1AAAAFDeJzLYWBg4MhgTmHgT84vTc5ISXKA0jlACaY8FiDJ8ABI_QeCrEQGAioPQFTeJ6xyAUTlfsIqGyAq5-NTmZQAJJPqCbgxyQGkKp6QKgWQKnsCqhIZkuQhSrIA1tJnlg",
       "update_seq": "0-g1AAAAJDeJzLYWBg4MhgTmHgT84vTc5ISXKA0jlACaY8FiDJ8ABI_QeCrAzmRIZcoAC7pYWhmaWBBaYuAiYdgJh0H2FSspFxkkmKMckmLYCYtB9hUoqhWWKqmRHJJjVATJqPMCktzcQy1dSUBJOSEoBkUj1KGJkbmVsYWCSRYooDyJR4FFNSLRNNkkxIcosCyBR7FFNSEg1TDC1MSDAlkSFJHsUIs2SL5DQLM0zlWQBKqLC0",
       "sizes": { "file": 66784, "external": 0, "active": 0 },
       "props": {},
       "doc_del_count": 0,
       "doc_count": 0,
       "disk_format_version": 8,
       "compact_running": false,
       "cluster": { "q": 8, "n": 1, "w": 1, "r": 1 }
     }
     ```
   </CodeGroup>
5. Create document:
   ```bash theme={null}
   curl --cacert certs/ca.pem \
        -u admin:admin \
        -X PUT \
        -H "Content-Type: application/json" \
        -d '{
          "test": "Welcome to TLS couchdb running Minimus image",
          "timestamp": "'$(date -u +"%Y-%m-%dT%H:%M:%SZ")'"
        }' \
        https://localhost:15984/testdb/doc1
   ```
