Как поставить веб-сервер и VLESS на одном VPS?

Как реализовать веб-сервер и VLESS на одном VPS?

Добрый день!

Имеется:

  1. Один VPS (Debian 12) с xray, настроенный на три протокола.
  2. Второй VPS (Debian 12) c веб-сервером. Apache2, mariadb-server, phpMyAdmin, composer. Сам сайт - банальная html-ка - заглушка, собранная за пару минут в конструкторе сайтов.
  3. Желание не платить за два VPS, а поставить все на одном с SNI в лице моего собственного сайта.
  4. Большая удаленная статья сами-знаете-о-чем, где был краткий раздел про то, что это реально, нужно только заставить веб-сервер слушать localhost на нестандартном порте.
  5. Полнейший нуб, не имеющий никакого опыта в разработке и сетях. Который умеет только следовать подробным инструкциям. Максимум, что я могу - догадаться, что если какая-то команда не срабатывает - возможно надо сделать apt install с первым словом из команды :slight_smile:

Далее постараюсь кратко про весь процесс:

  • Поставил веб-сервер, сайт работает, все супер.
  • Почитал ту статью, погуглил как заставить Apache слушать только определенные IP и порты, для верности уточнил еще и у ChatGPT.
  • Установил xray, конфиг скопировал предыдущий (до переустановки сервера), поменял только SNI, UUID и приватный ключ. Результат - xray при старте выдал ошибку. Собрал конфиг с нуля - то же самое.
  • Предположил, что уже в этот момент возник конфликт с веб-сервером. Полез в конфиг ports в Apache и его же конфиг виртуального хоста.
  • В первом увидел три строчки - базовая (с 80 портом) и еще две с ним же. Как я понял - одна (mod_gnutls.c) про какие-то Apache’ные штуки, другая для сертификата let’s encrypt (т.к. там было слово SSL). Во втором конфиге - аналогично 80 порт для виртуального хоста. Недолго думая, заменил все 4 строчки на 127.0.0.1:12345, сохранил, systemctl restart apache2 - и вылезла ошибка. Далее откатывал каждую из 4 строчек до дефолтного 80 порта - то же самое. Откатил оба конфига в изначальное состояние - и снова ошибка. Финишом стало то, что после перезагрузки VPS я не смог подключиться к нему по SSH, и его пришлось переустанавливать.
    P.S. Не исключаю, что проблема с Apache возникла не в момент изменения конфигов, а в момент установки и запуска xray.

Вопросы:
а) как подружить xray с apache (если это возможно)? Если можно - что конкретно, где и как указать руками, иначе я не разберусь (мне уже попадались упоминания каких-то правок в iptables)
б) какие порты за что в них отвечают, как правильно их “подружить”? Например, по какому порту в итоге можно будет попасть на мой сайт, а по какому - в админку? И по какому порту обращаться к xray. Учитывая, что они указываются:

  • в конфиге xray в разделе inbound (входной порт для xray, как я понимаю);
  • в нем же - порт для SNI (моего сайта);
  • 3 порта в конфиге Apache для вышеуказанных целей;
  • порт виртуалки в отдельном конфиге Apache.

Рекомендую учиться на локальной виртуальной машине с самоподписанным сертификатом, механизм снапшотов позволит быстро откатывать изменения. Затем рабочие конфигурации можно применить на VPS.

Есть вариант “веб-сервер” позади vless (через fallback и только для варианта vision, с reality вроде как fallback не используется)
Есть вариант веб-сервер перед vless с разделением по доменам в sni.

Но к сожалению примеры конфигурации видел только для caddy и nginx.

В правилах инбаунда? Можно пример, если не сложно?

Edit: Ответил не туда)

Использую такой кейс, только сервер nginx. Слушает 443, 8443, 80 порты 3xui, в случае если авторизация клиента не прошла (это цензор или кто-то любопытствующий), то перекидывает на nginx (какой-то внутренний порт используем

Всем спасибо за ответы! Все получилось.

Сначала пришлось помучаться с попытками подружить haproxy с apache (до установки xray даже не добрался, т.к. не смог настроить маршрутизацию на сайт).

В итоге снёс сервер, поставил nginx с переадресацией либо на сайт на нём же или xray. Сайт заработал, xray - не заработал. На стороне сервера xray выдавал ошибку, пока не отключил reality. Клиент “ругался” перестал ругаться на TLS после отключения flow, и начал выдавать ошибку “в доступе отказано”.

В итоге поставил “шлюзом” все-таки сам xray, с распределением трафика через fallback в зависимости от наличия path.

Слушайте, я почему fallback? Возможно, я чего-то упускаю, но по идее reality в режиме steal oneself прекрасно работает по такой схеме:

"inbounds": [
    {
      "port": 443,
      "protocol": "vless",
      "tag": "vless_tls",
      "settings": {
        "clients": [
          {
            "id": "$ID_HERE",
            "email": "user1@myserver",
            "flow": "xtls-rprx-vision"
          }
        ],
        "decryption": "none"
      },
      "streamSettings": {
        "network": "tcp",
        "security": "reality",
		"realitySettings": {
			"show": false,
			"dest": "127.0.0.1:12345", // СЕРВЕР СЛУШАЕТ ЗДЕСЬ
			"serverNames": [
				"$DOMAIN_NAME_HERE"
			],
			"privateKey": "$PRIVATE_KEY_HERE",
			"minClientVer": "",
			"maxClientVer": "",
			"maxTimeDiff": 0,
			"shortIds": [
				"$SHORT_ID_HERE"
			]
		}
      },
      "sniffing": {
        "enabled": true,
        "destOverride": [
          "http",
          "tls",
		  "quic"
        ]
      }
    }
  ]

В этом случае xray слушает 443 и перенаправляет все прочее на localhost 12345, который в вашем случае слушает nginx. Повторюсь, возможно что-то упускаю, но в целом маскировка под свой сайт сейчас настраивается как-то так.

Попробовал запустить ваш конфиг - xray на стороне сервера все так же наотрез отказывается запускаться с включенным reality, как и в сценарии, в котором я пытался поставить nginx “до” xray.

Это странно. А что в journalctl -u xray -e после неудачной попытки запуска xray?

  1. Во-первых, надо где покупали домен настроить DNS запись A-типа, чтобы указывала на IP вашего сервера c Xray. Займет какое-то время. Когда ping по имени сервера начнет выдавать ваш новый IP адрес, движемся дальше.

  2. Ставим nginx.

sudo apt update
sudo apt install nginx

Конфигурации серверов на nginx живут в папке

etx/nginx/sites-available

Сcылка на текущий рабочий конфиг должна быть в

etx/nginx/sites-enabled

По умолчанию там лежит конфиг default. Если выкинуть из него все каменты, вот минимально рабочий конфиг.

server {

	root /var/www/html;
	index index.html index.htm index.nginx-debian.html;

	server_name mydomain.com www.mydomain.com; # Вписать свой домен

	location / {
		try_files $uri $uri/ =404;
	}
}
  1. Дальше нужно установить SSL сертификаты для сайта.

Устанавливаем скрипт Certbot

sudo apt install python3-certbot-nginx

Генерируем сертификат. Впишите свой домен.

sudo certbot --nginx -d mydomain.com -d www.mydomain.com

Certbot этой командой сам изменит конфиг Nginx, так что он теперь будет выглядеть вот так.

server {

	root /var/www/html;
	index index.html index.htm index.nginx-debian.html;

	server_name mydomain.com www.mydomain.com;

	location / {
		try_files $uri $uri/ =404;
	}

	listen [::]:443 ssl ipv6only=on; # managed by Certbot
	listen 443 ssl; # managed by Certbot
	ssl_certificate /etc/letsencrypt/live/mydomain.com/fullchain.pem; # managed by Certbot
	ssl_certificate_key /etc/letsencrypt/live/mydomain.com/privkey.pem; # managed by Certbot
	include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
	ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = mydomain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

	listen 80 default_server;
	listen [::]:80 default_server;

	server_name mydomain.com;
	return 404; # managed by Certbot
}

Теперь Nginx и Xray конфликтуют, потому что оба слушают 443 порт. Если выключить Xray или перенастроить его на другой порт, это конфиг должен при обращении к сайту выдавать стандартную заглушку Nginx.

  1. Теперь в конфиге Nginx надо закомментить строчки, слушающие 443.
#	listen [::]:443 ssl ipv6only=on; # managed by Certbot
#	listen 443 ssl; # managed by Certbot

И заставить его вместо этого слушать localhost на порту, который мы потом впишем в Xray

listen 127.0.0.1:1234 ssl http2;

Второй серверный блок на 80 порту оставляем как есть, чтобы Сертбот мог обновлять сертификат.

Проверяем синтаксис конфига командой

nginx -t

И перезапускаем сервер

systemctl restart nginx

  1. Осталось только настроить Xray. Настраиваете все как обычно, чтобы он слушал 443. Если у вас security = Reality, то в поле dest оно же target, там где вы обычно воруете google.com:443 прописываете вместо этого 127.0.0.1:1234. Это схема называется “steal oneself”, т.е. мы как бы воруем хендшейк у своего же сервера. Если security = TLS, то нужно прописать fallback, где опять же в поле dest указываем 127.0.0.1:1234, все будет работать так же.

  2. Если все настроили правильно, то теперь кидаем свой сайт-заглушку в папку var/www/html и Xray будет слушать 443 порт и принимать VLESS соединение, если вы проходите за своего и перебрасывать на Nginx все прочие запросы.

Кому интересно, как сделал я. В качестве прокси выступает сам vless xray, который слушает 443 порт, nginx слушает на 44443 порту. Если пришел легитимный запрос к прокси, работает vless, если любой другой, то отправляется на nginx, который показывает сайт-заглушку, либо, если в запросе указан верный путь, обращается к панеле 3x-ui (работает на порту 18443). В самой панели убираем ссылки на файлы сертификатов, панель слушает только с адреса 127.0.0.1. SNI - ваш сайт, dest: 127.0.0.1:44443

# Переадресация с HTTP (80) на HTTPS (443)
server {
    listen 80;
    server_name my.site;

    # Перенаправление на HTTPS
    return 301 https://$server_name$request_uri;
}

server {
    listen 127.0.0.1:44443 ssl;
    server_name my.site;

    # Укажите путь к SSL-сертификатам
    ssl_certificate             /root/ssl/certs/fullchain.cer;
    ssl_certificate_key         /root/ssl/certs_ecc/my.site.key;
   
    # Настройки SSL
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers HIGH:!aNULL:!MD5;

    # Корневая директория для сайта
    root /var/www/html;
    index index.html index.htm;

    # Обработка запросов
    location / {
        try_files $uri $uri/ =404;
    }

    # Обработка запроса к /panelpath/
    location /panelpath/ {
        proxy_pass http://127.0.0.1:18443;
        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;
    }
}

Судя по всему я как-то неправильно чекал журнал (через journal -xeu). Сейчас уже не хочу снова менять конфиг, чтобы чекнуть ошибки)

Инструкция - супер, жаль пришлось самостоятельно разбираться через chatgpt. Есть идеи почему у меня не запускается xray с reality? Даже если брать конфиг от xofamim548. Xray слушает 443, nginx - виртуальный порт. Сертификаты от let’s encrypt есть, сайт есть, всё - как в инструкции.

Разбирайтесь по-отдельности. Чтобы Xray сам по себе работал и сайт на Nginx сам по себе. А увязать их это всего две строчки, как вы поняли, в тот и в тот конфиги одинаковый внутренний порт прописать.

Добрый день! Пока ковырялся со своим сервером - случайно наткнулся на старенькую тему.. Как я понимаю - разницы между tls+xtls+fallback и reality особо никакой, но reality мне (субъективно, как человеку, который в этом глубоко не шарит) кажется более более сложной, замороченной (маскировка под собственный сайт, когда у тебя он реально есть и есть сертификаты?) и приоритетной для блокировок (т.к. собственный веб-сервер, домен и сертификаты имеются у меньшинства людей).

Ну и пока я не плюнул на попытки настроить routing на сервере - структура с fallback мне казалась лаконичнее.

P.S. Не обратил внимание на localhost в ваших настройках в dest, из-за которого у меня не работал reality. Случайно наткнулся в одной статье, и - да - я просто не заметил)