From d7dd50231db93987c0d6a2aaa5d5f913be25c0cd Mon Sep 17 00:00:00 2001 From: zerox80 Date: Fri, 10 Apr 2026 09:52:00 +0200 Subject: [PATCH 1/5] docs: add documentation for running OpenCloud behind an external Nginx proxy and configure Euro Office category --- .../configuration/euro-office/_category_.json | 4 + docs/admin/configuration/euro-office/index.md | 103 +++++++++++ .../docker-compose/docker-external-proxy.md | 164 +++++++++++++++++- 3 files changed, 263 insertions(+), 8 deletions(-) create mode 100644 docs/admin/configuration/euro-office/_category_.json create mode 100644 docs/admin/configuration/euro-office/index.md diff --git a/docs/admin/configuration/euro-office/_category_.json b/docs/admin/configuration/euro-office/_category_.json new file mode 100644 index 00000000..fd7b5664 --- /dev/null +++ b/docs/admin/configuration/euro-office/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Euro Office", + "position": 31 +} diff --git a/docs/admin/configuration/euro-office/index.md b/docs/admin/configuration/euro-office/index.md new file mode 100644 index 00000000..066921c9 --- /dev/null +++ b/docs/admin/configuration/euro-office/index.md @@ -0,0 +1,103 @@ +--- +sidebar_position: 1 +id: euro-office +title: Euro Office +description: Configuration guides for Euro Office integration in OpenCloud +draft: false +--- + +# Euro Office + +[Euro Office](https://github.com/EURO-office/DocumentServer) is a sovereign document editing suite based on ONLYOFFICE that integrates with OpenCloud via the WOPI protocol. + +:::warning +The Euro Office project is currently in its early stages and may have stability issues. +::: + +## What you will find here + +- Set up Euro Office with OpenCloud using Docker Compose. +- Configure Euro Office behind an external Nginx reverse proxy. + +## Docker Compose Setup + +Euro Office is available as a compose module in the [opencloud-compose](https://github.com/opencloud-eu/opencloud-compose) project. + +### With Traefik (built-in reverse proxy) + +Set the following in your `.env` file: + +```env +COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/euroffice.yml + +EURO_OFFICE_DOMAIN=euro-office.YOUR.DOMAIN +EURO_OFFICE_WOPISERVER_DOMAIN=wopiserver-eo.YOUR.DOMAIN +EURO_OFFICE_JWT_SECRET=YOUR.SECRET +``` + +### With an external proxy (Nginx, Caddy, etc.) + +Set the following in your `.env` file: + +```env +COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/euroffice.yml + +EURO_OFFICE_DOMAIN=euro-office.YOUR.DOMAIN +EURO_OFFICE_WOPISERVER_DOMAIN=wopiserver-eo.YOUR.DOMAIN +EURO_OFFICE_JWT_SECRET=YOUR.SECRET +``` + +For the full Nginx configuration guide, see [Behind External Proxy](../../getting-started/container/docker-compose/external-proxy). + +### Using both Collabora and Euro Office + +Both office suites can run simultaneously. In this case, OpenDocument formats (`.odt`, `.ods`, `.odp`) open in Collabora while Microsoft Office formats (`.docx`, `.xlsx`, `.pptx`) open in Euro Office. + +:::info +To avoid app interlocking issues, be aware that there is currently no cross-app file locking. If a file is opened in one app, the other app must wait for the lock to be released. +::: + +With Traefik: + +```env +COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/collabora.yml:traefik/euroffice.yml +``` + +With external proxy: + +```env +COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/collabora.yml:external-proxy/euroffice.yml +``` + +## Environment Variables + +| Variable | Default | Description | +|---|---|---| +| `EURO_OFFICE_DOMAIN` | `euro-office.opencloud.test` | Domain of the Euro Office document server | +| `EURO_OFFICE_WOPISERVER_DOMAIN` | `wopiserver-eo.opencloud.test` | Domain of the WOPI server for Euro Office | +| `EURO_OFFICE_JWT_SECRET` | `changeme` | JWT secret for Euro Office. **Change this for production!** | +| `EURO_OFFICE_DOCKER_IMAGE` | `ghcr.io/euro-office/documentserver` | Docker image for the document server | +| `EURO_OFFICE_DOCKER_TAG` | `latest` | Docker image tag | + +## Exposed Ports (External Proxy) + +When using an external reverse proxy, the following ports are exposed on the host: + +| Service | Host Port | Description | +|---|---|---| +| Euro Office Document Server | `9900` | The document editing interface | +| Euro Office WOPI Server | `9302` | WOPI protocol endpoint (collaboration service) | + +## DNS Entries + +When deploying with custom domains, make sure DNS records point to your server for: + +- `euro-office.YOUR.DOMAIN` +- `wopiserver-eo.YOUR.DOMAIN` + +For local testing with `.test` domains, add to `/etc/hosts`: + +```text +127.0.0.1 euro-office.opencloud.test +127.0.0.1 wopiserver-eo.opencloud.test +``` diff --git a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md index 54783ad9..33908b4e 100644 --- a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md +++ b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md @@ -15,13 +15,19 @@ This guide walks you through setting up OpenCloud behind an external Nginx rever - A public server with a static IP - Proper DNS records for your domain: - `cloud.YOUR.DOMAIN` - - `collabora.YOUR.DOMAIN` - - `wopiserver.YOUR.DOMAIN` + - `collabora.YOUR.DOMAIN` (if using Collabora) + - `wopiserver.YOUR.DOMAIN` (if using Collabora) + - `euro-office.YOUR.DOMAIN` (if using Euro Office) + - `wopiserver-eo.YOUR.DOMAIN` (if using Euro Office) - Installed software: - [Docker & Docker Compose](https://docs.docker.com/engine/install/) - `nginx` - `certbot` +:::tip Office Suite Choice +OpenCloud supports [Collabora](../../../configuration/collabora) and [Euro Office](../../../configuration/euro-office) as web office editors. You can use one or both. Adjust the DNS entries, certificates, and Nginx configuration below based on your choice. +::: + ## Connect to Your Server Log into your server via SSH: @@ -67,9 +73,10 @@ Create a temporary config to allow HTTP validation: sudo nano /etc/nginx/sites-available/certbot-challenge ``` -Paste the following config and adjust the URLs: +Paste the following config and adjust the URLs. Include the domains for the office suite(s) you are using: ```nginx +# Collabora only: server { listen 80; server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; @@ -83,6 +90,24 @@ server { } ``` +If using Euro Office (alone or alongside Collabora), add the Euro Office domains to `server_name`: + +```nginx +# Euro Office only: +server { + listen 80; + server_name cloud.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver-eo.YOUR.DOMAIN; + # ...same location block as above... +} + +# Both Collabora and Euro Office: +server { + listen 80; + server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver-eo.YOUR.DOMAIN; + # ...same location block as above... +} +``` + Enable and reload Nginx: ```bash @@ -92,14 +117,41 @@ sudo nginx -t && sudo systemctl reload nginx ## Obtain SSL Certificates -Use `certbot` to get your TLS certificates with adjusted URLs: +Use `certbot` to get your TLS certificates with adjusted URLs. Include all domains you need: + +```bash +# Collabora only: +sudo certbot certonly --webroot \ + -w /var/www/certbot \ + -d cloud.YOUR.DOMAIN \ + -d collabora.YOUR.DOMAIN \ + -d wopiserver.YOUR.DOMAIN \ + --email your@email.com \ + --agree-tos \ + --no-eff-email +``` + +If using Euro Office, add the Euro Office domains: ```bash +# Euro Office only: +sudo certbot certonly --webroot \ + -w /var/www/certbot \ + -d cloud.YOUR.DOMAIN \ + -d euro-office.YOUR.DOMAIN \ + -d wopiserver-eo.YOUR.DOMAIN \ + --email your@email.com \ + --agree-tos \ + --no-eff-email + +# Both Collabora and Euro Office: sudo certbot certonly --webroot \ -w /var/www/certbot \ -d cloud.YOUR.DOMAIN \ -d collabora.YOUR.DOMAIN \ -d wopiserver.YOUR.DOMAIN \ + -d euro-office.YOUR.DOMAIN \ + -d wopiserver-eo.YOUR.DOMAIN \ --email your@email.com \ --agree-tos \ --no-eff-email @@ -121,7 +173,9 @@ cp .env.example .env nano .env ``` -Set the following environment variables: +Set the following environment variables based on your office suite choice: + +**Collabora only:** ```env # INSECURE=true @@ -137,6 +191,43 @@ COLLABORA_DOMAIN=collabora.YOUR.DOMAIN WOPISERVER_DOMAIN=wopiserver.YOUR.DOMAIN ``` +**Euro Office only:** + +```env +# INSECURE=true + +COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/euroffice.yml + +OC_DOMAIN=cloud.YOUR.DOMAIN + +INITIAL_ADMIN_PASSWORD=YOUR.SECRET.PASSWORD + +EURO_OFFICE_DOMAIN=euro-office.YOUR.DOMAIN + +EURO_OFFICE_WOPISERVER_DOMAIN=wopiserver-eo.YOUR.DOMAIN + +EURO_OFFICE_JWT_SECRET=YOUR.EURO.OFFICE.SECRET +``` + +**Both Collabora and Euro Office:** + +```env +# INSECURE=true + +COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/collabora.yml:external-proxy/euroffice.yml + +OC_DOMAIN=cloud.YOUR.DOMAIN + +INITIAL_ADMIN_PASSWORD=YOUR.SECRET.PASSWORD + +COLLABORA_DOMAIN=collabora.YOUR.DOMAIN +WOPISERVER_DOMAIN=wopiserver.YOUR.DOMAIN + +EURO_OFFICE_DOMAIN=euro-office.YOUR.DOMAIN +EURO_OFFICE_WOPISERVER_DOMAIN=wopiserver-eo.YOUR.DOMAIN +EURO_OFFICE_JWT_SECRET=YOUR.EURO.OFFICE.SECRET +``` + The initial Admin password is mandatory for security reasons. For production releases, please refer to the considerations outlined in the Docker Compose base instructions: @@ -163,13 +254,16 @@ sudo rm /etc/nginx/sites-enabled/certbot-challenge sudo nano /etc/nginx/sites-available/opencloud ``` -Paste the following configuration and adjust the URLs: +Paste the following configuration and adjust the URLs. Include only the server blocks you need based on your office suite choice. + +### Core blocks (always required) ```nginx # Redirect HTTP to HTTPS +# Add all domains you use to server_name server { listen 80; - server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; + server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver-eo.YOUR.DOMAIN; location /.well-known/acme-challenge/ { root /var/www/certbot; @@ -213,7 +307,11 @@ server { proxy_set_header X-Forwarded-Proto $scheme; } } +``` +### Collabora blocks (if using Collabora) + +```nginx # Collabora server { listen 443 ssl http2; @@ -239,7 +337,7 @@ server { } -# WOPI Server +# Collabora WOPI Server server { listen 443 ssl http2; server_name wopiserver.YOUR.DOMAIN; @@ -258,6 +356,56 @@ server { } ``` +### Euro Office blocks (if using Euro Office) + +```nginx +# Euro Office Document Server +server { + listen 443 ssl http2; + server_name euro-office.YOUR.DOMAIN; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + client_max_body_size 100M; + + location / { + proxy_pass http://127.0.0.1:9900; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + # Required for WebSocket support + proxy_set_header X-Forwarded-Proto https; + } + + location ~ ^/(web-apps/apps/.*/(main|mobile|embed)/.*\.json|doc/.*/(c|s)/.*) { + proxy_pass http://127.0.0.1:9900; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + } +} + +# Euro Office WOPI Server +server { + listen 443 ssl http2; + server_name wopiserver-eo.YOUR.DOMAIN; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + location / { + proxy_pass http://127.0.0.1:9302; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + :::info Version Differences Starting from nginx 1.25.0, the `http2` directive syntax changed from: `listen 443 ssl http2;` to `listen 443 ssl; http2 on;` ::: From 795237ae8c5bfece258929361cd916445503c6d3 Mon Sep 17 00:00:00 2001 From: zerox80 Date: Fri, 10 Apr 2026 10:26:16 +0200 Subject: [PATCH 2/5] docs: add guide for running OpenCloud behind an external Nginx proxy with Certbot --- .../docker-compose/docker-external-proxy.md | 255 ++++++++++++++++++ 1 file changed, 255 insertions(+) diff --git a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md index 33908b4e..d3940458 100644 --- a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md +++ b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md @@ -430,3 +430,258 @@ sudo certbot renew --dry-run ``` Your OpenCloud instance is now running securely behind a fully configured external Nginx reverse proxy with HTTPS. + +## Optional: HTTP/3 (QUIC) Support + +:::warning Advanced Setup +HTTP/3 over QUIC requires an nginx build with QUIC support. The stock nginx package on most distributions does **not** include QUIC. At the time of writing, Ubuntu 26.04+ ships an nginx version with QUIC enabled out of the box. On older distributions you need to build nginx from source with `--with-http_v3_module` or use the [official nginx QUIC packages](https://nginx.org/en/docs/quic.html). + +Verify that your nginx supports QUIC before proceeding: + +```bash +nginx -V 2>&1 | grep -o -- '--with-http_v3_module' +``` + +If this returns nothing, your nginx does not support QUIC. +::: + +HTTP/3 uses QUIC (UDP) alongside the traditional TCP connections for HTTP/1.1 and HTTP/2. This can improve performance for high-latency connections and reduce head-of-line blocking. + +The following configuration replaces the HTTP/2 configuration above. It uses `upstream` blocks with keepalive connections and a `map` directive for cleaner WebSocket handling. + +### Full configuration with HTTP/3 + +```nginx +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +upstream opencloud_backend { server 127.0.0.1:9200; keepalive 32; } +upstream wopi_backend { server 127.0.0.1:9300; keepalive 16; } +upstream collabora_backend { server 127.0.0.1:9980; keepalive 16; } +# Add these if using Euro Office: +# upstream euroffice_backend { server 127.0.0.1:9900; keepalive 16; } +# upstream wopi_eo_backend { server 127.0.0.1:9302; keepalive 16; } + +# ── HTTP → HTTPS redirect ────────────────────────────────── +server { + listen 80; + server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; + # Add Euro Office domains if needed: + # server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver-eo.YOUR.DOMAIN; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + return 301 https://$host$request_uri; + } +} + +# ── OpenCloud ─────────────────────────────────────────────── +server { + # QUIC (UDP) — reuseport must only appear on the FIRST server block + listen 443 quic reuseport; + # HTTP/1.1 and HTTP/2 (TCP) + listen 443 ssl; + http2 on; + server_name cloud.YOUR.DOMAIN; + + # Advertise HTTP/3 availability to clients + add_header Alt-Svc 'h3=":443"; ma=86400' always; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + client_max_body_size 0; + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + proxy_pass http://opencloud_backend; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_read_timeout 3600; + proxy_buffering off; + } +} + +# ── Collabora ────────────────────────────────────────────── +server { + listen 443 quic; + listen 443 ssl; + http2 on; + server_name collabora.YOUR.DOMAIN; + + add_header Alt-Svc 'h3=":443"; ma=86400' always; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + proxy_pass http://collabora_backend; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_read_timeout 3600; + proxy_send_timeout 3600; + proxy_buffering off; + } +} + +# ── Collabora WOPI Server ────────────────────────────────── +server { + listen 443 quic; + listen 443 ssl; + http2 on; + server_name wopiserver.YOUR.DOMAIN; + + add_header Alt-Svc 'h3=":443"; ma=86400' always; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + proxy_pass http://wopi_backend; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_read_timeout 3600; + proxy_buffering off; + } +} +``` + +### Euro Office blocks with HTTP/3 + +If using Euro Office, add the following `upstream` definitions to the top of your config and append these server blocks: + +```nginx +upstream euroffice_backend { server 127.0.0.1:9900; keepalive 16; } +upstream wopi_eo_backend { server 127.0.0.1:9302; keepalive 16; } + +# ── Euro Office Document Server ──────────────────────────── +server { + listen 443 quic; + listen 443 ssl; + http2 on; + server_name euro-office.YOUR.DOMAIN; + + add_header Alt-Svc 'h3=":443"; ma=86400' always; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + client_max_body_size 100M; + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + proxy_pass http://euroffice_backend; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_read_timeout 3600; + proxy_send_timeout 3600; + proxy_buffering off; + } +} + +# ── Euro Office WOPI Server ──────────────────────────────── +server { + listen 443 quic; + listen 443 ssl; + http2 on; + server_name wopiserver-eo.YOUR.DOMAIN; + + add_header Alt-Svc 'h3=":443"; ma=86400' always; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + proxy_pass http://wopi_eo_backend; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_read_timeout 3600; + proxy_buffering off; + } +} +``` + +### Key differences from the HTTP/2 configuration + +| Detail | HTTP/2 config | HTTP/3 config | +|---|---|---| +| Listen directives | `listen 443 ssl http2;` | `listen 443 quic;` + `listen 443 ssl;` + `http2 on;` | +| `reuseport` | Not needed | Required on the **first** `listen 443 quic` directive only | +| `Alt-Svc` header | Not needed | Required to advertise HTTP/3 to browsers | +| Upstream blocks | Inline `proxy_pass` to `127.0.0.1` | Named `upstream` blocks with `keepalive` | +| WebSocket upgrade | Per-location `Connection` / `Upgrade` | Global `map` directive | +| Firewall | TCP 443 only | TCP 443 **and** UDP 443 | + +:::warning Firewall +HTTP/3 uses UDP port 443. Make sure your firewall allows **both** TCP and UDP traffic on port 443: + +```bash +sudo ufw allow 443/tcp +sudo ufw allow 443/udp +``` +::: From b6c0dd6652437cc4638676d2f1706d2367c0a541 Mon Sep 17 00:00:00 2001 From: zerox80 <115537871+zerox80@users.noreply.github.com> Date: Sat, 11 Apr 2026 11:16:19 +0200 Subject: [PATCH 3/5] Update docker-external-proxy.md --- .../container/docker-compose/docker-external-proxy.md | 8 -------- 1 file changed, 8 deletions(-) diff --git a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md index d3940458..01811a45 100644 --- a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md +++ b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md @@ -1,11 +1,3 @@ ---- -sidebar_position: 2 -id: external-proxy -title: Behind External Proxy -description: How to run OpenCloud behind an external Nginx proxy with Certbot (manual setup). -draft: false ---- - # Running OpenCloud Behind an External Proxy (Nginx + Certbot Setup) This guide walks you through setting up OpenCloud behind an external Nginx reverse proxy with Let's Encrypt certificates using `certbot certonly --webroot`. From fb6483ecc355aae6c6e94ef4600177e112b5afff Mon Sep 17 00:00:00 2001 From: zerox80 Date: Mon, 20 Apr 2026 14:03:04 +0200 Subject: [PATCH 4/5] docs: update Euro Office domain references and Nginx configuration for clarity --- docs/admin/configuration/euro-office/index.md | 29 +- .../docker-compose/docker-external-proxy.md | 354 ++++++++++++------ 2 files changed, 248 insertions(+), 135 deletions(-) diff --git a/docs/admin/configuration/euro-office/index.md b/docs/admin/configuration/euro-office/index.md index 066921c9..a42d4efb 100644 --- a/docs/admin/configuration/euro-office/index.md +++ b/docs/admin/configuration/euro-office/index.md @@ -31,7 +31,7 @@ Set the following in your `.env` file: COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/euroffice.yml EURO_OFFICE_DOMAIN=euro-office.YOUR.DOMAIN -EURO_OFFICE_WOPISERVER_DOMAIN=wopiserver-eo.YOUR.DOMAIN +WOPISERVER_DOMAIN=wopiserver.YOUR.DOMAIN EURO_OFFICE_JWT_SECRET=YOUR.SECRET ``` @@ -43,38 +43,19 @@ Set the following in your `.env` file: COMPOSE_FILE=docker-compose.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/euroffice.yml EURO_OFFICE_DOMAIN=euro-office.YOUR.DOMAIN -EURO_OFFICE_WOPISERVER_DOMAIN=wopiserver-eo.YOUR.DOMAIN +WOPISERVER_DOMAIN=wopiserver.YOUR.DOMAIN EURO_OFFICE_JWT_SECRET=YOUR.SECRET ``` For the full Nginx configuration guide, see [Behind External Proxy](../../getting-started/container/docker-compose/external-proxy). -### Using both Collabora and Euro Office -Both office suites can run simultaneously. In this case, OpenDocument formats (`.odt`, `.ods`, `.odp`) open in Collabora while Microsoft Office formats (`.docx`, `.xlsx`, `.pptx`) open in Euro Office. - -:::info -To avoid app interlocking issues, be aware that there is currently no cross-app file locking. If a file is opened in one app, the other app must wait for the lock to be released. -::: - -With Traefik: - -```env -COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:traefik/opencloud.yml:traefik/collabora.yml:traefik/euroffice.yml -``` - -With external proxy: - -```env -COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/collabora.yml:external-proxy/euroffice.yml -``` ## Environment Variables | Variable | Default | Description | |---|---|---| | `EURO_OFFICE_DOMAIN` | `euro-office.opencloud.test` | Domain of the Euro Office document server | -| `EURO_OFFICE_WOPISERVER_DOMAIN` | `wopiserver-eo.opencloud.test` | Domain of the WOPI server for Euro Office | | `EURO_OFFICE_JWT_SECRET` | `changeme` | JWT secret for Euro Office. **Change this for production!** | | `EURO_OFFICE_DOCKER_IMAGE` | `ghcr.io/euro-office/documentserver` | Docker image for the document server | | `EURO_OFFICE_DOCKER_TAG` | `latest` | Docker image tag | @@ -86,18 +67,18 @@ When using an external reverse proxy, the following ports are exposed on the hos | Service | Host Port | Description | |---|---|---| | Euro Office Document Server | `9900` | The document editing interface | -| Euro Office WOPI Server | `9302` | WOPI protocol endpoint (collaboration service) | +| Euro Office WOPI Server | `9300` | WOPI protocol endpoint (collaboration service) | ## DNS Entries When deploying with custom domains, make sure DNS records point to your server for: - `euro-office.YOUR.DOMAIN` -- `wopiserver-eo.YOUR.DOMAIN` +- `wopiserver.YOUR.DOMAIN` For local testing with `.test` domains, add to `/etc/hosts`: ```text 127.0.0.1 euro-office.opencloud.test -127.0.0.1 wopiserver-eo.opencloud.test +127.0.0.1 wopiserver.opencloud.test ``` diff --git a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md index 01811a45..3a33c36e 100644 --- a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md +++ b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md @@ -10,7 +10,6 @@ This guide walks you through setting up OpenCloud behind an external Nginx rever - `collabora.YOUR.DOMAIN` (if using Collabora) - `wopiserver.YOUR.DOMAIN` (if using Collabora) - `euro-office.YOUR.DOMAIN` (if using Euro Office) - - `wopiserver-eo.YOUR.DOMAIN` (if using Euro Office) - Installed software: - [Docker & Docker Compose](https://docs.docker.com/engine/install/) - `nginx` @@ -88,14 +87,7 @@ If using Euro Office (alone or alongside Collabora), add the Euro Office domains # Euro Office only: server { listen 80; - server_name cloud.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver-eo.YOUR.DOMAIN; - # ...same location block as above... -} - -# Both Collabora and Euro Office: -server { - listen 80; - server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver-eo.YOUR.DOMAIN; + server_name cloud.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; # ...same location block as above... } ``` @@ -131,19 +123,7 @@ sudo certbot certonly --webroot \ -w /var/www/certbot \ -d cloud.YOUR.DOMAIN \ -d euro-office.YOUR.DOMAIN \ - -d wopiserver-eo.YOUR.DOMAIN \ - --email your@email.com \ - --agree-tos \ - --no-eff-email - -# Both Collabora and Euro Office: -sudo certbot certonly --webroot \ - -w /var/www/certbot \ - -d cloud.YOUR.DOMAIN \ - -d collabora.YOUR.DOMAIN \ -d wopiserver.YOUR.DOMAIN \ - -d euro-office.YOUR.DOMAIN \ - -d wopiserver-eo.YOUR.DOMAIN \ --email your@email.com \ --agree-tos \ --no-eff-email @@ -196,27 +176,8 @@ INITIAL_ADMIN_PASSWORD=YOUR.SECRET.PASSWORD EURO_OFFICE_DOMAIN=euro-office.YOUR.DOMAIN -EURO_OFFICE_WOPISERVER_DOMAIN=wopiserver-eo.YOUR.DOMAIN - -EURO_OFFICE_JWT_SECRET=YOUR.EURO.OFFICE.SECRET -``` - -**Both Collabora and Euro Office:** - -```env -# INSECURE=true - -COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:weboffice/euroffice.yml:external-proxy/opencloud.yml:external-proxy/collabora.yml:external-proxy/euroffice.yml - -OC_DOMAIN=cloud.YOUR.DOMAIN - -INITIAL_ADMIN_PASSWORD=YOUR.SECRET.PASSWORD - -COLLABORA_DOMAIN=collabora.YOUR.DOMAIN WOPISERVER_DOMAIN=wopiserver.YOUR.DOMAIN -EURO_OFFICE_DOMAIN=euro-office.YOUR.DOMAIN -EURO_OFFICE_WOPISERVER_DOMAIN=wopiserver-eo.YOUR.DOMAIN EURO_OFFICE_JWT_SECRET=YOUR.EURO.OFFICE.SECRET ``` @@ -246,16 +207,15 @@ sudo rm /etc/nginx/sites-enabled/certbot-challenge sudo nano /etc/nginx/sites-available/opencloud ``` -Paste the following configuration and adjust the URLs. Include only the server blocks you need based on your office suite choice. +Paste the full configuration that matches your deployment choice. Do not mix them. -### Core blocks (always required) +### Configuration 1: OpenCloud Only ```nginx # Redirect HTTP to HTTPS -# Add all domains you use to server_name server { listen 80; - server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver-eo.YOUR.DOMAIN; + server_name cloud.YOUR.DOMAIN; location /.well-known/acme-challenge/ { root /var/www/certbot; @@ -274,21 +234,16 @@ server { ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - # Increase max upload size (required for Tus — without this, uploads over 1 MB fail) + + # Increase max upload size client_max_body_size 10M; - - # Disable buffering - essential for SSE proxy_buffering off; proxy_request_buffering off; - - # Extend timeouts for long connections proxy_read_timeout 3600s; proxy_send_timeout 3600s; keepalive_requests 100000; keepalive_timeout 5m; http2_max_concurrent_streams 512; - - # Prevent nginx from trying other upstreams proxy_next_upstream off; location / { @@ -301,56 +256,138 @@ server { } ``` -### Collabora blocks (if using Collabora) +### Configuration 2: OpenCloud + Collabora ```nginx +# Redirect HTTP to HTTPS +server { + listen 80; + server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://$host$request_uri; + } +} + +# OpenCloud +server { + listen 443 ssl http2; + server_name cloud.YOUR.DOMAIN; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + client_max_body_size 10M; + proxy_buffering off; + proxy_request_buffering off; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + proxy_next_upstream off; + + location / { + proxy_pass http://127.0.0.1:9200; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + # Collabora server { - listen 443 ssl http2; - server_name collabora.YOUR.DOMAIN; - - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - # Increase max upload size to collabora editor - client_max_body_size 10M; - - location / { - proxy_pass http://127.0.0.1:9980; - proxy_set_header Host $host; - } - - location ~ ^/cool/(.*)/ws$ { - proxy_pass http://127.0.0.1:9980; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header Host $host; - } + listen 443 ssl http2; + server_name collabora.YOUR.DOMAIN; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + client_max_body_size 10M; + location / { + proxy_pass http://127.0.0.1:9980; + proxy_set_header Host $host; + } + + location ~ ^/cool/(.*)/ws$ { + proxy_pass http://127.0.0.1:9980; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + } } # Collabora WOPI Server server { - listen 443 ssl http2; - server_name wopiserver.YOUR.DOMAIN; - - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - location / { - proxy_pass http://127.0.0.1:9300; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } + listen 443 ssl http2; + server_name wopiserver.YOUR.DOMAIN; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + location / { + proxy_pass http://127.0.0.1:9300; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } } ``` -### Euro Office blocks (if using Euro Office) +### Configuration 3: OpenCloud + Euro Office ```nginx +# Redirect HTTP to HTTPS +server { + listen 80; + server_name cloud.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://$host$request_uri; + } +} + +# OpenCloud +server { + listen 443 ssl http2; + server_name cloud.YOUR.DOMAIN; + + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + client_max_body_size 10M; + proxy_buffering off; + proxy_request_buffering off; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + proxy_next_upstream off; + + location / { + proxy_pass http://127.0.0.1:9200; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + # Euro Office Document Server server { listen 443 ssl http2; @@ -366,7 +403,6 @@ server { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - # Required for WebSocket support proxy_set_header X-Forwarded-Proto https; } @@ -382,14 +418,14 @@ server { # Euro Office WOPI Server server { listen 443 ssl http2; - server_name wopiserver-eo.YOUR.DOMAIN; + server_name wopiserver.YOUR.DOMAIN; ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; location / { - proxy_pass http://127.0.0.1:9302; + proxy_pass http://127.0.0.1:9300; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; @@ -439,9 +475,67 @@ If this returns nothing, your nginx does not support QUIC. HTTP/3 uses QUIC (UDP) alongside the traditional TCP connections for HTTP/1.1 and HTTP/2. This can improve performance for high-latency connections and reduce head-of-line blocking. -The following configuration replaces the HTTP/2 configuration above. It uses `upstream` blocks with keepalive connections and a `map` directive for cleaner WebSocket handling. +The following configurations replace the HTTP/2 configurations above. They use `upstream` blocks with keepalive connections and a `map` directive for cleaner WebSocket handling. Pick the configuration that matches your deployment. + +### Configuration 1: OpenCloud Only with HTTP/3 + +```nginx +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +upstream opencloud_backend { server 127.0.0.1:9200; keepalive 32; } + +# ── HTTP → HTTPS redirect ────────────────────────────────── +server { + listen 80; + server_name cloud.YOUR.DOMAIN; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + return 301 https://$host$request_uri; + } +} + +# ── OpenCloud ─────────────────────────────────────────────── +server { + listen 443 quic reuseport; + listen 443 ssl; + http2 on; + server_name cloud.YOUR.DOMAIN; + + add_header Alt-Svc 'h3=":443"; ma=86400' always; + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + client_max_body_size 0; + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + proxy_pass http://opencloud_backend; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_read_timeout 3600; + proxy_buffering off; + } +} +``` -### Full configuration with HTTP/3 +### Configuration 2: OpenCloud + Collabora with HTTP/3 ```nginx map $http_upgrade $connection_upgrade { @@ -452,16 +546,11 @@ map $http_upgrade $connection_upgrade { upstream opencloud_backend { server 127.0.0.1:9200; keepalive 32; } upstream wopi_backend { server 127.0.0.1:9300; keepalive 16; } upstream collabora_backend { server 127.0.0.1:9980; keepalive 16; } -# Add these if using Euro Office: -# upstream euroffice_backend { server 127.0.0.1:9900; keepalive 16; } -# upstream wopi_eo_backend { server 127.0.0.1:9302; keepalive 16; } # ── HTTP → HTTPS redirect ────────────────────────────────── server { listen 80; server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; - # Add Euro Office domains if needed: - # server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver-eo.YOUR.DOMAIN; root /var/www/certbot; location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } @@ -473,16 +562,12 @@ server { # ── OpenCloud ─────────────────────────────────────────────── server { - # QUIC (UDP) — reuseport must only appear on the FIRST server block listen 443 quic reuseport; - # HTTP/1.1 and HTTP/2 (TCP) listen 443 ssl; http2 on; server_name cloud.YOUR.DOMAIN; - # Advertise HTTP/3 availability to clients add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; @@ -517,7 +602,6 @@ server { server_name collabora.YOUR.DOMAIN; add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; @@ -552,7 +636,6 @@ server { server_name wopiserver.YOUR.DOMAIN; add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; @@ -579,13 +662,64 @@ server { } ``` -### Euro Office blocks with HTTP/3 - -If using Euro Office, add the following `upstream` definitions to the top of your config and append these server blocks: +### Configuration 3: OpenCloud + Euro Office with HTTP/3 ```nginx +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} + +upstream opencloud_backend { server 127.0.0.1:9200; keepalive 32; } +upstream wopi_backend { server 127.0.0.1:9300; keepalive 16; } upstream euroffice_backend { server 127.0.0.1:9900; keepalive 16; } -upstream wopi_eo_backend { server 127.0.0.1:9302; keepalive 16; } + +# ── HTTP → HTTPS redirect ────────────────────────────────── +server { + listen 80; + server_name cloud.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + return 301 https://$host$request_uri; + } +} + +# ── OpenCloud ─────────────────────────────────────────────── +server { + listen 443 quic reuseport; + listen 443 ssl; + http2 on; + server_name cloud.YOUR.DOMAIN; + + add_header Alt-Svc 'h3=":443"; ma=86400' always; + ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; + + client_max_body_size 0; + keepalive_requests 100000; + keepalive_timeout 5m; + http2_max_concurrent_streams 512; + + root /var/www/certbot; + location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } + + location / { + proxy_pass http://opencloud_backend; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-Proto https; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Real-IP $remote_addr; + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_read_timeout 3600; + proxy_buffering off; + } +} # ── Euro Office Document Server ──────────────────────────── server { @@ -595,7 +729,6 @@ server { server_name euro-office.YOUR.DOMAIN; add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; @@ -628,10 +761,9 @@ server { listen 443 quic; listen 443 ssl; http2 on; - server_name wopiserver-eo.YOUR.DOMAIN; + server_name wopiserver.YOUR.DOMAIN; add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; @@ -644,7 +776,7 @@ server { location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } location / { - proxy_pass http://wopi_eo_backend; + proxy_pass http://wopi_backend; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; From f281c72d32b3262f748562aa989ce88677b92cd6 Mon Sep 17 00:00:00 2001 From: zerox80 Date: Mon, 20 Apr 2026 15:09:47 +0200 Subject: [PATCH 5/5] docs: separate HTTP/3 into own PR --- .../docker-compose/docker-external-proxy.md | 351 ------------------ 1 file changed, 351 deletions(-) diff --git a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md index f14a2a66..84e36b01 100644 --- a/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md +++ b/docs/admin/getting-started/container/docker-compose/docker-external-proxy.md @@ -459,354 +459,3 @@ sudo certbot renew --dry-run ``` Your OpenCloud instance is now running securely behind a fully configured external Nginx reverse proxy with HTTPS. - -## Optional: HTTP/3 (QUIC) Support - -:::warning Advanced Setup -HTTP/3 over QUIC requires an nginx build with QUIC support. The stock nginx package on most distributions does **not** include QUIC. At the time of writing, Ubuntu 26.04+ ships an nginx version with QUIC enabled out of the box. On older distributions you need to build nginx from source with `--with-http_v3_module` or use the [official nginx QUIC packages](https://nginx.org/en/docs/quic.html). - -Verify that your nginx supports QUIC before proceeding: - -```bash -nginx -V 2>&1 | grep -o -- '--with-http_v3_module' -``` - -If this returns nothing, your nginx does not support QUIC. -::: - -HTTP/3 uses QUIC (UDP) alongside the traditional TCP connections for HTTP/1.1 and HTTP/2. This can improve performance for high-latency connections and reduce head-of-line blocking. - -The following configurations replace the HTTP/2 configurations above. They use `upstream` blocks with keepalive connections and a `map` directive for cleaner WebSocket handling. Pick the configuration that matches your deployment. - -### Configuration 1: OpenCloud Only with HTTP/3 - -```nginx -map $http_upgrade $connection_upgrade { - default upgrade; - '' close; -} - -upstream opencloud_backend { server 127.0.0.1:9200; keepalive 32; } - -# ── HTTP → HTTPS redirect ────────────────────────────────── -server { - listen 80; - server_name cloud.YOUR.DOMAIN; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - return 301 https://$host$request_uri; - } -} - -# ── OpenCloud ─────────────────────────────────────────────── -server { - listen 443 quic reuseport; - listen 443 ssl; - http2 on; - server_name cloud.YOUR.DOMAIN; - - add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - client_max_body_size 0; - keepalive_requests 100000; - keepalive_timeout 5m; - http2_max_concurrent_streams 512; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - proxy_pass http://opencloud_backend; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Real-IP $remote_addr; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_read_timeout 3600; - proxy_buffering off; - } -} -``` - -### Configuration 2: OpenCloud + Collabora with HTTP/3 - -```nginx -map $http_upgrade $connection_upgrade { - default upgrade; - '' close; -} - -upstream opencloud_backend { server 127.0.0.1:9200; keepalive 32; } -upstream wopi_backend { server 127.0.0.1:9300; keepalive 16; } -upstream collabora_backend { server 127.0.0.1:9980; keepalive 16; } - -# ── HTTP → HTTPS redirect ────────────────────────────────── -server { - listen 80; - server_name cloud.YOUR.DOMAIN collabora.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - return 301 https://$host$request_uri; - } -} - -# ── OpenCloud ─────────────────────────────────────────────── -server { - listen 443 quic reuseport; - listen 443 ssl; - http2 on; - server_name cloud.YOUR.DOMAIN; - - add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - client_max_body_size 0; - keepalive_requests 100000; - keepalive_timeout 5m; - http2_max_concurrent_streams 512; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - proxy_pass http://opencloud_backend; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Real-IP $remote_addr; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_read_timeout 3600; - proxy_buffering off; - } -} - -# ── Collabora ────────────────────────────────────────────── -server { - listen 443 quic; - listen 443 ssl; - http2 on; - server_name collabora.YOUR.DOMAIN; - - add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - keepalive_requests 100000; - keepalive_timeout 5m; - http2_max_concurrent_streams 512; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - proxy_pass http://collabora_backend; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Real-IP $remote_addr; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_read_timeout 3600; - proxy_send_timeout 3600; - proxy_buffering off; - } -} - -# ── Collabora WOPI Server ────────────────────────────────── -server { - listen 443 quic; - listen 443 ssl; - http2 on; - server_name wopiserver.YOUR.DOMAIN; - - add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - keepalive_requests 100000; - keepalive_timeout 5m; - http2_max_concurrent_streams 512; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - proxy_pass http://wopi_backend; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Real-IP $remote_addr; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_read_timeout 3600; - proxy_buffering off; - } -} -``` - -### Configuration 3: OpenCloud + Euro Office with HTTP/3 - -```nginx -map $http_upgrade $connection_upgrade { - default upgrade; - '' close; -} - -upstream opencloud_backend { server 127.0.0.1:9200; keepalive 32; } -upstream wopi_backend { server 127.0.0.1:9300; keepalive 16; } -upstream euroffice_backend { server 127.0.0.1:9900; keepalive 16; } - -# ── HTTP → HTTPS redirect ────────────────────────────────── -server { - listen 80; - server_name cloud.YOUR.DOMAIN euro-office.YOUR.DOMAIN wopiserver.YOUR.DOMAIN; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - return 301 https://$host$request_uri; - } -} - -# ── OpenCloud ─────────────────────────────────────────────── -server { - listen 443 quic reuseport; - listen 443 ssl; - http2 on; - server_name cloud.YOUR.DOMAIN; - - add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - client_max_body_size 0; - keepalive_requests 100000; - keepalive_timeout 5m; - http2_max_concurrent_streams 512; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - proxy_pass http://opencloud_backend; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Real-IP $remote_addr; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_read_timeout 3600; - proxy_buffering off; - } -} - -# ── Euro Office Document Server ──────────────────────────── -server { - listen 443 quic; - listen 443 ssl; - http2 on; - server_name euro-office.YOUR.DOMAIN; - - add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - client_max_body_size 100M; - keepalive_requests 100000; - keepalive_timeout 5m; - http2_max_concurrent_streams 512; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - proxy_pass http://euroffice_backend; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Real-IP $remote_addr; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_read_timeout 3600; - proxy_send_timeout 3600; - proxy_buffering off; - } -} - -# ── Euro Office WOPI Server ──────────────────────────────── -server { - listen 443 quic; - listen 443 ssl; - http2 on; - server_name wopiserver.YOUR.DOMAIN; - - add_header Alt-Svc 'h3=":443"; ma=86400' always; - ssl_certificate /etc/letsencrypt/live/cloud.YOUR.DOMAIN/fullchain.pem; - ssl_certificate_key /etc/letsencrypt/live/cloud.YOUR.DOMAIN/privkey.pem; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always; - - keepalive_requests 100000; - keepalive_timeout 5m; - http2_max_concurrent_streams 512; - - root /var/www/certbot; - location ^~ /.well-known/acme-challenge/ { try_files $uri =404; } - - location / { - proxy_pass http://wopi_backend; - proxy_set_header Host $host; - proxy_set_header X-Forwarded-Proto https; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Real-IP $remote_addr; - proxy_http_version 1.1; - proxy_set_header Connection $connection_upgrade; - proxy_set_header Upgrade $http_upgrade; - proxy_read_timeout 3600; - proxy_buffering off; - } -} -``` - -### Key differences from the HTTP/2 configuration - -| Detail | HTTP/2 config | HTTP/3 config | -|---|---|---| -| Listen directives | `listen 443 ssl http2;` | `listen 443 quic;` + `listen 443 ssl;` + `http2 on;` | -| `reuseport` | Not needed | Required on the **first** `listen 443 quic` directive only | -| `Alt-Svc` header | Not needed | Required to advertise HTTP/3 to browsers | -| Upstream blocks | Inline `proxy_pass` to `127.0.0.1` | Named `upstream` blocks with `keepalive` | -| WebSocket upgrade | Per-location `Connection` / `Upgrade` | Global `map` directive | -| Firewall | TCP 443 only | TCP 443 **and** UDP 443 | - -:::warning Firewall -HTTP/3 uses UDP port 443. Make sure your firewall allows **both** TCP and UDP traffic on port 443: - -```bash -sudo ufw allow 443/tcp -sudo ufw allow 443/udp -``` -:::