polaris-vpn 0.7.0 → 2.0.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +12 -2
- package/docs/ORACLE_CLOUD.md +56 -0
- package/docs/SETUP.md +93 -0
- package/package.json +6 -1
- package/src/cli.js +33 -1
- package/src/core/deploy-service.js +23 -4
- package/src/core/peer-service.js +37 -14
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.0-beta] - 2026-07-12
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Zero-Log Self-Hosted DNS (Unbound)**: `polaris deploy` now automatically installs and configures Unbound directly on the VPS, binding it to the tunnel interface (`10.0.0.1:53`). Client configs use this by default, ensuring your DNS queries never hit public resolvers (like Cloudflare) and never leave the encrypted tunnel.
|
|
13
|
+
- **Server Hardening (Fail2Ban)**: Deployment now automatically secures the VPS SSH port against automated botnet brute-force attacks by installing and enabling `fail2ban`.
|
|
14
|
+
|
|
15
|
+
## [1.0.0] - 2026-07-12
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **Multi-Peer Management**: `polaris peer add <name>` allows you to provision additional client configurations dynamically on your existing WireGuard or AmneziaWG server. Use `polaris peer list` and `polaris peer remove <name>` to manage your peers.
|
|
20
|
+
- **Terminal QR Codes**: Automatically generate terminal-rendered QR codes using `polaris peer qr <name>` for instantly setting up mobile devices (iOS/Android).
|
|
21
|
+
- **System Kill Switch**: Run `polaris killswitch on` to drop all non-VPN outbound traffic (using `iptables` or `pf`) when the tunnel is active, ensuring zero IP leaks.
|
|
22
|
+
|
|
8
23
|
## [0.7.0] - 2026-07-12
|
|
9
24
|
|
|
10
25
|
### Added
|
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|

|
|
4
4
|
|
|
5
5
|
Your True North in Digital Privacy. `polaris` is a production-quality, open-source, self-hosted VPN CLI tool. It supports SSH dynamic port forwarding, WireGuard, and AmneziaWG (Stealth) tunnels.
|
|
6
|
+
|
|
6
7
|
### Prerequisites
|
|
7
8
|
|
|
8
9
|
- Node.js (v18+)
|
|
@@ -50,6 +51,11 @@ polaris stop
|
|
|
50
51
|
| `polaris dashboard` | Opens a rich Terminal User Interface (TUI) with real-time stats. |
|
|
51
52
|
| `polaris status [--full]` | Show current tunnel status. `--full` shows GeoIP, ping latency, and WG stats. |
|
|
52
53
|
| `polaris monitor` | Live bandwidth monitor for WireGuard tunnels. |
|
|
54
|
+
| `polaris killswitch on/off` | Enable or disable the system-wide VPN kill switch. |
|
|
55
|
+
| `polaris peer add <name>` | Generate and add a new peer config for WireGuard/AmneziaWG. |
|
|
56
|
+
| `polaris peer list` | List all peers configured on the server. |
|
|
57
|
+
| `polaris peer remove <name>` | Revoke a peer from the server. |
|
|
58
|
+
| `polaris peer qr <name>` | Display the peer config as a QR code for mobile devices. |
|
|
53
59
|
| `polaris check` | Run a 3-point privacy check (IP, DNS leak, IPv6 leak). |
|
|
54
60
|
| `polaris add <alias> --server user@host` | Save a server profile for quick access. |
|
|
55
61
|
| `polaris list` | List all saved server profiles. |
|
|
@@ -58,15 +64,19 @@ polaris stop
|
|
|
58
64
|
| `polaris update` | Update `polaris-vpn` to the latest version via npm. |
|
|
59
65
|
|
|
60
66
|
#### `polaris dashboard`
|
|
67
|
+
|
|
61
68
|
Opens a rich Terminal User Interface (TUI) with real-time graphs, server location maps, and live statistics (Rx/Tx, Ping).
|
|
62
69
|
|
|
63
70
|
#### `polaris status [--full]`
|
|
71
|
+
|
|
64
72
|
Displays the connection state, mode, current proxy IP, and active server. Use `--full` to query GeoIP and ping latency.
|
|
65
73
|
|
|
66
74
|
#### `polaris monitor`
|
|
75
|
+
|
|
67
76
|
Live bandwidth monitor that actively graphs the download and upload speeds of your tunnel.
|
|
68
77
|
|
|
69
78
|
#### `polaris check`
|
|
79
|
+
|
|
70
80
|
Checks if your IP matches the proxy, tests for DNS leaks via `ipleak.net`, and verifies IPv6 routing.
|
|
71
81
|
|
|
72
82
|
> All commands support the `--json` flag for machine-readable output.
|
|
@@ -106,8 +116,8 @@ One Oracle VM can serve multiple people:
|
|
|
106
116
|
- **v0.1**: MVP — SSH SOCKS5 tunnel
|
|
107
117
|
- **v0.5**: WireGuard full tunnel + server provisioning
|
|
108
118
|
- **v0.6**: Windows NT Service bindings + Blessed TUI Dashboard
|
|
109
|
-
- **v0.7**: AmneziaWG stealth mode (DPI bypass)
|
|
110
|
-
- **v1.0**: Multi-peer management + QR codes + Kill switch
|
|
119
|
+
- **v0.7**: AmneziaWG stealth mode (DPI bypass)
|
|
120
|
+
- **v1.0**: Multi-peer management + QR codes + Kill switch (Current)
|
|
111
121
|
|
|
112
122
|
## Contributing
|
|
113
123
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Oracle Cloud "Always Free" VPS Guide
|
|
2
|
+
|
|
3
|
+
Oracle Cloud offers the most generous free tier in the cloud computing market, making it the perfect companion for a self-hosted Polaris VPN.
|
|
4
|
+
|
|
5
|
+
This guide will walk you through exactly how to set up an Oracle ARM instance, configure the firewall, and prepare it for Polaris.
|
|
6
|
+
|
|
7
|
+
## 1. Sign Up for Oracle Cloud
|
|
8
|
+
|
|
9
|
+
1. Go to [Oracle Cloud Free Tier](https://www.oracle.com/cloud/free/) and sign up.
|
|
10
|
+
2. You will need to provide a credit/debit card for verification. **You will not be charged.** Oracle requires this to prevent spam.
|
|
11
|
+
3. Select your **Home Region** carefully. You cannot change this later without deleting your account. Pick the region geographically closest to you for the lowest latency.
|
|
12
|
+
- *Example: If you are in South Asia, pick Mumbai or Hyderabad. If you are in Southeast Asia, pick Singapore.*
|
|
13
|
+
|
|
14
|
+
## 2. Create the Compute Instance
|
|
15
|
+
|
|
16
|
+
1. From the Oracle Cloud Dashboard, click **Create a VM instance**.
|
|
17
|
+
2. **Name**: `polaris-vpn` (or whatever you prefer).
|
|
18
|
+
3. **Placement**: Leave as default (AD-1).
|
|
19
|
+
4. **Image and Shape**:
|
|
20
|
+
- Click **Edit**.
|
|
21
|
+
- **Image**: Select **Ubuntu** (Recommend version 22.04 or newer).
|
|
22
|
+
- **Shape**: Select **Ampere (ARM)** (`VM.Standard.A1.Flex`).
|
|
23
|
+
- Configure the shape to use **2 OCPUs** and **12 GB RAM**. (You are allowed up to 4 OCPUs and 24 GB RAM for free, but 2 OCPUs is more than enough for a VPN).
|
|
24
|
+
5. **Networking**:
|
|
25
|
+
- Leave the default VCN settings.
|
|
26
|
+
- Ensure **Assign a public IPv4 address** is checked.
|
|
27
|
+
6. **Add SSH keys**:
|
|
28
|
+
- Select **Generate a key pair for me**.
|
|
29
|
+
- Click **Save private key**. Keep this `.key` file safe! You will need it to connect.
|
|
30
|
+
7. Click **Create** at the bottom of the page. Your instance will take about 2-3 minutes to provision.
|
|
31
|
+
|
|
32
|
+
## 3. Configure the Virtual Cloud Network (VCN) Firewall
|
|
33
|
+
|
|
34
|
+
By default, Oracle Cloud blocks all incoming traffic except SSH (Port 22). WireGuard (and AmneziaWG) requires UDP port 51820 to be open.
|
|
35
|
+
|
|
36
|
+
1. On your instance details page, look for the **Primary VNIC** section and click on the **Subnet** link (e.g., `subnet-xxxx`).
|
|
37
|
+
2. Under **Security Lists**, click the Default Security List.
|
|
38
|
+
3. Click **Add Ingress Rules**.
|
|
39
|
+
4. Configure the rule as follows:
|
|
40
|
+
- **Source Type**: CIDR
|
|
41
|
+
- **Source CIDR**: `0.0.0.0/0`
|
|
42
|
+
- **IP Protocol**: UDP
|
|
43
|
+
- **Destination Port Range**: `51820`
|
|
44
|
+
- **Description**: Allow WireGuard/AmneziaWG
|
|
45
|
+
5. Click **Add Ingress Rules**.
|
|
46
|
+
|
|
47
|
+
*(Note: If you plan to use the SSH SOCKS5 proxy instead of WireGuard, you don't need to open port 51820, as SSH uses port 22 which is already open).*
|
|
48
|
+
|
|
49
|
+
## 4. Get Ready for Polaris
|
|
50
|
+
|
|
51
|
+
1. Go back to your **Instance Details** page.
|
|
52
|
+
2. Note down the **Public IP Address** (e.g., `123.45.67.89`).
|
|
53
|
+
3. Note the default username for Ubuntu images is always `ubuntu`.
|
|
54
|
+
4. Locate the private key you downloaded in Step 2.6 (e.g., `ssh-key-2026-07-12.key`).
|
|
55
|
+
|
|
56
|
+
You are now ready to deploy Polaris! Head back to the [Full Setup Guide](./SETUP.md) and run the `polaris deploy` command with your new Oracle IP and SSH key.
|
package/docs/SETUP.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Full Step-by-Step Setup Guide
|
|
2
|
+
|
|
3
|
+
Welcome to Polaris VPN! This guide will take you from scratch to having a fully functional, DPI-resistant self-hosted VPN.
|
|
4
|
+
|
|
5
|
+
## 1. Prepare a Virtual Private Server (VPS)
|
|
6
|
+
|
|
7
|
+
Polaris needs a Linux server (Ubuntu/Debian recommended) to host the VPN.
|
|
8
|
+
If you don't already have one, you can easily get a powerful one for **free forever**.
|
|
9
|
+
|
|
10
|
+
👉 **[Click here for the Oracle Cloud Free Tier Guide](./ORACLE_CLOUD.md)**
|
|
11
|
+
|
|
12
|
+
*Once you have your server's Public IP address and SSH Private Key, continue to Step 2.*
|
|
13
|
+
|
|
14
|
+
## 2. Install Polaris VPN
|
|
15
|
+
|
|
16
|
+
On your local machine (where you want to connect *from*), you need Node.js installed.
|
|
17
|
+
|
|
18
|
+
Install the Polaris CLI globally:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g polaris-vpn
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## 3. Provision the Server
|
|
25
|
+
|
|
26
|
+
You will now use Polaris to automatically install and configure the VPN on your new VPS.
|
|
27
|
+
|
|
28
|
+
Run the `deploy` command. We highly recommend using the `amneziawg` mode to ensure your VPN traffic cannot be blocked by Deep Packet Inspection (DPI):
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
polaris deploy --server ubuntu@<YOUR_SERVER_IP> --mode amneziawg
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
*Note: If you receive an SSH authentication error, you need to provide your SSH private key. By default, Polaris looks for `~/.ssh/id_rsa`. If your key is saved elsewhere (like the one downloaded from Oracle), you can use it like this:*
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
eval "$(ssh-agent -s)"
|
|
38
|
+
ssh-add /path/to/your/oracle-ssh-key.key
|
|
39
|
+
polaris deploy --server ubuntu@<YOUR_SERVER_IP> --mode amneziawg
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This process takes about 2-3 minutes. Polaris will install AmneziaWG, configure the stealth parameters, set up the kernel modules, and generate your local client configuration.
|
|
43
|
+
|
|
44
|
+
## 4. Start the Tunnel
|
|
45
|
+
|
|
46
|
+
Once deployment is successful, you can connect to your new VPN!
|
|
47
|
+
|
|
48
|
+
Run:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
polaris start
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
You should see a success message. All your internet traffic is now encrypted and routed through your VPS!
|
|
55
|
+
|
|
56
|
+
To verify everything is working and your IP has changed, run:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
polaris check
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## 5. Enable the Kill Switch (Optional)
|
|
63
|
+
|
|
64
|
+
To ensure your real IP is never leaked if the VPN connection drops, enable the system kill switch:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
polaris killswitch on
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## 6. Connect Mobile Devices
|
|
71
|
+
|
|
72
|
+
Want to use the VPN on your phone? Polaris can generate terminal QR codes!
|
|
73
|
+
First, generate a new peer configuration on the server:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
polaris peer add my-iphone
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Then, display the QR code on your terminal:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
polaris peer qr my-iphone
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Download the **AmneziaWG** app on iOS or Android, tap the `+` button, select **Create from QR code**, and scan your screen!
|
|
86
|
+
|
|
87
|
+
## 7. Stop the Tunnel
|
|
88
|
+
|
|
89
|
+
When you are done, simply run:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
polaris stop
|
|
93
|
+
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polaris-vpn",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.0-beta",
|
|
4
4
|
"description": "Your True North in Digital Privacy. A self-hosted VPN CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -9,10 +9,15 @@
|
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"src",
|
|
12
|
+
"docs",
|
|
12
13
|
"README.md",
|
|
13
14
|
"LICENSE",
|
|
14
15
|
"CHANGELOG.md"
|
|
15
16
|
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/Divyo/polaris-vpn.git"
|
|
20
|
+
},
|
|
16
21
|
"engines": {
|
|
17
22
|
"node": ">=18"
|
|
18
23
|
},
|
package/src/cli.js
CHANGED
|
@@ -219,7 +219,39 @@ program
|
|
|
219
219
|
}
|
|
220
220
|
});
|
|
221
221
|
|
|
222
|
-
const
|
|
222
|
+
const ksCmd = program.command('killswitch').description('Manage the system VPN kill switch');
|
|
223
|
+
|
|
224
|
+
ksCmd
|
|
225
|
+
.command('on')
|
|
226
|
+
.description('Enable the kill switch')
|
|
227
|
+
.action(async (options, cmd) => {
|
|
228
|
+
if (!cmd.optsWithGlobals().json) printBanner();
|
|
229
|
+
try {
|
|
230
|
+
const { setKillSwitchConfig } = await import('./utils/kill-switch.js');
|
|
231
|
+
setKillSwitchConfig(true);
|
|
232
|
+
printSuccess('Kill switch enabled. All non-VPN traffic will be blocked when the tunnel is active.');
|
|
233
|
+
} catch (err) {
|
|
234
|
+
if (!cmd.optsWithGlobals().json) printError('Command failed', err);
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
ksCmd
|
|
240
|
+
.command('off')
|
|
241
|
+
.description('Disable the kill switch')
|
|
242
|
+
.action(async (options, cmd) => {
|
|
243
|
+
if (!cmd.optsWithGlobals().json) printBanner();
|
|
244
|
+
try {
|
|
245
|
+
const { setKillSwitchConfig } = await import('./utils/kill-switch.js');
|
|
246
|
+
setKillSwitchConfig(false);
|
|
247
|
+
printSuccess('Kill switch disabled.');
|
|
248
|
+
} catch (err) {
|
|
249
|
+
if (!cmd.optsWithGlobals().json) printError('Command failed', err);
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const peerCmd = program.command('peer').description('Manage WireGuard/AmneziaWG client peers');
|
|
223
255
|
|
|
224
256
|
peerCmd
|
|
225
257
|
.command('add <name>')
|
|
@@ -63,10 +63,10 @@ export const deployServer = async (serverStr, options = {}) => {
|
|
|
63
63
|
const quickCmd = isAwg ? 'awg-quick' : 'wg-quick';
|
|
64
64
|
|
|
65
65
|
// Step 1: Install packages
|
|
66
|
-
onProgress(`Installing ${isAwg ? 'AmneziaWG' : 'WireGuard'}
|
|
67
|
-
let installCmd = 'sudo apt-get update -y && sudo apt-get install -y wireguard ufw';
|
|
66
|
+
onProgress(`Installing ${isAwg ? 'AmneziaWG' : 'WireGuard'}, UFW, Unbound, and Fail2Ban...`);
|
|
67
|
+
let installCmd = 'sudo apt-get update -y && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y wireguard ufw unbound fail2ban';
|
|
68
68
|
if (isAwg) {
|
|
69
|
-
installCmd = 'sudo apt-get update -y && sudo apt-get install -y software-properties-common && sudo add-apt-repository -y ppa:amnezia/ppa && sudo apt-get update -y && sudo apt-get install -y amneziawg-dkms amneziawg-tools ufw';
|
|
69
|
+
installCmd = 'sudo apt-get update -y && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y software-properties-common && sudo add-apt-repository -y ppa:amnezia/ppa && sudo apt-get update -y && sudo DEBIAN_FRONTEND=noninteractive apt-get install -y amneziawg-dkms amneziawg-tools ufw unbound fail2ban';
|
|
70
70
|
}
|
|
71
71
|
let res = await sshExec(conn, installCmd);
|
|
72
72
|
if (res.code !== 0) throw new Error(`Installation failed: ${res.stderr}`);
|
|
@@ -118,6 +118,24 @@ AllowedIPs = 10.0.0.2/32
|
|
|
118
118
|
res = await sshExec(conn, `sudo systemctl stop ${quickCmd}@${ifaceName} || true && sudo systemctl start ${quickCmd}@${ifaceName} && sudo systemctl enable ${quickCmd}@${ifaceName}`);
|
|
119
119
|
if (res.code !== 0) throw new Error(`Starting tunnel failed: ${res.stderr}`);
|
|
120
120
|
|
|
121
|
+
// Step 5b: Configure Unbound DNS
|
|
122
|
+
onProgress('Configuring Unbound Zero-Log DNS...');
|
|
123
|
+
const unboundConf = `server:
|
|
124
|
+
interface: 10.0.0.1
|
|
125
|
+
access-control: 10.0.0.0/24 allow
|
|
126
|
+
hide-identity: yes
|
|
127
|
+
hide-version: yes
|
|
128
|
+
use-caps-for-id: yes
|
|
129
|
+
prefetch: yes
|
|
130
|
+
`;
|
|
131
|
+
res = await sshExec(conn, `cat << 'EOF' > /tmp/polaris-dns.conf\n${unboundConf}\nEOF\nsudo mv /tmp/polaris-dns.conf /etc/unbound/unbound.conf.d/polaris-dns.conf && sudo systemctl restart unbound && sudo systemctl enable unbound`);
|
|
132
|
+
if (res.code !== 0) throw new Error(`Unbound setup failed: ${res.stderr}`);
|
|
133
|
+
|
|
134
|
+
// Step 5c: Start Fail2Ban
|
|
135
|
+
onProgress('Starting Fail2Ban SSH protection...');
|
|
136
|
+
res = await sshExec(conn, 'sudo systemctl enable fail2ban && sudo systemctl restart fail2ban');
|
|
137
|
+
if (res.code !== 0) throw new Error(`Fail2ban setup failed: ${res.stderr}`);
|
|
138
|
+
|
|
121
139
|
// Step 6: Configure UFW firewall
|
|
122
140
|
onProgress('Configuring UFW firewall...');
|
|
123
141
|
res = await sshExec(conn, 'sudo ufw allow 51820/udp && sudo ufw allow 22/tcp && echo "y" | sudo ufw enable');
|
|
@@ -128,7 +146,7 @@ AllowedIPs = 10.0.0.2/32
|
|
|
128
146
|
const clientConf = `[Interface]
|
|
129
147
|
PrivateKey = ${clientKeys.privateKey}
|
|
130
148
|
Address = 10.0.0.2/24
|
|
131
|
-
DNS =
|
|
149
|
+
DNS = 10.0.0.1
|
|
132
150
|
${obfuscationBlock}
|
|
133
151
|
|
|
134
152
|
[Peer]
|
|
@@ -152,6 +170,7 @@ PersistentKeepalive = 25
|
|
|
152
170
|
serverPublicKey: serverKeys.publicKey,
|
|
153
171
|
clientPublicKey: clientKeys.publicKey,
|
|
154
172
|
interface: ethInterface,
|
|
173
|
+
awgParams: isAwg ? awgParams : null,
|
|
155
174
|
timestamp: new Date().toISOString()
|
|
156
175
|
}, null, 2), 'utf-8');
|
|
157
176
|
|
package/src/core/peer-service.js
CHANGED
|
@@ -65,10 +65,13 @@ const sshExec = (client, command) => {
|
|
|
65
65
|
export const addPeer = async (name) => {
|
|
66
66
|
const info = getDeployInfo();
|
|
67
67
|
const conn = await sshConnect(info);
|
|
68
|
+
const isAwg = info.mode === 'amneziawg';
|
|
69
|
+
const confFile = isAwg ? '/etc/amnezia/amneziawg/awg0.conf' : '/etc/wireguard/wg0.conf';
|
|
70
|
+
const quickCmd = isAwg ? 'awg-quick@awg0' : 'wg-quick@wg0';
|
|
68
71
|
|
|
69
72
|
try {
|
|
70
|
-
// 1. Read remote
|
|
71
|
-
const catRes = await sshExec(conn,
|
|
73
|
+
// 1. Read remote config
|
|
74
|
+
const catRes = await sshExec(conn, `sudo cat ${confFile}`);
|
|
72
75
|
if (catRes.code !== 0) throw new Error(`Failed to read server config: ${catRes.stderr}`);
|
|
73
76
|
const configContent = catRes.stdout;
|
|
74
77
|
|
|
@@ -99,18 +102,32 @@ PublicKey = ${peerKeys.publicKey}
|
|
|
99
102
|
AllowedIPs = ${peerIp}/32
|
|
100
103
|
`;
|
|
101
104
|
|
|
102
|
-
const writeCmd = `echo "${peerConfigBlock.replace(/"/g, '\\"')}" | sudo tee -a
|
|
105
|
+
const writeCmd = `echo "${peerConfigBlock.replace(/"/g, '\\"')}" | sudo tee -a ${confFile}`;
|
|
103
106
|
let res = await sshExec(conn, writeCmd);
|
|
104
107
|
if (res.code !== 0) throw new Error(`Failed to append remote peer: ${res.stderr}`);
|
|
105
108
|
|
|
106
|
-
// Sync remote
|
|
107
|
-
await sshExec(conn,
|
|
109
|
+
// Sync remote tunnel
|
|
110
|
+
await sshExec(conn, `sudo systemctl restart ${quickCmd}`);
|
|
111
|
+
|
|
112
|
+
let obfuscationBlock = '';
|
|
113
|
+
if (isAwg && info.awgParams) {
|
|
114
|
+
obfuscationBlock = `Jc = ${info.awgParams.Jc}
|
|
115
|
+
Jmin = ${info.awgParams.Jmin}
|
|
116
|
+
Jmax = ${info.awgParams.Jmax}
|
|
117
|
+
S1 = ${info.awgParams.S1}
|
|
118
|
+
S2 = ${info.awgParams.S2}
|
|
119
|
+
H1 = ${info.awgParams.H1}
|
|
120
|
+
H2 = ${info.awgParams.H2}
|
|
121
|
+
H3 = ${info.awgParams.H3}
|
|
122
|
+
H4 = ${info.awgParams.H4}`;
|
|
123
|
+
}
|
|
108
124
|
|
|
109
125
|
// 3. Save peer config locally
|
|
110
126
|
const clientConf = `[Interface]
|
|
111
127
|
PrivateKey = ${peerKeys.privateKey}
|
|
112
128
|
Address = ${peerIp}/24
|
|
113
|
-
DNS =
|
|
129
|
+
DNS = 10.0.0.1
|
|
130
|
+
${obfuscationBlock}
|
|
114
131
|
|
|
115
132
|
[Peer]
|
|
116
133
|
PublicKey = ${info.serverPublicKey}
|
|
@@ -135,10 +152,13 @@ PersistentKeepalive = 25
|
|
|
135
152
|
export const listPeers = async () => {
|
|
136
153
|
const info = getDeployInfo();
|
|
137
154
|
const conn = await sshConnect(info);
|
|
155
|
+
const isAwg = info.mode === 'amneziawg';
|
|
156
|
+
const confFile = isAwg ? '/etc/amnezia/amneziawg/awg0.conf' : '/etc/wireguard/wg0.conf';
|
|
157
|
+
const showCmd = isAwg ? 'awg show awg0 dump' : 'wg show wg0 dump';
|
|
138
158
|
|
|
139
159
|
try {
|
|
140
160
|
// 1. Read remote configuration to parse names
|
|
141
|
-
const catRes = await sshExec(conn,
|
|
161
|
+
const catRes = await sshExec(conn, `sudo cat ${confFile}`);
|
|
142
162
|
if (catRes.code !== 0) throw new Error('Failed to read remote config');
|
|
143
163
|
const content = catRes.stdout;
|
|
144
164
|
|
|
@@ -158,9 +178,9 @@ export const listPeers = async () => {
|
|
|
158
178
|
}
|
|
159
179
|
}
|
|
160
180
|
|
|
161
|
-
// 2. Fetch
|
|
162
|
-
const showRes = await sshExec(conn,
|
|
163
|
-
if (showRes.code !== 0) throw new Error('Failed to run
|
|
181
|
+
// 2. Fetch tunnel status
|
|
182
|
+
const showRes = await sshExec(conn, `sudo ${showCmd}`);
|
|
183
|
+
if (showRes.code !== 0) throw new Error('Failed to run show command');
|
|
164
184
|
|
|
165
185
|
const dumpLines = showRes.stdout.trim().split('\n');
|
|
166
186
|
const list = [];
|
|
@@ -193,9 +213,12 @@ export const listPeers = async () => {
|
|
|
193
213
|
export const removePeer = async (name) => {
|
|
194
214
|
const info = getDeployInfo();
|
|
195
215
|
const conn = await sshConnect(info);
|
|
216
|
+
const isAwg = info.mode === 'amneziawg';
|
|
217
|
+
const confFile = isAwg ? '/etc/amnezia/amneziawg/awg0.conf' : '/etc/wireguard/wg0.conf';
|
|
218
|
+
const quickCmd = isAwg ? 'awg-quick@awg0' : 'wg-quick@wg0';
|
|
196
219
|
|
|
197
220
|
try {
|
|
198
|
-
const catRes = await sshExec(conn,
|
|
221
|
+
const catRes = await sshExec(conn, `sudo cat ${confFile}`);
|
|
199
222
|
if (catRes.code !== 0) throw new Error('Failed to read remote config');
|
|
200
223
|
const content = catRes.stdout;
|
|
201
224
|
|
|
@@ -209,11 +232,11 @@ export const removePeer = async (name) => {
|
|
|
209
232
|
const newContent = filteredBlocks.join('[Peer]');
|
|
210
233
|
|
|
211
234
|
// Save remote config back
|
|
212
|
-
const writeRes = await sshExec(conn, `cat << 'EOF' > /tmp/
|
|
235
|
+
const writeRes = await sshExec(conn, `cat << 'EOF' > /tmp/temp.conf\n${newContent}\nEOF\nsudo mv /tmp/temp.conf ${confFile} && sudo chmod 600 ${confFile}`);
|
|
213
236
|
if (writeRes.code !== 0) throw new Error('Failed to update remote config');
|
|
214
237
|
|
|
215
|
-
// Sync remote
|
|
216
|
-
await sshExec(conn,
|
|
238
|
+
// Sync remote tunnel
|
|
239
|
+
await sshExec(conn, `sudo systemctl restart ${quickCmd}`);
|
|
217
240
|
|
|
218
241
|
// Remove local peer config if it exists
|
|
219
242
|
const peerConfPath = path.join(CONFIG_DIR, 'wg', 'peers', `${name}.conf`);
|