Ранее, я уже описывал установку, обновление и настройку связки Nextcloud + ONLYOFFICE Docs. Почитать можно тут:
https://typical-admin.ru/item/99-nextcloud-update-18-to-30
Но что если эта связка будет настроена во внутреннем контуре, не имеющим выхода наружу, и, при этом, внешним пользователям тоже требуется пользоваться Nextcloud + ONLYOFFICE Docs?
Для этой цели подойдёт реверс прокси.
Постановка задачи.
Итак, пусть у меня есть две полностью изолированные друг от друга сети:
- 192.168.10.0/24 — изолированная сеть без DNS и DHCP. В ней работают два сервера:
nextcloud.company.local(192.168.10.107) — Nextcloud 30 на Apache + PHP 8.3 + MySQL 8.4.docsrv.company.local(192.168.10.109) — ONLYOFFICE Docs Community Edition 9.1 на nginx.
- 10.10.102.0/24 — полноценная корпоративная сеть с Active Directory, DNS и DHCP.
Nextcloud и ONLYOFFICE настроены на взаимодействие строго по доменным именам (из файла hosts) и используют валидный wildcard-сертификат *.company.local. При обращении по IP‑адресам связка не работает.
Передо мной стояла цель: дать пользователям из сети 10.10.102.0/24 доступ к этим серверам, но не под теми же именами, а под новыми публичными доменами с сертификатом *.mydomain.ru:
nextcloud.mydomain.ru→nextcloud.company.localdocsrv.mydomain.ru→docsrv.company.local
При этом, требовалось сохранить работоспособность больших файлов (загрузка до 10 ГБ в Nextcloud) и совместное редактирование в реальном времени (WebSocket в ONLYOFFICE).
Выбор решения.
Я решил использовать промежуточный компьютер с двумя сетевыми интерфейсами, который будет выполнять роль шлюза и обратного прокси.
- Интерфейс в изолированную сеть:
192.168.10.17/24 - Интерфейс в корпоративную сеть:
10.10.102.234/24 - ПО: Debian 13, nginx 1.26.3 (реверс-прокси)
Nginx возьмёт на себя приём HTTPS-запросов с публичных доменов, проверку сертификатов и проксирование трафика на внутренние серверы по их оригинальным именам. Такая схема позволяет прозрачно работать с оригинальными сертификатами на бэкендах и не менять конфигурацию самих приложений (кроме нескольких финальных штрихов).
Подготовка шлюза.
1. Установка nginx.
На Debian 13 nginx ставится стандартно:
sudo apt update && sudo apt install nginx -y
2. Сертификаты.
У меня уже есть валидный wildcard-сертификат для *.mydomain.ru. Я разместил его в /etc/nginx/cert/:
/etc/nginx/cert/mydomain.ru.fullchain # полная цепочка (fullchain.pem)
/etc/nginx/cert/mydomain.ru.key # приватный ключ
Этот сертификат будет использоваться для обоих публичных доменов.
3. Сеть и hosts.
На шлюзе прописал оба интерфейса с указанными IP. Маршрутизация уже была настроена: пакеты между сетями не ходят напрямую, только через прокси.
Чтобы nginx на шлюзе мог резолвить внутренние имена из изолированной сети, я добавил в /etc/hosts:
192.168.10.107 nextcloud.company.local
192.168.10.109 docsrv.company.local
4. Доработка глобального nginx.conf
Я немного подкорректировал /etc/nginx/nginx.conf. Основные изменения:
- Увеличил
worker_connectionsдо 2048 (по умолчанию 1024), чтобы держать больше одновременных сессий WebSocket. - Добавил
keepalive_timeout 65иkeepalive_requests 100для клиентских соединений.
events {
worker_connections 2048;
}
http {
keepalive_timeout 65;
keepalive_requests 100;
# ... остальные настройки ...
}
Остальные параметры я оставил по умолчанию. Теперь переходим к главному — конфигам сайтов.
Конфигурация nginx на шлюзе.
Я решил сделать два независимых файла в /etc/nginx/sites-available/, чтобы можно было включать и выключать прокси для каждого сервиса отдельно через символические ссылки в sites-enabled.
Конфиг для Nextcloud: /etc/nginx/sites-available/nextcloud.mydomain.ru
# ======================================================================
# Nextcloud gateway
# Публичное имя: nextcloud.mydomain.ru
# Внутренний хост: nextcloud.company.local
# ======================================================================
upstream nextcloud_backend {
# Внутренний сервер Nextcloud в изолированной сети.
# Если на gateway нет DNS для этого имени, добавьте запись в /etc/hosts.
server nextcloud.company.local:443;
keepalive 64;
}
# ----------------------------------------------------------------------
# HTTP -> HTTPS
# ----------------------------------------------------------------------
server {
listen 80;
server_name nextcloud.mydomain.ru;
# Всегда отправляем пользователей на HTTPS.
return 301 https://$host$request_uri;
}
# ----------------------------------------------------------------------
# HTTPS reverse proxy for Nextcloud
# ----------------------------------------------------------------------
server {
listen 443 ssl;
http2 on; # Включаем HTTP/2 (актуально для nginx 1.25+)
server_name nextcloud.mydomain.ru;
ssl_certificate /etc/nginx/cert/vsmpo-avisma.ru.fullchain;
ssl_certificate_key /etc/nginx/cert/vsmpo-avisma.ru.key;
# Большие файлы: загрузки/скачивания до 10 ГБ.
client_max_body_size 10g;
client_body_timeout 7200s;
# Долгие операции с файлами и большие ответы от upstream.
proxy_connect_timeout 60s;
proxy_send_timeout 7200s;
proxy_read_timeout 7200s;
# Для Nextcloud лучше не буферизовать ответы и тело запроса на диск.
proxy_buffering off;
proxy_request_buffering off;
# Nextcloud использует эти URL для автоконфигурации CalDAV/CardDAV.
location = /.well-known/carddav {
return 301 https://$host/remote.php/dav/;
}
location = /.well-known/caldav {
return 301 https://$host/remote.php/dav/;
}
location ^~ /.well-known {
return 301 https://$host/index.php$request_uri;
}
location / {
proxy_pass https://nextcloud_backend;
proxy_http_version 1.1;
# Заголовки, которые нужны Nextcloud за reverse proxy.
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 https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port 443;
# Важно для переиспользования upstream keepalive
proxy_set_header Connection "";
# Важно для HTTPS-upstream: nginx должен отправлять SNI и
# проверять сертификат именно под внутренним именем хоста.
proxy_ssl_server_name on;
proxy_ssl_name nextcloud.company.local;
# Не задаём proxy_redirect off; оставляем стандартную обработку nginx.
# Это безопаснее для редиректов, которые может отдавать Nextcloud.
}
}
Конфиг для ONLYOFFICE: /etc/nginx/sites-available/docsrv.mydomain.ru
Здесь основной нюанс — правильная маршрутизация WebSocket. Реальный URL для веб-сокетов содержит версионный префикс, например /9.1.0-.../doc/.../c/?transport=websocket. Поэтому я использовал регулярное выражение, которое ищет doc/ или websocket/ в любом месте пути.
# ======================================================================
# ONLYOFFICE Docs gateway
# Публичное имя: docsrv.mydomain.ru
# Внутренний хост: docsrv.company.local
# ======================================================================
upstream onlyoffice_backend {
# Внутренний сервер ONLYOFFICE Docs в изолированной сети.
# Если на gateway нет DNS для этого имени, добавьте запись в /etc/hosts.
server docsrv.company.local:443;
keepalive 64;
}
# ----------------------------------------------------------------------
# HTTP -> HTTPS
# ----------------------------------------------------------------------
server {
listen 80;
server_name docsrv.mydomain.ru;
# Всегда отправляем пользователей на HTTPS.
return 301 https://$host$request_uri;
}
# ----------------------------------------------------------------------
# HTTPS reverse proxy for ONLYOFFICE Docs
# ----------------------------------------------------------------------
server {
listen 443 ssl;
http2 on; # Включаем HTTP/2 (актуально для nginx 1.25+)
server_name docsrv.mydomain.ru;
ssl_certificate /etc/nginx/cert/vsmpo-avisma.ru.fullchain;
ssl_certificate_key /etc/nginx/cert/vsmpo-avisma.ru.key;
# Для редактора достаточно обычных размеров, но загрузки документов
# и длительные сессии редактирования всё равно требуют нормальных таймаутов.
client_max_body_size 100m;
proxy_connect_timeout 60s;
proxy_send_timeout 7200s;
proxy_read_timeout 7200s;
proxy_buffering off;
proxy_request_buffering off;
# Обычный HTTP-трафик к ONLYOFFICE.
location / {
proxy_pass https://onlyoffice_backend;
proxy_http_version 1.1;
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 https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header Connection "";
# Для HTTPS-upstream обязательно указываем SNI.
proxy_ssl_server_name on;
proxy_ssl_name docsrv.company.local;
# Стандартное поведение nginx по переписыванию редиректов оставляем.
}
# WebSocket / realtime editing.
# location ~ ^/(doc/|websocket/) {
location ~ /(doc|websocket)/ {
proxy_pass https://onlyoffice_backend;
proxy_http_version 1.1;
# Для WebSocket обязательно передаём Upgrade/Connection именно здесь.
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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 https;
proxy_set_header X-Forwarded-Host $host;
proxy_ssl_server_name on;
proxy_ssl_name docsrv.company.local;
proxy_read_timeout 7200s;
proxy_send_timeout 7200s;
}
}
Активировал оба конфига:
sudo ln -s /etc/nginx/sites-available/nextcloud.mydomain.ru /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/docsrv.mydomain.ru /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
Настройка серверов в изолированной сети.
Теперь нужно сделать так, чтобы сами серверы Nextcloud и ONLYOFFICE «видели» друг друга под правильными именами и корректно обрабатывали запросы, приходящие через прокси.
1. Файл /etc/hosts на обоих серверах.
На сервере Nextcloud (192.168.10.107) и на сервере ONLYOFFICE (192.168.10.109) я добавил следующие строки:
192.168.10.17 nextcloud.mydomain.ru
192.168.10.17 docsrv.mydomain.ru
Это заставляет внутренние запросы, обращённые к публичным именам, идти на шлюз. Шлюз терминирует SSL с сертификатом *.mydomain.ru и проксирует их дальше. Таким образом, проверка сертификата всегда успешна, а маршрут остаётся корректным.
2. Nextcloud: правка config.php
На сервере Nextcloud я открыл /var/www/html/nextcloud/config/config.php и добавил/изменил следующие параметры:
'trusted_domains' => [
'nextcloud.company.local',
'nextcloud.mydomain.ru',
],
'trusted_proxies' => [
'192.168.10.17', // IP шлюза в изолированной сети
],
'overwritehost' => 'nextcloud.mydomain.ru',
'overwriteprotocol' => 'https',
'overwrite.cli.url' => 'https://nextcloud.mydomain.ru',
'overwritecondaddr' => '^192\.168\.10\.17$',
3. Настройка ONLYOFFICE в Nextcloud.
Этот момент важный! В веб-интерфейсе Nextcloud зашёл в «Настройки» → «ONLYOFFICE» и указал:
- Адрес ONLYOFFICE Docs:
https://docsrv.mydomain.ru/ - Адрес ONLYOFFICE Docs для внутренних запросов сервера:
https://docsrv.company.local/ - Адрес сервера Nextcloud для внутренних запросов от ONLYOFFICE Docs:
https://nextcloud.company.local/
Healthcheck успешно прошёл (зелёная галочка).
Проблемы и их решение.
Первая попытка — ошибка SSL и healthcheck.
Сначала я попытался прописать в настройках ONLYOFFICE публичный адрес docsrv.mydomain.ru как для внешних, так и для внутренних запросов. Healthcheck валился с ошибкой:
cURL error 60: SSL: no alternative certificate subject name matches target host name 'docsrv.mydomain.ru'
Дело в том, что Nextcloud пытается проверить сертификат на самом сервере ONLYOFFICE, а там установлен сертификат *.company.local. Помогла описанная выше схема с /etc/hosts и разделением адресов на внешние и внутренние. Внутренние запросы от Nextcloud к ONLYOFFICE и обратно теперь идут по короткому пути через шлюз (или напрямую внутри сети), но с правильными именами и сертификатами.
Вторая проблема — тормоза при открытии документов.
После того как healthcheck загорелся зелёным, я открыл несколько файлов. Первые 5–6 открывались нормально, но дальше начинались заметные тормоза, а новые документы просто переставали загружаться. При этом напрямую из изолированной сети открывалось до 20 документов без проблем.
Я заглянул в логи nginx на шлюзе (/var/log/nginx/access.log) и увидел странную картину: на запросы с transport=websocket возвращался статус 400 Bad Request, а не ожидаемый 101 Switching Protocols.
GET /9.1.0-.../doc/.../c/?...&transport=websocket HTTP/1.1" 400 ...
Проанализировав конфиг ONLYOFFICE, я понял причину. Мой первый вариант WebSocket-блока использовал привязку к началу строки:
location ~ ^/(doc/|websocket/) {
Но фактический URL содержит версионный префикс (/9.1.0-555e.../doc/...), поэтому регулярка не срабатывала. Запрос попадал в общий location /, где не было заголовков Upgrade и Connection: upgrade, и nginx не мог установить WebSocket-соединение. ONLYOFFICE Docs в ответ использовал long polling, который потребляет больше ресурсов и не справлялся с нагрузкой.
Исправление: я заменил регулярное выражение на такое, которое ищет doc/ или websocket/ в любом месте пути:
location ~ /(doc|websocket)/ {
После перезагрузки nginx WebSocket‑запросы начали получать статус 101, а тормоза полностью исчезли. Я спокойно открыл 20 файлов одновременно, и все они работали так же быстро, как при прямом доступе.
Результат
Теперь пользователи из локальной сети 10.10.102.0/24 заходят на:
https://nextcloud.mydomain.ru— полноценный доступ к Nextcloudhttps://docsrv.mydomain.ru— редактор ONLYOFFICE (прозрачно, через Nextcloud)
Работает совместное редактирование, загрузка больших файлов, автоконфигурация CalDAV/CardDAV. Схема надёжна, потому что все TLS-соединения терминируются с правильными сертификатами как на шлюзе, так и на бэкендах. При необходимости любой из сервисов можно быстро отключить, просто удалив символьную ссылку из sites-enabled.
Этот опыт ещё раз подтвердил: казалось бы, мелочь вроде регулярного выражения может полностью сломать производительность. Но когда всё собрано правильно, nginx отлично справляется с ролью шлюза для сложных веб-приложений.
Донаты принимаются на кошельки:
Yoomoney:
4100118091867315
Карта Т-Банк (бывший Тиньков):
2200 7017 2612 2077
Карта Альфа-Банк:
2200 1539 1357 2013
