Skip to content

OpenAPI servers URL uses http:// behind an HTTPS reverse proxy #8129

Description

@distinguished-penguin

Describe the bug
When Etherpad is deployed behind a TLS-terminating reverse proxy, the generated OpenAPI document at /api/openapi.json uses an http:// URL in servers[0].url, even though Etherpad is publicly accessible over HTTPS.

Deployment topology:

Client --HTTPS--> Traefik --HTTP--> Etherpad

Etherpad is configured with:

TRUST_PROXY=true
PUBLIC_URL=https://pad.example.com

The reverse proxy preserves the public host and sends the original protocol, including:

Host: pad.example.com
X-Forwarded-Proto: https

The generated OpenAPI JSON contains:

{
  "servers": [
    {
      "url": "http://pad.example.com/api/1.2.15"
    }
  ]
}

The expected output is:

{
  "servers": [
    {
      "url": "https://pad.example.com/api/1.2.15"
    }
  ]
}

This affects OpenAPI clients, code generators, Swagger UI instances, and other consumers that use servers[0].url as the API base URL.

To Reproduce
Steps to reproduce the behavior:

  1. Run Etherpad without enabling Etherpad's native SSL support.

  2. Place Traefik or another TLS-terminating reverse proxy in front of Etherpad.

  3. Expose Etherpad publicly at https://pad.example.com.

  4. Forward requests from the reverse proxy to Etherpad over HTTP.

  5. Configure Etherpad with:

    TRUST_PROXY=true
    PUBLIC_URL=https://pad.example.com
  6. Ensure the reverse proxy sends:

    Host: pad.example.com
    X-Forwarded-Proto: https
  7. Request the generated OpenAPI document:

    curl -fsS https://pad.example.com/api/openapi.json \
      | jq '.servers[0].url'
  8. Observe that the result starts with http://:

    "http://pad.example.com/api/1.2.15"
    

The same issue is also present in the version-specific OpenAPI endpoint:

/api/<version>/openapi.json

Expected behavior
The generated OpenAPI document should describe the externally reachable API URL.

When Etherpad trusts the reverse proxy and the original request protocol is HTTPS, servers[0].url should use HTTPS:

{
  "servers": [
    {
      "url": "https://pad.example.com/api/1.2.15"
    }
  ]
}

Direct HTTP installations should continue to generate http:// URLs, and installations where Etherpad itself terminates TLS should continue to generate https:// URLs.

Screenshots
Not applicable. The issue is visible directly in the generated JSON response.

Server (please complete the following information):

  • Etherpad version: 3.3.2
  • OS: RHEL 9
  • Node.js version (node --version): The one shipped with the docker image
  • npm version (npm --version): The one shipped with the docker image
  • Is the server free of plugins: yes
  • Are you using any abstraction IE docker? yes the default image is used (https://hub.docker.com/r/etherpad/etherpad)

Desktop (please complete the following information):

  • OS: Windows 11
  • Browser: Edege/Firefox
  • Version 151.0.4129.72/140.13.0esr

Smartphone (please complete the following information):

  • Device: Not applicable
  • OS: Not applicable
  • Browser: Not applicable
  • Version: Not applicable

Additional context
The OpenAPI server URL is currently generated in src/node/hooks/express/openapi.ts using logic equivalent to:

url: `${settings.ssl ? 'https' : 'http'}://${req.headers.host}${apiRoot}`,

settings.ssl indicates whether Etherpad itself terminates TLS. It does not describe the protocol used by the client before TLS is terminated by a reverse proxy.

In a typical reverse-proxy deployment:

Client --HTTPS--> Traefik --HTTP--> Etherpad

Etherpad's native SSL setting is disabled, so the generated URL uses http://, despite the original client request using HTTPS.

The OpenAPI URL generation currently appears not to use:

req.protocol

It also appears not to use the configured public URL when constructing servers[0].url.

I am not sure what the optimal fix is for this.
It might make sense to construct the the URL differently.
For example one could use the configured public URL for things like this.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions