How to Configure SSL Termination for a Collabora CODE Container

SSL termination is a strong fit for a Collabora Online Development Edition (CODE) container when you want one public HTTPS endpoint while keeping certificate management at a reverse proxy such as Nginx. In this design, the browser connects to Nginx over HTTPS, Nginx decrypts the traffic, and Collabora receives plain HTTP on its internal port. The quality target is not merely “the page loads.” A successful deployment should have a valid public certificate, a reachable WOPI discovery endpoint, working WebSocket upgrades, and a real document-editing session that stays connected.

Collabora’s own proxy documentation describes this SSL-offload pattern as an HTTP-only connection between the proxy and Collabora, with ssl.enable=false and ssl.termination=true on the Collabora side. See the Collabora Online reverse proxy settings. The examples below use Nginx and Docker Compose, but the same outcome can be achieved with other reverse proxies if they preserve the required host and WebSocket behavior.

What a Good SSL-Termination Setup Should Achieve

CheckExpected resultIf it fails
Public TLShttps://office.example.com presents a trusted certificateFix DNS, certificate, or Nginx listener first
Discovery/hosting/discovery returns XML through HTTPSCheck proxy routing and upstream reachability
WebSocketDocument session upgrades successfully and remains connectedCheck Upgrade, Connection, and timeout settings
Internal exposurePort 9980 is reachable only where the proxy needs itBind to localhost or a private Docker network
End-to-end editingA document opens, edits, and saves without connection errorsInspect WOPI host allowlisting and proxy logs
Diagram showing a browser connecting to Nginx over HTTPS on port 443, while Nginx forwards plain HTTP to a Collabora CODE container on port 9980
SSL termination separates the public HTTPS connection from the private HTTP connection to Collabora CODE on port 9980.

Step 1: Confirm the Network Boundary Before Changing Collabora

Decide where TLS ends and which hosts can reach port 9980. If Nginx runs on the same machine as Docker, binding the published port to 127.0.0.1 is a simple way to prevent direct Internet access. Docker documents that publishing a port to 127.0.0.1 keeps it local to the host; see Docker’s port-publishing documentation.

If Nginx runs in another container, a shared private Docker network is usually cleaner than publishing 9980 publicly. The principle is the same: clients should use the HTTPS reverse-proxy hostname, not the Collabora container directly.

Step 2: Run CODE in SSL-Termination Mode

For proxy-side TLS termination, Collabora should know that the original client-facing scheme is HTTPS even though its immediate upstream connection is HTTP. The documented settings are:

--o:ssl.enable=false --o:ssl.termination=true

A minimal Compose example looks like this:

services:
  collabora:
    image: collabora/code:YOUR_TESTED_TAG
    restart: unless-stopped
    ports:
      - "127.0.0.1:9980:9980"
    environment:
      - "extra_params=--o:ssl.enable=false --o:ssl.termination=true"
      - "server_name=office.example.com"

Replace YOUR_TESTED_TAG with a version you have validated rather than automatically assuming that latest is safe for a production-like deployment. Also configure the appropriate WOPI host or alias settings for your integration; those values depend on whether you are connecting Nextcloud, ownCloud, another WOPI host, or a custom integration.

Code editor showing a Docker Compose service for collabora/code with port 9980 bound to localhost and SSL termination parameters enabled
A Compose configuration can keep port 9980 local while passing ssl.enable=false and ssl.termination=true to CODE.

After starting the container, confirm that it is running and that the port mapping matches your intended boundary:

docker compose up -d
docker compose ps
docker logs --tail=100 collabora
Terminal window showing a Collabora CODE Docker container started with port 9980 published only on 127.0.0.1 and then listed with docker ps
Binding CODE to 127.0.0.1:9980 is appropriate when Nginx runs on the same host and is the only service that needs direct access.

Version note for 26.04 deployments

Do not treat the two SSL flags as the only variable when troubleshooting a current 26.04 image. In mid-2026, Collabora tracked regressions around the distroless Docker image and SSL-disabled configurations. An official GitHub issue documents a 26.04 startup regression, and Collabora community follow-up reported the affected SSL-termination behavior working again in a later 26.04.2.4.1 image. Review CollaboraOnline/online issue #16019 if a previously working termination configuration breaks immediately after an image upgrade.

This is also a reason to pin and test your image version. A configuration error and a container-image regression can look similar from Nginx: both may surface as a 502 response or a failed upstream connection.

Step 3: Configure Nginx to Terminate TLS and Proxy Collabora Paths

Nginx needs a valid certificate for the Collabora hostname and must forward Collabora’s HTTP endpoints plus WebSocket traffic. Collabora’s proxy guide shows dedicated locations for browser assets, discovery, capabilities, main WebSocket connections, download/upload paths, and the admin WebSocket. The following configuration follows that structure while adding common forwarded headers:

server {
    listen 443 ssl;
    server_name office.example.com;

    ssl_certificate     /etc/letsencrypt/live/office.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/office.example.com/privkey.pem;

    location ^~ /browser {
        proxy_pass http://127.0.0.1:9980;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location ^~ /hosting/discovery {
        proxy_pass http://127.0.0.1:9980;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }

    location ^~ /hosting/capabilities {
        proxy_pass http://127.0.0.1:9980;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }

    location ~ ^/cool/(.*)/ws$ {
        proxy_pass http://127.0.0.1:9980;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_read_timeout 36000s;
    }

    location ~ ^/(c|l)ool {
        proxy_pass http://127.0.0.1:9980;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
    }

    location ^~ /cool/adminws {
        proxy_pass http://127.0.0.1:9980;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto https;
        proxy_read_timeout 36000s;
    }
}

The WebSocket headers are not cosmetic. Nginx’s official documentation explains that Upgrade and Connection are hop-by-hop headers and must be passed explicitly for reverse-proxied WebSockets. See Nginx WebSocket proxying. The standard proxy module documentation also covers proxy_set_header, proxy_pass, and proxy_read_timeout: ngx_http_proxy_module.

Code editor showing an Nginx HTTPS server block that proxies to Collabora CODE on 127.0.0.1 port 9980 and forwards WebSocket upgrade headers for the cool path
The reverse proxy terminates TLS at port 443, forwards requests to CODE over HTTP, and preserves WebSocket upgrade headers for live editing.

Step 4: Validate Nginx Before Reloading

Test the Nginx configuration before replacing a known-good running configuration:

sudo nginx -t

Only reload if the syntax test succeeds:

sudo systemctl reload nginx

Then confirm that Nginx itself can reach the local Collabora backend. On a same-host setup, a useful check is:

curl -I http://127.0.0.1:9980/hosting/discovery

The exact response headers can vary by Collabora release, but the key result is that the TCP connection succeeds and the endpoint responds rather than timing out or refusing the connection. If this local request fails, changing public TLS settings will not fix the underlying container or network problem.

Step 5: Verify the Public HTTPS Endpoint

From a client that resolves the public hostname, request the discovery endpoint through Nginx:

curl -I https://office.example.com/hosting/discovery

A browser request to https://office.example.com/hosting/discovery should return XML. This is a better functional check than relying on the root URL because root-page behavior is not the main WOPI contract and can differ by version.

Also inspect the certificate chain with your browser or a TLS diagnostic tool. The hostname should match the certificate, the chain should be trusted, and there should be no mixed-content warnings caused by Collabora advertising plain HTTP URLs to the browser.

Step 6: Test a Real Document and the WebSocket

Discovery success is necessary but not sufficient. Open a document from your actual WOPI host and keep it open long enough to exercise the live session. In browser developer tools, the Collabora WebSocket request should upgrade successfully rather than repeatedly reconnecting or returning a 400/502 error. A healthy session should allow you to type, save, and reopen the document.

If the editor shell loads but the document fails shortly afterward, prioritize the WebSocket path, proxy timeout, WOPI allowlist, and host-header behavior. If Nginx logs show an upstream connection error before any WebSocket is established, inspect CODE’s listener and image version first.

How to Diagnose Common Failure Modes

502 Bad Gateway

A 502 usually means Nginx could not get a valid response from the configured upstream. Check whether CODE is actually listening on 9980 and whether you are using the correct upstream protocol. In the intended SSL-termination design, the proxy-to-CODE hop is HTTP. If an image regression causes CODE to keep serving HTTPS internally despite your flags, logs and a direct curl test will reveal the mismatch. Do not permanently switch to an HTTPS upstream merely to hide an unexplained configuration regression; first verify the behavior of the exact CODE image you are running.

Discovery works but documents do not open

This often points to WebSocket forwarding or WOPI authorization rather than TLS itself. Verify the /cool/.../ws route, the upgrade headers, and the host you allowed as a WOPI source. Collabora can be perfectly reachable over HTTPS while still rejecting or failing an editing session.

Mixed-content or incorrect scheme URLs

If a browser sees an HTTPS page that references HTTP resources, verify ssl.termination=true, your forwarded scheme header, and the server name. The public side of the deployment must consistently identify itself as HTTPS even though the private hop is HTTP.

Container reports unhealthy even though editing works

Recent 26.04 releases introduced health-check behavior that has changed during the distroless-image transition. Collabora tracked a case where the probe did not respect an HTTP backend configuration behind TLS termination. If functional tests pass but Docker health is unexpectedly red, check the release-specific issue history before redesigning a working proxy. See CollaboraOnline/online issue #16032.

When to Use a Different Design

Proxy-side SSL termination is appropriate when the reverse proxy and Collabora communicate over a trusted local interface or isolated private network. If traffic between Nginx and CODE crosses an untrusted network, plain HTTP on the internal hop may not meet your security requirements. In that case, use TLS to the backend as well, or place both services on a protected network where interception is not a realistic threat.

Likewise, if you already operate a platform-managed ingress that handles certificates, routing, and WebSockets correctly, there is little benefit in adding a second Nginx layer only for Collabora. The correct architecture is the one that gives you a single, observable TLS boundary without unnecessary hops.

Final Validation Checklist

  • The Collabora hostname resolves to the reverse proxy.
  • Port 443 presents a trusted certificate for that hostname.
  • CODE is not unnecessarily exposed to the public Internet on port 9980.
  • ssl.enable=false and ssl.termination=true are applied for the HTTP backend design.
  • Nginx can reach CODE on its private address.
  • /hosting/discovery responds through the public HTTPS URL.
  • The /cool/.../ws WebSocket upgrades successfully.
  • A real document opens, edits, saves, and reopens.
  • You have pinned and tested the exact CODE image version you plan to deploy.

If all of those checks pass, SSL termination is doing its job: external traffic is protected by HTTPS, Collabora understands the public connection as secure, and the editing path remains functional. If one check fails, troubleshoot at that layer instead of changing several parts of the stack at once.

Leave a Comment

How to Create and Send a Meeting Invite in Outlook

How to Create and Send a Meeting Invite in Outlook

Create an Outlook meeting invite, add required or optional attendees, choose a time, add Teams details, set recurrence, and check replies in new or classic Outlook.

How to Add a Character Limit to Cells in Excel

How to Add a Character Limit to Cells in Excel

Use Excel's Data Validation settings to set a maximum, minimum, exact length, or character range, then add clear prompts and error alerts.

How to Fix the “We Can’t Schedule the Meeting” Error in Outlook

How to Fix the “We Can’t Schedule the Meeting” Error in Outlook

Fix the Outlook “We can’t schedule the meeting” error by checking account support, refreshing Teams sign-in, and repairing the Classic Outlook add-in.

How to Change the Language in Office 365 (Microsoft 365)

How to Change the Language in Office 365 (Microsoft 365)

Change Office 365 menus, spelling and grammar settings, or keyboard input in desktop apps and Microsoft 365 for the web.

How to Auto-Forward Emails in Outlook 365

How to Auto-Forward Emails in Outlook 365

Learn how to auto-forward all or selected emails in Outlook 365 using Forwarding settings or Rules, plus how to stop forwarding and fix blocked external forwards.

How to Use Microsoft Editor in Word for Microsoft 365

How to Use Microsoft Editor in Word for Microsoft 365

Use Microsoft Editor in Word for Microsoft 365 to check spelling, grammar, clarity, and conciseness, review suggestions, and tune proofing settings.

How to Add an RSS Feed to Outlook 365 in Classic Outlook

How to Add an RSS Feed to Outlook 365 in Classic Outlook

Learn how to add an RSS feed to Outlook 365 in classic Outlook for Windows, find the correct feed URL, manage subscriptions, and fix common RSS issues.

How to Go to a Page in Word for Microsoft 365

How to Go to a Page in Word for Microsoft 365

Jump straight to any page in Word for Microsoft 365 with Ctrl+G or F5, relative page numbers, or the Navigation pane, with Windows and Mac shortcuts.

How to Add Contacts to Outlook on Web, Windows, and Mobile

How to Add Contacts to Outlook on Web, Windows, and Mobile

Learn how to add contacts to Outlook on the web, new Outlook, classic Outlook, and mobile, plus how contact syncing and CSV imports work.

How to Change the Microsoft Word Background Color or Add an Image

How to Change the Microsoft Word Background Color or Add an Image

Change a Word page color, add a picture background, remove either, and enable background printing on Windows or Mac with clear, current steps.