ops: add isolated AnyTLS node onboarding workflow
This commit is contained in:
commit
31c22f71be
25
dpl-node.service
Normal file
25
dpl-node.service
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=dpl isolated AnyTLS node backend
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=/var/lib/dpl-node
|
||||||
|
EnvironmentFile=/etc/dpl-node/secret.env
|
||||||
|
ExecStart=/opt/dpl-node/xboard-node -c /etc/dpl-node/config.yml
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
UMask=0077
|
||||||
|
NoNewPrivileges=true
|
||||||
|
PrivateTmp=true
|
||||||
|
ProtectSystem=strict
|
||||||
|
ProtectHome=true
|
||||||
|
ReadWritePaths=/var/lib/dpl-node
|
||||||
|
MemoryHigh=450M
|
||||||
|
MemoryMax=600M
|
||||||
|
CPUQuota=100%
|
||||||
|
LimitNOFILE=65536
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
21
install-node.sh
Normal file
21
install-node.sh
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
# Credential files are installed separately with mode 0600.
|
||||||
|
[[ $(id -u) == 0 ]] || exit 1
|
||||||
|
[[ -s /etc/dpl-node/config.yml && -s /etc/dpl-node/secret.env ]] || { echo 'Private node configuration missing'; exit 1; }
|
||||||
|
if ss -lntH '( sport = :24443 )' | grep -q .; then
|
||||||
|
echo 'Port 24443 already in use; inspect before deployment'; exit 1
|
||||||
|
fi
|
||||||
|
systemctl is-active --quiet XrayR
|
||||||
|
install -d -m 755 /opt/dpl-node
|
||||||
|
install -d -m 700 /var/lib/dpl-node /var/lib/dpl-node/kernel
|
||||||
|
curl --fail --location --silent --show-error \
|
||||||
|
https://github.com/cedar2025/Xboard-Node/releases/download/v1.13/xboard-node-linux-amd64 \
|
||||||
|
-o /opt/dpl-node/xboard-node.new
|
||||||
|
echo '55bf71fa9d9f2048d3255ae7c0af929a41897ca7743f6ead34132a6ca4c79043 /opt/dpl-node/xboard-node.new' | sha256sum --check
|
||||||
|
chmod 755 /opt/dpl-node/xboard-node.new
|
||||||
|
mv /opt/dpl-node/xboard-node.new /opt/dpl-node/xboard-node
|
||||||
|
/opt/dpl-node/xboard-node -v
|
||||||
|
install -m 644 "$(dirname "$0")/dpl-node.service" /etc/systemd/system/dpl-node.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
echo 'Binary and independent unit installed. Obtain certificate before starting.'
|
||||||
80
stage.php
Normal file
80
stage.php
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<?php
|
||||||
|
// Run from the production application root. All credential output is private.
|
||||||
|
require getcwd() . '/vendor/autoload.php';
|
||||||
|
$app = require getcwd() . '/bootstrap/app.php';
|
||||||
|
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\ServerGroup;
|
||||||
|
use App\Models\ServerMachine;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
$opts = getopt('', ['key:', 'name:', 'relay-host:', 'relay-port:', 'listen-port:', 'tls-domain:', 'backup:']);
|
||||||
|
foreach (['key', 'name', 'relay-host', 'relay-port', 'listen-port', 'tls-domain', 'backup'] as $key) {
|
||||||
|
if (empty($opts[$key])) throw new RuntimeException("Missing --$key");
|
||||||
|
}
|
||||||
|
if (!preg_match('/^[a-z0-9-]+$/', $opts['key'])) throw new RuntimeException('Invalid key');
|
||||||
|
foreach (['relay-port', 'listen-port'] as $key) {
|
||||||
|
if (!ctype_digit((string)$opts[$key]) || $opts[$key] < 1024 || $opts[$key] > 65535) throw new RuntimeException('Invalid port');
|
||||||
|
}
|
||||||
|
$dir = rtrim($opts['backup'], '/');
|
||||||
|
umask(0077);
|
||||||
|
if (!is_dir($dir) && !mkdir($dir, 0700, true)) throw new RuntimeException('Backup creation failed');
|
||||||
|
if (is_file("$dir/manifest.json")) {
|
||||||
|
$manifest = json_decode(file_get_contents("$dir/manifest.json"), true, flags: JSON_THROW_ON_ERROR);
|
||||||
|
if ($manifest['key'] !== $opts['key']) throw new RuntimeException('Backup belongs to another node');
|
||||||
|
echo json_encode(['already_staged' => true, 'node_id' => $manifest['node_id']]) . PHP_EOL;
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (ServerMachine::where('name', 'dpl-' . $opts['key'])->exists() || Server::where('name', $opts['name'])->exists()) {
|
||||||
|
throw new RuntimeException('Existing resources found without this backup manifest');
|
||||||
|
}
|
||||||
|
file_put_contents("$dir/before.json", json_encode([
|
||||||
|
'servers' => DB::table('v2_server')->get(),
|
||||||
|
'groups' => DB::table('v2_server_group')->get(),
|
||||||
|
'machines' => DB::table('v2_server_machine')->get(),
|
||||||
|
], JSON_THROW_ON_ERROR));
|
||||||
|
|
||||||
|
$manifest = DB::transaction(function () use ($opts) {
|
||||||
|
$group = ServerGroup::create(['name' => 'dpl 接入验收 ' . $opts['key']]);
|
||||||
|
$machine = ServerMachine::create([
|
||||||
|
'name' => 'dpl-' . $opts['key'], 'notes' => 'Independent AnyTLS service; existing XrayR preserved',
|
||||||
|
'is_active' => true, 'token' => ServerMachine::generateToken(),
|
||||||
|
]);
|
||||||
|
$node = Server::create([
|
||||||
|
'name' => $opts['name'], 'type' => 'anytls', 'host' => $opts['relay-host'],
|
||||||
|
'port' => (string)$opts['relay-port'], 'server_port' => (string)$opts['listen-port'],
|
||||||
|
'group_ids' => [(string)$group->id], 'route_ids' => [], 'tags' => [],
|
||||||
|
'rate' => 1, 'show' => true, 'enabled' => true, 'machine_id' => $machine->id, 'sort' => 1,
|
||||||
|
'protocol_settings' => ['tls' => ['server_name' => $opts['tls-domain'], 'allow_insecure' => false]],
|
||||||
|
'cert_config' => [
|
||||||
|
'cert_mode' => 'file', 'domain' => $opts['tls-domain'],
|
||||||
|
'cert_file' => '/etc/letsencrypt/live/' . $opts['tls-domain'] . '/fullchain.pem',
|
||||||
|
'key_file' => '/etc/letsencrypt/live/' . $opts['tls-domain'] . '/privkey.pem',
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
$user = new User([
|
||||||
|
'email' => 'node-qa-' . $opts['key'] . '-' . Str::lower(Str::random(8)) . '@example.invalid',
|
||||||
|
'password' => password_hash(Str::random(40), PASSWORD_BCRYPT),
|
||||||
|
'uuid' => (string)Str::uuid(), 'token' => Str::random(32),
|
||||||
|
'group_id' => $group->id, 'transfer_enable' => 104857600,
|
||||||
|
'expired_at' => time() + 86400, 'banned' => 0, 'is_admin' => 0,
|
||||||
|
'remind_expire' => 0, 'remind_traffic' => 0, 'device_limit' => 2,
|
||||||
|
]);
|
||||||
|
$user->saveQuietly();
|
||||||
|
return ['key' => $opts['key'], 'node_id' => $node->id, 'machine_id' => $machine->id,
|
||||||
|
'group_id' => $group->id, 'test_user_id' => $user->id];
|
||||||
|
});
|
||||||
|
file_put_contents("$dir/manifest.json", json_encode($manifest, JSON_THROW_ON_ERROR));
|
||||||
|
$machine = ServerMachine::findOrFail($manifest['machine_id']);
|
||||||
|
$user = User::findOrFail($manifest['test_user_id']);
|
||||||
|
$config = "panel:\n url: \"https://dp-link.net\"\nmachine:\n machine_id: {$machine->id}\n token_env: DPL_MACHINE_TOKEN\nkernel:\n type: singbox\n config_dir: /var/lib/dpl-node/kernel\nlog:\n level: info\nruntime:\n gomemlimit: 384MiB\n gogc: 75\nnode:\n push_interval: 30\n pull_interval: 30\n";
|
||||||
|
file_put_contents("$dir/node-config.yml", $config);
|
||||||
|
file_put_contents("$dir/node-secret.env", 'DPL_MACHINE_TOKEN=' . $machine->token . "\n");
|
||||||
|
file_put_contents("$dir/qa-private.json", json_encode([
|
||||||
|
'user_id' => $user->id, 'uuid' => $user->uuid, 'subscribe_token' => $user->token,
|
||||||
|
'host' => $opts['relay-host'], 'port' => (int)$opts['relay-port'], 'sni' => $opts['tls-domain'],
|
||||||
|
], JSON_THROW_ON_ERROR));
|
||||||
|
echo json_encode($manifest, JSON_UNESCAPED_UNICODE) . PHP_EOL;
|
||||||
Loading…
Reference in New Issue
Block a user