apertodns 1.2.1 → 1.2.2
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/README.md +315 -0
- package/index.js +10 -10
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# ApertoDNS CLI
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/apertodns)
|
|
4
|
+
[](https://www.npmjs.com/package/apertodns)
|
|
5
|
+
[](https://github.com/1r0n3d3v3l0per/apertodns/blob/main/LICENSE)
|
|
6
|
+
[](https://nodejs.org)
|
|
7
|
+
|
|
8
|
+
**Dynamic DNS management from your terminal.** Manage domains, tokens, API keys, and DNS updates with style.
|
|
9
|
+
|
|
10
|
+
ApertoDNS is a free Dynamic DNS service that lets you point a subdomain to your dynamic IP address. Perfect for home servers, IoT devices, game servers, NAS systems, and remote access.
|
|
11
|
+
|
|
12
|
+
## Why ApertoDNS?
|
|
13
|
+
|
|
14
|
+
| Feature | ApertoDNS | No-IP | DuckDNS | Dynu |
|
|
15
|
+
|---------|-----------|-------|---------|------|
|
|
16
|
+
| Free subdomains | Unlimited | 1 (free) | 5 | 4 |
|
|
17
|
+
| API Keys with scopes | Yes | No | No | Limited |
|
|
18
|
+
| CLI tool | Yes | No | No | No |
|
|
19
|
+
| IPv6 support | Yes | Paid | Yes | Yes |
|
|
20
|
+
| No forced renewal | Yes | 30 days | Yes | Yes |
|
|
21
|
+
| DynDNS2 compatible | Yes | Yes | No | Yes |
|
|
22
|
+
| Webhooks | Yes | No | No | No |
|
|
23
|
+
| Team sharing | Yes | No | No | No |
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Easy Setup** - Login or register directly from CLI
|
|
28
|
+
- **Multiple Domains** - Manage unlimited subdomains
|
|
29
|
+
- **API Keys** - Create and manage API keys with granular scopes
|
|
30
|
+
- **Auto Updates** - Set up cron or daemon mode for automatic IP updates
|
|
31
|
+
- **Interactive Mode** - Beautiful terminal UI with menus
|
|
32
|
+
- **JSON Output** - Machine-readable output for scripting
|
|
33
|
+
- **IPv4 & IPv6** - Full dual-stack support
|
|
34
|
+
- **Real-time Stats** - View usage statistics and logs
|
|
35
|
+
- **Router/NAS Compatible** - Works with Synology, QNAP, and DynDNS2-compatible routers
|
|
36
|
+
|
|
37
|
+
## Requirements
|
|
38
|
+
|
|
39
|
+
- Node.js 18.0.0 or higher
|
|
40
|
+
- An ApertoDNS account ([register free](https://apertodns.com/register))
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# npm
|
|
46
|
+
npm install -g apertodns
|
|
47
|
+
|
|
48
|
+
# yarn
|
|
49
|
+
yarn global add apertodns
|
|
50
|
+
|
|
51
|
+
# pnpm
|
|
52
|
+
pnpm add -g apertodns
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or use without installing:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx apertodns --help
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quick Start
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
# 1. Setup (login or register)
|
|
65
|
+
apertodns --setup
|
|
66
|
+
|
|
67
|
+
# 2. View your dashboard
|
|
68
|
+
apertodns --dashboard
|
|
69
|
+
|
|
70
|
+
# 3. List your domains
|
|
71
|
+
apertodns --domains
|
|
72
|
+
|
|
73
|
+
# 4. Force DNS update
|
|
74
|
+
apertodns --force
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Commands
|
|
78
|
+
|
|
79
|
+
### Main Commands
|
|
80
|
+
|
|
81
|
+
| Command | Description |
|
|
82
|
+
|---------|-------------|
|
|
83
|
+
| `--dashboard` | Complete dashboard with all info |
|
|
84
|
+
| `--domains` | List all your domains |
|
|
85
|
+
| `--tokens` | List all your tokens |
|
|
86
|
+
| `--stats` | Statistics and metrics |
|
|
87
|
+
| `--logs` | Recent activity logs |
|
|
88
|
+
| `--my-ip` | Show your current public IP |
|
|
89
|
+
|
|
90
|
+
### Domain Management
|
|
91
|
+
|
|
92
|
+
| Command | Description |
|
|
93
|
+
|---------|-------------|
|
|
94
|
+
| `--add-domain <name>` | Create a new subdomain |
|
|
95
|
+
| `--delete-domain` | Delete a domain (interactive) |
|
|
96
|
+
| `--test <domain>` | Test DNS resolution |
|
|
97
|
+
|
|
98
|
+
### Token Management
|
|
99
|
+
|
|
100
|
+
| Command | Description |
|
|
101
|
+
|---------|-------------|
|
|
102
|
+
| `--enable <id>` | Enable a token |
|
|
103
|
+
| `--disable <id>` | Disable a token |
|
|
104
|
+
| `--toggle <id>` | Toggle token state |
|
|
105
|
+
| `--verify` | Verify token validity |
|
|
106
|
+
|
|
107
|
+
### API Keys
|
|
108
|
+
|
|
109
|
+
| Command | Description |
|
|
110
|
+
|---------|-------------|
|
|
111
|
+
| `--api-keys` | List all API keys |
|
|
112
|
+
| `--create-api-key <name>` | Create new API key |
|
|
113
|
+
| `--delete-api-key <id>` | Delete an API key |
|
|
114
|
+
| `--scopes` | Show available scopes |
|
|
115
|
+
| `--api-key <key>` | Use API key for authentication |
|
|
116
|
+
|
|
117
|
+
### Configuration
|
|
118
|
+
|
|
119
|
+
| Command | Description |
|
|
120
|
+
|---------|-------------|
|
|
121
|
+
| `--setup` | Guided setup (login/register) |
|
|
122
|
+
| `--status` | Show current status and IP |
|
|
123
|
+
| `--config` | Edit configuration |
|
|
124
|
+
| `--logout` | Remove local configuration |
|
|
125
|
+
| `--force` | Force DNS update now |
|
|
126
|
+
|
|
127
|
+
### Daemon Mode
|
|
128
|
+
|
|
129
|
+
| Command | Description |
|
|
130
|
+
|---------|-------------|
|
|
131
|
+
| `--daemon` | Start daemon mode (continuous updates) |
|
|
132
|
+
| `--interval <sec>` | Update interval (default: 300s) |
|
|
133
|
+
|
|
134
|
+
### Options
|
|
135
|
+
|
|
136
|
+
| Option | Description |
|
|
137
|
+
|--------|-------------|
|
|
138
|
+
| `--cron` | Silent mode for cron jobs |
|
|
139
|
+
| `--quiet` | Hide banner |
|
|
140
|
+
| `--json` | JSON output (machine-readable) |
|
|
141
|
+
| `-v, --version` | Show version |
|
|
142
|
+
| `-h, --help` | Show help |
|
|
143
|
+
|
|
144
|
+
## Interactive Mode
|
|
145
|
+
|
|
146
|
+
Run `apertodns` without arguments for an interactive menu with all options.
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
apertodns
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Authentication Methods
|
|
153
|
+
|
|
154
|
+
You can authenticate in 3 ways:
|
|
155
|
+
|
|
156
|
+
1. **Interactive Login** - Run `apertodns --setup` (saves JWT to ~/.config/apertodns/)
|
|
157
|
+
2. **API Key** - Use `--api-key <key>` for single operations
|
|
158
|
+
3. **Environment Variable** - Set `APERTODNS_API_KEY`
|
|
159
|
+
|
|
160
|
+
## JSON Output
|
|
161
|
+
|
|
162
|
+
All commands support `--json` flag for machine-readable output:
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Get domains as JSON
|
|
166
|
+
apertodns --domains --json
|
|
167
|
+
|
|
168
|
+
# Get your IP as JSON
|
|
169
|
+
apertodns --my-ip --json
|
|
170
|
+
|
|
171
|
+
# Combine with API key for scripting
|
|
172
|
+
apertodns --api-key ak_xxx... --domains --json
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Daemon Mode
|
|
176
|
+
|
|
177
|
+
Run continuously to keep your DNS updated:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Default interval (5 minutes)
|
|
181
|
+
apertodns --daemon
|
|
182
|
+
|
|
183
|
+
# Custom interval (60 seconds)
|
|
184
|
+
apertodns --daemon --interval 60
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Automatic Updates (Cron)
|
|
188
|
+
|
|
189
|
+
Set up automatic IP updates with cron:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
# Update every 5 minutes
|
|
193
|
+
*/5 * * * * /usr/local/bin/apertodns --cron >> /var/log/apertodns.log 2>&1
|
|
194
|
+
|
|
195
|
+
# Or every minute for faster updates
|
|
196
|
+
* * * * * /usr/local/bin/apertodns --cron
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Find your apertodns path with: `which apertodns`
|
|
200
|
+
|
|
201
|
+
## Router Integration (DynDNS2)
|
|
202
|
+
|
|
203
|
+
ApertoDNS is compatible with routers that support DynDNS2 protocol:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
Server: api.apertodns.com
|
|
207
|
+
Protocol: DynDNS2
|
|
208
|
+
Path: /nic/update
|
|
209
|
+
Username: your-token
|
|
210
|
+
Password: your-token
|
|
211
|
+
Hostname: yourdomain.apertodns.com
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Compatible Devices
|
|
215
|
+
|
|
216
|
+
- **Routers**: ASUS, TP-Link, Netgear, Ubiquiti, pfSense, OPNsense, DD-WRT, OpenWRT
|
|
217
|
+
- **NAS**: Synology DSM, QNAP QTS, TrueNAS
|
|
218
|
+
- **Other**: Any device supporting DynDNS2/DynDNS protocol
|
|
219
|
+
|
|
220
|
+
## Configuration Storage
|
|
221
|
+
|
|
222
|
+
Configuration is stored in platform-specific locations:
|
|
223
|
+
|
|
224
|
+
- **Linux**: `~/.config/apertodns/` or `~/.apertodns/`
|
|
225
|
+
- **macOS**: `~/.config/apertodns/`
|
|
226
|
+
- **Windows**: `%APPDATA%\apertodns\`
|
|
227
|
+
|
|
228
|
+
## Troubleshooting
|
|
229
|
+
|
|
230
|
+
### Common Issues
|
|
231
|
+
|
|
232
|
+
**"Unable to detect IP address"**
|
|
233
|
+
- Check your internet connection
|
|
234
|
+
- Try a different IP detection service: the CLI automatically tries multiple fallbacks
|
|
235
|
+
- If behind a corporate proxy, the detected IP may be the proxy's IP
|
|
236
|
+
|
|
237
|
+
**"Authentication failed"**
|
|
238
|
+
- Run `apertodns --logout` then `apertodns --setup` to re-authenticate
|
|
239
|
+
- If using API key, verify it has the required scopes
|
|
240
|
+
- Check if the token/API key is still active in your dashboard
|
|
241
|
+
|
|
242
|
+
**"DNS not updating"**
|
|
243
|
+
- Use `apertodns --force` to force an immediate update
|
|
244
|
+
- Check `apertodns --status` to see current IP vs DNS IP
|
|
245
|
+
- DNS propagation can take up to 5 minutes
|
|
246
|
+
|
|
247
|
+
**IPv6 not working**
|
|
248
|
+
- IPv6 requires your ISP and network to support it
|
|
249
|
+
- Use `apertodns --my-ip --json` to check if IPv6 is detected
|
|
250
|
+
- Some networks only provide IPv4
|
|
251
|
+
|
|
252
|
+
**Permission denied on Linux**
|
|
253
|
+
- If installed globally, you may need sudo: `sudo npm install -g apertodns`
|
|
254
|
+
- Or use a Node version manager (nvm) to avoid permission issues
|
|
255
|
+
|
|
256
|
+
**Daemon mode exits unexpectedly**
|
|
257
|
+
- Check logs in `/var/log/apertodns.log` if using cron
|
|
258
|
+
- Ensure stable internet connection
|
|
259
|
+
- Consider using a process manager like PM2 or systemd
|
|
260
|
+
|
|
261
|
+
### Getting Help
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
# Show all commands
|
|
265
|
+
apertodns --help
|
|
266
|
+
|
|
267
|
+
# Check current status
|
|
268
|
+
apertodns --status
|
|
269
|
+
|
|
270
|
+
# Verify authentication
|
|
271
|
+
apertodns --verify
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Security
|
|
275
|
+
|
|
276
|
+
- Credentials are stored locally, never transmitted except to ApertoDNS servers
|
|
277
|
+
- API keys support granular scopes for least-privilege access
|
|
278
|
+
- All API communication uses HTTPS
|
|
279
|
+
- No cross-account data access - strict user isolation
|
|
280
|
+
|
|
281
|
+
## Examples
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
# Quick status check
|
|
285
|
+
apertodns --status
|
|
286
|
+
|
|
287
|
+
# Test DNS propagation
|
|
288
|
+
apertodns --test myserver.apertodns.com
|
|
289
|
+
|
|
290
|
+
# Create domain and get token
|
|
291
|
+
apertodns --add-domain newserver.apertodns.com
|
|
292
|
+
|
|
293
|
+
# List domains as JSON
|
|
294
|
+
apertodns --domains --json
|
|
295
|
+
|
|
296
|
+
# Use API key for automation
|
|
297
|
+
APERTODNS_API_KEY=ak_xxx... apertodns --domains --json
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
## Links
|
|
301
|
+
|
|
302
|
+
- **Website**: [apertodns.com](https://apertodns.com)
|
|
303
|
+
- **Dashboard**: [apertodns.com/dashboard](https://apertodns.com/dashboard)
|
|
304
|
+
- **Documentation**: [apertodns.com/docs](https://apertodns.com/docs)
|
|
305
|
+
- **Issues**: [GitHub Issues](https://github.com/1r0n3d3v3l0per/apertodns/issues)
|
|
306
|
+
|
|
307
|
+
## Support
|
|
308
|
+
|
|
309
|
+
Need help?
|
|
310
|
+
- Open an issue on [GitHub](https://github.com/1r0n3d3v3l0per/apertodns/issues)
|
|
311
|
+
- Email: support@apertodns.com
|
|
312
|
+
|
|
313
|
+
## License
|
|
314
|
+
|
|
315
|
+
MIT - [Aperto Network](https://apertodns.com)
|
package/index.js
CHANGED
|
@@ -397,7 +397,7 @@ const showDomainsList = async () => {
|
|
|
397
397
|
});
|
|
398
398
|
|
|
399
399
|
domains.forEach(d => {
|
|
400
|
-
const status = d.
|
|
400
|
+
const status = d.ip ? green('● ONLINE') : red('● OFFLINE');
|
|
401
401
|
const lastUpdate = d.lastUpdated
|
|
402
402
|
? new Date(d.lastUpdated).toLocaleString("it-IT", { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' })
|
|
403
403
|
: gray('Mai');
|
|
@@ -405,7 +405,7 @@ const showDomainsList = async () => {
|
|
|
405
405
|
table.push([
|
|
406
406
|
status,
|
|
407
407
|
chalk.bold(d.name),
|
|
408
|
-
d.
|
|
408
|
+
d.ip || gray('N/D'),
|
|
409
409
|
`${d.ttl}s`,
|
|
410
410
|
lastUpdate
|
|
411
411
|
]);
|
|
@@ -488,7 +488,7 @@ const deleteDomain = async (name) => {
|
|
|
488
488
|
name: "selected",
|
|
489
489
|
message: "Quale dominio vuoi eliminare?",
|
|
490
490
|
choices: domains.map(d => ({
|
|
491
|
-
name: `${d.
|
|
491
|
+
name: `${d.ip ? green('●') : red('●')} ${d.name}`,
|
|
492
492
|
value: d.name
|
|
493
493
|
}))
|
|
494
494
|
}]);
|
|
@@ -1038,7 +1038,7 @@ const showStatsCommand = async () => {
|
|
|
1038
1038
|
console.log(JSON.stringify({
|
|
1039
1039
|
summary: {
|
|
1040
1040
|
totalDomains: domains.length,
|
|
1041
|
-
onlineDomains: domains.filter(d => d.
|
|
1041
|
+
onlineDomains: domains.filter(d => d.ip).length,
|
|
1042
1042
|
totalTokens: tokens.length,
|
|
1043
1043
|
activeTokens: tokens.filter(t => t.active).length
|
|
1044
1044
|
},
|
|
@@ -1060,7 +1060,7 @@ const showStatsCommand = async () => {
|
|
|
1060
1060
|
└─────────────────┘`;
|
|
1061
1061
|
|
|
1062
1062
|
const box3 = `┌─────────────────┐
|
|
1063
|
-
│ ${cyan.bold(String(domains.filter(d => d.
|
|
1063
|
+
│ ${cyan.bold(String(domains.filter(d => d.ip).length).padStart(2))} Online │
|
|
1064
1064
|
└─────────────────┘`;
|
|
1065
1065
|
|
|
1066
1066
|
console.log(gray(box1.split('\n')[0] + ' ' + box2.split('\n')[0] + ' ' + box3.split('\n')[0]));
|
|
@@ -1209,8 +1209,8 @@ const showDashboardCommand = async () => {
|
|
|
1209
1209
|
currentIp: ipRes?.trim() || null,
|
|
1210
1210
|
domains: {
|
|
1211
1211
|
total: domains.length,
|
|
1212
|
-
online: domains.filter(d => d.
|
|
1213
|
-
list: domains.map(d => ({ name: d.name, ip: d.
|
|
1212
|
+
online: domains.filter(d => d.ip).length,
|
|
1213
|
+
list: domains.map(d => ({ name: d.name, ip: d.ip, lastUpdated: d.lastUpdated }))
|
|
1214
1214
|
},
|
|
1215
1215
|
tokens: {
|
|
1216
1216
|
total: tokens.length,
|
|
@@ -1230,7 +1230,7 @@ const showDashboardCommand = async () => {
|
|
|
1230
1230
|
console.log();
|
|
1231
1231
|
|
|
1232
1232
|
// Stats row
|
|
1233
|
-
const onlineDomains = domains.filter(d => d.
|
|
1233
|
+
const onlineDomains = domains.filter(d => d.ip).length;
|
|
1234
1234
|
const activeTokens = tokens.filter(t => t.active).length;
|
|
1235
1235
|
|
|
1236
1236
|
console.log(` ┌──────────────┬──────────────┬──────────────┬──────────────┐`);
|
|
@@ -1243,8 +1243,8 @@ const showDashboardCommand = async () => {
|
|
|
1243
1243
|
if (domains.length > 0) {
|
|
1244
1244
|
console.log(` ${gray('Ultimi domini:')}`);
|
|
1245
1245
|
domains.slice(0, 5).forEach(d => {
|
|
1246
|
-
const status = d.
|
|
1247
|
-
console.log(` ${status} ${chalk.bold(d.name)} ${gray('→')} ${d.
|
|
1246
|
+
const status = d.ip ? green('●') : red('●');
|
|
1247
|
+
console.log(` ${status} ${chalk.bold(d.name)} ${gray('→')} ${d.ip || gray('N/D')}`);
|
|
1248
1248
|
});
|
|
1249
1249
|
if (domains.length > 5) console.log(` ${gray(`... e altri ${domains.length - 5}`)}`);
|
|
1250
1250
|
}
|
package/package.json
CHANGED