diff --git a/docs/installation/advanced/custom-certificates.md b/docs/installation/advanced/custom-certificates.md index 18f0ed20..5e7eda99 100644 --- a/docs/installation/advanced/custom-certificates.md +++ b/docs/installation/advanced/custom-certificates.md @@ -8,10 +8,11 @@ By default, Seatable uses Let's Encrypt to generate valid certificates for publi !!! warning "Limitations of Self-Signed Certificates" - Self-signed certificates should only be used for testing purposes. Even if your clients or browsers trust the certificate, Docker containers do not trust each other by default. - As a result, the Python Runner will be unable to communicate with your Base data, and the Python Pipeline will not work with an **untrusted** self-signed certificate. + Self-signed certificates should only be used for testing purposes. Even if your clients or browsers trust the certificate, Docker containers do not trust each other by default. - To avoid these issues, use a valid (standard or wildcard) certificate issued by a recognized certificate authority. + For SeaTable Server and the Python Pipeline (scheduler and starter), the trust can be established by adding the certificate to their truststore (see below). The `python-runner` is started on demand by the `python-starter` and requires a separate setup (see [Custom CA for the python-runner](#custom-ca-for-the-python-runner)). + + To avoid these issues entirely, use a valid (standard or wildcard) certificate issued by a recognized certificate authority. ## Make certificates available to caddy @@ -83,6 +84,43 @@ You can mount multiple certificates by adding additional volume mounts. Every `. Make sure that `REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt` is set in your environment variables. This tells all Python libraries (requests, pysaml2, etc.) to use the system trust store instead of their own bundled certificates. This variable is included by default since version 5.0 in the [seatable-server.yml](https://github.com/seatable/seatable-release/blob/main/compose/seatable-server.yml). +## Custom CA for the python-runner + +The truststore setup described above covers the long-running `python-scheduler` and `python-starter` containers, but **not** the `python-runner`. The runner is an ephemeral container that the starter launches via `docker run` for every script execution. It is based on Alpine, runs as a non-root user, never executes `update-ca-certificates`, and has no certificate mounted into it. As a result, scripts that call `base.auth()` (or any other HTTPS endpoint with your custom CA) will fail with an SSL error — even though `print("hello world")` works fine. + +To fix this, you need to do two things at the same time, both via [`PYTHON_RUNNER_OTHER_OPTIONS`](python-pipeline-configuration.md#mounting-additional-directories): + +1. Mount the trusted CA bundle from the host into the runner. +2. Set `REQUESTS_CA_BUNDLE` inside the runner so that Python's `requests` library uses it (without this, `requests` falls back to the `certifi` bundle and ignores `/etc/ssl/certs/`). + +### Build a merged CA bundle on the host + +If you only mount your own certificate, the runner will no longer trust any public CAs, which can break scripts that call third-party APIs. The cleanest solution is to merge the host's public CA bundle with your custom certificate: + +```bash +cat /etc/ssl/certs/ca-certificates.crt /opt/caddy/certs/cert.pem \ + > /opt/seatable-compose/runner-ca-bundle.crt +``` + +The bundle is placed next to your compose files and `.env` so that it is co-located with the configuration that references it. Repeat this step whenever your custom certificate is renewed. + +### Configure the python-starter + +Add the following to your `custom-python-pipeline.yml` (create it if it does not exist) and reference the file in the `COMPOSE_FILE` variable of your `.env`: + +```yaml +services: + python-starter: + environment: + - PYTHON_RUNNER_OTHER_OPTIONS=["--volume=/opt/seatable-compose/runner-ca-bundle.crt:/etc/ssl/certs/runner-ca-bundle.crt:ro","--env=REQUESTS_CA_BUNDLE=/etc/ssl/certs/runner-ca-bundle.crt"] +``` + +!!! info "Syntax of PYTHON_RUNNER_OTHER_OPTIONS" + + The value must be a valid Python list literal (parsed via `ast.literal_eval`). Each item is appended verbatim to the `docker run` command, so environment variables must use the `--env=KEY=VALUE` form — a bare `KEY=VALUE` would be interpreted as a positional argument and break the container start. Do not wrap the list in additional quotes. + +Restart the `python-starter` with `docker compose up -d` afterwards. To verify, set `PYTHON_STARTER_LOG_LEVEL=DEBUG` and check `docker compose logs -f python-starter` — the full `docker run` command should now include both the volume mount and the `REQUESTS_CA_BUNDLE` environment variable. + ## Self-signed certificates generated by Caddy Even if it is not recommended, it is possible to ask Caddy to use auto generated self-signed certificates.