portok 1.0.3 → 1.0.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/portok.js +69 -35
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "portok",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "Zero-downtime deployment proxy - routes traffic through a stable port to internal app instances with health-gated switching",
5
5
  "main": "portokd.js",
6
6
  "bin": {
package/portok.js CHANGED
@@ -353,46 +353,80 @@ async function cmdInit(options) {
353
353
  results.push({ path: stateDir, status: 'error', error: err.message });
354
354
  }
355
355
 
356
- // Install systemd template unit
356
+ // Install systemd template unit (embedded content)
357
357
  const systemdDest = path.join(systemdDir, serviceFileName);
358
+ const serviceContent = `# Portok systemd template unit for multi-instance deployments
359
+ # Auto-generated by: portok init
360
+
361
+ [Unit]
362
+ Description=Portok Zero-Downtime Proxy (%i)
363
+ After=network.target
364
+ Documentation=https://github.com/nicatdursunlu/portok
365
+
366
+ [Service]
367
+ Type=simple
368
+ User=www-data
369
+ Group=www-data
370
+
371
+ # Instance configuration from env file
372
+ EnvironmentFile=/etc/portok/%i.env
373
+
374
+ # Set instance name automatically from systemd specifier
375
+ Environment=INSTANCE_NAME=%i
376
+
377
+ # Working directory
378
+ WorkingDirectory=/opt/portok
379
+
380
+ # Start the daemon
381
+ ExecStart=/usr/bin/node /opt/portok/portokd.js
382
+
383
+ # Restart policy
384
+ Restart=always
385
+ RestartSec=5
386
+ StartLimitBurst=5
387
+ StartLimitIntervalSec=60
388
+
389
+ # Logging
390
+ StandardOutput=journal
391
+ StandardError=journal
392
+ SyslogIdentifier=portok-%i
393
+
394
+ # Security hardening
395
+ NoNewPrivileges=true
396
+ ProtectSystem=strict
397
+ ProtectHome=true
398
+ PrivateTmp=true
399
+ ProtectKernelTunables=true
400
+ ProtectKernelModules=true
401
+ ProtectControlGroups=true
402
+
403
+ # Allow writing to state directory
404
+ ReadWritePaths=/var/lib/portok
405
+
406
+ # Network access (required for proxying)
407
+ RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
408
+
409
+ [Install]
410
+ WantedBy=multi-user.target
411
+ `;
412
+
358
413
  try {
359
- // Find the service file relative to this script
360
- const scriptDir = path.dirname(process.argv[1]);
361
- const possiblePaths = [
362
- path.join(scriptDir, serviceFileName),
363
- path.join(scriptDir, '..', serviceFileName),
364
- '/opt/portok/' + serviceFileName,
365
- ];
414
+ const existingContent = fs.existsSync(systemdDest) ? fs.readFileSync(systemdDest, 'utf-8') : null;
366
415
 
367
- let sourceFile = null;
368
- for (const p of possiblePaths) {
369
- if (fs.existsSync(p)) {
370
- sourceFile = p;
371
- break;
372
- }
373
- }
374
-
375
- if (sourceFile) {
376
- const content = fs.readFileSync(sourceFile, 'utf-8');
377
- const existingContent = fs.existsSync(systemdDest) ? fs.readFileSync(systemdDest, 'utf-8') : null;
416
+ if (existingContent === serviceContent) {
417
+ results.push({ path: systemdDest, status: 'exists' });
418
+ } else {
419
+ fs.writeFileSync(systemdDest, serviceContent, { mode: 0o644 });
420
+ results.push({ path: systemdDest, status: 'created' });
378
421
 
379
- if (existingContent === content) {
380
- results.push({ path: systemdDest, status: 'exists' });
381
- } else {
382
- fs.writeFileSync(systemdDest, content, { mode: 0o644 });
383
- results.push({ path: systemdDest, status: 'created' });
384
-
385
- // Reload systemd daemon
386
- try {
387
- const { execSync } = require('child_process');
388
- execSync('systemctl daemon-reload', { stdio: 'pipe' });
389
- results.push({ path: 'systemctl daemon-reload', status: 'created' });
390
- } catch (e) {
391
- // Ignore if systemctl not available (e.g., in Docker)
392
- }
422
+ // Reload systemd daemon
423
+ try {
424
+ const { execSync } = require('child_process');
425
+ execSync('systemctl daemon-reload', { stdio: 'pipe' });
426
+ results.push({ path: 'systemctl daemon-reload', status: 'created' });
427
+ } catch (e) {
428
+ // Ignore if systemctl not available (e.g., in Docker)
393
429
  }
394
- } else {
395
- results.push({ path: systemdDest, status: 'skipped', error: 'Template file not found' });
396
430
  }
397
431
  } catch (err) {
398
432
  results.push({ path: systemdDest, status: 'error', error: err.message });