- JavaScript 86.4%
- TypeScript 6%
- Vue 4.9%
- Dockerfile 1.1%
- CSS 1%
- Other 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
|
||
| .gitea/workflows | ||
| assets | ||
| bin | ||
| scripts | ||
| src | ||
| templates/encore-nuxt | ||
| test | ||
| website | ||
| .gitignore | ||
| AGENTS.md | ||
| DEVTO.md | ||
| install.sh | ||
| package.json | ||
| paseo.json | ||
| README.md | ||
| USING_NSTACK.md | ||
nstack
nstack is a small release layer for Encore + Nuxt apps on Dokploy.
Install Node.js 22.23.4+, 24.22.1+, or 26.12.1+ before installing or updating
nstack. Version 0.1.165 enforces the October 2026 Node security release floor.
Existing apps must update their own Dockerfile Node pins and rebuild; updating
nstack alone does not replace deployed runtimes. In the nstack checkout, run
node scripts/upgrade-node-images.mjs /path/to/app/backend/Dockerfile /path/to/app/frontend/Dockerfile
for existing Node 22, 24, or 26 images, then review, test, and deploy the app.
Include any Node sidecar Dockerfiles. The script preserves distro variants and
requires manual review for older release lines.
Create and deploy an app:
curl -fsSL https://nstack.tech/install.sh | bash
nstack init my-app
cd my-app
nstack setup
nstack deploy
Interactive nstack init can link Dokploy by picking a saved Dokploy instance
or adding a new one, then asks you to pick an existing Git provider or add a
manual Git source. It also asks which package manager to use for init; the
Encore + Nuxt template currently supports pnpm and can remember it as the
default for new projects. In CI, use nstack configure with flags or env vars
for the same settings.
nstack init initializes a git repository when needed, creates the initial
init commit, and sets origin when a repository URL is configured. If the app
is created inside an existing worktree, nstack does not create a nested repo; it
commits only the new app directory into the parent worktree. Before that commit,
it runs pnpm install and pnpm approve-builds --all, so the lockfile and pnpm
build approvals are part of the first commit. Source-backed deploys push the
current repo before asking Dokploy to build it. When the backing Git repository
needs to be created first, nstack treats a private repository as the default.
On the initial Gitea or Forgejo push, nstack explicitly requests private
visibility for push-to-create.
Each new app gets a DESIGN.md brief with its own font pair, generated palette,
mobile and desktop padding, content width, section spacing, and starter
composition. The same choices configure the frontend and its agent
instructions. Agents refine the brief around the product, use ImageGen for
whole-page layout concepts and individual visual assets, and verify changes
through static checks, builds, and direct runtime checks. Generated instructions
exclude unit tests and screenshots.
nstack deploy discovers Encore resources, renders Encore infra and Dokploy
Compose, lets Dokploy build the production backend/frontend services from source,
provisions Dokploy resources, creates Dokploy Domains/Traefik routes, deploys,
verifies the public URL, and prints the result.
Dokploy's standard Compose deployment remains the default. An experimental
health-gated rollout is available with deploy.zeroDowntime: true or
NSTACK_ZERO_DOWNTIME=1. It starts replacement backend and frontend containers,
waits for their health checks, then removes the previous containers. Run
nstack deploy after changing this setting so Dokploy stores the selected
deployment command for provider-backed pushes.
For automatic deploy-on-push, connect the matching Git provider in Dokploy first.
nstack can configure Dokploy Compose source deployments for GitHub, GitLab,
Bitbucket, and Gitea/Forgejo when Dokploy has that provider connected. Plain Git
source mode is available for custom hosts, but provider-backed sources are the
path that gives Dokploy native push webhooks.
Provider-backed push deploys reuse infrastructure credentials prepared by
nstack deploy. When code declares a new Postgres database, cache, or object
storage bucket, run nstack deploy once before relying on push deployment. A
push with missing infrastructure credentials stops instead of generating a
predictable fallback. Provider-backed nstack deploy updates Compose and its
private Dokploy environment before pushing, then waits for the push webhook
deployment when that push occurs.
If the pushed commit only changes files outside the provider watch paths,
nstack deploy triggers Dokploy directly after the push instead of waiting for
a webhook that the provider filters out.
Daily Commands
nstack setup # install local tooling and dependencies
pnpm dev # or: nstack dev
nstack devexec 'await apiJson("/status")'
pnpm check # or: nstack check
nstack deploy
nstack status
Add runtime variables to .env directly or use nstack env set NAME. nstack dev, deploys, and nstack env run -- <command> load the same file. Use
nstack logs --follow when a deploy is running. nstack update refreshes a
git-installed nstack checkout.
The CLI prints an update notice after normal commands when nstack.tech reports a
newer version.
When Needed
nstack doctor
nstack target create staging --domain staging.example.com
nstack pull
nstack update
nstack backup
nstack rollback
nstack undeploy --yes
nstack cleanup
nstack open dashboard
The generated app keeps package scripts as aliases to the CLI. nstack setup
installs project dependencies, bootstraps pnpm through Corepack when needed,
installs the Encore CLI with the official installer when it is missing, and
checks Docker only when declared Encore resources need it. pnpm dev calls
nstack dev to run the Encore backend, Nuxt frontend, and generated client sync
for HMR. On a fresh clone, pnpm dev and pnpm check reuse the CLI setup path
before running. They stop with direct instructions when Docker is not running or
cannot be accessed. pnpm check runs the Encore startup check, backend
TypeScript check, and Nuxt typecheck concurrently. Backend and frontend
TypeScript project state is reused on later checks. pnpm check, pnpm build,
and nstack deploy sync the Encore TypeScript client used by the Nuxt frontend.
Cached client sync does not start Encore. nstack client gen is available when
you explicitly want to regenerate it. Client generation and deploy metadata use
local Encore commands for Dokploy/nstack targets. Backend images include only
production dependencies declared by the backend package, which keeps build
contexts and image pushes independent of frontend dependency size. Registry
builds reuse the staged backend dependency tree until its lockfile, package
manifests, package-manager settings, or local workspace dependencies change.
The generated frontend includes Tailwind CSS 4 through its official Vite
plugin, with shared theme tokens in frontend/app/assets/css/main.css. Nuxt
Icon bundles the local icon set, and Nitro precompresses production assets with
Brotli and gzip.
Generated templates intentionally keep backend/encore.app with an empty
Encore app id. That is Encore's local-only mode and prevents local
encore run or encore check from fetching Encore Cloud secrets. nstack uses
nstack.config.mjs app.slug as the Dokploy/nstack identity instead.
When nstack dev detects an AI coding harness such as Codex or Claude Code, it
refuses to start a long-running dev server by default. Agents should use
nstack devexec '<js>' for one-shot checks against a temporary dev stack. Set
NSTACK_AGENT_HARNESS=<name> for custom harnesses, or AI_ALLOW_DEVSERVER=1
when an agent truly needs an interactive dev server.
nstack cleanup asks for confirmation before using server-wide Dokploy cleanup
endpoints for stopped containers, unused images, unused volumes, and Docker
builder cache. Pass --yes only when that server-wide cleanup is intended.
nstack backup writes local snapshots under
.nstack/backups/<target>/<year-month-day-hour-minute-second-utc>/. It stores
Dokploy/app metadata, remote Dokploy Compose env values in compose.env, and
data artifacts for stateful resources:
Postgres dumps and Dokploy volume tars for Redis-compatible cache, RustFS object
storage, NSQ Pub/Sub data, and custom named volumes declared with
deploy.volumes.<name>.backup. A custom volume backup stops its declared
service before Dokploy archives the volume, then restarts the service after the
archive completes. Downloaded artifacts must match Dokploy's reported
size and pass gzip or tar validation. Manifests record a SHA-256 for each verified
artifact. Snapshot files preserve secrets for recovery and are written with
private local permissions.
Source-controlled private services can be declared under deploy.services with
either an image or a build, internal exposed ports, environment values, secret
names, health checks, and named-volume mounts. They join only the private
Compose network. Registry deployments build and push service images alongside
the backend and frontend. Source-backed deployments render their Docker builds
into Compose. A singleton service that mounts a named volume cannot use
zeroDowntime: true.
Destructive deletion paths create a critical local backup first and refuse to
continue if the backup cannot be completed. To intentionally delete without that
guard, start the CLI with NSTACK_NO_BACKUPS_ON_DELETION=1. Data backups use
Dokploy API-backed backup jobs and require a Dokploy backup destination; pass
--backup-destination-id <id> or set NSTACK_BACKUP_DESTINATION_ID when more
than one destination exists. If none exists, nstack aborts before destructive
deletion.
For the detailed operator guide, see USING_NSTACK.md.
Dokploy Model
- Dokploy Projects and Environments own the app.
- Dokploy native Postgres and Redis-compatible Dragonfly cache resources are created when Encore declares SQL databases or cache clusters.
- Source-backed Git pushes use infrastructure credentials previously prepared
by
nstack deploy. Push deployment stops when a newly declared stateful resource has no prepared credential. - A provider-backed
nstack deploythat pushes a new commit relies on the push webhook deployment instead of triggering a second Compose deploy. - Dokploy Compose builds and runs the backend/frontend services plus generated
support services such as NSQ for Pub/Sub and RustFS for Encore object storage
buckets. Public buckets add a small RustFS public-route adapter so Dokploy can
keep
/objectson the app domain while backend S3 traffic stays internal. - Dokploy Domains/Traefik route
/to Nuxt,/apito Encore, and/objectsto the RustFS public adapter only when a public Encore bucket is declared. - Dokploy Schedules run Encore cron jobs inside the backend container through a
bundled private runner; cron endpoints should use
api({ expose: false }, ...)so they cannot be triggered from public HTTP. .envis the app runtime environment inventory. nstack discovers Encore secrets and source references, routes matching variables into each service, and synchronizes every value to Dokploy during env push or deploy.
Large structured values can stay in a separate ignored file. Set an app value
to @file:path, for example CHAIN_CONFIG=@file:chains.config.json. nstack
reads the file for local commands and sends its contents to Dokploy while
preserving the reference in .env.
There is no Caddy container and no manual Traefik label surface in generated Compose.
Cache resources are still addressed through Encore/Dokploy Redis connection settings, but new Dokploy cache resources use the official Dragonfly image by default. Existing Dokploy Redis resources are reused instead of replaced during normal code deploys.
Builds
The default build mode is compose: Dokploy receives a Compose file with
build: sections, local image tags, and production Dockerfiles. That path does
not need GHCR, Docker Hub, or any external image registry. The first deploy can
pay for dependency downloads on the server; consecutive deploys reuse Docker and
pnpm caches on the Dokploy host.
The Nuxt service is built with nuxt build and runs .output/server/index.mjs.
It is not deployed with a dev server.
Registry/image mode is still available when needed:
nstack configure --build-mode registry --registry ghcr.io/acme/my-app
nstack build
nstack deploy --prebuilt
Registry builds run the backend and frontend image pipelines concurrently. Repeated backend builds reuse the isolated production dependency tree when its dependency inputs have not changed.
Files
nstack.config.mjsis stable source config..nstack/local.envstores local deploy settings with private permissions and is ignored..envstores the app runtime environment with private permissions and is ignored.deploy/nstack/encore.infra.jsonis passed to the backend runtime.deploy/nstack/compose.dokploy.yamlis sent to Dokploy Compose.deploy/nstack/release.jsonrecords the build mode and release fromnstack build.
For staging or other targets, pass --env <name>. nstack writes target-scoped
files such as .nstack/local.staging.env, .env.staging, and
.nstack/state.staging.json. If multiple local targets exist, interactive
nstack deploy asks which environment to deploy; automation should pass
--env <name>.
Monorepos are supported without repo-in-repo layouts. Run nstack from the app
directory, for example nstack deploy --cwd apps/web; nstack scopes dirty Git
checks, generated deploy artifact commits, and client generation to that app.
For source-backed Dokploy deploys, subdirectory apps default to app-prefixed
Compose source settings such as apps/web/deploy/nstack/compose.dokploy.yaml
and watchPaths: ["apps/web/**"], so multiple nstack apps can share one
repository without blocking each other.
Deployment servers and storage
Choose the Dokploy deployment server with nstack configure --server-id <id>.
Use --server-id local for the Dokploy manager. Existing apps retain their
remote server; nstack rejects a conflicting server choice rather than moving
volumes. Deploying a new app prompts when remote servers are available.
Automation must choose a server explicitly in that case.
nstack deploy inspects Docker networks on the selected deployment server.
It reuses the app's existing bridge without changing its subnet. New apps get
a free /24 from 10.240.0.0/12, reserved through Dokploy before Compose is
rendered. Concurrent allocation conflicts trigger a fresh inventory and retry.
Docker assigns container IPs within that subnet; services use DNS names.
The generated default network is external so Compose reuses the reservation,
including on provider-triggered Git builds. The name is saved per target as
NSTACK_NETWORK_NAME. Networks remain after app removal and require explicit
removal in Dokploy once no containers use them.
For hosts with routes or VPNs in that range, set deploy.networkSubnet in
nstack.config.mjs, or NSTACK_NETWORK_SUBNET in the target's local env, to an
unused private IPv4 CIDR before deploying. Docker's network inventory does not
include host or VPN routes. Explicit subnets are checked against Docker
networks on that server. Each app and target on the same host needs a
non-overlapping range. The private Compose network stays separate from
dokploy-network. Changing an existing network's subnet requires a planned
network migration. nstack does not prune networks or change Docker daemon
address pools automatically. Allocation requires Dokploy's network API;
incomplete inventory stops deployment.
Encore buckets use RustFS and its rc client with a dedicated rustfs_data
volume. New deployments use NSTACK_RUSTFS_ACCESS_KEY and
NSTACK_RUSTFS_SECRET_KEY. Pulling or deploying an older app imports its
NSTACK_MINIO_* credentials without rotating them.
For an existing MinIO service, run:
nstack deploy --migrate-storage --docker-host ssh://user@server --env prod
Use Docker access to the selected Dokploy server. nstack checks the container
identity before stopping writers. The migration stops the app, clones its
single named /data volume, and verifies every object version, content hash,
delete marker, object metadata, bucket versioning setting, and public policy
through RustFS before deploying. It retains the original MinIO volume. A failed
verification removes only the new clone and restarts the original containers.
A verified migration can be retried with the same command after a deploy failure;
the original service stays stopped until cutover. Do not restart MinIO after
RustFS accepts writes without reconciling those writes first.
RustFS supports MinIO disk-format import, but migration is one-way. Distributed drive sets, encryption integrations, and external identity or notification services require a separate migration. Unsupported data fails verification before cutover. The command needs downtime and enough disk space for a copy.
Dokploy host firewall
Apply host hardening separately on the manager and every deployment server.
For a server with a single-node Swarm, copy scripts/harden-dokploy-firewall.sh
and scripts/nstack-security-firewall.service to the server, then run as root:
install -m 755 harden-dokploy-firewall.sh /usr/local/sbin/nstack-security-firewall
/usr/local/sbin/nstack-security-firewall
install -m 644 nstack-security-firewall.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now nstack-security-firewall
nft list table inet nstack_guard
The rules allow public SSH, HTTP, HTTPS, and HTTP/3, and block other inbound host and Docker-forwarded traffic on the default-route interfaces. The boot unit restores the rules before Docker starts. It preserves container egress and internal traffic. Multi-node Swarms require explicit trusted peer rules; the initial check refuses them. Verify SSH and application health from another machine after installation and after reboot.
After updating nstack, refresh existing storage image references with
node scripts/upgrade-storage-images.mjs path/to/compose.dokploy.yaml. This
changes image references only. Back up storage and verify data compatibility
before restarting an older RustFS release.