From d5b56e31c676569d5a4d7f4bed07fd9e5f3504d2 Mon Sep 17 00:00:00 2001 From: Jesus <75259437+Jolymmiles@users.noreply.github.com> Date: Wed, 14 May 2025 12:36:36 +0300 Subject: [PATCH 01/11] chore: add telegram shop bot to list. chore: add telegram shop bot to list. --- docs/awesome-remnawave.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/awesome-remnawave.md b/docs/awesome-remnawave.md index 1830333..e30edfb 100644 --- a/docs/awesome-remnawave.md +++ b/docs/awesome-remnawave.md @@ -379,9 +379,22 @@ ansible-playbook playbook.yml -K --- +### Remnawave Telegram Shop Bot + +A Telegram bot for selling subscriptions with integration to Remnawave. This service allows users to purchase and manage subscriptions through Telegram with multiple payment system options. Юкасса | Telegram Stars | CryptoBot + +Author: [jolymmiels](https://github.com/Jolymmiles) + +
+
+
+ +--- + ## Add project to the list -If you want to add your project to the list, please open a PR on [GitHub](https://github.com/remnawave/panel/blob/main/docs/awesome-remnawave/index.md). +If you want to add your project to the list, please open a PR on [GitHub](https://github.com/remnawave/panel/blob/main/docs/awesome-remnawave.md). Make sure that the target branch is `main`. From c3ed786722d4a231f9f7a01007520a3beeca2940 Mon Sep 17 00:00:00 2001 From: Jesus Date: Wed, 14 May 2025 13:46:56 +0400 Subject: [PATCH 02/11] fix: solve errors from bot. --- docs/awesome-remnawave.md | 8 ++++++-- static/awesome/remnawave-telegram-shop-bot.webp | Bin 0 -> 28032 bytes 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 static/awesome/remnawave-telegram-shop-bot.webp diff --git a/docs/awesome-remnawave.md b/docs/awesome-remnawave.md index e30edfb..9b67c1b 100644 --- a/docs/awesome-remnawave.md +++ b/docs/awesome-remnawave.md @@ -381,15 +381,19 @@ ansible-playbook playbook.yml -K ### Remnawave Telegram Shop Bot -A Telegram bot for selling subscriptions with integration to Remnawave. This service allows users to purchase and manage subscriptions through Telegram with multiple payment system options. Юкасса | Telegram Stars | CryptoBot +A Telegram bot for selling subscriptions with integration to Remnawave. This service allows users to purchase and manage subscriptions through Telegram with multiple payment system options. YooKass | Telegram Stars | CryptoBot -Author: [jolymmiels](https://github.com/Jolymmiles) +Author: [jolymmiles](https://github.com/Jolymmiles)

+
+ Remnawave Telegram Shop Bot +
+ --- ## Add project to the list diff --git a/static/awesome/remnawave-telegram-shop-bot.webp b/static/awesome/remnawave-telegram-shop-bot.webp new file mode 100644 index 0000000000000000000000000000000000000000..c775cbbfcc5631cc8a75b61ed5ca52f1614c650a GIT binary patch literal 28032 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℞H##MdIDU)mXY&4o+cN!CJd7Vv%X8cV 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 Date: Wed, 14 May 2025 14:35:22 +0300 Subject: [PATCH 03/11] Updated docs for Remnawave v1.6.0 (subscription page docker-compose file structure and envs) and Migrate v1.4.0 with custom headers support --- docs/migrate/marzban.md | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/docs/migrate/marzban.md b/docs/migrate/marzban.md index d912505..85cf548 100644 --- a/docs/migrate/marzban.md +++ b/docs/migrate/marzban.md @@ -35,8 +35,8 @@ Download the precompiled Remnawave migration tool from the GitHub releases page. # Create and navigate to a working directory mkdir -p /opt/remnawave && cd /opt/remnawave -# Download the latest version (v1.3.0 as of this guide) -wget https://github.com/remnawave/migrate/releases/download/v1.3.0/remnawave-migrate-v1.3.0-linux-amd64.tar.gz +# Download the latest version (v1.4.0 as of this guide) +wget https://github.com/remnawave/migrate/releases/download/v1.4.0/remnawave-migrate-v1.4.0-linux-amd64.tar.gz ``` ### 2.2. Extracting the Tool @@ -45,7 +45,7 @@ Unpack the downloaded archive to access the binary. ```bash # Extract the tarball -tar -xf remnawave-migrate-v1.3.0-linux-amd64.tar.gz +tar -xf remnawave-migrate-v1.4.0-linux-amd64.tar.gz ``` :::tip @@ -84,10 +84,21 @@ The tool supports the following flags and their corresponding environment variab | `--batch-size` | `BATCH_SIZE` | Number of users to process per batch | `100` | | `--last-users` | `LAST_USERS` | Migrate only the last N users (0 = all users) | `0` | | `--preferred-strategy` | `PREFERRED_STRATEGY` | Traffic reset strategy for all users | - | +| `--source-headers` | `SOURCE_HEADERS` | Additional headers for source panel | - | +| `--dest-headers` | `DEST_HEADERS` | Additional headers for Remnawave (e.g., X-Api-Key) | - | | `--preserve-status` | `PRESERVE_STATUS` | Preserve user status from source panel | `false` | :::tip +If you’re using Remnawave with additional security provided by Caddy, you need to follow these steps: +1. Log in to the Auth Portal and navigate to API Keys +2. Issue a new API key +3. Pass this key using the --dest-headers flag in the following format: +```bash +--dest-headers="X-Api-Key:api-key-from-auth-portal" +``` + ::: +:::tip - Use `--last-users=5` for a test migration with a small subset of users. - Obtain your Remnawave API token from the Remnawave panel settings (e.g., under API or Integrations). ::: @@ -126,13 +137,14 @@ services: hostname: remnawave-subscription-page restart: always environment: - - REMNAWAVE_PLAIN_DOMAIN=domain.com - - SUBSCRIPTION_PAGE_PORT=3010 + - APP_PORT=3010 + - REMNAWAVE_PANEL_URL=http://remnawave:3000 ports: - '127.0.0.1:3010:3010' networks: - remnawave-network - + volumes: + - ./app-config.json:/opt/app/frontend/assets/app-config.json networks: remnawave-network: driver: bridge @@ -151,17 +163,18 @@ services: hostname: remnawave-subscription-page restart: always environment: - - REMNAWAVE_PLAIN_DOMAIN=domain.com - - SUBSCRIPTION_PAGE_PORT=3010 + - APP_PORT=3010 + - REMNAWAVE_PANEL_URL=http://remnawave:3000 - MARZBAN_LEGACY_LINK_ENABLED=true - MARZBAN_LEGACY_SECRET_KEY=secret - REMNAWAVE_API_TOKEN=token - - CUSTOM_SUB_PREFIX=custom + - CUSTOM_SUB_PREFIX=sub ports: - '127.0.0.1:3010:3010' networks: - remnawave-network - + volumes: + - ./app-config.json:/opt/app/frontend/assets/app-config.json networks: remnawave-network: driver: bridge @@ -172,8 +185,8 @@ networks: | Variable | Description | Example Value | | ----------------------------- | ----------------------------------------------------------------------------------------------- | ------------------ | -| `REMNAWAVE_PLAIN_DOMAIN` | The address of your Remnawave panel (without `https://`). | `panel.domain.com` | -| `SUBSCRIPTION_PAGE_PORT` | The port on which the subscription page service runs. | `3010` | +| `REMNAWAVE_PANEL_URL` | Remnawave Panel URL, can be http://remnawave:3000 or https://panel.example.com | `http://remnawave:3000` | +| `APP_PORT` | The port on which the subscription page service runs. | `3010` | | `MARZBAN_LEGACY_LINK_ENABLED` | Enables support for legacy Marzban subscription links. Must be `true` to use the options below. | `true` | | `MARZBAN_LEGACY_SECRET_KEY` | The secret key from your Marzban database, required for decrypting legacy links. | `secret` | | `REMNAWAVE_API_TOKEN` | The API token generated from your Remnawave panel dashboard (under "API Tokens"). | `token` | From 7da0215bcf4be07a1938b8321666e6f0a8b78d03 Mon Sep 17 00:00:00 2001 From: mishablokhin Date: Wed, 14 May 2025 14:46:34 +0300 Subject: [PATCH 04/11] Fix formating --- docs/migrate/marzban.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/migrate/marzban.md b/docs/migrate/marzban.md index 85cf548..0b4005f 100644 --- a/docs/migrate/marzban.md +++ b/docs/migrate/marzban.md @@ -84,18 +84,18 @@ The tool supports the following flags and their corresponding environment variab | `--batch-size` | `BATCH_SIZE` | Number of users to process per batch | `100` | | `--last-users` | `LAST_USERS` | Migrate only the last N users (0 = all users) | `0` | | `--preferred-strategy` | `PREFERRED_STRATEGY` | Traffic reset strategy for all users | - | -| `--source-headers` | `SOURCE_HEADERS` | Additional headers for source panel | - | -| `--dest-headers` | `DEST_HEADERS` | Additional headers for Remnawave (e.g., X-Api-Key) | - | -| `--preserve-status` | `PRESERVE_STATUS` | Preserve user status from source panel | `false` | +| `--source-headers` | `SOURCE_HEADERS` | Additional headers for source panel | - | +| `--dest-headers` | `DEST_HEADERS` | Additional headers for Remnawave (e.g., X-Api-Key) | - | +| `--preserve-status` | `PRESERVE_STATUS` | Preserve user status from source panel | `false` | :::tip If you’re using Remnawave with additional security provided by Caddy, you need to follow these steps: 1. Log in to the Auth Portal and navigate to API Keys 2. Issue a new API key 3. Pass this key using the --dest-headers flag in the following format: -```bash ---dest-headers="X-Api-Key:api-key-from-auth-portal" -``` + ```bash + --dest-headers="X-Api-Key:api-key-from-auth-portal" + ``` ::: :::tip From 1889f2d4523c6a73812d2ec2c90a55641c96fbd7 Mon Sep 17 00:00:00 2001 From: Fraybyl Date: Wed, 14 May 2025 16:43:59 +0300 Subject: [PATCH 05/11] feat: Custom template --- docs/install/remnawave-subscription-page.md | 38 +++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/docs/install/remnawave-subscription-page.md b/docs/install/remnawave-subscription-page.md index 409d1e3..06af620 100644 --- a/docs/install/remnawave-subscription-page.md +++ b/docs/install/remnawave-subscription-page.md @@ -68,8 +68,8 @@ You can replace it parameter with, for example, - CUSTOM_SUB_PREFIX=sub ``` -to get an additional nested path for the subscription page. -But in that case, in the `.env` file for the `remnawave` container, you will need to set the corresponding parameter correctly: `SUB_PUBLIC_DOMAIN=link.domain.com/sub`. +to get an additional nested path for the subscription page. +But in that case, in the `.env` file for the `remnawave` container, you will need to set the corresponding parameter correctly: `SUB_PUBLIC_DOMAIN=link.domain.com/sub`. And you will need to specify similar changes to the valid path in your configurations for Nginx/Caddy. ::: @@ -693,6 +693,40 @@ Some applications require the subscription URL to be Base64 encoded: "isNeedBase64Encoding": true ``` +### Mounting custom template + +- **`index.html`** + Must be mounted at: + ```yaml + volumes: + - ./index.html:/opt/app/frontend/index.html + ``` +* **Static assets (all files in the `assets` directory)** + Must be mounted at: + + ```yaml + volumes: + - ./assets:/opt/app/frontend/assets + ``` +:::tip +You can find the source index.html here: +[subscription-page/frontend/index.html](https://github.com/remnawave/subscription-page/blob/main/frontend/index.html) +::: + +#### Template Variables + +Your HTML template must include three variables: + +| Variable | Description | +| --------------------------- | -------------------------------------------------------------------------------------------------------- | +| `<%= metaTitle %>` | The tag content for the subscription page. | +| `<%= metaDescription %>` | The <meta name="description"> tag content for the subscription page. | +| `<%- panelData %>` | Base64‑encoded data (string), exactly matching the response from the /api/sub/<shortUuid>/info endpoint. | + +:::danger +After mounting your template, ensure all three variables are present and used correctly in your code. If so, your subscription page will work out of the box without any further modifications. +::: + ### Mounting to the subscrion-page Modify your docker-compose.yml file to mount the app-config.json file to the subscription-page container: From 56e1a9158af593d4725f71164a56c3037908d39a Mon Sep 17 00:00:00 2001 From: Fraybyl <fraybyl@gmail.co> Date: Wed, 14 May 2025 16:46:05 +0300 Subject: [PATCH 06/11] fix: formatting --- docs/install/remnawave-subscription-page.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/install/remnawave-subscription-page.md b/docs/install/remnawave-subscription-page.md index 06af620..9f6777c 100644 --- a/docs/install/remnawave-subscription-page.md +++ b/docs/install/remnawave-subscription-page.md @@ -701,7 +701,7 @@ Some applications require the subscription URL to be Base64 encoded: volumes: - ./index.html:/opt/app/frontend/index.html ``` -* **Static assets (all files in the `assets` directory)** +- **Static assets (all files in the `assets` directory)** Must be mounted at: ```yaml From a95285f7128b95baa64ef541eb98944d1260b431 Mon Sep 17 00:00:00 2001 From: Fraybyl <fraybyl@gmail.co> Date: Wed, 14 May 2025 16:51:26 +0300 Subject: [PATCH 07/11] fix: formatting and text --- docs/install/remnawave-subscription-page.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/install/remnawave-subscription-page.md b/docs/install/remnawave-subscription-page.md index 9f6777c..bf5502c 100644 --- a/docs/install/remnawave-subscription-page.md +++ b/docs/install/remnawave-subscription-page.md @@ -719,15 +719,15 @@ Your HTML template must include three variables: | Variable | Description | | --------------------------- | -------------------------------------------------------------------------------------------------------- | -| `<%= metaTitle %>` | The <title> tag content for the subscription page. | -| `<%= metaDescription %>` | The <meta name="description"> tag content for the subscription page. | -| `<%- panelData %>` | Base64‑encoded data (string), exactly matching the response from the /api/sub/<shortUuid>/info endpoint. | +| `<%= metaTitle %>` | The <title> tag content for the subscription page. | +| `<%= metaDescription %>` | The <meta name="description"> tag content for the subscription page. | +| `<%- panelData %>` | Base64‑encoded data (string), exactly matching the response from the /api/sub/`<shortUuid>`/info endpoint. | :::danger After mounting your template, ensure all three variables are present and used correctly in your code. If so, your subscription page will work out of the box without any further modifications. ::: -### Mounting to the subscrion-page +### Mounting to the subscription-page Modify your docker-compose.yml file to mount the app-config.json file to the subscription-page container: From 460cc7a97e6398dca6d064dd5628043095681810 Mon Sep 17 00:00:00 2001 From: kastov <kastov@gog.sh> Date: Wed, 14 May 2025 16:59:14 +0300 Subject: [PATCH 08/11] docs: enhance subscription page template instructions and examples --- docs/install/remnawave-subscription-page.md | 62 +++++++++++++++------ 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/docs/install/remnawave-subscription-page.md b/docs/install/remnawave-subscription-page.md index bf5502c..a5f8b64 100644 --- a/docs/install/remnawave-subscription-page.md +++ b/docs/install/remnawave-subscription-page.md @@ -693,41 +693,67 @@ Some applications require the subscription URL to be Base64 encoded: "isNeedBase64Encoding": true ``` +--- + ### Mounting custom template +This can be helpful if you want fully change UI of the subscription page. + - **`index.html`** Must be mounted at: - ```yaml - volumes: - - ./index.html:/opt/app/frontend/index.html - ``` + ```yaml + volumes: + - ./index.html:/opt/app/frontend/index.html + ``` - **Static assets (all files in the `assets` directory)** Must be mounted at: - ```yaml - volumes: - - ./assets:/opt/app/frontend/assets - ``` -:::tip -You can find the source index.html here: -[subscription-page/frontend/index.html](https://github.com/remnawave/subscription-page/blob/main/frontend/index.html) -::: + ```yaml + volumes: + - ./assets:/opt/app/frontend/assets + ``` + + :::tip + You can find the source index.html here: + [subscription-page/frontend/index.html](https://github.com/remnawave/subscription-page/blob/main/frontend/index.html) + ::: #### Template Variables Your HTML template must include three variables: -| Variable | Description | -| --------------------------- | -------------------------------------------------------------------------------------------------------- | -| `<%= metaTitle %>` | The <title> tag content for the subscription page. | -| `<%= metaDescription %>` | The <meta name="description"> tag content for the subscription page. | -| `<%- panelData %>` | Base64‑encoded data (string), exactly matching the response from the /api/sub/`<shortUuid>`/info endpoint. | +| Variable | Description | +| ------------------------ | ---------------------------------------------------------------------------------------------------------- | +| `<%= metaTitle %>` | Will by resolved as META_TITLE | +| `<%= metaDescription %>` | Will by resolved as META_DESCRIPTION | +| `<%- panelData %>` | Base64‑encoded data (string), exactly matching the response from the /api/sub/`<shortUuid>`/info endpoint. | + +<details> +<summary>Example of using panelData</summary> + +```js +let panelData +panelData = '<%- panelData %>' +try { + panelData = JSON.parse(atob(panelData)) +} catch (error) { + console.error('Error parsing panel data:', error) +} +``` + +</details> :::danger After mounting your template, ensure all three variables are present and used correctly in your code. If so, your subscription page will work out of the box without any further modifications. ::: -### Mounting to the subscription-page +Restart the subscription-page container to apply the changes. + +```bash +docker compose down && docker compose up -d && docker compose logs -f +``` + +### Custom app-config.json (custom apps) Modify your docker-compose.yml file to mount the app-config.json file to the subscription-page container: From 243bc6e519206ae919135bd3329afbc3e9f0b501 Mon Sep 17 00:00:00 2001 From: kastov <kastov@gog.sh> Date: Wed, 14 May 2025 17:04:34 +0300 Subject: [PATCH 09/11] docs: correct variable descriptions in subscription page template --- docs/install/remnawave-subscription-page.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install/remnawave-subscription-page.md b/docs/install/remnawave-subscription-page.md index a5f8b64..2724d31 100644 --- a/docs/install/remnawave-subscription-page.md +++ b/docs/install/remnawave-subscription-page.md @@ -724,8 +724,8 @@ Your HTML template must include three variables: | Variable | Description | | ------------------------ | ---------------------------------------------------------------------------------------------------------- | -| `<%= metaTitle %>` | Will by resolved as META_TITLE | -| `<%= metaDescription %>` | Will by resolved as META_DESCRIPTION | +| `<%= metaTitle %>` | Will be resolved as META_TITLE (from .env) | +| `<%= metaDescription %>` | Will be resolved as META_DESCRIPTION (from .env) | | `<%- panelData %>` | Base64‑encoded data (string), exactly matching the response from the /api/sub/`<shortUuid>`/info endpoint. | <details> From f847e9168722f20ea96dd5c98c2700c55331aeb3 Mon Sep 17 00:00:00 2001 From: Fraybyl <fraybyl@gmail.co> Date: Thu, 15 May 2025 10:43:45 +0300 Subject: [PATCH 10/11] feat: node logging --- docs/install/remnawave-node.md | 50 +++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/docs/install/remnawave-node.md b/docs/install/remnawave-node.md index 6fdca76..4f4b39a 100644 --- a/docs/install/remnawave-node.md +++ b/docs/install/remnawave-node.md @@ -68,7 +68,7 @@ docker compose up -d && docker compose logs -f -t You can mount additional geosite files into the `/usr/local/share/xray/` directory in the container. -:::caution +:::caution Do not mount the entire folder. Otherwise, you will overwrite the default Xray geosite files. Mount each file individually. ::: @@ -110,3 +110,51 @@ Usage in xray config: ] } ``` +### Log from Node + +You can access logs from the node by mounting them to your host's file system. + +:::caution +You **must** set up log rotation, otherwise the logs will fill up your disk! +::: + +Add the following to the `docker-compose.yml` file: + +```yaml +services: + remnanode: + container_name: remnanode + hostname: remnanode + image: remnawave/node:latest + restart: always + network_mode: host + env_file: + - .env + // highlight-next-line-green + volumes: + // highlight-next-line-green + - '/var/lib/remna:/var/lib/remna' +``` + +Usage in xray config: + +```json + "log": { + "error": "/var/lib/remna/error.log", + "access": "/var/lib/remna/access.log", + "loglevel": "warning" + } +``` + +Log rotation using logrotate: + +```bash + /var/lib/remna/*.log { + size 50M + rotate 5 + compress + missingok + notifempty + copytruncate + } +``` From 7cd2a1cea35088ecf46278e4b237237017460200 Mon Sep 17 00:00:00 2001 From: kastov <kastov@gog.sh> Date: Fri, 16 May 2025 19:20:29 +0300 Subject: [PATCH 11/11] docs: update SDK version compatibility table in TypeScript SDK documentation --- docs/sdk/typescript-sdk.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/sdk/typescript-sdk.md b/docs/sdk/typescript-sdk.md index 6a06566..b69c866 100644 --- a/docs/sdk/typescript-sdk.md +++ b/docs/sdk/typescript-sdk.md @@ -28,6 +28,8 @@ Always pick and pin the correct version of the SDK to match the version of the R | Contract Version | Remnawave Panel Version | | ---------------- | ----------------------- | +| 0.7.2 | 1.6.3 | +| 0.7.1 | 1.6.2 | | 0.7.1 | 1.6.1 | | 0.7.0 | 1.6.0 | | 0.4.5 | 1.5.7 |