Skip to Content
ConfigurationDeployment

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

PropertyTypeDefaultDescription
targetstringRequired. SSH connection string (e.g., root@185.47.172.104).
sshKeystringPath to the private key. Supports ~/, relative paths, and vault:// URIs.
sshPortnumber22SSH port on the target host.
methodrsync | gitrsyncSynchronization mechanism.
repositorystringRemote Git repository URL (required if method is git).
runtimestringnode:22-slimDocker image used for the prepare step isolation (e.g., php:8.2-cli).
preparestringCommand executed inside the runtime container on the remote host after sync.
prunestring[]['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 .gitignore rules
  • 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:

  1. Code Sync: Nanokit copies your source code to the VPS host.
  2. Container Launch: Nanokit starts a container using the image specified in runtime (defaults to node:22-slim).
  3. Volume Mounting: The project folder is mounted into the container at /workspace.
  4. Persistent Cache:
    • For Node runtimes: Nanokit automatically creates a persistent Docker volume for node_modules to speed up subsequent deployments.
    • For PHP runtimes: Nanokit creates a volume for vendor and composer cache.
  5. Execution: The prepare command is executed inside the container via sh -c.
  6. 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 migrate

SSH Key Handling

Nanokit supports three SSH key formats:

File Path

deploy: sshKey: ~/.ssh/id_nanokit

Relative Path

deploy: sshKey: .nanokit-mock/id_rsa

Vault-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:

  1. Docker Engine — Installs if not present
  2. UFW Firewall — Configures rules for ports 80, 443
  3. Project Directory — Creates /opt/nanokit/projects/<name>/

You can also pre-bootstrap a server manually:

nkapp host setup stage

SSL 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

  1. The deploy command runs a cache pruning step by default (--cache flag is false).
  2. It reads the deploy.prune configuration to determine which directories to delete.
  3. If prune is not defined, it defaults to cleaning only the dist directory.
  4. If defined, it deletes only the specified paths — no additional defaults are applied.

[!IMPORTANT] The cache pruning is enabled by default (--cache is false). To skip pruning, pass --cache to 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/*/dist

This configuration tells Nanokit to clean:

  • .next build caches for all Next.js apps (apps/website/.next, apps/docs/.next, etc.)
  • The top-level dist directory
  • 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-offline

Production 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