mirror of
https://github.com/remnawave/panel.git
synced 2026-04-18 20:33:49 +00:00
Update documentation with detailed project overview and component descriptions
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
### Remnawave
|
||||
# Remnawave
|
||||
|
||||
TODO
|
||||
|
||||
> Click on the badges above to view the package on NPM or GitHub.
|
||||
Learn more about Remnawave [here](https://remna.st).
|
||||
|
||||
### XTLS SDK
|
||||
|
||||
|
||||
@@ -4,12 +4,20 @@ slug: /
|
||||
title: Introduction
|
||||
---
|
||||
|
||||
# Introduction
|
||||
## About Remnawave
|
||||
|
||||
[](https://github.com/remnawave/panel)
|
||||
|
||||
<Button label="Check out latest release" link="https://github.com/remnawave/panel" variant="secondary" size="md" outline style={{ marginBottom: '1rem' }} />
|
||||
|
||||
Remnawave is a powerful proxy managment tool, built on top of [Xray-core](https://github.com/XTLS/Xray-core), with a focus on simplicity and ease of use.
|
||||
|
||||
Backend, Node and Frontend are fully written in TypeScript with [NestJS](https://github.com/nestjs/nest) and [React](https://github.com/facebook/react) with [MantineUI](https://github.com/mantinedev/mantine) respectively.
|
||||
|
||||
## Quick start
|
||||
|
||||
<Button label="Start using Remnawave" variant="secondary" outline link="#using" />
|
||||
|
||||
## Components
|
||||
|
||||
### Panel
|
||||
@@ -18,20 +26,50 @@ Main entrypoint for Remnawave, containts this documentation and releases.
|
||||
|
||||
### Backend
|
||||
|
||||
[](https://github.com/remnawave/backend)
|
||||
[](https://hub.docker.com/r/remnawave/backend)
|
||||
|
||||
Backend for Remnawave, written in NestJS.
|
||||
|
||||
### Frontend
|
||||
|
||||
[](https://github.com/remnawave/frontend)
|
||||
|
||||
Frontend for Remnawave, written in React.
|
||||
|
||||
### Node
|
||||
|
||||
[](https://github.com/remnawave/node)
|
||||
[](https://hub.docker.com/r/remnawave/node)
|
||||
|
||||
Node for Remnawave, written in TypeScript.
|
||||
|
||||
### XTLS-SDK
|
||||
|
||||
XTLS-SDK, written for ease of use and speed of development, not only for Remnawave, but also for any Typescript project.
|
||||
[](https://www.npmjs.com/package/@remnawave/xtls-sdk)
|
||||
[](https://github.com/remnawave/xtls-sdk)
|
||||
|
||||
A TypeScript/JavaScript SDK for interacting with XTLS/Xray-core - a powerful network proxy tool that supports protocols like VLESS, XTLS, REALITY and more. Built on top of the official Xray-core project.
|
||||
|
||||
Key features:
|
||||
|
||||
- Full TypeScript support
|
||||
- Wrapper around Xray-core functionality
|
||||
- Supports core XTLS/Xray features and protocols
|
||||
|
||||
### XTLS-SDK-NestJS
|
||||
|
||||
XTLS-SDK-NestJS, a simple wrapper for NestJS.
|
||||
[](https://www.npmjs.com/package/@remnawave/xtls-sdk-nestjs)
|
||||
[](https://github.com/remnawave/xtls-sdk-nestjs)
|
||||
|
||||
A simple wrapper for NestJS.
|
||||
|
||||
### Internal usage contracts
|
||||
|
||||
#### Backend Contract
|
||||
|
||||
[](https://www.npmjs.com/package/@remnawave/backend-contract)
|
||||
|
||||
#### Node Contract
|
||||
|
||||
[](https://www.npmjs.com/package/@remnawave/node-contract)
|
||||
|
||||
8
docs/installation/_category_.yml
Normal file
8
docs/installation/_category_.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
position: 2.5 # float position is supported
|
||||
label: 'Installation'
|
||||
collapsible: true # make the category collapsible
|
||||
collapsed: false # keep the category open by default
|
||||
className: red
|
||||
link:
|
||||
type: generated-index
|
||||
title: Installation overview
|
||||
240
docs/installation/env-variables.md
Normal file
240
docs/installation/env-variables.md
Normal file
@@ -0,0 +1,240 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
slug: /installation/env
|
||||
title: Env variables
|
||||
---
|
||||
|
||||
## Main Panel (aka Backend) {#panel}
|
||||
|
||||
### APP_PORT
|
||||
|
||||
Port for the main panel inside Docker container.
|
||||
|
||||
```bash
|
||||
APP_PORT=3000
|
||||
```
|
||||
|
||||
### DATABASE_URL
|
||||
|
||||
Database URL. Supported only Postgres.
|
||||
|
||||
Format: `postgresql://{user}:{password}@{host}:{port}/{database}`
|
||||
|
||||
```bash
|
||||
DATABASE_URL="postgresql://postgres:postgres@remnawave-db:5432/postgres"
|
||||
```
|
||||
|
||||
### JWT
|
||||
|
||||
Be sure to change the secrets.
|
||||
|
||||
It is recommended to use a random string generator to create the secrets with a minimum length of 64 characters.
|
||||
|
||||
This values are used to sign/verify the JWT tokens.
|
||||
|
||||
:::danger
|
||||
|
||||
Do not use default credentials in production.
|
||||
Be sure to generate strong secrets!
|
||||
|
||||
:::
|
||||
|
||||
```bash
|
||||
JWT_AUTH_SECRET=change_me
|
||||
JWT_API_TOKENS_SECRET=change_me
|
||||
```
|
||||
|
||||
### TELEGRAM
|
||||
|
||||
This values are used to send notifications to the Telegram bot.
|
||||
|
||||
You can set up the same `chat id` for `TELEGRAM_ADMIN_ID` and `NODES_NOTIFY_CHAT_ID`.
|
||||
|
||||
`NODES_NOTIFY_CHAT_ID` is used to send notifications of nodes status changes, so it is recommended to set it up to a channel with turned on notifications.
|
||||
|
||||
```bash
|
||||
TELEGRAM_BOT_TOKEN=change_me
|
||||
TELEGRAM_ADMIN_ID=change_me
|
||||
NODES_NOTIFY_CHAT_ID=change_me
|
||||
```
|
||||
|
||||
### FRONT_END_DOMAIN
|
||||
|
||||
Frontend domain, used by Helmet middleware.
|
||||
|
||||
Example: `FRONT_END_DOMAIN=panel.example.com`
|
||||
|
||||
```bash
|
||||
FRONT_END_DOMAIN=*
|
||||
```
|
||||
|
||||
### SUBSCRIPTION INFO
|
||||
|
||||
This values will be passed to response headers in subscription response.
|
||||
|
||||
A lot of clients relay on these headers.
|
||||
|
||||
For example, `SUB_UPDATE_INTERVAL` is used to update subscription in Streisand, Clash Verge and other clients.
|
||||
|
||||
```bash
|
||||
SUB_SUPPORT_URL=https://support.example.com
|
||||
SUB_PROFILE_TITLE=Subscription Profile
|
||||
SUB_UPDATE_INTERVAL=12
|
||||
SUB_WEBPAGE_URL=https://example.com
|
||||
```
|
||||
|
||||
### SUBSCRIPTION PUBLIC DOMAIN
|
||||
|
||||
This value is used for a easy access to subscription URL in Frontend and API.
|
||||
|
||||
Must be a valid domain, without http/https. Do not place `/` to end of domain/path.
|
||||
|
||||
```bash
|
||||
SUB_PUBLIC_DOMAIN=example.com
|
||||
```
|
||||
|
||||
### User statuses
|
||||
|
||||
It can be used to customize user statuses remarks, which will see user if their status in not ACTIVE.
|
||||
|
||||
Must be an array of strings, each string is a remark.
|
||||
|
||||
```bash
|
||||
EXPIRED_USER_REMARKS=["⚠️ Subscription expired","Contact support"]
|
||||
DISABLED_USER_REMARKS=["❌ Subscription disabled","Contact support"]
|
||||
LIMITED_USER_REMARKS=["🔴 Subscription limited","Contact support"]
|
||||
```
|
||||
|
||||
### Admin credentials
|
||||
|
||||
Be sure to change the credentials.
|
||||
|
||||
:::danger
|
||||
|
||||
Do not use default credentials in production.
|
||||
|
||||
:::
|
||||
|
||||
```bash
|
||||
SUPERADMIN_USERNAME=change_me
|
||||
SUPERADMIN_PASSWORD=change_me
|
||||
```
|
||||
|
||||
### Docs
|
||||
|
||||
Enable docs.
|
||||
|
||||
```bash
|
||||
IS_DOCS_ENABLED=true
|
||||
```
|
||||
|
||||
If `IS_DOCS_ENABLED` is `true`, you can set up the paths to SwaggerUI and Scalar.
|
||||
|
||||
You can freely explore all the API routes and endpoints.
|
||||
|
||||
:::tip
|
||||
|
||||
Check out `API Keys` page in admin dashboard with enabled `IS_DOCS_ENABLED` for quick route to documentation.
|
||||
|
||||
:::
|
||||
|
||||
```bash
|
||||
SWAGGER_PATH=/docs
|
||||
SCALAR_PATH=/scalar
|
||||
```
|
||||
|
||||
### PROMETHEUS
|
||||
|
||||
Metrics are enabled by default, currently you can't disable them.
|
||||
|
||||
You can set up the credentials to access the metrics.
|
||||
|
||||
:::danger
|
||||
|
||||
Do not use default credentials in production.
|
||||
|
||||
:::
|
||||
|
||||
```bash
|
||||
METRICS_USER=admin
|
||||
METRICS_PASS=change_me
|
||||
```
|
||||
|
||||
Metrics are available at `/api/metrics` path.
|
||||
|
||||
Sample Prometheus config:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
# scrape_interval: 15s
|
||||
scrape_timeout: 10s
|
||||
evaluation_interval: 15s
|
||||
scrape_configs:
|
||||
- job_name: 'remnawave'
|
||||
scheme: http
|
||||
metrics_path: /api/metrics
|
||||
static_configs:
|
||||
- targets: ['remnawave:3000']
|
||||
scrape_interval: 30s
|
||||
basic_auth:
|
||||
username: admin
|
||||
password: change_me
|
||||
```
|
||||
|
||||
### Webhook
|
||||
|
||||
Enable webhook.
|
||||
|
||||
```bash
|
||||
WEBHOOK_ENABLED=true
|
||||
```
|
||||
|
||||
If webhook is enabled, you must set up the URL and secret.
|
||||
|
||||
:::danger
|
||||
|
||||
Do not use default credentials in production.
|
||||
|
||||
:::
|
||||
|
||||
`WEBHOOK_SECRET_HEADER` is used to sign the webhook payload, must be exact 64 characters. Only a-z, 0-9, A-Z are allowed.
|
||||
|
||||
```bash
|
||||
WEBHOOK_URL=https://webhook.site/1234567890
|
||||
WEBHOOK_SECRET_HEADER=vsmu67Kmg6R8FjIOF1WUY8LWBHie4scdEqrfsKmyf4IAf8dY3nFS0wwYHkhh6ZvQ
|
||||
```
|
||||
|
||||
### Shared environment variables
|
||||
|
||||
These variables are not used by Remnawave iteself, but can be used by Postgres database or Cloudflare Tunnel, if you will run them from the same `docker-compose.yml` file.
|
||||
|
||||
```bash
|
||||
CLOUDFLARE_TOKEN=ey...
|
||||
POSTGRES_USER=username
|
||||
POSTGRES_PASSWORD=password
|
||||
POSTGRES_DB=database_name
|
||||
```
|
||||
|
||||
## Node {#node}
|
||||
|
||||
### APP_PORT
|
||||
|
||||
Port for the node inside Docker container.
|
||||
|
||||
```bash
|
||||
APP_PORT=3001
|
||||
```
|
||||
|
||||
### SSL_CERT
|
||||
|
||||
It can be retrieved from the main panel.
|
||||
|
||||
:::warning
|
||||
|
||||
Do not share your certificate with anyone.
|
||||
|
||||
:::
|
||||
|
||||
```bash
|
||||
SSL_CERT=PUT CERTIFICATE HERE
|
||||
```
|
||||
139
docs/installation/quick-start.md
Normal file
139
docs/installation/quick-start.md
Normal file
@@ -0,0 +1,139 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
slug: /installation/quick-start
|
||||
title: Quick start
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
Remnawave consists of two parts:
|
||||
|
||||
- Main panel (aka backend)
|
||||
- Node (with XRay Core inside)
|
||||
|
||||
You can install both parts on the same machine or separate machines.
|
||||
|
||||
Minimum requirements for Backend:
|
||||
|
||||
- 2GB of RAM
|
||||
- 2 CPU cores
|
||||
- Docker Engine
|
||||
|
||||
Minimum requirements for Node:
|
||||
|
||||
- 1GB of RAM
|
||||
- 1 CPU core
|
||||
- Docker Engine
|
||||
|
||||
## Configuration
|
||||
|
||||
First of all, you need to configure the environment variables.
|
||||
|
||||
You can find the list of all environment variables in the [Environment Variables](/installation/env) page.
|
||||
|
||||
:::warning
|
||||
|
||||
Be sure to change the default credentials in the environment variables.
|
||||
|
||||
:::
|
||||
|
||||
## Installation
|
||||
|
||||
### Main Panel
|
||||
|
||||
:::info
|
||||
|
||||
This guide written for Ubuntu 22.04, instructions may vary for other distributions.
|
||||
:::
|
||||
|
||||
1. Create separate directory for the project.
|
||||
|
||||
```bash
|
||||
mkdir remnawave && cd remnawave
|
||||
```
|
||||
|
||||
2. Download and configure the environment variables.
|
||||
|
||||
```bash
|
||||
curl -o .env https://raw.githubusercontent.com/remnawave/backend/refs/heads/main/.env.sample
|
||||
```
|
||||
|
||||
3. Configure the environment variables.
|
||||
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
4. Create `docker-compose.yml` file, example below.
|
||||
|
||||
:::danger
|
||||
|
||||
Do not expose the services to the public internet, use only `127.0.0.1` for Remnawave services.
|
||||
|
||||
You must use Nginx/Caddy/Apache/etc. to expose the services to the public internet.
|
||||
|
||||
This guide does not cover the configuration of the reverse proxy, but just a bit later we will use Cloudflare Tunnel to expose the services to the public internet.
|
||||
|
||||
:::
|
||||
|
||||
```yaml title="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
|
||||
ports:
|
||||
- '127.0.0.1:6767:5432'
|
||||
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: remnawave/backend:latest
|
||||
container_name: 'remnawave'
|
||||
hostname: remnawave
|
||||
restart: always
|
||||
ports:
|
||||
- '127.0.0.1:3000:3000'
|
||||
env_file:
|
||||
- .env
|
||||
networks:
|
||||
- remnawave-network
|
||||
|
||||
networks:
|
||||
remnawave-network:
|
||||
driver: bridge
|
||||
external: false
|
||||
|
||||
volumes:
|
||||
remnawave-db-data:
|
||||
driver: local
|
||||
external: false
|
||||
name: remnawave-db-data
|
||||
```
|
||||
|
||||
5. Run containers.
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
6. Check the logs.
|
||||
|
||||
```bash
|
||||
docker compose logs -f
|
||||
```
|
||||
@@ -7,24 +7,12 @@ const config: Config = {
|
||||
title: 'Remnawave Documentation',
|
||||
tagline: 'Remnawave Documentation',
|
||||
favicon: 'img/favicon.ico',
|
||||
|
||||
// Set the production url of your site here
|
||||
url: 'https://remna.st',
|
||||
// Set the /<baseUrl>/ pathname under which your site is served
|
||||
// For GitHub pages deployment, it is often '/<projectName>/'
|
||||
baseUrl: '/',
|
||||
|
||||
// GitHub pages deployment config.
|
||||
// If you aren't using GitHub pages, you don't need these.
|
||||
organizationName: 'remnawave', // Usually your GitHub org/user name.
|
||||
projectName: 'panel', // Usually your repo name.
|
||||
|
||||
organizationName: 'remnawave',
|
||||
projectName: 'panel',
|
||||
onBrokenLinks: 'throw',
|
||||
onBrokenMarkdownLinks: 'warn',
|
||||
|
||||
// Even if you don't use internationalization, you can use this field to set
|
||||
// useful metadata like html lang. For example, if your site is Chinese, you
|
||||
// may want to replace "en" with "zh-Hans".
|
||||
i18n: {
|
||||
defaultLocale: 'en',
|
||||
locales: ['en']
|
||||
@@ -36,8 +24,6 @@ const config: Config = {
|
||||
{
|
||||
docs: {
|
||||
sidebarPath: './sidebars.ts',
|
||||
// Please change this to your repo.
|
||||
// Remove this to remove the "edit this page" links.
|
||||
routeBasePath: '/',
|
||||
editUrl: 'https://github.com/remnawave/panel/tree/main'
|
||||
},
|
||||
@@ -50,11 +36,13 @@ const config: Config = {
|
||||
],
|
||||
|
||||
themeConfig: {
|
||||
// Replace with your project's social card
|
||||
image: 'img/docusaurus-social-card.jpg',
|
||||
sidebar: {
|
||||
hideable: true,
|
||||
autoCollapseCategories: false
|
||||
// image: 'img/docusaurus-social-card.jpg',
|
||||
|
||||
docs: {
|
||||
sidebar: {
|
||||
hideable: true,
|
||||
autoCollapseCategories: false
|
||||
}
|
||||
},
|
||||
navbar: {
|
||||
title: 'Remnawave',
|
||||
@@ -95,6 +83,10 @@ const config: Config = {
|
||||
{
|
||||
label: 'Telegram',
|
||||
href: 'https://t.me/remnawave'
|
||||
},
|
||||
{
|
||||
label: 'Telegram Group',
|
||||
href: 'https://t.me/+cAFRGkqSWJcxNjE6'
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -117,7 +109,8 @@ const config: Config = {
|
||||
},
|
||||
|
||||
prism: {
|
||||
darkTheme: prismThemes.oneDark
|
||||
darkTheme: prismThemes.oneDark,
|
||||
additionalLanguages: ['bash']
|
||||
}
|
||||
} satisfies Preset.ThemeConfig
|
||||
}
|
||||
|
||||
76
src/components/Button/index.tsx
Normal file
76
src/components/Button/index.tsx
Normal file
@@ -0,0 +1,76 @@
|
||||
import { CSSProperties } from 'react'
|
||||
import Link from '@docusaurus/Link'
|
||||
import clsx from 'clsx'
|
||||
|
||||
// Define the Button type to control the props that can be passed to the Button component.
|
||||
type Button = {
|
||||
// The block prop is a boolean that determines if the button should be a block-level button.
|
||||
block?: boolean
|
||||
// The className prop is a string that allows you to add custom classes to the button.
|
||||
className?: string
|
||||
// The disabled prop is a boolean that determines if the button should be disabled.
|
||||
disabled?: boolean
|
||||
// The label prop is a string that determines the text of the button.
|
||||
label: string
|
||||
// The link prop is a string that determines the URL the button should link to.
|
||||
link: string
|
||||
// The outline prop is a boolean that determines if the button should be an outline button.
|
||||
outline?: boolean
|
||||
// The size prop can be one of the following values: 'sm', 'lg', 'small', 'medium', 'large', or null.
|
||||
// We'll convert 'small' to 'sm' and 'large' to 'lg' in the component. 'medium' will be considered null.
|
||||
size?: 'large' | 'lg' | 'medium' | 'sm' | 'small' | null
|
||||
// The style prop is an object that allows you to add custom styles to the button.
|
||||
style?: CSSProperties
|
||||
// The variant prop is a string that determines the color of the button.
|
||||
// It can be one of the following values: 'primary', 'secondary', 'danger', 'warning', 'success', 'info', 'link', or any other string.
|
||||
// The default value is 'primary'.
|
||||
variant: 'danger' | 'info' | 'link' | 'primary' | 'secondary' | 'success' | 'warning' | string
|
||||
}
|
||||
|
||||
// Button component that accepts the specified props.
|
||||
export default function Button({
|
||||
size = null,
|
||||
outline = false,
|
||||
variant = 'primary',
|
||||
block = false,
|
||||
disabled = false,
|
||||
className,
|
||||
style,
|
||||
link,
|
||||
label
|
||||
}: Button) {
|
||||
const sizeMap = {
|
||||
sm: 'sm',
|
||||
small: 'sm',
|
||||
lg: 'lg',
|
||||
large: 'lg',
|
||||
medium: null
|
||||
}
|
||||
const buttonSize = size ? sizeMap[size] : ''
|
||||
const sizeClass = buttonSize ? `button--${buttonSize}` : ''
|
||||
const outlineClass = outline ? 'button--outline' : ''
|
||||
const variantClass = variant ? `button--${variant}` : ''
|
||||
const blockClass = block ? 'button--block' : ''
|
||||
const disabledClass = disabled ? 'disabled' : ''
|
||||
const destination = disabled ? null : link
|
||||
return (
|
||||
<Link to={destination}>
|
||||
<button
|
||||
aria-disabled={disabled}
|
||||
className={clsx(
|
||||
'button',
|
||||
sizeClass,
|
||||
outlineClass,
|
||||
variantClass,
|
||||
blockClass,
|
||||
disabledClass,
|
||||
className
|
||||
)}
|
||||
role="button"
|
||||
style={style}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
7
src/theme/MDXComponents.tsx
Normal file
7
src/theme/MDXComponents.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import MDXComponents from '@theme-original/MDXComponents'
|
||||
import Button from '@site/src/components/Button'
|
||||
|
||||
export default {
|
||||
...MDXComponents,
|
||||
Button
|
||||
}
|
||||
Reference in New Issue
Block a user