Ноды здесь не рассматриваются, хотя в конце одну команду для них оставлю. Если вы хотите, чтобы API панели торчало в сеть, то делайте это на отдельном поддомене и только с директивой remote_ip в Caddy, мы не хотим лишний раз себя показывать. С отдельным поддоменом для API можно будет вынести подписки и запустить их на отдельном сервере. Если вам это неинтересно, то хватит и двух поддоменов, но всегда лучше все разделить.
В самом начале необходимо создать приложение OAuth в Github. Переходим в https://github.com/settings/developers и создаем новое приложение, где указываем данные следующим образом:
- Application name - Что хотим;
- Homepage URL - https://panel.domain.com/;
- Authorization callback URL - https://panel.domain.com/oauth2/callback
В OAuth также необходимо создать Client secret.
Теперь можно на VPS. Создаем путь /opt/remnawave. Создаем в этой папке docker-compose.yml:
services:
remnawave-db:
image: postgres:17
container_name: 'remnawave-db'
hostname: remnawave-db
restart: always
env_file:
- .env
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- POSTGRES_DB=${POSTGRES_DB}
- TZ=UTC
volumes:
- remnawave-db-data:/var/lib/postgresql/data
networks:
- remnawave-network
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}']
interval: 3s
timeout: 10s
retries: 3
remnawave:
image: ghcr.io/remnawave/backend:latest
container_name: 'remnawave'
hostname: remnawave
restart: always
env_file:
- .env
networks:
- remnawave-network
remnawave-redis:
image: valkey/valkey:8.0.2-alpine
container_name: remnawave-redis
hostname: remnawave-redis
restart: always
networks:
- remnawave-network
volumes:
- remnawave-redis-data:/data
healthcheck:
test: [ "CMD", "valkey-cli", "ping" ]
interval: 3s
timeout: 10s
retries: 3
oauth2:
environment:
OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_CLIENT_ID}
OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_CLIENT_SECRET}
OAUTH2_PROXY_COOKIE_SECRET: ${OAUTH2_COOKIE_SECRET}
OAUTH2_PROXY_GITHUB_USERS: ${OAUTH2_GITHUB_USERS}
OAUTH2_PROXY_EMAIL_DOMAINS: '*'
OAUTH2_PROXY_PROVIDER: ${OAUTH2_PROVIDER}
image: bitnami/oauth2-proxy:latest
env_file:
- .env
container_name: 'oauth2'
hostname: oauth2
restart: always
networks:
- remnawave-network
caddy:
image: caddy:2.9
container_name: 'caddy'
hostname: caddy
restart: always
ports:
- 0.0.0.0:443:443
networks:
- remnawave-network
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- caddy-ssl-data:/data
networks:
remnawave-network:
name: remnawave-network
driver: bridge
external: false
volumes:
remnawave-db-data:
driver: local
external: false
name: remnawave-db-data
remnawave-redis-data:
driver: local
external: false
name: remnawave-redis-data
caddy-ssl-data:
driver: local
external: false
name: caddy-ssl-data
В этой же папке нужно создать .env:
### APP ###
APP_PORT=3000
DATABASE_URL="postgresql://postgres:postgres@remnawave-db:5432/postgres"
API_INSTANCES=1
REDIS_HOST=remnawave-redis
REDIS_PORT=6379
### JWT ###
### CHANGE DEFAULT VALUES ###
JWT_AUTH_SECRET=CHANGE_ME
JWT_API_TOKENS_SECRET=CHANGE_ME
### TELEGRAM ###
IS_TELEGRAM_ENABLED=false
TELEGRAM_BOT_TOKEN=change_me
TELEGRAM_ADMIN_ID=change_me
NODES_NOTIFY_CHAT_ID=change_me
### FRONT_END ###
FRONT_END_DOMAIN=*
SUB_PUBLIC_DOMAIN=subs.domain.com/api/sub
### SWAGGER ###
SWAGGER_PATH=/docs
SCALAR_PATH=/scalar
IS_DOCS_ENABLED=false
### PROMETHEUS ###
METRICS_USER=admin
METRICS_PASS=admin
### WEBHOOK ###
WEBHOOK_ENABLED=false
### Only https:// is allowed
WEBHOOK_URL=https://webhook.site/1234567890
### This secret is used to sign the webhook payload, must be exact 64 characters. Only a-z, 0-9, A-Z are allowed.
WEBHOOK_SECRET_HEADER=vsmu67Kmg6R8FjIOF1WUY8LWBHie4scdEqrfsKmyf4IAf8dY3nFS0wwYHkhh6ZvQ
### CLOUDFLARE ###
# USED ONLY FOR docker-compose-prod-with-cf.yml
# NOT USED BY THE APP ITSELF
CLOUDFLARE_TOKEN=ey...
### Database ###
### For Postgres Docker container ###
# NOT USED BY THE APP ITSELF
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=postgres
### OAuth2 ###
OAUTH2_CLIENT_ID="CHANGE_ME"
OAUTH2_CLIENT_SECRET="CHANGE_ME"
OAUTH2_COOKIE_SECRET="CHANGE_ME"
OAUTH2_GITHUB_USERS="CHANGE_ME"
OAUTH2_PROVIDER="github"
Для панели нужно создать следующие данные:
JWT_AUTH_SECRET - openssl rand -hex 64;
JWT_API_TOKENS_SECRET - openssl rand -hex 64;
SUB_PUBLIC_DOMAIN - ваш домен для подписок, обязательно в конце /api/sub;
OAUTH2_CLIENT_ID - из OAuth приложения;
OAUTH2_CLIENT_SECRET - из OAuth приложения;
OAUTH2_COOKIE_SECRET - openssl rand -base64 32 | tr -- '+/' '-_';
OAUTH2_PROVIDER - ваш пользователь в Github. Если не знаете какой, то откройте свою страницу и скопируйте из строки, т.е. github.com/Akiyamov это Akiyamov.
Также создаем файл Caddyfile
https://panel.domain.com {
handle /oauth2/* {
reverse_proxy oauth2:4180 {
header_up X-Real-IP {remote_host}
header_up X-Forwarded-Uri {uri}
}
}
handle {
forward_auth oauth2:4180 {
uri /oauth2/auth
header_up X-Real-IP {remote_host}
@error status 401
handle_response @error {
redir * /oauth2/sign_in?rd={scheme}://{host}{uri}
}
}
reverse_proxy http://remnawave:3000
}
}
https://subs.domain.com {
reverse_proxy /api/sub/* http://remnawave:3000
}
Если хотите, чтоб API торчал, то добавляем еще одно:
https://api.domain.com {
@denied not remote_ip xx.xx.xx.xx
abort @denied
reverse_proxy /api/* http://remnawave:3000
}
Вот и все, больше ниче интересного. А, для нод
iptables -I INPUT \! --src айпи_панели -m tcp -p tcp --dport порт_ноды -j DROP