@fabioplunser/epd 0.1.0

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/docs/guide.md ADDED
@@ -0,0 +1,576 @@
1
+ # Complete Guide to epd (Easy Project Deployer)
2
+
3
+ `epd` is a zero-downtime deployment tool designed to deploy any application to one server or a fleet of servers over standard SSH. It combines zero-downtime blue/green deployments, automatic Let's Encrypt SSL, a shared reverse proxy (Traefik), and multi-host load balancing without requiring Kubernetes or complex container orchestration.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Key Features & Architecture](#1-key-features--architecture)
10
+ 2. [Prerequisites & Installation](#2-prerequisites--installation)
11
+ 3. [Quick Start (5 Minutes)](#3-quick-start-5-minutes)
12
+ 4. [Deployment Modes: Docker vs. Process](#4-deployment-modes-docker-vs-process)
13
+ 5. [The Blue/Green Zero-Downtime Lifecycle](#5-the-bluegreen-zero-downtime-lifecycle)
14
+ 6. [Multi-Site Hosting on a Single VPS](#6-multi-site-hosting-on-a-single-vps)
15
+ 7. [High Availability & Multi-Server Clustering](#7-high-availability--multi-server-clustering)
16
+ 8. [Advanced Routing & Traefik Features](#8-advanced-routing--traefik-features)
17
+ 9. [Secrets & Environment Management](#9-secrets--environment-management)
18
+ 10. [Accessories (Databases, Caches & Dashboards)](#10-accessories-databases-caches--dashboards)
19
+ 11. [CLI Commands Reference](#11-cli-commands-reference)
20
+ 12. [Configuration Reference (`epd.yml`)](#12-configuration-reference-epdyml)
21
+ 13. [Operations, Troubleshooting & Disaster Recovery](#13-operations-troubleshooting--disaster-recovery)
22
+
23
+ ---
24
+
25
+ ## 1. Key Features & Architecture
26
+
27
+ ```
28
+ Internet (HTTP:80 / HTTPS:443)
29
+
30
+
31
+ ┌─────────────────────────────────────────────────────────────┐
32
+ │ SERVER (Host) │
33
+ │ │
34
+ │ ┌───────────────────────────────────────────────────────┐ │
35
+ │ │ Shared Traefik Proxy (:80 / :443) │ │
36
+ │ │ Automatically routes traffic based on dynamic YAML │ │
37
+ │ └────────┬─────────────────────────────┬────────────────┘ │
38
+ │ │ │ │
39
+ │ ▼ ▼ │
40
+ │ ┌─────────────────────┐ ┌────────────────────────┐ │
41
+ │ │ App 1 (Blog) │ │ App 2 (Store) │ │
42
+ │ │ Blue/Green replicas │ │ Blue/Green replicas │ │
43
+ │ │ blog.example.com │ │ store.example.com │ │
44
+ │ └─────────────────────┘ └────────────────────────┘ │
45
+ │ │ │
46
+ │ ▼ │
47
+ │ ┌─────────────────────┐ │
48
+ │ │ Accessory: Postgres │ │
49
+ │ │ /var/lib/epd/... │ │
50
+ │ └─────────────────────┘ │
51
+ └─────────────────────────────────────────────────────────────┘
52
+ ```
53
+
54
+ ### Why epd?
55
+ - **Many Sites on One Server**: Every app maintains its own isolated dynamic routing file under `/var/lib/epd/proxy/dynamic/<app>.yml`. They share one global Traefik instance. Adding or removing an application leaves other apps on the same machine completely untouched.
56
+ - **Docker Optional (`mode: process`)**: If you don't want containers, `epd` uploads your code via `rsync`, installs dependencies, and manages processes using `pm2` with the same blue/green slot switching, health checks, and rollbacks.
57
+ - **True Zero Downtime**: The existing version continues serving live traffic until the new version passes all health checks and Traefik switches traffic. Old replicas are drained gracefully before being stopped.
58
+ - **Cross-Host Failover (`proxy.cross_host: true`)**: With multi-server setups, each server's proxy can route requests across the entire fleet. If a server goes offline, the other nodes immediately absorb the traffic.
59
+ - **SSH Only**: No agent daemons, no control planes, no vendor lock-in.
60
+
61
+ ---
62
+
63
+ ## 2. Prerequisites & Installation
64
+
65
+ ### Requirements
66
+ - **Local Machine**:
67
+ - [Bun](https://bun.sh) (v1.1+)
68
+ - `ssh` client
69
+ - `docker` (if using `mode: docker`)
70
+ - `rsync` (if using `mode: process`)
71
+ - **Remote Server(s)**:
72
+ - Any modern Linux machine (Ubuntu, Debian, Fedora, Arch, Alpine, etc.)
73
+ - Open SSH port with root or passwordless `sudo` access
74
+
75
+ ### Installation
76
+
77
+ Install globally using Bun:
78
+ ```bash
79
+ bun install -g epd
80
+ ```
81
+
82
+ Or run directly from source or git:
83
+ ```bash
84
+ git clone https://github.com/FabioPlunser/EPD.git
85
+ cd EPD && bun install
86
+ bun run src/cli.ts --help
87
+ ```
88
+
89
+ To compile a standalone, self-contained binary (no Bun runtime required on your local machine):
90
+ ```bash
91
+ bun run build # Produces dist/epd
92
+ sudo cp dist/epd /usr/local/bin/epd
93
+ ```
94
+
95
+ ---
96
+
97
+ ## 3. Quick Start (5 Minutes)
98
+
99
+ ### Step 1: Initialize Your Project
100
+ From inside your application directory:
101
+ ```bash
102
+ epd init
103
+ ```
104
+ This interactive command detects your runtime (Node, Bun, Python, Go, Ruby, etc.), suggests sensible defaults, creates `epd.yml`, and optionally generates a starter `Dockerfile`.
105
+
106
+ ### Step 2: Configure Your Servers
107
+ Edit `epd.yml`:
108
+ ```yaml
109
+ name: my-app
110
+ mode: docker
111
+ image: my-app
112
+
113
+ ssh:
114
+ user: root
115
+
116
+ servers:
117
+ web:
118
+ hosts: [203.0.113.10]
119
+ port: 3000
120
+ domains: [myapp.example.com]
121
+
122
+ proxy:
123
+ email: admin@example.com
124
+ ```
125
+
126
+ ### Step 3: Run Server Setup
127
+ ```bash
128
+ epd setup
129
+ ```
130
+ `epd setup`:
131
+ 1. Verifies SSH connectivity.
132
+ 2. Installs Docker (or PM2 and Node/Bun for process mode) if not already installed.
133
+ 3. Sets up the directory structure and reserved port blocks.
134
+ 4. Starts the shared Traefik proxy.
135
+ 5. Deploys your project.
136
+
137
+ ### Step 4: Subsequent Deployments
138
+ For every change thereafter:
139
+ ```bash
140
+ epd deploy
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 4. Deployment Modes: Docker vs. Process
146
+
147
+ `epd` supports two distinct runtimes configured via the top-level `mode` field.
148
+
149
+ ### Mode: `docker` (Default)
150
+ In Docker mode:
151
+ 1. `epd` builds an image locally (using BuildKit / buildx if available) tagged with the commit SHA.
152
+ 2. If a `registry:` is specified, the image is pushed and pulled by servers. If omitted, `epd` streams the image directly over SSH (`docker save | gzip | ssh ... docker load`).
153
+ 3. Replicas run in containers on a shared Docker bridge network (`epd`).
154
+ 4. Replicas communicate with Traefik using internal container DNS names (`http://epd-<app>-<service>-<slot>-<replica>:<port>`).
155
+
156
+ ```yaml
157
+ mode: docker
158
+ image: ghcr.io/my-org/my-app
159
+ registry:
160
+ server: ghcr.io
161
+ username: my-user
162
+ password: ${GITHUB_TOKEN}
163
+ ```
164
+
165
+ ### Mode: `process` (No Docker on Server)
166
+ In process mode:
167
+ 1. No Docker is needed on the remote host.
168
+ 2. `epd` uploads your code via `rsync` (or clean `git archive`) into `/var/lib/epd/apps/<app>/releases/<version>`.
169
+ 3. Runs your `install` and `build` commands on the host.
170
+ 4. Starts each replica under `pm2` with unique assigned host ports and environment variables.
171
+ 5. Traefik runs as a native binary managed by PM2, routing traffic to localhost ports.
172
+
173
+ ```yaml
174
+ mode: process
175
+
176
+ process:
177
+ install: bun install --frozen-lockfile
178
+ build: bun run build
179
+ start: bun run start
180
+ exclude: [".git", "node_modules", ".env", "dist"]
181
+
182
+ servers:
183
+ web:
184
+ hosts: [203.0.113.10]
185
+ replicas: 2
186
+ port: 3000
187
+ domains: [myapp.example.com]
188
+
189
+ proxy:
190
+ ssl: false
191
+ ```
192
+
193
+ ---
194
+
195
+ ## 5. The Blue/Green Zero-Downtime Lifecycle
196
+
197
+ Every deploy follows an automated zero-downtime sequence:
198
+
199
+ ```
200
+ [Build & Push/Ship]
201
+
202
+
203
+ [Start New Slot (e.g. Green)] ───► New replicas start on alternative slot
204
+
205
+
206
+ [Health Probe Verification] ───► If probes fail: Green is removed, Blue stays live!
207
+
208
+
209
+ [Atomic Route Switch] ───► Traefik dynamic config updated to point to Green
210
+
211
+
212
+ [Drain & Retire Old Slot] ───► In-flight requests complete; Blue slot retired
213
+ ```
214
+
215
+ 1. **Slots**: Each service alternates between `blue` and `green`.
216
+ 2. **Health Check**: Before any routing changes, `epd` executes an in-server probe against every new replica.
217
+ 3. **Safety Fallback**: If health checks fail or timeout, the new slot is killed and the current slot remains in service. Zero traffic is dropped.
218
+ 4. **Instant Rollback**: Because previous releases and images remain on the server, `epd rollback` can reactivate the previous version within seconds without rebuilding:
219
+ ```bash
220
+ epd rollback
221
+ ```
222
+
223
+ ---
224
+
225
+ ## 6. Multi-Site Hosting on a Single VPS
226
+
227
+ Kamal and other deploy tools often assume ownership of ports 80/443, making it painful to run multiple distinct web apps on a single machine.
228
+
229
+ With `epd`, every application writes its own isolated configuration file into Traefik's dynamic directory:
230
+ - Site A (`epd.yml` with `name: blog`): writes `/var/lib/epd/proxy/dynamic/blog.yml`
231
+ - Site B (`epd.yml` with `name: shop`): writes `/var/lib/epd/proxy/dynamic/shop.yml`
232
+
233
+ Both applications share the same server IP, the same Traefik instance, and automatic Let's Encrypt certificates without conflict. Removing Site B (`epd remove`) removes only `shop.yml`, leaving Site A operating seamlessly.
234
+
235
+ ---
236
+
237
+ ## 7. High Availability & Multi-Server Clustering
238
+
239
+ ### Across-Host Load Balancing (`proxy.cross_host: true`)
240
+
241
+ By default, Traefik routes traffic to replicas located on its own server. When you have multiple servers behind round-robin DNS or a cloud load balancer, set `proxy.cross_host: true`:
242
+
243
+ ```yaml
244
+ proxy:
245
+ cross_host: true
246
+ private_ips:
247
+ 203.0.113.10: 10.0.0.10
248
+ 203.0.113.11: 10.0.0.11
249
+
250
+ servers:
251
+ web:
252
+ hosts: [203.0.113.10, 203.0.113.11]
253
+ replicas: 2
254
+ port: 3000
255
+ domains: [example.com]
256
+ ```
257
+
258
+ With `cross_host: true`:
259
+ - The application port is published on each host (bound to the private IP when specified).
260
+ - Traefik on Server A balances across all replicas on Server A **and** Server B.
261
+ - If Server B goes down, visitors hitting Server B's DNS address will still be routed to Server A by Server A's proxy, guaranteeing high availability.
262
+
263
+ ### Deployment Strategy
264
+ Control rolling vs. parallel execution across multiple hosts:
265
+ ```yaml
266
+ strategy: rolling # Default: rolls one host at a time, keeping the cluster serving
267
+ # strategy: parallel # Deploys to all hosts simultaneously
268
+ ```
269
+
270
+ ---
271
+
272
+ ## 8. Advanced Routing & Traefik Features
273
+
274
+ Use the `routes:` block under any server group for fine-grained routing control:
275
+
276
+ ```yaml
277
+ servers:
278
+ web:
279
+ hosts: [203.0.113.10]
280
+ port: 3000
281
+ routes:
282
+ # 1. Standard Domain
283
+ - host: example.com
284
+
285
+ # 2. Subdomain to different container port
286
+ - host: api.example.com
287
+ port: 8080
288
+
289
+ # 3. Path-based routing with prefix stripping and Basic Auth
290
+ - host: example.com
291
+ path: /admin
292
+ port: 4000
293
+ strip_path: true
294
+ basic_auth:
295
+ - "admin:$apr1$xyz$0123456789abcdefghijk."
296
+
297
+ # 4. Domain Redirect (HTTP 301)
298
+ - host: www.example.com
299
+ redirect: https://example.com
300
+
301
+ # 5. Temporary Redirect (HTTP 302)
302
+ - host: promo.example.com
303
+ redirect: https://example.com/special
304
+ permanent: false
305
+
306
+ # 6. Sticky Session Load Balancing (Cookie pinned)
307
+ - host: app.example.com
308
+ path: /socket
309
+ sticky: true
310
+
311
+ # 7. Custom Headers
312
+ - host: secure.example.com
313
+ headers:
314
+ X-Frame-Options: "DENY"
315
+ X-Content-Type-Options: "nosniff"
316
+
317
+ # 8. Wildcard Subdomains (requires DNS challenge)
318
+ - host: "*.example.com"
319
+ priority: 1
320
+ ```
321
+
322
+ ### Let's Encrypt DNS Challenge
323
+ For wildcard certificates (`*.example.com`) or multi-server setups:
324
+ ```yaml
325
+ proxy:
326
+ challenge: dns
327
+ dns_provider: cloudflare
328
+ dns_env: [CF_DNS_API_TOKEN]
329
+ ```
330
+
331
+ ---
332
+
333
+ ## 9. Secrets & Environment Management
334
+
335
+ `epd` ensures secrets are never checked into git, never printed in `docker inspect`, and never written to shell histories.
336
+
337
+ ### Environment Declarations
338
+ ```yaml
339
+ env:
340
+ clear:
341
+ NODE_ENV: production
342
+ LOG_LEVEL: info
343
+ secret:
344
+ - DATABASE_URL
345
+ - STRIPE_SECRET_KEY
346
+ ```
347
+
348
+ ### How Secret Resolution Works
349
+ 1. When you run `epd deploy`, variables in `env.secret` are read from:
350
+ - Your local environment (`export DATABASE_URL=...`)
351
+ - `.env` / `.env.local` in your project root
352
+ - `.env.<destination>` (when using `--destination`)
353
+ 2. On the server, `epd` writes a `0600` root-owned environment file.
354
+ 3. Containers read secrets via `--env-file`; process mode loads them into PM2 environments.
355
+
356
+ ### Destination Overlays
357
+ Manage staging vs. production effortlessly:
358
+ ```bash
359
+ epd deploy -d staging
360
+ ```
361
+ Merges `epd.staging.yml` over `epd.yml` and loads `.env.staging`.
362
+
363
+ ---
364
+
365
+ ## 10. Accessories (Databases, Caches & Dashboards)
366
+
367
+ Accessories are persistent companion containers (like PostgreSQL, Redis, MinIO, or Adminer) that `epd` provisions and manages alongside your app. Unlike application containers, accessories are **not** replaced on every deploy.
368
+
369
+ ```yaml
370
+ accessories:
371
+ db:
372
+ image: postgres:17
373
+ host: 203.0.113.10
374
+ env:
375
+ clear:
376
+ POSTGRES_DB: myapp
377
+ secret:
378
+ - POSTGRES_PASSWORD
379
+ volumes:
380
+ - /var/lib/epd/volumes/myapp-db:/var/lib/postgresql/data
381
+ ports:
382
+ - "127.0.0.1:5432:5432"
383
+
384
+ redis:
385
+ image: redis:7-alpine
386
+ host: 203.0.113.10
387
+ volumes:
388
+ - /var/lib/epd/volumes/myapp-redis:/data
389
+
390
+ # Accessory with public HTTP routing through Traefik
391
+ db_ui:
392
+ image: adminer:latest
393
+ host: 203.0.113.10
394
+ port: 8080
395
+ domains: [db.myapp.example.com]
396
+ ```
397
+
398
+ ### Managing Accessories
399
+ - **View accessory status**: `epd status` shows accessory state and ports.
400
+ - **View accessory logs**: `epd logs --accessory db -f`
401
+ - **Execute commands in an accessory**: `epd exec --accessory db -i -- psql -U myapp`
402
+ - **Recreate accessory container**: `epd deploy --recreate-accessories`
403
+ - **Inspect Docker run command**: `epd docker-command` prints the exact `docker run` command for each accessory.
404
+
405
+ ---
406
+
407
+ ## 11. CLI Commands Reference
408
+
409
+ | Command | Flags | Description |
410
+ |---|---|---|
411
+ | `epd init` | `--name`, `--mode`, `--host`, `--domain`, `--port`, `--dockerfile` | Initialize a new `epd.yml` for the current project. |
412
+ | `epd setup` | `--skip-deploy`, `--host` | Install prerequisites on servers, start the proxy, and deploy. |
413
+ | `epd deploy` | `--version`, `--no-build`, `--service`, `--host`, `--skip-health`, `--skip-hooks`, `--skip-lock`, `--recreate-accessories`, `-d` | Build and deploy with zero downtime. |
414
+ | `epd redeploy` | `--service`, `--host`, `--skip-health`, `--skip-lock` | Restart the current version without rebuilding or uploading. |
415
+ | `epd rollback [v]`| `--list`, `--service`, `--host` | Roll back to the previous version or a specified version. |
416
+ | `epd status` | `--json` | Show running replicas, slots, health status, and live routes. |
417
+ | `epd logs` | `-f/--follow`, `-n/--lines`, `--service`, `--accessory`, `--host`, `--grep`, `--since` | View or tail logs from servers, services, or accessories. |
418
+ | `epd exec -- <cmd>`| `--host`, `--service`, `--accessory`, `--reuse`, `-i` | Run a one-off command with the app's image and environment. |
419
+ | `epd shell` | `--host`, `--service`, `--accessory` | Open an interactive shell inside a running replica or accessory. |
420
+ | `epd proxy <cmd>` | `status`, `reboot`, `logs`, `routes`, `remove` (`--host`, `-f`, `-n`) | Inspect, follow logs, or restart the shared Traefik proxy. |
421
+ | `epd config` | `--json`, `--raw`, `--traefik` | Validate and print the resolved configuration or Traefik specs. |
422
+ | `epd docker-command`| `--host`, `--service`, `--slot`, `--version`, `--replica` | Output copy-pasteable `docker run` / `pm2` commands. |
423
+ | `epd lock <cmd>` | `status`, `release` | Inspect or clear the atomic deploy lock. |
424
+ | `epd remove` | `-y/--yes`, `--keep-data`, `--host` | Stop this app, remove its routes, and delete files from servers. |
425
+
426
+ ---
427
+
428
+ ## 12. Configuration Reference (`epd.yml`)
429
+
430
+ Full annotated schema of `epd.yml`:
431
+
432
+ ```yaml
433
+ name: myapp # App name (alphanumeric, dashes, underscores)
434
+ mode: docker # docker | process
435
+
436
+ # Docker Build Settings
437
+ image: ghcr.io/org/myapp # Docker image repository (docker mode)
438
+ registry: # Optional: registry credentials
439
+ server: ghcr.io
440
+ username: deployer
441
+ password: ${GITHUB_TOKEN} # Interpolated from environment
442
+ build:
443
+ dockerfile: Dockerfile # Relative path to Dockerfile
444
+ context: . # Build context
445
+ platform: linux/amd64 # Target architecture
446
+ args: # Build arguments
447
+ COMMIT_SHA: ${GIT_SHA:-dev}
448
+ secrets: # BuildKit build secrets
449
+ npm_token: NPM_TOKEN
450
+
451
+ # Process Mode Settings
452
+ process:
453
+ install: bun install # Dependency install command
454
+ build: bun run build # Build command
455
+ start: bun run start # Start command (receives $PORT)
456
+ exclude: [".git", "node_modules"]
457
+ source: rsync # rsync | git
458
+
459
+ # SSH Configuration
460
+ ssh:
461
+ user: root # Remote SSH user
462
+ port: 22 # Remote SSH port
463
+ key: ~/.ssh/id_ed25519 # Optional explicit private key
464
+ proxy_jump: bastion.net # Optional Jump host / Bastion
465
+ options: # Extra SSH options
466
+ - ServerAliveInterval=30
467
+
468
+ # Server Definitions
469
+ servers:
470
+ web:
471
+ hosts: [203.0.113.10] # Server IPs or hostnames
472
+ replicas: 2 # Replicas per host
473
+ port: 3000 # Internal application port
474
+ domains: [myapp.com] # Domains to serve
475
+ cpus: "2.0" # CPU limit
476
+ memory: "1g" # Memory limit
477
+ drain: 10 # Seconds to drain old slot
478
+ stop_timeout: 15 # SIGTERM grace period in seconds
479
+ volumes:
480
+ - /var/lib/epd/volumes/uploads:/app/uploads
481
+ env:
482
+ clear:
483
+ APP_ENV: production
484
+ secret:
485
+ - APP_SECRET
486
+
487
+ worker: # Background worker (no exposed routes)
488
+ hosts: [203.0.113.10]
489
+ replicas: 1
490
+ command: bun run worker.ts
491
+
492
+ # Shared Reverse Proxy
493
+ proxy:
494
+ enabled: true
495
+ ssl: true # Automatically request Let's Encrypt certificates
496
+ email: admin@myapp.com # Registration email for ACME
497
+ challenge: http # http | dns | tlsalpn
498
+ entrypoints:
499
+ web: 80
500
+ websecure: 443
501
+ cross_host: false # Enable cross-server load balancing
502
+ reload_wait: 3 # Throttle duration for route changes
503
+
504
+ # Health Check Settings
505
+ healthcheck:
506
+ path: /health # HTTP path to probe (null for TCP-only check)
507
+ status: 200-399 # Acceptable status codes
508
+ timeout: 60 # Timeout in seconds
509
+ interval: 2 # Seconds between probe attempts
510
+ delay: 1 # Initial delay before probing
511
+
512
+ # Global Environment
513
+ env:
514
+ clear:
515
+ NODE_ENV: production
516
+ secret:
517
+ - DATABASE_URL
518
+
519
+ # Lifecycle Hooks
520
+ hooks:
521
+ pre_build: ./scripts/lint.sh
522
+ pre_deploy: ./scripts/db-migrate.sh
523
+ post_deploy: ./scripts/notify-slack.sh
524
+ on_failure: ./scripts/alert-ops.sh
525
+
526
+ # Deployment Strategy
527
+ strategy: rolling # rolling | parallel
528
+ keep_releases: 5 # Retain last N images / release directories
529
+ remote_root: /var/lib/epd # Root directory on remote hosts
530
+ ```
531
+
532
+ ---
533
+
534
+ ## 13. Operations, Troubleshooting & Disaster Recovery
535
+
536
+ ### Common Scenarios
537
+
538
+ #### 1. Deployment Fails on Health Check
539
+ - **What Happened**: New replicas started, but `/health` (or `/`) did not return `200-399` within the timeout.
540
+ - **Result**: The new replicas were automatically purged. The previous slot is still live. Zero downtime occurred.
541
+ - **Investigation**:
542
+ ```bash
543
+ epd logs --service web --lines 50
544
+ ```
545
+ - **Remedy**: Fix the issue, or adjust `healthcheck.timeout` / `healthcheck.path` in `epd.yml`.
546
+
547
+ #### 2. Deploy Lock Held
548
+ - **What Happened**: A previous deploy process was terminated abruptly (e.g. laptop closed or killed with `kill -9`).
549
+ - **Investigation**:
550
+ ```bash
551
+ epd lock status
552
+ ```
553
+ - **Remedy**:
554
+ ```bash
555
+ epd lock release
556
+ ```
557
+
558
+ #### 3. Inspecting Server Routes
559
+ To see the exact Traefik route file epd generated on the server:
560
+ ```bash
561
+ epd proxy routes
562
+ ```
563
+
564
+ #### 4. Checking Proxy Health & Restarting
565
+ If you updated global proxy options (such as adding an entrypoint or enabling the dashboard):
566
+ ```bash
567
+ epd proxy status
568
+ epd proxy reboot
569
+ ```
570
+
571
+ #### 5. Completely Removing an Application
572
+ When decommissioning an app from your servers:
573
+ ```bash
574
+ epd remove
575
+ ```
576
+ This cleans up all replicas, releases, and Traefik dynamic routes without touching any other epd applications sharing the machine.
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@fabioplunser/epd",
3
+ "version": "0.1.0",
4
+ "description": "Easy Project Deployer — deploy any project to one or many servers with Docker or PM2, fronted by Traefik.",
5
+ "type": "module",
6
+ "author": "Fabio Plünser",
7
+ "license": "MIT",
8
+ "homepage": "https://github.com/FabioPlunser/epd#readme",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/FabioPlunser/epd.git"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/FabioPlunser/epd/issues"
15
+ },
16
+ "keywords": [
17
+ "deployment",
18
+ "docker",
19
+ "traefik",
20
+ "zero-downtime",
21
+ "devops",
22
+ "pm2",
23
+ "cli"
24
+ ],
25
+ "bin": {
26
+ "epd": "bin/epd.js",
27
+ "edp": "bin/epd.js"
28
+ },
29
+ "files": [
30
+ "bin",
31
+ "dist/cli.js",
32
+ "README.md",
33
+ "LICENSE",
34
+ "docs"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ },
39
+ "scripts": {
40
+ "start": "bun run src/cli.ts",
41
+ "build": "bun run build:bundle && bun run build:binary",
42
+ "build:bundle": "bun build src/cli.ts --target=bun --outfile dist/cli.js",
43
+ "build:binary": "bun build --compile --minify --sourcemap src/cli.ts --outfile dist/epd",
44
+ "build:binaries": "bun run scripts/build-all.ts",
45
+ "typecheck": "tsc --noEmit",
46
+ "test": "bun test",
47
+ "prepublishOnly": "bun run typecheck && bun test && bun run build:bundle"
48
+ },
49
+ "engines": {
50
+ "bun": ">=1.1.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/bun": "latest",
54
+ "typescript": "^5.6.0"
55
+ }
56
+ }