Deployment (deploy)
The deploy block defines how Nanokit communicates with and prepares your remote target host. It can be defined globally or per-environment.
Property Reference
| Property | Type | Default | Description |
|---|---|---|---|
target | string | — | Required. SSH connection string (e.g., root@185.47.172.104). |
sshKey | string | — | Path to the private key. Supports ~/, relative paths, and vault:// URIs. |
sshPort | number | 22 | SSH port on the target host. |
method | rsync | git | rsync | Synchronization mechanism. |
repository | string | — | Remote Git repository URL (required if method is git). |
runtime | string | node:22-slim | Docker image used for the prepare step isolation (e.g., php:8.2-cli). |
prepare | string | — | Command executed inside the runtime container on the remote host after sync. |
prune | string[] | ['dist'] | List of directory paths to delete on the remote host before the prepare step. Required if your build outputs artifacts in non-standard locations (e.g., .next, apps/*/dist). See Cache Pruning below. |
Synchronization Methods
rsync (Default)
The fastest way to deploy. Nanokit performs an incremental file sync from your local machine to the target server:
- Respects
.gitignorerules - Only transfers modified file chunks
- Ideal for iterative development and staging
git
The target server performs a git pull from your repository:
- Ensures only committed code is deployed
- Ideal for CI/CD and production environments
- Requires the repository to be cloned on the remote host
Isolated Build (prepare)
Nanokit enforces Build Isolation by default. When you define a prepare script, Nanokit launches an ephemeral Docker container on the target host to execute the setup tasks. This ensures your VPS host remains clean and that different projects can use different build runtimes without version conflicts.
How it works:
- Code Sync: Nanokit copies your source code to the VPS host.
- Container Launch: Nanokit starts a container using the image specified in
runtime(defaults tonode:22-slim). - Volume Mounting: The project folder is mounted into the container at
/workspace. - Persistent Cache:
- For Node runtimes: Nanokit automatically creates a persistent Docker volume for
node_modulesto speed up subsequent deployments. - For PHP runtimes: Nanokit creates a volume for
vendorand composer cache.
- For Node runtimes: Nanokit automatically creates a persistent Docker volume for
- Execution: The
preparecommand is executed inside the container viash -c. - Cleanup: The container is automatically removed (
--rm) after the build completes.
Example: Custom PHP Build
deploy:
runtime: php:8.2-cli
prepare: composer install --no-dev && php artisan migrateSSH Key Handling
Nanokit supports three SSH key formats:
File Path
deploy:
sshKey: ~/.ssh/id_nanokitRelative Path
deploy:
sshKey: .nanokit-mock/id_rsaVault-Backed Ephemeral Key
When the sshKey value is a vault:// URI, Nanokit resolves the raw PEM key from Vault, writes it to a temporary file with strict permissions (0600), uses it for the connection, and deletes it immediately after deployment.
deploy:
sshKey: "vault://infra/ssh#private_key"[!IMPORTANT] Ephemeral keys never persist on disk. They exist only for the duration of the deployment operation.
VPS Bootstrap
When deploying to a fresh server, Nanokit’s nkapp deploy command automatically detects missing dependencies and offers to bootstrap the VPS:
- Docker Engine — Installs if not present
- UFW Firewall — Configures rules for ports 80, 443
- Project Directory — Creates
/opt/nanokit/projects/<name>/
You can also pre-bootstrap a server manually:
nkapp host setup stageSSL Factory Reset
When deploying to public domains (.app, .dev, etc.), Nanokit automatically purges stale Caddy certificates on the remote host to force fresh ACME challenges. This prevents SSL errors from expired or mismatched certificates.
Cache Pruning
When deploying to a remote host, Nanokit automatically cleans build artifacts before executing the prepare step. This prevents stale files from previous deployments from interfering with the new build.
How it works
- The
deploycommand runs a cache pruning step by default (--cacheflag isfalse). - It reads the
deploy.pruneconfiguration to determine which directories to delete. - If
pruneis not defined, it defaults to cleaning only thedistdirectory. - If defined, it deletes only the specified paths — no additional defaults are applied.
[!IMPORTANT] The cache pruning is enabled by default (
--cacheisfalse). To skip pruning, pass--cacheto the deploy command.
Why define prune?
If your project produces build artifacts in multiple directories — for example, a monorepo with Next.js apps and Vite apps — you must list all of them in the prune section.
Otherwise, stale artifacts (like old .next caches or previous apps/*/dist outputs) will remain on the remote host and can cause:
- Conflicting build outputs resulting in runtime errors
- Serving outdated content after deployment
- Unexpected disk usage from accumulated artifacts
Example
deploy:
method: rsync
runtime: node:22
prepare: npm run build:all
prune:
- apps/*/.next
- dist
- apps/*/distThis configuration tells Nanokit to clean:
.nextbuild caches for all Next.js apps (apps/website/.next,apps/docs/.next, etc.)- The top-level
distdirectory - Vite/other build outputs in
apps/*/dist(apps/admin/dist,apps/hub/dist, etc.)
Remote Directory Structure
On the target host, Nanokit creates the following layout:
/opt/nanokit/
└── projects/
└── <project-name>/
├── [your project files]
└── .nanokit/
└── gateway/
└── data/
└── caddy/Examples
Staging with Mock VPS
environments:
stage:
deploy:
target: root@localhost
sshPort: 2222
sshKey: .nanokit-mock/id_rsa
method: rsync
prepare: npm install --prefer-offlineProduction with Vault
environments:
production:
deploy:
target: root@185.47.172.104
sshKey: vault://infra/ssh#private_key
method: rsync
runtime: node:22-slim
prepare: npm ci && npm run build:all