Короткий ответ: wss — это защищенный WebSocket, то есть WebSocket-соединение поверх TLS. Если ws:// похож на HTTP, то wss:// похож на HTTPS. Для публичных сайтов и любых личных данных используйте wss://
Пример:
const socket = new WebSocket("wss://example.com/realtime");
Если страница открыта по HTTPS, а вы пытаетесь подключиться к ws://, браузер может заблокировать соединение как mixed content
ws и wss
ws://:
- без TLS;
- подходит для локальной разработки;
- не годится для передачи личных данных на публичном сайте.
wss://:
- использует TLS;
- работает как защищенный канал;
- нужен для продакшена;
- совместим с HTTPS-страницами.
Для локальной разработки:
ws://localhost:8080
Для сайта:
wss://aglamov.biz/ws
Что нужно на сервере
Чтобы wss:// работал, сервер или reverse proxy должен иметь TLS-сертификат. Часто схема такая:
Браузер -> wss://site.com/ws -> Nginx/Caddy -> ws://backend:8080
TLS завершается на прокси, а внутренний backend может работать по обычному ws:// внутри закрытой сети
Для Nginx важно прокинуть Upgrade-заголовки:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
Без этого WebSocket может выглядеть как обычный HTTP-запрос и не подключиться
Как выбрать адрес в JS
Можно строить адрес от текущего протокола страницы:
const protocol = window.location.protocol === "https:" ? "wss" : "ws";
const socket = new WebSocket(`${protocol}://${window.location.host}/ws`);
Так локально страница на HTTP будет подключаться через ws, а продакшен на HTTPS — через wss
Авторизация в wss
wss:// защищает канал, но не решает вопрос: кто подключился. Авторизацию нужно добавить отдельно
Варианты:
- cookie-сессия, если WebSocket endpoint на том же домене;
- короткоживущий токен в первом сообщении после
open; - backend, который проверяет пользователя до upgrade;
- отдельный gateway для realtime-соединений.
Пример первого auth-сообщения:
socket.addEventListener("open", () => {
socket.send(JSON.stringify({
type: "auth",
token: accessToken,
}));
});
Не храните долгоживущие секреты в клиентском коде. Если токен утек, wss не спасет от авторизованного злоумышленника с этим токеном
Частые ошибки
Первая ошибка — использовать ws:// на HTTPS-странице. Это частая причина ошибки подключения в браузере
Вторая ошибка — думать, что wss сам авторизует пользователя. Нет, TLS защищает канал, но авторизацию нужно делать отдельно: cookie, токен, сессия или первое auth-сообщение
Третья ошибка — настроить TLS для сайта, но забыть Upgrade на reverse proxy
Четвертая ошибка — тестировать wss://localhost без сертификата. Для локалки проще использовать ws://localhost, если вы не тестируете именно TLS
Пятая ошибка — считать, что wss ускоряет WebSocket. Его задача — безопасность канала. Производительность зависит от сервера, сети, формата сообщений и нагрузки
Проверка
В браузере откройте DevTools -> Network -> WS. Подключение к wss:// должно появиться в списке WebSocket-соединений. Если ошибка есть в Console, проверьте протокол страницы, сертификат, домен и прокси
Через JS:
const socket = new WebSocket("wss://example.com/ws");
socket.addEventListener("open", () => console.log("secure ws open"));
socket.addEventListener("error", () => console.log("secure ws error"));
Локальная разработка и продакшен
Нормальная практика — использовать разные адреса:
const socketUrl =
import.meta.env.DEV
? "ws://localhost:8080"
: "wss://example.com/ws";
Главное — не зашить локальный ws://localhost в production-сборку. Такая ошибка часто всплывает только после публикации, когда сайт открывается по HTTPS, а приложение все еще пытается подключиться к локальному адресу разработчика
Что почитать дальше по WebSocket
Если нужен общий маршрут по теме, откройте рубрику WebSocket. Для соседних задач пригодятся эти разборы:
- Django: как подружить Celery с WebSocket
- Django: как сохранить биржевые данные, полученные по WebSocket
- FastAPI WebSocket: уведомления в браузер
- Fedora 43: как установить WebSocket сервер



