diff --git a/apps/docs/content/features/env-variables.mdx b/apps/docs/content/features/env-variables.mdx index ddf66bee..33d886a8 100644 --- a/apps/docs/content/features/env-variables.mdx +++ b/apps/docs/content/features/env-variables.mdx @@ -140,50 +140,73 @@ A security feature that controls the **visibility** of environment variables acr By default, Zerops isolates environment variables between services to enhance security and prevent unintended access to sensitive information. This isolation can be configured at both project and service levels. -### Isolation Modes +### Isolation Rules -Zerops supports two isolation modes: +The `envIsolation` value is a space-separated list of rules. **A service's own rules decide which other services can see its variables.** The rules of the service doing the reading are never consulted, so a service can widen or narrow what it exposes, but never what it receives. - + - + - + + + + + + + + +
ModeRule Description
serviceDefault mode. Variables are isolated to their respective services. Services can only access their own variables and must explicitly reference variables from other services.Default. Only the service itself sees its variables. Other services must reference them explicitly.
noneLegacy mode. All variables from all services are automatically shared and accessible via prefixing.Every service in the project sees the variables, prefixed with the service hostname.
service@nameThe service with hostname name additionally sees the variables.
-service@nameThe service with hostname name never sees the variables, even when none is present.
+#### Rule Evaluation Order + +When service `reader` asks for the variables of service `owner`, the rules of `owner` are checked in this order: + +1. `-service@reader` is present → **hidden** +2. `service@reader` is present → **visible** +3. `none` is present → **visible** +4. Otherwise → **hidden** + +Block rules always win over allow rules for the same service. A service always sees its own variables regardless of its rules, and explicit `${hostname_variable}` references keep working in every mode. + ### Configuring Isolation #### Project-Level Isolation -Zerops automatically creates the `envIsolation` project variable with the default value `service`. You only need to modify this if you want to disable isolation: +Zerops automatically creates the `envIsolation` project variable with the default value `service`. Every service inherits the project value unless it sets its own: ```yaml title="import.yaml" project: - envIsolation: none # Disables isolation, sharing all variables + envIsolation: service@zcp # The zcp service sees the variables of every other service ``` This can also be set through the Project Environment Variables section in the GUI. #### Service-Level Override -Individual services can override the project-level isolation setting: +Individual services can replace the project-level value with their own. The values are not merged, the service value applies on its own: ```yaml title="import.yaml" +project: + envIsolation: service@zcp services: - hostname: db - envIsolation: none # This service's variables will be visible to all services + envIsolation: none # Everyone sees the db variables + - hostname: api + envIsolation: service # Nobody sees the api variables, not even zcp ``` :::tip @@ -194,6 +217,31 @@ You might set a database service to `envIsolation: none` to expose its connectio In import YAML, `envIsolation` can also be nested under `envVariables`/`envSecrets`. (If both are present, the nested version takes precedence). ::: +#### Common Combinations + +**Single privileged reader** *(tooling, migrations, admin service)*: +```yaml +envIsolation: service@zcp +``` +- ✅ The `zcp` service sees the variables of every service that inherits this value +- ❌ Every other service stays isolated + +**Open project with one exception**: +```yaml +envIsolation: none -service@untrusted +``` +- ✅ All services see each other's variables +- ❌ The `untrusted` service sees only its own variables and project variables + +**Selective exposure on one service**: +```yaml +services: + - hostname: db + envIsolation: service@api service@worker +``` +- ✅ The `api` and `worker` services see the `db` variables +- ❌ Every other service must reference `db` variables explicitly + ### Accessing Variables Across Services #### With Isolation Enabled (`service` mode) @@ -210,12 +258,12 @@ run: This approach gives you complete control over which variables are shared between services. -#### With Isolation Disabled (`none` mode) +#### When Variables Are Shared (`none` or `service@name`) -When isolation is disabled, variables are automatically available across all services with the service name prefix: +When the owning service shares its variables, they are automatically available with the service name prefix: ```yaml -# In any service, you can directly access: +# In any service the 'db' service shares variables with, you can directly access them: ${db_password} # Accesses the 'password' variable from the 'db' service ``` @@ -224,7 +272,8 @@ ${db_password} # Accesses the 'password' variable from the 'db' service 1. **Use Default Isolation**: Keep the default `service` isolation for enhanced security. 2. **Explicit References**: Create explicit references only for variables that need to be shared. 3. **Naming Conventions**: Use clear naming patterns for reference variables (e.g. `DB_PASSWORD` for a reference to `db_password`). -4. **Service-Level Exceptions**: Use service-level isolation overrides sparingly and only for services that need to expose their variables widely. +4. **Grant, Don't Open**: Prefer `service@name` for the one service that needs broad access over `none`, which exposes variables to every service. +5. **Service-Level Exceptions**: Use service-level isolation overrides sparingly and only for services that need to expose their variables widely. ## Referencing Variables @@ -350,6 +399,6 @@ With this setup: - The `db` service cannot see any variables from `api` or `cache` - The `cache` service cannot see any variables from `api` or `db` -If we changed the project's `envIsolation` to `none`, all services would be able to see all variables from all other services (prefixed with the service name). +If we changed the project's `envIsolation` to `none`, all services would be able to see all variables from all other services (prefixed with the service name). With `service@api` instead, only the `api` service would see the `db` and `cache` variables, and `db` and `cache` would stay isolated from each other. *Need help? Join our [Discord community](https://discord.gg/zeropsio).* \ No newline at end of file diff --git a/apps/docs/content/guides/environment-variables.mdx b/apps/docs/content/guides/environment-variables.mdx index a317a079..9e334ea0 100644 --- a/apps/docs/content/guides/environment-variables.mdx +++ b/apps/docs/content/guides/environment-variables.mdx @@ -3,7 +3,7 @@ title: "Environment Variables" description: "Zerops manages environment variables at two scopes (project and service) with strict build/runtime isolation. Variables are set via zerops.yml, import.yml, or GUI. Cross-service references use `${hostname_varname}` syntax. Project vars auto-inherit into all services. Secret vars are write-only after creation. Changes require service restart." --- -Zerops manages environment variables at two scopes (project and service) with strict build/runtime isolation. Variables are set via zerops.yml, import.yml, or GUI. **Project vars auto-inherit into every service** — read them directly, no declaration. **Cross-service (sibling) vars do NOT auto-inject under the default `envIsolation=service`** — reference a sibling's value explicitly as `${hostname_varname}` in `run.envVariables` (only legacy `none` mode injects siblings as bare vars). Secret reads are privilege-gated (an admin token returns the value; a read-only token gets `REDACTED`). A running process keeps its boot-time env — restart it (not reload) to pick up a changed value. +Zerops manages environment variables at two scopes (project and service) with strict build/runtime isolation. Variables are set via zerops.yml, import.yml, or GUI. **Project vars auto-inherit into every service** — read them directly, no declaration. **Cross-service (sibling) vars do NOT auto-inject under the default `envIsolation=service`** — reference a sibling's value explicitly as `${hostname_varname}` in `run.envVariables` (siblings are injected as bare `_KEY` vars only when the owning service shares them via `none` or `service@`). Secret reads are privilege-gated (an admin token returns the value; a read-only token gets `REDACTED`). A running process keeps its boot-time env — restart it (not reload) to pick up a changed value. --- @@ -63,7 +63,7 @@ run: - An **unresolved ref stays literal** (`${db_hostname}` reaches the process verbatim) — no error, no blank. A wrong hostname/var on the right-hand side becomes a literal string and the app fails at connect time. - **Hostname charset**: service hostnames are lowercase alphanumeric only (`[a-z0-9]`) — the platform rejects dashes, underscores, and uppercase with `serviceStackNameInvalid`. So a ref is simply `${hostname_varname}` with the literal hostname (service `cache` → `${cache_port}`); there is no dash-to-underscore rewrite to reason about, because a dashed hostname cannot exist. -Only legacy `envIsolation=none` auto-injects every sibling's vars as bare `_KEY` OS env vars without a ref — see Isolation Modes. New projects are `service`; rely on explicit refs. +Sibling vars are auto-injected as bare `_KEY` OS env vars only when the **owning** service shares them, via `none` or a `service@` grant — see Isolation Modes. New projects are `service`; rely on explicit refs. ### Cross-Service References in API vs Runtime @@ -75,23 +75,31 @@ Cross-service references (`${hostname_varname}`) are **resolved at container sta ### Isolation Modes (envIsolation) -`envIsolation` is a project-scope setting that controls whether sibling-service vars are auto-injected. +`envIsolation` is a space-separated rule list set at project scope and optionally overridden per service (the service value replaces the project value, no merge). **It is owner-side and directional**: a service's own rules decide who sees ITS vars. The reader's rules never widen what the reader receives, so a compromised container cannot grant itself access to sibling secrets. -| Mode | Behavior | +| Rule | Behavior | |------|----------| | `service` (default) | **Siblings are isolated.** A service sees only its own vars + project vars + the explicit `${hostname_varname}` refs it declares in `run.envVariables`. Managed-service connection vars also require an explicit ref. | -| `none` (legacy) | Every service's vars are auto-injected into every other container as bare `_KEY` OS env vars (source-side, directional). Ambiguous and broad — avoid for new projects. | +| `none` | Every service sees this service's vars as bare `_KEY` OS env vars. Broad — prefer `service@name` for new projects. | +| `service@name` | The service with hostname `name` additionally sees this service's vars as bare `_KEY` vars. | +| `-service@name` | The service with hostname `name` never sees this service's vars, even when `none` is present. | + +Evaluation for reader R against owner O's rules: `-service@R` → hidden, else `service@R` → visible, else `none` → visible, else hidden. A service always sees its own vars. Set in import.yml at project or service level: ```yaml project: - envIsolation: none # legacy — avoid; default is service + envIsolation: service@zcp # zcp sees every service that inherits this value services: - hostname: db - envIsolation: none # per-service: expose THIS service's vars to siblings + envIsolation: none # per-service: expose THIS service's vars to all siblings + - hostname: api + envIsolation: service # per-service: opt out of the project grant, nobody sees api vars + - hostname: cache + envIsolation: none -service@api # everyone except api sees cache vars ``` -**Default (`service`) is the right choice.** Wire cross-service explicitly with `${hostname_varname}` — it works in both modes, so code stays correct if isolation ever changes. +**Default (`service`) is the right choice.** Wire cross-service explicitly with `${hostname_varname}` — it works in every mode, so code stays correct if isolation ever changes. When one tooling or admin service needs broad read access, grant it with `service@` at project level instead of switching to `none`. ## Project Variables -- Auto-Inherited diff --git a/apps/docs/content/guides/networking.mdx b/apps/docs/content/guides/networking.mdx index 7c416ed6..6087e634 100644 --- a/apps/docs/content/guides/networking.mdx +++ b/apps/docs/content/guides/networking.mdx @@ -31,7 +31,7 @@ http://postgres:5432 - Service discovery is automatic — no manual network config - VPN uses same hostnames: `http://api:3000` from local machine (both `api` and `api.zerops` resolve — VPN sets up DNS search domain) -**Cross-service env vars**: under the default `envIsolation=service`, reference a sibling's var explicitly as `${hostname_varname}` in `run.envVariables` (e.g. `${app_API_TOKEN}`) — siblings are NOT auto-injected. The bare `_KEY` injected form only appears under legacy `envIsolation=none`. Zerops auto-generates connection vars for managed services — reference them the same way (`${db_*}`). +**Cross-service env vars**: under the default `envIsolation=service`, reference a sibling's var explicitly as `${hostname_varname}` in `run.envVariables` (e.g. `${app_API_TOKEN}`) — siblings are NOT auto-injected. The bare `_KEY` injected form only appears when the owning service shares its vars, via `envIsolation=none` or a `service@` grant. Zerops auto-generates connection vars for managed services — reference them the same way (`${db_*}`). **DO NOT** use `https://` for service-to-service calls — SSL terminates at the L7 balancer, internal network is already isolated. diff --git a/apps/docs/content/mariadb/how-to/backup.mdx b/apps/docs/content/mariadb/how-to/backup.mdx index 911f2ccc..0b0101db 100644 --- a/apps/docs/content/mariadb/how-to/backup.mdx +++ b/apps/docs/content/mariadb/how-to/backup.mdx @@ -52,7 +52,7 @@ Use the `zerops-import.yaml` file from the repository to import the service. See Connect to the `mariadbrestore` service using the GUI terminal or via [VPN](/references/networking/vpn) and [SSH](/references/networking/ssh). :::note -To use environment variables from your MariaDB service in the backup and restore commands, make sure the `envIsolation` project variable is set to `none`. See [Environment Variable Isolation](/features/env-variables#environment-variable-isolation) and [Referencing Variables](/features/env-variables#referencing-variables) for details. +To use environment variables from your MariaDB service in the backup and restore commands, make sure the MariaDB service shares its variables with the `mariadbrestore` service, for example with `envIsolation: service@mariadbrestore` on the MariaDB service or on the project, or with `envIsolation: none`. See [Environment Variable Isolation](/features/env-variables#environment-variable-isolation) and [Referencing Variables](/features/env-variables#referencing-variables) for details. ::: Run the backup script: diff --git a/apps/docs/content/references/zsc.mdx b/apps/docs/content/references/zsc.mdx index 14a10187..54cfbc8d 100644 --- a/apps/docs/content/references/zsc.mdx +++ b/apps/docs/content/references/zsc.mdx @@ -336,7 +336,7 @@ When using an object storage service, the command requires the following environ * `objectstorage_secretAccessKey` - Secret access key for authentication * `objectstorage_bucketName` - Name of the bucket to use -These environment variables will be automatically available if the object storage service has `envIsolation: none` configured, or if the entire project has `envIsolation: none` set. Otherwise, you need to explicitly reference these environment variables in your `zerops.yaml` file. +These environment variables will be automatically available if the object storage service shares them with your service, either with `envIsolation: none` or with `envIsolation: service@` (set on the object storage service or inherited from the project). Otherwise, you need to explicitly reference these environment variables in your `zerops.yaml` file. #### Sub-commands diff --git a/apps/docs/static/llms-full.txt b/apps/docs/static/llms-full.txt index b593aed6..b9fba534 100644 --- a/apps/docs/static/llms-full.txt +++ b/apps/docs/static/llms-full.txt @@ -1,349 +1,327 @@ ---------------------------------------- -# Homepage +# Alpine > How To > Build Pipeline -export const runtimes = [ - { name: "Node.js", link: "/nodejs/overview", icon: }, - { name: "PHP", link: "/php/overview", icon: }, - { name: "Python", link: "/python/overview", icon: }, - { name: "Go", link: "/go/overview", icon: }, - { name: ".NET", link: "/dotnet/overview", icon: }, - { name: "Rust", link: "/rust/overview", icon: }, - { name: "Java", link: "/java/overview", icon: }, - { name: "Deno", link: "/deno/overview", icon: }, - { name: "Bun", link: "/bun/overview", icon: }, - { name: "Elixir", link: "/elixir/overview", icon: }, - { name: "Gleam", link: "/gleam/overview", icon: }, - { name: "Ruby", link: "/ruby/overview", icon: }, - { name: "Nginx", link: "/nginx/overview", icon: }, - { name: "Static", link: "/static/overview", icon: }, -] +Zerops provides a customizable build and runtime environment for your Alpine application. -export const containers = [ - { name: "Ubuntu", link: "/ubuntu/overview", icon: }, - { name: "Alpine", link: "/alpine/overview", icon: }, - { name: "Docker", link: "/docker/overview", icon: }, -] +## Add zerops.yaml to your repository -export const databases = [ - { name: "PostgreSQL", link: "/postgresql/overview", icon: }, - { name: "MariaDB", link: "/mariadb/overview", icon: }, - { name: "Valkey", link: "/valkey/overview", icon: }, - { name: "Elasticsearch", link: "/elasticsearch/overview", icon: }, - { name: "Typesense", link: "/typesense/overview", icon: }, - { name: "Meilisearch", link: "/meilisearch/overview", icon: }, - { name: "Qdrant", link: "/qdrant/overview", icon: }, - { name: "NATS", link: "/nats/overview", icon: }, - { name: "Kafka", link: "/kafka/overview", icon: }, - { name: "ClickHouse", link: "/clickhouse/overview", icon: }, - { name: "KeyDB", link: "/keydb/overview", icon: }, -] +Start by adding `zerops.yaml` file to the **root of your repository** and modify it to fit your application: -export const storages = [ - { name: "Storage overview", link: "/storage/overview", icon: }, - { name: "Object storage", link: "/object-storage/overview", icon: }, - { name: "Local storage", link: "/local-storage/overview", icon: }, - { name: "SeaweedFS", link: "/seaweedfs/overview", icon: }, -] +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: alpine@3.20 -
+ # OPTIONAL. Customize the build environment by installing additional packages + # or tools to the base build environment. + prepareCommands: + - sudo apk add --no-cache something + - curl something else -Zerops is a **developer-first Platform-as-a-Service**, running on bare metal, with every part built from scratch. Zerops aims to be the perfect mix of **developer experience**, **flexibility**, **scalability** and **affordability**, making it a great fit for applications of any size, complexity and traffic. + # OPTIONAL. Build your application + buildCommands: + - -## Natively supported services + # REQUIRED. Select which files / folders to deploy after + # the build has successfully finished + deployFiles: app -### Runtimes & web servers + # OPTIONAL. Which files / folders you want to cache for the next build. + # Next builds will be faster when the cache is used. + cache: some_file -For these services Zerops provides pre-prepared build and runtime images and flexible pipeline that allows you to modify them and build your applications. + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: alpine@3.20 -### Linux containers & VMs + # OPTIONAL. Sets the internal port(s) your app listens on: + ports: + # port number + - port: 8080 -These services can be deployed either as plain Linux containers or using Docker images, giving you flexibility to run any application or service. + # OPTIONAL. Customize the runtime Alpine environment by installing additional + # dependencies to the base Alpine runtime environment. + prepareCommands: + - sudo apk add --no-cache something + - curl something else -### Databases, search engines & message brokers + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your Alpine application is started. + initCommands: + - rm -rf ./cache -These services are fully managed by Zerops and offered in highly available and single container modes. + # OPTIONAL. Your Alpine application start command + start: ./app +``` -### Storages +The top-level element is always `zerops`. -Fully managed S3 compatible storage running on a separate infrastructure, persistent disk volumes that can be mounted to multiple services, and a managed SeaweedFS distributed filesystem. Runtime containers are replaced on every deploy, so persistent data belongs in one of these — see [Storage on Zerops](/storage/overview). +### Setup -## Quicklinks +The first element `setup` contains the **hostname** of your service. A runtime service with the same hostname must exist in Zerops. +Zerops supports the definition of multiple runtime services in a single `zerops.yaml`. This is useful when you use a monorepo. Just add multiple setup elements in your `zerops.yaml`: -- [zCLI](/references/cli) -- [zerops.yaml](/zerops-yaml/specification) -- [Import YAML](/references/import) +```yaml +zerops: + # definition for app service + - setup: app + # optional + build: ... + # optional + deploy: ... + # required + run: ... -## Feature highlights + # definition for api service + - setup: api + # optional + build: ... + # optional + deploy: ... + # required + run: ... +``` -Four concepts that play together to make Zerops developer-first and live up to the claim "no matter the size or environment". +Each service configuration contains at least the `run` section. Optional `build` and `deploy` sections can be added to further customize your process. -### ➡️ Custom dedicated infrastructure deployed with each project +## Build pipeline configuration -Zerops is made of three levels: **project** -> **service** -> **container**. For each project Zerops deploys dedicated **core services**, these consist of: +### base -- **L3 balancer** with a firewall and unique IP addresses assigned to it, this serves as the main entry point from the internet, -- **Logger** and **Statistics** containers that gather logs and resource metrics from all services inside the project and allow for log forwarding -- **L7 load balancer** that handles and routes http traffic, SSL termination and SSL certificates +_REQUIRED._ Sets the base technology for the build environment. -User services (which consist of one or more containers) inside the project share a private network created with VXLAN, have resources isolated with cgroups and can securely communicate with each other simply by using the hostname and ports and read and reference each other's environment variables. +Following options are available for Alpine builds: -:::tip[**What does this mean for you?**] +- `alpine@3.23`, `alpine@latest` +- `alpine@3.22` +- `alpine@3.21` +- `alpine@3.20` +- `alpine@3.19` +- `alpine@3.18` +- `alpine@3.17` -You get a fully managed, professional infrastructure setup that will scale no matter how much traffic you get and deals with all the networking, balancing and security stuff, so you can just focus on your actual applications. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: alpine@3.20 + ... +``` -[Read more about the project infrastructure](/features/infrastructure) +

+ The base build environment contains {data.alpine.default}, [Zerops command line tool](/references/cli), `git` and `wget`. +

+:::info +You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. ::: -### ➡️ Granular resource configuration, autoscaling and high availability of services - -Zerops has fully automatic horizontal and vertical scaling with configuration steps as small as 0.125 GB RAM and 1 CPU core. Your runtime services can go from a single container with 0.25 RAM and 1 CPU core to 10 containers each with 32 GB RAM and 10 CPU cores and then back in a matter of minutes. At the same time, all database and storage services are offered in well-crafted setups that go through performance optimizations while scaling and are available in both non-HA (single container) and high availability (multiple containers and balancers) modes. +If you need to install more technologies to the build environment, set multiple values as a yaml array. For example: -:::tip[**What does this mean for you?**] +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: + - alpine@3.20 + prepareCommands: + - zsc add nodejs@latest + ... +``` -You won't ever overprovision or underprovision your resources and your services will always have the exact resources they need. There won't be any cutting corners like sharing too few CPU cores between too many services. You will be able to rely on professional, reliable and highly available database setups with auto-repairing abilities that will scale along with your applications. +See the full list of supported [build base environments](/zerops-yaml/base-list#runtime-services). -[Read more about autoscaling and high availability](/features/scaling) +To customize your build environment use the [prepareCommands](#preparecommands) attribute. +:::note +Modifying the base technology will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for more details about cache invalidation. ::: -### ➡️ Full Linux OS containers with a powerful, flexible build and deploy pipeline +### prepareCommands -Zerops uses Incus to create containers, which means that you get a full Linux OS, either Ubuntu or Alpine, depending on your choices. This provides the perfect middle ground between a containerized process (Docker) and a full-fledged VM (Proxmox). Zerops provides build and runtime bases for all the popular runtime technologies and a powerful and flexible pipeline that allows you to modify and cache both the build and runtime images. This circumvents the need for Docker registries. The pipeline can be triggered either automatically, by connecting the service with GitHub or GitLab repositories, or manually using our CLI - either for triggering from your machine, or from any existing CI/CD process. +_OPTIONAL._ Customizes the build environment by installing additional dependencies or tools to the base build environment. -:::tip[**What does this mean for you?**] +The base build environment contains: -You get a built-in powerful and flexible pipeline to modify build and runtime images and deploy your code, without any downtime. It can be used standalone or easily plugged into any existing CI/CD process. +- {data.alpine.default} +- [Zerops command line tool](/references/cli) +- `git` and `wget` -[Read more about the build and deploy pipeline](/features/pipeline) +To install additional packages or tools add one or more prepare commands: -::: +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: alpine@3.20 -### ➡️ Pricing model that doesn't get in the way of good development practices + # OPTIONAL. Customize the build environment by installing additional packages + # or tools to the base build environment. + prepareCommands: + - sudo apk add --no-cache something + - curl something else + ... +``` -"Simple and predictable pricing"... is what others say and what we actually do. In Zerops, cost per hardware resource (CPU, RAM, Disk) is 3-5x cheaper than with popular alternatives. And there are no plans, no feature tiers, no fees for seats. PaaS is just hardware with a cherry and bow on top, so why would we charge you for anything else but hardware resources? +When the first build is triggered, Zerops will -:::tip[**What does this mean for you?**] +1. create a build container +2. download your application code from your repository +3. run the prepare commands in the defined order -You get a powerful managed platform with all the best features unlocked for a price that's nearly on par with VPS. You can create as many environments as you need, even one for each developer working on a project, all with the same infrastructure as production, so they can utilize Zerops for their local development. No more "but it works on my machine". +The application code is available in `/build/source` before the prepare commands are triggered, so you can use any file from your repository in your prepare commands (e.g. a configuration file). The commands themselves run in the `/home/zerops` directory. +:::note +These commands are skipped when using cached environment. Modifying `prepareCommands` will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache invalidation. ::: -
- - ----------------------------------------- - -# Zerops Yaml > Specification - - -export const languages = [ - { name: "Node.js", link: "/nodejs/how-to/build-pipeline" }, - { name: "PHP", link: "/php/how-to/build-pipeline" }, - { name: "Python", link: "/python/how-to/build-pipeline" }, - { name: "Go", link: "/go/how-to/build-pipeline" }, - { name: ".NET", link: "/dotnet/how-to/build-pipeline" }, - { name: "Rust", link: "/rust/how-to/build-pipeline" }, - { name: "Java", link: "/java/how-to/build-pipeline" }, - { name: "Deno", link: "/deno/how-to/build-pipeline" }, - { name: "Bun", link: "/bun/how-to/build-pipeline" }, - { name: "Elixir", link: "/elixir/how-to/build-pipeline" }, - { name: "Gleam", link: "/gleam/how-to/build-pipeline" }, - { name: "Nginx", link: "/nginx/how-to/build-pipeline" } -] -The `zerops.yaml` file is crucial for defining how Zerops should [build and deploy](/features/pipeline) your application. -Add the `zerops.yaml` file to the **root of your repository** and customize it to suit your application's needs. +#### Command exit code -:::note Parameter Availability -Not all parameters are available for every service type. Most parameters work across different runtime services, but some are specific to certain service types (e.g., documentRoot for webserver services, routing for Static services). This documentation covers zerops.yaml configuration for runtime services. -::: +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/alpine/how-to/logs#build-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all prepare commands are finished, your custom build environment is ready for the build phase. ---- +#### Single or separated shell instances -## Basic Structure +You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -```yaml title="zerops.yaml" -zerops: - - setup: app - # optional - build: ... - # optional - deploy: ... - # required - run: ... -``` +### buildCommands -Multiple services can be defined in a single `zerops.yaml` (useful for monorepos): +_OPTIONAL._ Defines build commands. ```yaml zerops: + # hostname of your service - setup: app - # optional - build: ... - # optional - deploy: ... - # required - run: ... + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: alpine@3.20 - - setup: api - # optional - build: ... - # optional - deploy: ... - # required - run: ... + # OPTIONAL. Build your application + buildCommands: + - + ... ``` -Each service configuration requires a `run` section. Optional `build` and `deploy` sections can be added to further customize your process. +Build commands are optional. Zerops triggers each command in the defined order in a dedicated build container, running from the `/build/source` directory. -## Service Configuration +Before the build commands are triggered the build container contains: -### setup *[Required]* +1. base environment defined by the [base](#base) attribute +2. optional customisation of the base environment defined in the [prepareCommands](#preparecommands) attribute +3. your application code -Contains the hostname of your service (must exist in Zerops). +For detailed information about build commands, refer to the documentation for your specific technology (e.g., [Node.js](/nodejs/how-to/build-pipeline), [Go](/go/how-to/build-pipeline), [Python](/python/how-to/build-pipeline), etc.). + +#### Run build commands as a single shell instance + +Use following syntax to run all commands in the same environment context. For example, if one command changes the current directory, the next command continues in that directory. When one command creates an environment variable, the next command can access it. ```yaml -setup: app +buildCommands: + - | + cd src + ./build.sh ``` -### extends *[Optional]* +#### Run build commands as separate shell instances -The `extends` key allows you to inherit configuration from another service defined in the same `zerops.yaml` file. This is useful for creating environment-specific configurations while maintaining a common base. +When the following syntax is used, each command is triggered in a separate environment context. For example, each shell instance starts in the home directory again. When one command creates an environment variable, it won't be available for the next command. ```yaml -zerops: - - setup: base - build: - buildCommands: - - npm run build - deployFiles: ./dist - run: - start: npm start - - - setup: prod - extends: base - run: - envVariables: - NODE_ENV: production - - - setup: dev - extends: base - run: - envVariables: - NODE_ENV: development +buildCommands: + - cd src + - ./build.sh ``` -When using `extends`: -- The `extends` value must refer to another service's `setup` value in the same file -- The child service inherits all configuration from the base service -- Configuration is merged at the section level (`build`, `run`, `deploy`) -- You can override specific sections by redefining them +#### Command exit code -:::tip -Create a base service with common configuration and extend it for environment-specific services to keep your `zerops.yaml` file DRY (Don't Repeat Yourself). -::: +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/alpine/how-to/logs#build-log) to troubleshoot the error. -## Build Configuration *[Optional]* +If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `buildCommands` are finished, the application build is completed and ready for the deploy phase. -### base *[Required]* +### deployFiles -Sets the base technology for the build environment. [See available options](/zerops-yaml/base-list). +_REQUIRED._ Selects which files or folders will be deployed after the build has successfully finished. To filter out specific files or folders, use [`.deployignore`](#deployignore) file. ```yaml -build: - base: nodejs@latest +# REQUIRED. Select which files / folders to deploy after +# the build has successfully finished +deployFiles: + - app ``` -You can specify multiple technologies: - -```yaml -build: - base: - - nodejs@latest - prepareCommands: - - zsc add python@3.9 -``` +Determines files or folders produced by your build, which should be deployed to your runtime service containers. -### os *[Optional]* +The path starts from the **root directory** of your project (the location of `zerops.yaml`). You must enclose the name in quotes if the folder or the file name contains a space. -Deprecated. The operating system is part of the `base` value, for example `ubuntu/nodejs@22` or `alpine/nodejs@22`. Use the OS-prefixed form in both `build.base` and `run.base` instead of setting `os`. A bare `nodejs@22` defaults to Alpine. +The files/folders will be placed into `/var/www` folder in runtime, e.g. `./src/assets/fonts` would result in `/var/www/src/assets/fonts`. -Current versions: +#### Examples -- {data.alpine.default} -- {data.ubuntu.default} +Deploys a folder, and a file from the project root directory: ```yaml -build: - base: ubuntu/nodejs@22 +deployFiles: + - app + - file.txt ``` -### prepareCommands *[Optional]* - -Customizes the build environment by installing additional dependencies or tools. +Deploys the whole content of the build container: ```yaml -build: - prepareCommands: - - sudo apt-get update - - sudo apt-get install -y some-package +deployFiles: . ``` -:::note -`build.prepareCommands` run in the `/home/zerops` directory. -::: - -### buildCommands *[Optional]* - -Defines the commands to build your application. +Deploys a folder, and a file in a defined path: ```yaml -build: - buildCommands: - - npm install - - npm run build +deployFiles: + - ./path/to/file.txt + - ./path/to/dir/ ``` -:::note -`build.buildCommands` run in the `/build/source` directory. -::: +#### How to use a wildcard in the path -#### Running commands in a single shell instance: +Zerops supports the `~` character as a wildcard for one or more folders in the path. + +Deploys all `file.txt` files that are located in any path that begins with `/path/` and ends with `/to/` ```yaml -buildCommands: - - | - npm install - npm run build +deployFiles: ./path/~/to/file.txt ``` -### deployFiles *[Required]* - -Specifies which files or folders to deploy after a successful build. +Deploys all folders that are located in any path that begins with `/path/to/` ```yaml -build: - deployFiles: - - dist - - package.json - - node_modules +deployFiles: ./path/to/~/ ``` -The files/folders will be placed into `/var/www` folder in runtime, e.g. `./src/assets/fonts` would result in `/var/www/src/assets/fonts`. - -#### Using wildcards: - -Zerops supports the `~` character as a wildcard for one or more folders in the path. - -Deploys all `file.txt` files that are located in any path that begins with `/path/` and ends with `/to/`. +Deploys all folders that are located in any path that begins with `/path/` and ends with `/to/` ```yaml -deployFiles: ./path/~/to/file.txt +deployFiles: ./path/~/to/ ``` +:::note Example By default, `./src/assets/fonts` deploys to `/var/www/src/assets/fonts`, keeping the full path. Adding `~`, like `./src/assets/~fonts`, shortens it to `/var/www/fonts` +::: #### .deployignore @@ -380,3376 +358,4280 @@ This example above ignores `file.txt` in ANY directory named `src`, such as: `.deployignore` file also works with [`zcli service deploy`](/references/zcli/commands#deploy) command. ::: -### cache *[Optional]* +### cache -Defines which files or folders to cache for subsequent builds. +_OPTIONAL._ Defines which files or folders will be cached for the next build. ```yaml -build: - cache: node_modules +# OPTIONAL. Which files / folders you want to cache for the next build. +# Next builds will be faster when the cache is used. +cache: file.txt ``` -For more information, see our detailed [guide on build cache](/features/build-cache), complete with extensive examples. - -### addToRunPrepare *[Optional]* - -Defines files or folders to be copied from the build container to the prepare runtime container. - -### envVariables *[Optional]* - -Sets environment variables for the build environment. +The cache attribute helps optimize build times by preserving specified files between builds. -```yaml -build: - envVariables: - DB_NAME: db - DB_HOST: db - DB_USER: db - DB_PASS: ${db_password} -``` +The cache attribute supports the [~ wildcard character](#how-to-use-a-wildcard-in-the-path). -:::info -The `yamlPreprocessor` option in your project & service import YAML allows you to generate random secret values, passwords, and public/private key pairs. For more information, see the [yamlPreprocessor](/references/import-yaml/pre-processor) page. -::: +Learn more about the [build cache system](/features/build-cache) in Zerops. -## Deploy Configuration *[Optional]* +### envVariables -### temporaryShutdown *[Optional]* +_OPTIONAL._ Defines the environment variables for the build environment. -Controls the container replacement order during deployment. +Enter one or more env variables in following format: ```yaml -deploy: - temporaryShutdown: true +zerops: + # define hostname of your service + - setup: app + # ==== how to build your application ==== + build: + base: alpine@3.20 + … + + # OPTIONAL. Defines the env variables for the build environment: + envVariables: + MODE: production + DB_NAME: db + DB_HOST: db + DB_USER: db + DB_PASS: ${db_password} ``` -- Type: `boolean` -- Default: `false` +Read more about [environment variables](/alpine/how-to/env-variables) in Zerops. -**When `false` (default):** New containers are started before old containers are removed, ensuring zero-downtime deployment. +## Runtime configuration -**When `true`:** Old containers are removed before new containers are started, causing temporary downtime but using fewer resources during deployment. +### base -### readinessCheck *[Optional]* +_OPTIONAL._ Sets the base technology for the runtime environment. +If you don't specify the `run.base` attribute, Zerops keeps the current Alpine version for your runtime. -Defines a readiness check for your application. Requires either `httpGet` object or `exec` object. +Following options are available for Alpine builds: + +- `alpine@3.23`, `alpine@latest` +- `alpine@3.22` +- `alpine@3.21` +- `alpine@3.20` +- `alpine@3.19` +- `alpine@3.18` +- `alpine@3.17` ```yaml -deploy: - readinessCheck: - # HTTP GET method example - httpGet: - port: 80 - path: /status - host: my-host.zerops - scheme: https +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: alpine@3.20 + ... - # Common parameters - failureTimeout: 60 - retryPeriod: 10 + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: alpine@3.20 + ... ``` -Readiness checks work similarly to [health checks](#healthcheck-) but are specifically for deployment. They verify if a new deployment is ready to receive traffic. +

+ The base runtime environment contains {data.alpine.default}, Zerops command line tool, `git` and `wget`. +

-Available parameters: +:::info +You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. +::: -#### httpGet and exec -The `httpGet` and `exec` options work the same way as in [health checks](#healthcheck-). See that section for detailed parameter descriptions. +If you need to install more technologies to the runtime environment, set multiple values as a yaml array. For example: -#### Common parameters *[Optional]* -The following parameters can be used with either `httpGet` or `exec` readiness checks: +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: alpine@3.20 + ... -- **failureTimeout** - Time in seconds until container is marked as failed. -- **retryPeriod** - Time interval in seconds between readiness check attempts (equivalent to `execPeriod` in health checks). + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: + - alpine@3.20 + prepareCommands: + - zsc add nodejs@latest + ... +``` -:::tip -Unlike health checks which run continuously, readiness checks only run during deployments to determine when your application is ready to accept traffic. -::: +See the full list of supported [run base environments](/zerops-yaml/base-list). -## Runtime Configuration *[Required]* +To customise your build environment use the `prepareCommands` attribute. -### base *[Optional]* +### ports -Sets the base technology for the runtime environment. If not specified, the current version is maintained. +_OPTIONAL._ Specifies one or more internal ports on which your application will listen. -```yaml -run: - base: nodejs@latest -``` +Projects in Zerops represent a group of one or more services. Services can be of different types (runtime services, databases, message brokers, object storage, etc.). All services of the same project share a **dedicated private network**. To connect to a service within the same project, just use the service hostname and its internal port. -### os *[Optional]* +For example, to connect to an Alpine service with hostname = "app" and port = 8080 from another service of the same project, simply use `app:8080`. Read more about [how to access an Alpine service](/references/networking/internal-access#basic-service-communication). -Deprecated, same as for the build environment: put the OS into `run.base` (`ubuntu/nodejs@22`) instead. +Each port has following attributes: -### ports *[Optional]* + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port number. You can set any port number between 10 and 65435. Ports outside this interval are reserved for internal Zerops systems.
protocolOptional. Defines the protocol. Allowed values are TCP or UDP. Default value is TCP.
httpSupportOptional. httpSupport = true is the default setting for TCP protocol. Set httpSupport = false if a web server isn't running on the port. Zerops uses this information for the configuration of [public access](/features/access). httpSupport = true is available only in combination with the TCP protocol.
-Specifies the internal ports on which your application will listen. +### prepareCommands + +_OPTIONAL._ Customises the Alpine runtime environment by installing additional dependencies or tools to the runtime base environment. + +

+ The base Alpine environment contains {data.alpine.default}, [Zerops command line tool](/references/cli) and `git` and `wget`. To install additional packages or tools add one or more prepare commands: +

```yaml -run: - ports: - - port: 8080 - protocol: TCP # Optional - httpSupport: true # Optional - - port: 8081 +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + ... + + # ==== how to run your application ==== + run: + # OPTIONAL. Customise the runtime environment by installing additional packages + # or tools to the base Alpine runtime environment. + prepareCommands: + - sudo apk add --no-cache something + - curl something else ... ``` -Available parameters: +When the first deploy with a defined prepare attribute is triggered, Zerops will -#### port *[Required]* -Defines the port number on which your application listens. Must be between *10* and *65435*, as ports outside this range are reserved for internal Zerops systems. +1. create a prepare runtime container +2. optionally: [copy selected folders or files from your build container](#copy-folders-or-files-from-your-build-container) +3. run the `prepareCommands` commands in the defined order -#### protocol *[Optional]* -Specifies the network protocol to use: -- Allowed values: `TCP` *(default)* or `UDP` +:::note +`run.prepareCommands` run in the `/home/zerops` directory. +::: -#### httpSupport *[Optional]* -Indicates whether the port is running a web server: -- Default value: `false` -- Set to `true` if a web server is running on the port -- Only available with TCP protocol -- Used by Zerops for [public access](/features/access) configuration +#### Command exit code -### prepareCommands *[Optional]* +If any command fails, it returns an exit code other than 0 and the deploy is canceled. Read the [prepare runtime log](/alpine/how-to/logs#prepare-runtime-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `prepareCommands` commands are finished, your custom runtime environment is ready for the deploy phase. -Customizes the runtime environment by installing additional dependencies or tools. +#### Cache of your custom runtime environment -:::note -`run.prepareCommands` run in the `/home/zerops` directory. -::: +Some packages or tools can take a long time to install. Therefore, Zerops caches your custom runtime environment after the installation of your custom packages or tools is completed. When the second or following deploy is triggered, Zerops will use the custom runtime cache from the previous deploy if following conditions are met: -### initCommands *[Optional]* +1. Content of the [build.addToRunPrepare](#copy-folders-or-files-from-your-build-container) and `run.prepareCommands` attributes didn't change from the previous deploy +2. The custom runtime cache wasn't invalidated in the Zerops GUI. -Defines commands to run each time a new runtime container starts or restarts. +To invalidate the Zerops runtime cache go to your service detail in Zerops GUI, choose **Service dashboard & runtime containers** from the left menu and click on the **Open pipeline detail** button. Then click on the **Clear runtime prepare cache** button. -```yaml -run: - initCommands: - - rm -rf ./cache -``` +When the prepare cache is used, Zerops doesn't create a prepare runtime container and executes the deployment of your application directly. -:::note -`run.initCommands` run in the `/var/www` directory. -::: +#### Single or separated shell instances -### start *[Required for some runtimes]* +You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -Defines the start command for your application. +### Copy folders or files from your build container + +

+ The prepare runtime container contains {data.alpine.default}, [Zerops command line tool](/references/cli) and `git` and `wget`. +

+ +The prepare runtime container does not contain your application code nor the built application. If you need to copy some folders or files from the build container to the runtime container (e.g. a configuration file) use the `addToRunPrepare` attribute in the [build section](#build-pipeline-configuration). ```yaml -run: - start: npm start +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + ... + addToRunPrepare: ./runtime-config.yaml + + # ==== how to run your application ==== + run: + # OPTIONAL. Customise the runtime environment by installing additional packages + # or tools to the base Alpine runtime environment. + prepareCommands: + - sudo apk add --no-cache something + - curl something else + ... ``` -### startCommands *[Optional]* +In the example above Zerops will copy the `runtime-config.yaml` file from your build container **after the build has finished** into the new **prepare runtime** container. The copied files and folders will be available in the `/home/zerops` folder in the new prepare runtime container before the prepare commands are triggered. -Defines start commands. +### initCommands -Unlike `start`, you can define multiple commands that starts their own processes. +_OPTIONAL._ Defines one or more commands to be run each time a new runtime container is started or a container is restarted. ```yaml -run: - startCommands: - # start the application - - command: npm run start:prod - name: server - # start the replication - - command: litestream replicate -config=litestream.yaml - name: replication - # restore the database on container init +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... + + # ==== how to run your application ==== + run: + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your Alpine application is started. initCommands: - - litestream restore -if-replica-exists -if-db-not-exists -config=litestream.yaml $DB_NAME + - rm -rf ./cache ``` -Each entry supports: +These commands are triggered in the runtime container before your Alpine application is started via the [start command](#start). -- `command` (required) - the command to run -- `name` (optional) - distinguishes the process in logs -- `workingDir` (optional, default `/var/www`) - the directory the command and its `initCommands` run in -- `user` (optional, default `zerops`) - the system user the command and its `initCommands` run under. The user has to exist in the runtime container, create it in `prepareCommands`. -- `initCommands` (optional) - commands run before this process starts, each time a container starts or restarts +:::note +`run.initCommands` run in the `/var/www` directory. +::: -```yaml -run: - prepareCommands: - - sudo adduser --system --group --home /home/git git - startCommands: - - command: gitea web - name: gitea - user: git -``` +Use init commands to clean or initialise your application cache or similar operations. -See [start-commands-example](https://github.com/zeropsio/start-commands-example) +:::caution +The init commands will delay the start of your application each time a new runtime container is started (including the horizontal [scaling](/alpine/how-to/scaling) or when a runtime container is restarted). -### documentRoot *[Optional]* +Do not use the init commands for customising your runtime environment. Use the [run:prepareCommands](#preparecommands-1) attribute instead. +::: -Customizes the root folder for publicly accessible web server content. The path is relative to `/var/www`. Available for the [Nginx](/nginx/how-to/build-pipeline#documentroot) and [PHP](/php/how-to/build-pipeline#documentroot) services. The [Static service](/static/overview#document-root) ignores it, use `routing.root` there. +#### Command exit code -```yaml -run: - base: alpine/nginx@latest - documentRoot: dist -``` +If any of the `initCommands` fails, it returns an exit code other than 0, but deploy is **not** canceled. After all init commands are finished, regardless of the status code, the application is started. Read the [runtime log](/alpine/how-to/logs#runtime-log) to troubleshoot the error. -### siteConfigPath *[Optional]* +#### Single or separated shell instances -Sets the custom webserver configuration for the [Nginx](/nginx/how-to/customize-web-server), [PHP](/php/how-to/customize-web-server) and [Static](/static/overview#custom-nginx-configuration) services. The path is relative to `/var/www` and the file must be part of the deployed files. A `.tmpl` file is rendered as a template with `{{.DocumentRoot}}` and `{{.Environment.NAME}}`, any other file is used verbatim. On the Static service `routing` takes precedence: when both are set, `siteConfigPath` is ignored. +You can configure your `initCommands` to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -```yaml -run: - base: alpine/nginx@latest - siteConfigPath: site_config.tmpl -``` +### envVariables -### envVariables *[Optional]* +_OPTIONAL._ Defines the environment variables for the runtime environment. -Defines environment variables for the runtime environment. +Enter one or more env variables in following format: ```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to run your application ==== run: - base: nodejs@20 + # OPTIONAL. Defines the env variables for the runtime environment: envVariables: + MODE: production DB_NAME: db DB_HOST: db DB_USER: db DB_PASS: ${db_password} ``` -### envReplace *[Optional]* +Read more about [environment variables](/alpine/how-to/env-variables) in Zerops. -Automatically replaces environment variable placeholders in your static files with their actual values during deployment. +### start + +_OPTIONAL._ Defines the start command for your Alpine application. ```yaml -run: - envReplace: - delimiter: "%%" - target: - - config/jwt/public.pem - - config/jwt/private.pem - - ./config/ +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... + + # ==== how to run your application ==== + run: + # OPTIONAL. Your Alpine application start command + start: ./app ``` -Available parameters: +### health check -#### delimiter *[Required]* -Characters that wrap your variable names in placeholders (e.g., `%%` means placeholders look like `%%VARIABLE%%`). -- Type: `string` or `array of strings` -- Supports multiple delimiters simultaneously +_OPTIONAL._ Defines a health check. -#### target *[Required]* -Files or directories to process for variable replacement. -- Type: `string` or `array of strings` -- Can be specific files or directories +`healthCheck` requires either one `httpGet` object or one `exec` object. -:::warning -Directory targets only process files directly in the specified directory, not subdirectories for performance reasons. To process files in subdirectories, specify each subdirectory explicitly in the target array. For example, ./config/ processes only files in the config directory itself, not files in ./config/jwt/ or other subdirectories. -::: +#### httpGet -:::info -Not to be confused with the [`zsc env-replace`](/references/zsc#env-replace) command, which renders `{{.VARIABLE}}` Go templates from a source path into a separate target path and can be run from `initCommands` or manually. -::: +Configures the health check to request a local URL using a HTTP GET method. -**How it works:** -1. Define placeholders in your files using the specified delimiters -2. Set environment variables with matching names -3. During deployment, Zerops finds and replaces placeholders with actual values +Following attributes are available: -**Example usage:** + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. +If your application requires a https request, set scheme: https
+ +**Example:** ```yaml -run: - envReplace: - delimiter: "%%" - target: - - ./config/ - - ./templates/ - - ./ # Only processes files in root, not subdirectories -``` +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -File content before replacement: -``` -# config/jwt/public.pem -%%JWT_PUBLIC_KEY_CONTENT%% -``` + # ==== how to run your application ==== + run: + # OPTIONAL. Your Alpine application start command + start: ./app -Environment variable: -``` -JWT_PUBLIC_KEY_CONTENT=-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... ------END PUBLIC KEY----- + # OPTIONAL. Define a health check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + healthCheck: + httpGet: + port: 80 + path: /status ``` -The placeholder gets replaced with the actual JWT public key during deployment. - -### routing *[Optional]* - -Configures the document root, redirects, CORS and HTTP headers of the [Static service](/static/overview#routing--configuration). Any other service, including the Nginx service, ignores this section without an error. +#### exec -```yaml -run: - base: alpine/static - routing: - root: dist - cors: "'*' always" - redirects: - - from: /old-path - to: /new-path - status: 301 - headers: - - for: "/*" - values: - X-Frame-Options: "'DENY'" -``` +Configures the health check to run a local command. +Following attributes are available: -Available parameters: + + + + + + + + + + + + + +
ParameterDescription
command + Defines a local command to be run. -#### root *[Optional]* -Sets the folder served by the service, relative to `/var/www` (default `/var/www` itself). This is the Static service's equivalent of `documentRoot`. -- Type: `string` + The command has access to the same [environment variables](/alpine/how-to/create#set-secret-environment-variables) as your Alpine application. -#### cors *[Optional]* -Enables CORS headers for cross-origin requests. -- Type: `string` -- Sets `Access-Control-Allow-Origin`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers`, and `Access-Control-Expose-Headers`, all to the same value -- Special case: `"*"` is automatically converted to `'*'` + A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. +
-#### redirects *[Optional]* -Defines URL redirects and rewrites. -- Type: `array of objects` -- Each redirect object supports: - - **from** *[Required]* - Source path to match. Without `*` it matches the exact path, with a trailing `*` it matches the path prefix ([path matching](/static/overview#path-matching)). An absolute URL (`https://old-domain.com/*`) matches on the request domain. - - **to** *[Required]* - Destination path or absolute URL - - **status** *[Optional]* - HTTP status code. Omit it for a masked redirect that serves the target content under the original URL. Required for absolute URLs, and limited to `301` or `302` when `from` is absolute. - - **preservePath** *[Optional]* - Append the part of the path after the wildcard to `to`. Not allowed on masked redirects. - - **preserveQuery** *[Optional]* - Append the original query string. Not allowed on masked redirects. +**Example:** -#### headers *[Optional]* -Sets custom HTTP headers for specific paths. -- Type: `array of objects` -- Each header object supports: - - **for** *[Required]* - Path to match, same rules as `from` (`"/*"` for the whole site, `"/"` matches the homepage only) - - **values** *[Required]* - Object with header name/value pairs. Values are inserted into `add_header` verbatim, so include the quotes: `X-Frame-Options: "'DENY'"` +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -**Example usage:** + # ==== how to run your application ==== + run: + # REQUIRED. Your Alpine application start command + start: ./app -```yaml -run: - routing: - cors: "'*' always" - redirects: - # Permanent redirect - - from: /old-page - to: /new-page - status: 301 - # Wildcard redirect with path preservation - - from: /blog/* - to: /articles/ - preservePath: true - status: 302 - headers: - - for: "/*" - values: - X-Frame-Options: "'DENY'" - Content-Security-Policy: '"default-src ''self''"' + # OPTIONAL. Define a health check with a shell command. + healthCheck: + exec: + command: | + touch grass + rm -rf life + mv /outside/user /home/user ``` -### healthCheck *[Optional]* +### crontab -Defines a health check for your application. +_OPTIONAL._ Defines cron jobs. + +Setup cron jobs in the following format: ```yaml -run: - healthCheck: - # HTTP GET method example - httpGet: - port: 80 - path: /status - host: my-host.zerops - scheme: https - # OR command-based example - exec: - command: | - curl -s http://localhost:8080/status > /tmp/status - grep -q "OK" /tmp/status +zerops: + # define hostname of your service + - setup: app - # Common parameters - failureTimeout: 60 - disconnectTimeout: 30 - recoveryTimeout: 30 - execPeriod: 10 + # ==== how to run your application ==== + run: + crontab: + # REQUIRED. Sets the command to execute: + - command: "" + # REQUIRED. Sets the interval time to execute: + timing: "0 * * * *" ``` -Available parameters: +Read more about setting up [cron](/zerops-yaml/cron) in Zerops. -#### httpGet *[Optional]* -Configures the health check to request a local URL using a HTTP GET method. +## Deploy configuration -- **port** *[Required]* - Defines the port of the HTTP GET request. -- **path** *[Required]* - Defines the URL path of the HTTP GET request. -- **host** *[Optional]* - The health check is triggered from inside of your runtime container so it uses the localhost (127.0.0.1). If you need to add a host to the request header, specify it in the host attribute. -- **scheme** *[Optional]* - The health check is triggered from inside of your runtime container so no https is required. If your application requires a https request, set scheme: `https`. +### readiness check -#### exec *[Optional]* -Configures the health check to run a local command. +_OPTIONAL._ Defines a readiness check. Read more about how the [readiness check works](/alpine/how-to/deploy-process#readiness-checks) in Zerops. -- **command** *[Required]* - Defines a local command to be run. The command has access to the same environment variables. A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example above. +`readinessCheck` requires either one `httpGet` object or one `exec` object. -#### Common parameters *[Optional]* -The following parameters can be used with either `httpGet` or `exec` health checks: -- **failureTimeout** - Time in seconds until container fails after consecutive health check failures (reset by success). -- **disconnectTimeout** - Time in seconds until container is disconnected and becomes publicly unavailable. -- **recoveryTimeout** - Time in seconds until container is connected and becomes publicly available. -- **execPeriod** - Time interval in seconds between health check attempts. +#### httpGet -:::tip -Health checks continuously monitor your running application, while readiness checks verify if a new deployment is ready to receive traffic. For readiness checks, see the [readinessCheck section](#readinesscheck-). -::: +Configures the readiness check to request a local URL using a http GET method. -### crontab *[Optional]* +Following attributes are available: -Defines scheduled commands to run as cron jobs within a service. + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. +If your application requires a https request, set scheme: https
+ +**Example:** ```yaml -run: - crontab: - - command: "date >> /var/log/cron.log" - timing: "0 * * * *" - allContainers: false +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... + + # ==== how to deploy your application ==== + deploy: + # OPTIONAL. Define a readiness check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + readinessCheck: + httpGet: + port: 80 + path: /status + + # ==== how to run your application ==== + run: ... ``` -Setup cron jobs. See [examples](/zerops-yaml/cron). +Read more about how the [readiness check works](/alpine/how-to/deploy-process#readiness-checks) in Zerops. -### volume *[Optional]* +#### exec -Mounts a [Local Storage](/local-storage/overview) service's volume into the runtime containers. The mount exists only in the run phase — it is not available in the build or prepare containers, so `build` and `run.prepareCommands` cannot access the volume. See [how the mount behaves](/local-storage/how-to/connect#how-the-mount-behaves). +Configures the readiness check to run a local command. +Following attributes are available: + + + + + + + + + + + + + + +
ParameterDescription
command + Defines a local command to be run. + + The command has access to the same [environment variables](/alpine/how-to/create#set-secret-environment-variables) as your Alpine application. + + A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. +
+ +**Example:** ```yaml -run: - volume: - hostname: vol # hostname of the Local Storage service - mountPath: /srv/data # optional, defaults to /mnt/{hostname} - readOnly: false # optional, defaults to false +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... + + # ==== how to deploy your application ==== + deploy: + # OPTIONAL. Define a readiness check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + readinessCheck: + exec: + command: | + touch grass + rm -rf life + mv /outside/user /home/user ``` -Available parameters: +Read more about how the [readiness check works](/alpine/how-to/deploy-process#readiness-checks) in Zerops. -#### hostname *[Required]* -Hostname of the Local Storage service in the same project. +---------------------------------------- -#### mountPath *[Optional]* -Absolute path the volume is mounted to inside the runtime containers. Defaults to `/mnt/{hostname}`. System directories (`/etc`, `/var`, `/var/www`, `/tmp`, ...) are rejected; their subdirectories are allowed. +# Alpine > How To > Build Process -#### readOnly *[Optional]* -Mounts the volume read-only. Defaults to `false`. -:::caution -All containers of a service that mounts a volume are placed on the physical machine holding the volume, together with the containers of every other service mounting it. A service can mount at most one volume. See [Mount Local Storage to a service](/local-storage/how-to/connect) for details. +## Build process overview + +Zerops starts a temporary build container and performs the following actions: + +1. **Installs the build environment** - Sets up base system and runtime +2. **Downloads your application source code** - From [GitHub ↗](https://www.github.com), [GitLab ↗](https://www.gitlab.com) or via [Zerops CLI](/references/cli) +3. **Optionally customizes the build environment** - Runs prepare commands if configured +4. **Runs the build commands** - Executes your build process +5. **Uploads the application artifact** - Stores build output to internal Zerops storage +6. **Caches selected files** - Preserves specified files for faster future builds + +The build container is automatically deleted after the build has finished or failed. + +## Build configuration + +Configure your build process in your `zerops.yaml` file according to the pipeline guide. + +## Build environment + +### Default build environment + +The default build environment contains: + +- {data.alpine.default} +- [zCLI](/references/cli), Zerops command line tool +- + +### Customize build environment + +To install additional packages or tools, add one or more to your `zerops.yaml`. + +:::info +The application code is available in the `/build/source` folder in your build container before the prepare commands are triggered. This allows you to use any file from your application code in your prepare commands (e.g. a configuration file). ::: -:::note -For more detailed information on specific configurations, refer to the runtime-specific guides linked at the beginning of this document. +### Build hardware resources + +All runtime services use the same hardware resources for build containers: + + + + + + + + + + + + + + + + + + + + + + + + + + +
HW resourceMinimumMaximum
CPU cores15
RAM8 GB8 GB
Disk1 GB100 GB
+ +Build containers start with minimum resources and scale vertically up to maximum capacity as needed. + +### Build time limit + +The time limit for the whole build pipeline is **1 hour**. After 1 hour, Zerops will terminate the build pipeline and delete the build container. + +:::info +Build container resources are not charged separately. Limited build time is included in your [project core plan](/company/pricing#project-core-plans), with additional build time available if needed. ::: -*Need help? Join our [Discord community](https://discord.gg/zeropsio).* +## Troubleshooting builds -## Editor support (JSON Schema) +:::tip Advanced troubleshooting +For complex build issues that require investigation, you can enable [debug mode](/features/debug-mode) to pause the build process at specific points and inspect the build container state interactively. +::: -Zerops publishes an official [JSON Schema ↗](https://json-schema.org/) for `zerops.yaml`: +### Build and prepare command failures -``` -https://api.app-prg1.zerops.io/api/rest/public/settings/zerops-yml-json-schema.json -``` +If any or fails (returns non-zero exit code), the build is canceled. Check the to troubleshoot the error. -With the schema attached, your editor gives you: +### Build cache issues -- **Autocomplete** for every key and nested field -- **Inline documentation** on hover -- **Validation** — typos, wrong types, and missing required fields are flagged as you type -- **Enum suggestions** for fields like `base` or `cache` +If you encounter unexpected build behavior or dependency issues, the problem might be related to cached build data. While Zerops maintains the build cache to speed up deployments, sometimes you may need to start fresh. -### Auto-detection via SchemaStore +To invalidate the build cache: -The schema is registered with [SchemaStore ↗](https://www.schemastore.org/), so most YAML-aware editors apply it automatically — no setup required — when the file is named: +1. Go to your service detail in Zerops GUI +2. Choose **Pipelines & CI/CD Settings** from the left menu +3. Click on the **Invalidate build cache** button -- `zerops.yml` -- `zerops.yaml` +This will force Zerops to run the next build clean, including all prepare commands. -This covers VS Code (with the [YAML extension by Red Hat ↗](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml)), all JetBrains IDEs, and any editor backed by [`yaml-language-server` ↗](https://github.com/redhat-developer/yaml-language-server) (Neovim, Helix, Sublime LSP, …). +Learn more about [build cache behavior](/features/build-cache). -### Manual attachment +## More resources -If your file is named differently, add a modeline at the top: +For more details about the build and deploy pipeline, including how to cancel builds and manage application versions, see the [general pipeline documentation](/features/pipeline). -```yaml -# yaml-language-server: $schema=https://api.app-prg1.zerops.io/api/rest/public/settings/zerops-yml-json-schema.json -zerops: - - setup: app - # ... -``` +## Next steps + +- Understand the +- Learn how to +- Explore + +---------------------------------------- + +# Alpine > How To > Controls -The same URL works in any editor that lets you map a schema to a file pattern manually (e.g., `yaml.schemas` in VS Code `settings.json`, or JetBrains' **JSON Schema Mappings** panel). ---------------------------------------- -# Zerops Yaml > Cron +# Alpine > How To > Create -Cron jobs are scheduled commands that execute automatically inside a service's containers based on defined timing rules. +Zerops provides a Alpine runtime service with extensive build support. Alpine runtime is highly scalable and customisable to suit both development and production. -In Zerops, these jobs are configured in the `run` section of `zerops.yaml` file under the `crontab` key. +## Create Alpine service using Zerops GUI -## Parameters +First, set up a project in Zerops GUI. Then go to the project dashboard page and choose **Add new service** in the left menu in the **Services** block. Then add a new Alpine service: -### command -*string, REQUIRED* +[Video: /vids/services/golang.webm](/vids/services/golang.webm) -The shell command to execute at the scheduled time. This can be any valid command. +### Choose Alpine version -### timing -*string, REQUIRED* +Following Alpine versions are currently supported: -The schedule for when the task should run, specified in standard cron format using five space-separated fields: - - Minute (0–59) - - Hour (0–23) - - Day of the month (1–31) - - Month (1–12) - - Day of the week (0–7; both 0 and 7 represent Sunday) +:::info +You can [change](/alpine/how-to/upgrade) the major version at any time later. +::: -#### Examples - - `"0 5 * * *"` – Runs daily at 5:00 AM. - - `"*/10 * * * *"` – Runs every 10 minutes. +### Set a hostname -### allContainers -*boolean, REQUIRED* +Enter a unique service identifier like "app","cache", "gui" etc. Duplicate services with the same name in the same project are forbidden. -**Options:** -- `true` – Command runs on all containers. -- `false` – Command runs on only one container. +#### Limitations: -### workingDir -*string, REQUIRED* +- maximum 25 characters +- must contain only lowercase ASCII letters (a-z) or numbers (0-9) -Specifies the directory where the command will be executed. If not set, it defaults to `/var/www`. +:::caution +The hostname is fixed after the service is created. It can't be changed later. +::: -## Example Configurations -Here’s a basic example of how to set up a cron job in your service's `zerops.yaml`: +### Set secret environment variables -```yaml -run: - crontab: - - command: "date >> /var/log/cron.log" - timing: "0 * * * *" -``` -This configuration logs the current date to `/var/log/cron.log` every hour. +Add environment variables with sensitive data, such as password, tokens, salts, certificates etc. These will be securely saved inside Zerops and added to your runtime service upon start. -### Running on Multiple Containers -By default, cron jobs run on a single container, even if multiple containers exist for the service. To execute a command across all containers, you can use the `allContainers` parameter: +Setting the secret environment variables is optional. You can set them later in Zerops GUI. + +Read more about [different types of env variables](/alpine/how-to/env-variables#service-env-variables) in Zerops. + +## Create Alpine service using zCLI + +zCLI is the Zerops command-line tool. To create a new Alpine service via the command-line, follow these steps: + +1. [Install & setup zCLI](/references/cli) +2. [Create a project description file](/alpine/how-to/create#create-a-project-description-file) +3. [Create a project with a Alpine and PostgreSQL service](#full-example) + +### Create a project description file + +Zerops uses a yaml format to describe the project infrastructure. + +#### Basic example: + +Create a directory `my-project`. Create an `description.yaml` file inside the `my-project` directory with following content: ```yaml -run: - crontab: - - command: "rm -rf /tmp/*" - timing: "0 0 * * *" - allContainers: true +# basic project data +project: + # project name + name: my-project +# array of project services +services: + - # service name + hostname: app + # service type and version number in alpine@{version} format + type: alpine@3.20 + # defines the minimum number of containers for horizontal autoscaling + minContainers: 1 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 6 + # optional: create env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' ``` -This example removes temporary files from all containers every day at midnight. -### Custom Working Directory -You can also specify a custom working directory for your commands using the `workingDir` parameter: +The yaml file describes your future project infrastructure. The project will contain one Alpine service with default [auto scaling](/alpine/how-to/scaling) configuration. Hostname will be set to "app", the internal port(s) the service listens on will be defined later in the [zerops.yaml](/alpine/how-to/build-pipeline#ports). Following secret env variables will be configured: -```yaml -run: - crontab: - - command: "php artisan schedule:run" - timing: "* * * * *" - workingDir: /var/www/html +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" ``` -In this case, the command runs every minute in the `/var/www/html` directory. -### Multiple Cronjobs -It is possible to define multiple cron jobs as a YAML object list under the `crontab` key. +#### Full example: + +Create a directory my-project. Create an description.yaml file inside the my-project directory with following content: ```yaml -run: - crontab: - - command: ... - ... - - command: ... - ... +# basic project data +project: + # project name + name: my-project + # optional: project description + description: A project with a Alpine and PostgreSQL database + # optional: project tags + tags: + - DEMO + - ZEROPS +# array of project services +services: + - # service name + hostname: app + # service type and version number in alpine@{version} format + type: alpine@3.20 + # optional: vertical auto scaling customization + verticalAutoscaling: + cpuMode: DEDICATED + minCpu: 2 + maxCpu: 5 + minRam: 2 + maxRam: 24 + minDisk: 6 + maxDisk: 50 + startCpuCoreCount: 3 + minFreeRamGB: 0.5 + minFreeRamPercent: 20 + # defines the minimum number of containers for horizontal autoscaling. Max value = 6. + minContainers: 2 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 4 + # optional: create secret env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' + - # second service hostname + hostname: db + # service type and version number in postgresql@{version} format + type: postgresql@12 + # mode of operation "HA"/"non_HA" + mode: NON_HA ``` +The yaml file describes your future project infrastructure. The project will contain an Alpine service and a [PostgreSQL](/postgresql/overview) service. ----------------------------------------- - -# Zerops Yaml > Base List +Alpine service with "app" hostname, the internal port(s) the service listens on will be defined later in the zerops.yaml. Alpine service will run with a custom vertical and horizontal scaling. Following secret env variables will be configured: +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" +``` -This is a list of all currently supported versions of technologies that can be used for [build.base](/zerops-yaml/specification#base-required) and [run.base](/zerops-yaml/specification#base) sections in `zerops.yaml`. +The hostname of the PostgreSQL service will be set to "db". The [single container](/features/scaling#single-container-mode) mode will be chosen and the default auto [scaling configuration](/postgresql/how-to/scale#configure-scaling) will be set. -:::note -Versions listed on the same line are aliases of the same underlying version. -::: +#### Description of description.yaml parameters -## Runtime services +The `project:` section is required. Only one project can be defined. - +
- - - + + - - - - + - - - - - - - - - - - - - - - - - - - - - - - + + - - - + + - - - + + - - - + + - - - + + - - - + + - - - - - - - - - + + Optional. Set the minDisk or maxDisk in GB (float). + - - - + - - -
Service TypeSupported OSVersionsParameterDescription
Build / Runtime
Bun`ubuntu` / `alpine` -- `bun@1.3.9`, `bun@1.3`, `bun@latest` -- `bun@1.2.2`, `bun@1.2` -- `bun@nightly` -- `bun@canary` -- `bun@1.1.34`, `bun@1.1(Ubuntu only)` -
Deno`ubuntu` -- `deno@2.0.0`, `deno@2`, `deno@latest` -- `deno@1.45.5`, `deno@1` -
.NET`ubuntu` / `alpine` -- `dotnet@10`, `dotnet@latest` -- `dotnet@9` -- `dotnet@8` -- `dotnet@7` -- `dotnet@6` -
Elixir`ubuntu` / `alpine` -- `elixir@1.16`, `elixir@1`, `elixir@latest` -
Gleam`ubuntu` -- `gleam@1.5`, `gleam@1`, `gleam@latest` -hostname + The unique service identifier. + + The hostname of the new database will be set to the `hostname` value. + + Limitations: +
    +
  • duplicate services with the same name in the same project are forbidden
  • +
  • maximum 25 characters
  • +
  • must contain only lowercase ASCII letters (a-z) or numbers (0-9)
  • +
+
Go`ubuntu` / `alpine` -- `go@1.22`, `go@1`, `golang@1`, `go@latest`, `golang@latest` -type + Specifies the service type and version. + + See what [Alpine service types](/references/import-yaml/type-list#runtime-services) are currently supported. +
Java`ubuntu` / `alpine` -- `java@21`, `java@latest` -- `java@17` -verticalAutoscaling + Optional. Defines [custom vertical auto scaling parameters](/alpine/how-to/create#set-auto-scaling-configuration). + + All verticalAutoscaling attributes are optional. Not specified attributes will be set to their default values. +
Node.js`ubuntu` / `alpine` -- `nodejs@24`, `nodejs@latest` -- `nodejs@22` -- `nodejs@20` -- `nodejs@18` -- cpuMode + Optional. Accepts `SHARED`, `DEDICATED` values. Default is `SHARED` +
Python`ubuntu` / `alpine` -- `python@3.14 (Ubuntu only)`, `python@latest` -- `python@3.12` -- `python@3.11` -- minCpu/maxCpu + Optional. Set the minCpu or maxCpu in CPU cores (integer). +
Rust`ubuntu` / `alpine` -- `rust@1`, `rust@latest`, `rust@stable` -- `rust@1.86` -- `rust@1.80` -- `rust@1.78` -- `rust@nightly` -- minRam/maxRam + Optional. Set the minRam or maxRam in GB (float). +
  BuildRuntime
PHP + Apache`ubuntu` / `alpine` -- `php@8.5`, `php@latest` -- `php@8.4` -- `php@8.3` -- `php@8.1` -- minDisk/maxDisk -- `php-apache@8.5`, `php-apache@latest` -- `php-apache@8.4` -- `php-apache@8.3` -- `php-apache@8.1` -
PHP + nginx`ubuntu` / `alpine` -- `php@8.5`, `php@latest` -- `php@8.4` -- `php@8.3` -- `php@8.1` -minContainers -- `php-nginx@8.5`, `php-nginx@latest` -- `php-nginx@8.4` -- `php-nginx@8.3` -- `php-nginx@8.1` -
+ Optional. Default = 1. Defines the minimum number of containers for [horizontal autoscaling](/alpine/how-to/create#horizontal-auto-scaling). -## Static services + Limitations: - - - - - - - - - - - - - - - - - - + Current maximum value = 10. + - - - + - - -
Service TypeSupported OSVersions
BuildRuntime
nginx`ubuntu`/`alpine`- -- `nginx@1.22`, `nginx@latest` -
static`ubuntu`/`alpine`-maxContainers -- `static`, `static@1.0`, `static@latest` -
+ Defines the maximum number of containers for [horizontal autoscaling](/alpine/how-to/create#horizontal-auto-scaling). -## Containers and virtual machines + Limitations: - - - - - - + Current maximum value = 10. + - - - - - - - - - + - - - - - - - - - - + Optional. Defines one or more secret env variables as a key value map. See env variable [restrictions](/alpine/how-to/env-variables#env-variable-restrictions). +
Service TypeSupported OSVersions
BuildRuntime
Docker`alpine`-envSecrets -- `docker@26.1`, `docker@latest` -
Alpine`alpine` -- `alpine@3.23`, `alpine@latest` -- `alpine@3.22` -- `alpine@3.21` -- `alpine@3.20` -- `alpine@3.19` -- `alpine@3.18` -- `alpine@3.17` -
Ubuntu`ubuntu` -- `ubuntu@26.04` -- `ubuntu@24.04` -- `ubuntu@22.04`, `ubuntu@latest` -
----------------------------------------- - -# Zcp > Quickstart - - -Use this when you want the fastest hands-on ZCP loop: deploy an **AI Agent** recipe, authorize your coding agent, open Browser VS Code, and ask for one product change. - -ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. The screenshots below use Claude Code as the walkthrough example. - -Some [Zerops recipes](https://app.zerops.io/recipes) include an **AI Agent** environment. That preset creates app services, managed services, the `zcp@1` workspace, Browser VS Code, and bundled agent wiring in one deploy. - -This quickstart uses [Laravel showcase](https://app.zerops.io/recipes/laravel-showcase?environment=ai-agent) because it includes real managed services. The same flow works for other recipes that offer AI Agent (local variants exist too). - -## Prerequisites - -- A Zerops account with permission to create a project. -- A subscription login or API credentials for your chosen coding agent (Claude Code, Codex, Antigravity, or Grok Build). Zerops wires the agent to ZCP, but your agent subscription or model credentials stay yours. - -## 1. Choose the AI Agent recipe - -1. Open the [Zerops recipes catalog](https://app.zerops.io/recipes). -2. Open a recipe with an **AI Agent** environment. For example, open [Laravel showcase](https://app.zerops.io/recipes/laravel-showcase?environment=ai-agent). -3. Select **AI Agent**. -4. Keep **Coding Agent** and **Cloud IDE** enabled. -5. Deploy the recipe. +### Create a project based on the description.yaml -The deploy creates app runtimes, managed dependencies, and a `zcp@1` workspace. In this recipe it appears as the `zcp` service. The agent, terminal, and browser IDE run there. App code still deploys to the app runtimes, not to `zcp`. +When you have your `description.yaml` ready, use the `zcli project project-import` command to create a new project and the service infrastructure. -## 2. Authorize your coding agent +```sh +Usage: + zcli project project-import importYamlPath [flags] -When provisioning finishes, the dashboard opens the authentication flow for your bundled agent. If you are using Claude Code (as in the screenshots below), use your own Claude Code subscription login or API credentials. +Flags: + -h, --help Help for the project import command. + --org-id string If you have access to more than one organization, you must specify the org ID for which the + project is to be created. + --working-dir string Sets a custom working directory. Default working directory is the current directory. (default "./") +``` -This is separate from `ZCP_API_KEY`, the Zerops token used by ZCP. Your agent login or API key is used only by the bundled agent. +Zerops will create a project and one or more services based on the `description.yaml` content. -If you close the prompt, open the `zcp` service in the dashboard. Its panel shows the browser workspace, web terminal, SSH access, desktop editor access, and agent authorization state. +Maximum size of the `description.yaml` file is 100 kB. -## 3. Open the workspace +You don't specify the project name in the `zcli project project-import` command, because the project name is defined in the `description.yaml`. -After authentication, continue into **Browser VS Code**. The workspace opens with files, ZCP configuration, terminal access, and your coding agent panel (the Claude Code panel in the screenshots below). +If you have access to more than one client, you must specify the client ID for which the project is to be created. The `clientID` is located in the Zerops GUI under the client name on the project dashboard page. -You are now inside the remote workspace. The agent can read live state, use the MCP tools, reach private services, and deploy app changes to the runtimes created by the recipe. +### Add Alpine service to an existing project -## 4. Ask for a product outcome +#### Example: -In your coding agent, ask for the app behavior in natural language. A good first prompt is intentionally short: +Create a directory `my-project` if it doesn't exist. Create an `import.yaml` file inside the `my-project` directory with following content: -```text -Build a task board for my team. -Tasks should stay saved after refresh. +```yaml +# basic project data +project: + # project name + name: my-project +# array of project services +services: + - # service name + hostname: app + # service type and version number in alpine@{version} format + type: alpine@3.20 + # defines the minimum number of containers for horizontal autoscaling + minContainers: 1 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 6 + # optional: create env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' ``` -The agent should deploy, verify, read evidence, and return proof for the app task. Add detail only when it changes the work. - -Add details when they change the product, stack, runtime layout, acceptance criteria, or delivery preference: +The yaml file describes the list of one or more services that you want to add to your existing project. In the example above, one Alpine service version 1 with default [auto scaling](/alpine/how-to/scaling) configuration will be added to your project. Hostname of the new service will be set to `app`. Following secret env variables will be configured: -```text -In this Laravel app, add a task board backed by the existing PostgreSQL service. -A user can create a task, refresh the page, and still see it. +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" ``` -:::note Prompt shape - -Quickstart prompts are short so you can see what ZCP carries behind the request. Longer, detailed prompts are fine for larger engineering work, especially when they change product behavior, stack, runtime layout, acceptance criteria, delivery preference, credentials, or safety approvals. -::: - -## 5. Read the proof +The content of the `services:` section of `import.yaml` is identical to the project description file. The `import.yaml` never contains the `project:` section because the project already exists. -The final answer should give you a real URL, endpoint, UI state, stored result, or blocker. Open the URL and try the behavior the agent says it verified. +When you have your `import.yaml` ready, use the `zcli project service-import` command to add one or more services to your existing Zerops project. -For the task-board prompt, create a task, refresh the page, and confirm the task is still there. If it disappears, the app is not done; ask the agent to verify that exact behavior again and continue from current evidence rather than starting over. +```sh +Usage: + zcli project service-import importYamlPath [flags] -If the agent cannot finish, useful output names the blocker: missing credential, missing decision, unsupported runtime choice, or repeated failure it could not recover from. +Flags: + -h, --help Help for the project service import command. + -P, --project-id string If you have access to more than one project, you must specify the project ID for which the + command is to be executed. +``` -## Next steps +zCLI commands are interactive, when you press enter after `zcli project service-import importYamlPath`, you will be given a list of your projects to choose from. -- [Build and ship](/zcp/workflows/build-with-zcp) — Runtime layout, development work, delivery, packaging, and production release. -- [How it works](/zcp/concept/how-it-works) — Live state, runtime fit, app wiring, deploy evidence, behavior proof, and blockers. -- [Trust model](/zcp/security/trust-model) — What the project-scoped token lets the agent do, and where the safety boundary sits. +Maximum size of the import.yaml file is 100 kB. ---------------------------------------- -# Zcp > Overview +# Alpine > How To > Customize Runtime -This section covers, in order: +## Build Custom Runtime Images -
+Zerops allows you to build custom runtime images (CRI) when the default base runtime images don't meet your application's requirements. This is an optional phase in the [build and deploy pipeline](/features/pipeline#runtime-prepare-phase-optional). -
+Alpine is a versatile base for running anything not explicitly offered as a dedicated Zerops runtime. You can install any packages and tools you need, treating it as a clean OS to customize however you want. -GET STARTED +It is also a great option when you need a specific version of a technology (like Go, Node.js, or PHP) that Zerops doesn't support by default—whether it's an older version for legacy projects or a newer release not yet available. -

Quickstart and concept

+## Configuration -[Quickstart](/zcp/quickstart) for hands-on; [How it works](/zcp/concept/how-it-works) for the work loop. +### Default Runtime Environment -
+The default runtime environment contains: -
+- {data.alpine.default} +- [zCLI](/references/cli) +- -SETUP +### When You Need a Custom Runtime Image -

Remote or local workspace

+Since Alpine serves as a general-purpose base, you'll likely want to customize it for your specific use case. Common scenarios include: -[Remote or local setup](/zcp/setup/choose-workspace), [Trust model](/zcp/security/trust-model), and [Production boundary](/zcp/security/production-policy). +:::important +You should not include your application code in the custom runtime image, as your built/packaged code is deployed automatically into fresh containers. +::: -
+Here are examples of configuring custom runtime images in your `zerops.yml`: -
+### Basic Setup -WORKFLOWS +### Using Build Files in Runtime Preparation -

Build, package, promote

+For complete configuration details, see the [runtime prepare phase configuration guide](/features/pipeline#configuration). -[Build and ship](/zcp/workflows/build-with-zcp), [Package a running service](/zcp/workflows/package-running-service), [Promote to production](/zcp/workflows/promote-to-production). +## Process and Caching -
+### How Runtime Prepare Works +The runtime prepare process follows the same steps for all runtimes. See [how runtime prepare works](/features/pipeline#how-it-works) for the complete process details. -
+### Caching Behavior +Zerops caches custom runtime images to optimize deployment times. Learn about [custom runtime image caching](/features/pipeline#custom-runtime-image-caching) including when images are cached and reused. -REFERENCE +### Build Management +For information about managing builds and deployments, see [managing builds and deployments](/features/pipeline#manage-builds-and-deployments). -

Troubleshooting and lookup

+:::warning +Local Storage volumes are not available during the runtime prepare phase, and start commands (such as a SeaweedFS mount) do not run there. +::: -[Workflows in depth](/zcp/reference/agent-workflow), [ZCP MCP tools](/zcp/reference/mcp-operations), [Troubleshooting](/zcp/reference/troubleshooting), [Glossary](/zcp/glossary). +## Troubleshooting -
+If your `prepareCommands` fail, check the for specific error messages. -
+---------------------------------------- -For the broader feature concept — why coding agents need real project infrastructure rather than a sandbox or generated artifact — start with [Infrastructure for Coding Agents](/features/coding-agents). +# Alpine > How To > Deploy Process -With the generated workflow instructions enabled, an app task ends in proof or a blocker. **Proof** is a deployed runtime plus the URL, endpoint response, UI state, worker result, or stored data that shows the requested behavior works. A **blocker** is the agent reading the relevant Zerops evidence and naming the missing credential, decision, unsupported fit, or repeated failure. -Your prompt can stay about the product. Name the stack, runtime layout, acceptance criteria, delivery path, external credentials, or risky approval only when those decisions matter. -## What the agent gets +---------------------------------------- -
+# Alpine > How To > Env Variables -
-STATE -### Current state +---------------------------------------- -Services, runtime layout, managed dependencies, env-var keys and references, logs, events, deploy history, verification state, and saved work state. +# Alpine > How To > Filebrowser -
-
-CONTROLS +---------------------------------------- -### Zerops operations +# Alpine > How To > Logs -Project-scoped tools for discovering services, changing env vars, managing runtimes, deploying, verifying, scaling, public access, and delivery setup. -
-
+---------------------------------------- -INSTRUCTIONS +# Alpine > How To > Scaling -### Workflow -The generated instructions combine service setup and app development: inspect state, choose the runtime target, use or create services, wire code and `zerops.yaml`, deploy, verify, and choose delivery. The Zerops work stays behind the product task instead of becoming another checklist. -
+---------------------------------------- -
+# Alpine > How To > Trigger Pipeline -EVIDENCE -### Evidence-based completion -A build or deploy is not the finish line. A completed app task should end with a working URL, endpoint result, UI proof, or a blocker backed by logs, events, and verification evidence. +---------------------------------------- -
+# Alpine > How To > Upgrade -
-## What you no longer have to script -Without this layer, an app prompt often turns into an operations runbook. With MCP tools and workflow instructions enabled, you should not need to paste: +---------------------------------------- -- the service map, runtime target, dev/stage state, or managed-service inventory, -- database credentials, private hostnames, env-var references, or generated connection strings, -- build logs, runtime logs, event timelines, or a guess about why the last deploy failed, -- a deploy/verify/recovery script for every task, -- a recap after the chat loses context; the agent can read current workflow status. +# Alpine > Overview -**You still own the decisions that need human judgment:** product intent, technology constraints, acceptance criteria, external credentials, repository policy, and approval for destructive actions. -## Where it runs +[Alpine Linux ↗](https://alpinelinux.org/) is a lightweight, security-oriented Linux distribution based on musl libc and busybox, known for its small footprint and efficiency. -The **same `zcp` binary** runs in both setups. In [remote setup](/zcp/setup/hosted-workspace), Zerops packages it as a `zcp@1` service with Browser VS Code and bundled agent wiring. In [local setup](/zcp/setup/local-agent-bridge), you install it on your machine and connect your own editor or CLI agent. The project surface is the same; the workspace, network access, deploy source, and safety profile differ. +Alpine services in Zerops provide a minimal base environment for running applications built with technologies that aren't officially supported by Zerops, or for custom setups requiring full control over the runtime environment while keeping resource usage low. -To start, add remote setup in Zerops or initialize local setup beside your editor or CLI agent. The [Quickstart](/zcp/quickstart) uses remote setup because it needs no local install. +:::tip +Do you have any questions? Check the step-by-step tutorial, browse the documentation and join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. +::: -## Your agent, credentials, and workspace +## Feature Highlights -**Agent account.** ZCP supports multiple coding agents including Claude Code (Anthropic), Codex (OpenAI), Antigravity, and Grok Build. Remote setup can bundle one of these, already configured for MCP. Zerops wires the agent to the tools; you still authenticate with your own subscription login or API credentials. +- [Create Alpine service](/alpine/how-to/create) — Start with creating an Alpine service using GUI or zCLI. +- [zerops.yaml](/alpine/how-to/build-pipeline#add-zeropsyaml-to-your-repository) — See a full example of zerops.yaml file to configure your own app. +- [Scaling configuration](/alpine/how-to/scaling) — Set up scaling of your Alpine service so that it runs smoothly while using only necessary resources. -**Zerops token.** The MCP server connects through `ZCP_API_KEY`, a Zerops token limited to one project. Remote setup gets it from the platform; local setup reads it from `.mcp.json`. Token details live in [Tokens and credentials](/zcp/security/tokens-and-project-access). +{" "} -**Workspace freedom.** The `zcp@1` service is still a normal Zerops service. You can install another agent CLI, add private MCP servers or helper tools, edit `CLAUDE.md`, add team dotfiles, and adapt the workspace. Details live in [What remote workspace gives you](/zcp/setup/hosted-workspace). +- [Customize build environment](/alpine/how-to/build-process#customize-build-environment) +- [Customize runtime environment](/alpine/how-to/customize-runtime) -:::caution Production boundary -Use this setup for development or staging work. Production should stay in a separate Zerops project and receive released work through your CI or release process; see [Promote to production](/zcp/workflows/promote-to-production) for the practical flow and [Production boundary](/zcp/security/production-policy) for the policy. -::: +## When in doubt, reach out -## What stays outside +Don't know how to start or got stuck during the process? You might not be the first one, visit the FAQ section to find out. -This section is not a replacement for Zerops platform references. The Zerops [build and deploy pipeline](/features/pipeline), [permissions](/features/rbac), networking, scaling, and service references remain canonical for platform behavior. +In case you haven't found an answer (and also if you have), we and our community are looking forward to hearing from you on Discord. +Have you built something that others might find useful? Don't hesitate to share your knowledge! ----------------------------------------- +- [FAQ](/alpine/faq) — Most common questions in one place. +- [Discord](https://discord.com/invite/WDvCZ54) — Join our core team and Zerops community on Discord. Ask questions and share your tips with other members. -# Zcp > Glossary +## Popular Guides +- [zCLI](/references/cli) — Get even more out of Zerops with the zCLI command line tool. +- [Zerops VPN](/references/networking/vpn) — Connect to your services easily with Zerops VPN. -Use these definitions when a page, workflow status, agent handoff, or policy needs exact wording. In normal prompts, describe the outcome you want. -## Core names +---------------------------------------- -**ZCP MCP** - Zerops Control Plane MCP: the MCP tool surface that exposes project-scoped Zerops operations to coding agents. +# Bun > How To > Build Pipeline -**MCP server** - the Model Context Protocol server exposed by the `zcp` binary. -**ZCP MCP tools** - the project-scoped Zerops operations exposed to an agent or MCP-capable client. In MCP clients, this usually appears as the `zerops` server. +Zerops provides a customizable build and runtime environment for your Bun application. -**`zcp` binary** - the executable that can run inside remote setup or on your machine in local setup. +## Add zerops.yaml to your repository -**`zcp` service** - the service instance in a Zerops project that hosts remote setup. +Start by adding `zerops.yaml` file to the **root of your repository** and modify it to fit your application: -**`zcp@1` service** - the Zerops service type used for remote setup. +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: bun@latest -**zCLI** - the Zerops command-line client for humans, scripts, VPN, and CI. It is separate from ZCP MCP. + # OPTIONAL. Set the operating system for the build environment. + # os: ubuntu -**zsc** - the in-container Zerops Setup Control utility used from `zerops.yaml`. + # OPTIONAL. Customise the build environment by installing additional packages + # or tools to the base build environment. + # prepareCommands: + # - sudo apt-get something + # - curl something else -## Setup and workspace + # OPTIONAL. Build your application + buildCommands: + - bun i + - bun run build -**Remote setup** - the `zcp` binary running inside a Zerops `zcp@1` service. + # REQUIRED. Select which files / folders to deploy after + # the build has successfully finished + deployFiles: + - dist + - package.json + - node_modules -**Include Coding Agent** - remote setup option that adds a bundled agent CLI (Claude Code, Codex, Antigravity, or Grok Build) and preconfigures it to use ZCP MCP tools. + # OPTIONAL. Which files / folders you want to cache for the next build. + # Next builds will be faster when the cache is used. + cache: node_modules -**Cloud IDE** - browser-based VS Code served by remote setup. - -**Browser VS Code** - dashboard entry point into the Cloud IDE. + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: bun@latest -**AI Agent environment** - recipe environment preset that creates app services plus remote setup with **Include Coding Agent** enabled. + # OPTIONAL. Sets the internal port(s) your app listens on: + ports: + # port number + - port: 3000 -**Local setup** - the `zcp` binary running on your machine after `zcp init`, while your local editor or CLI agent talks to it. + # OPTIONAL. Customise the runtime Bun environment by installing additional + # dependencies to the base Bun runtime environment. + # prepareCommands: + # - sudo apt-get something + # - curl something else -**Env bridge** - local setup behavior that writes a local `.env` snapshot from Zerops env vars and references so local app code can reach managed services over VPN. + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your Bun application is started. + # initCommands: + # - rm -rf ./cache -**Agent client** - the editor, CLI, hosted agent runtime, or custom MCP client that connects to ZCP MCP. + # REQUIRED. Your Bun application start command + start: bun start +``` -## Generated files and state +The top-level element is always `zerops`. -**Generated workflow block** - the managed section in `CLAUDE.md` between `` and ``. Durable project instructions belong outside it. +### Setup -**`.mcp.json`** - local MCP server config. It points the local agent client at `zcp serve` and stores `ZCP_API_KEY`; keep it out of git. +The first element `setup` contains the **hostname** of your service. A runtime service with the same hostname must exist in Zerops. +Zerops supports the definition of multiple runtime services in a single `zerops.yaml`. This is useful when you use a monorepo. Just add multiple setup elements in your `zerops.yaml`: -**`.zcp/state/`** - local workflow metadata for a project directory: known runtimes, pairing, delivery choice, sessions, deploy attempts, verify attempts, and coordination locks. It is not source code. +```yaml +zerops: + # definition for app service + - setup: app + # optional + build: ... + # optional + deploy: ... + # required + run: ... -**Workflow state** - saved metadata that lets the agent resume, audit, or close a guided run after interruption. + # definition for api service + - setup: api + # optional + build: ... + # optional + deploy: ... + # required + run: ... +``` -## Workflow +Each service configuration contains at least the `run` section. Optional `build` and `deploy` sections can be added to further customize your process. -**Bootstrap** - workflow phase that reads the current project and settles which runtime services and managed services the app should use before app code work starts. +## Build pipeline configuration -**Service setup** - the phase that decides which runtime services and managed services the app should use before app code work starts. +### base -**Develop** - workflow phase that changes app code/config, deploys, verifies reachability and behavior, and fixes failures from evidence. +_REQUIRED._ Sets the base technology for the build environment. -**Runtime target** - the app runtime selected for the current change, such as `appdev`, `appstage`, `app`, or a linked local target. +Following options are available for Bun builds: -**Runtime layout** - which app runtime services the workflow should use: +- `bun@1.3.9`, `bun@1.3`, `bun@latest` +- `bun@1.2.2`, `bun@1.2` +- `bun@nightly` +- `bun@canary` +- `bun@1.1.34`, `bun@1.1(Ubuntu only)` -- `standard` - dev runtime plus explicit stage runtime. -- `dev` - one mutable development runtime. -- `simple` - one runtime with no dev/stage split. -- `local-stage` - local source directory linked to one Zerops runtime as deploy target. -- `local-only` - local source directory with no linked runtime yet. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: bun@latest + ... +``` -**Managed service** - database, cache, queue, search, storage, mail, or similar dependency. It provides connection details; it is not an app deploy target. +

+ The base build environment contains {data.alpine.default}, the selected + major version of Bun, + [Zerops command line tool](/references/cli), `npm`, + `yarn`, `git` and `npx` tools. +

-**Direct deploy** - deploy from the current source to the scoped runtime through ZCP MCP. The first verified running result uses direct deploy before delivery setup is applied. +:::info +You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. +::: -**Reachability verification** - checks that the runtime exists, is running, has no recent blocking errors, and can answer an HTTP probe when it is an HTTP service. +If you need to install more technologies to the build environment, set multiple values as a yaml array. For example: -**Behavior verification** - checks that the requested app behavior works on the real URL, endpoint, worker result, or stored state. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: + - bun@latest + prepareCommands: + - zsc add go@latest + ... +``` -**Proof** - user-inspectable completion evidence, such as a URL, endpoint result, UI state, processed job, or stored result. +See the full list of supported [build base environments](/zerops-yaml/base-list#runtime-services). -**Blocker** - a clear stop state with evidence: failure category, runtime in scope, what was tried, and what decision or credential is needed. +To customise your build environment use the [prepareCommands](build-pipeline#preparecommands) attribute. -## Delivery and production +:::note +Modifying the base technology will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for more details about cache invalidation. +::: -**Delivery choice** - what happens after a verified deploy: keep direct deploy, push to git, or hand off to CI/release/human process. +### os -**Delivery mode** - exact reference label for delivery choice: +_OPTIONAL._ Sets the operating system for the build environment. -- `auto` - keep direct deploy for future changes. -- `git-push` - commit and push to a configured remote, then observe/verify any tracked build. -- `manual` - external CI, release process, or a human owns future delivery. +Following options are available: -**Git-push capability** - whether remote setup has enough remote URL and credential setup to push from remote setup. It can exist even when the current delivery mode is `auto`. +- `alpine` +- `ubuntu` -**Build integration** - repository-triggered build/deploy path that ZCP MCP may configure or observe, such as a Zerops dashboard webhook or GitHub Actions. It is separate from git-push capability and delivery mode. +Default value is `alpine`. -**Package a running service** - workflow that turns one verified runtime and its managed dependencies into a re-importable, git-backed Zerops bundle. +We are currently using following os version: -**Production release** - the release operation that moves verified dev or stage work into a separate production Zerops project. It is set up once per project (production infrastructure) and once per runtime (production deploy trigger), then runs every release. +- {data.alpine.default} +- {data.ubuntu.default} -**Production boundary** - policy that production should live in a separate Zerops project without a `zcp` service and receive promoted work through CI, release process, or human action. +:::caution +The os version is fixed and cannot be customised. +::: -## Platform and failure terms +:::note +Changing the OS setting will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache behavior. +::: -**Service scaling mode** - Zerops scaling setting such as `HA` or `NON_HA`. Different from runtime layout. +### prepareCommands -**Public subdomain access** - Zerops `.zerops.app` URL access for an eligible HTTP runtime. Workers and non-HTTP services do not get useful public URLs. +_OPTIONAL._ Customises the build environment by installing additional dependencies or tools to the base build environment. -**Failure category** - label that points to the first useful evidence surface: +The base build environment contains: -- `build` - build phase failed. -- `start` - build passed, but runtime start or prepare failed. -- `verify` - runtime exists, but reachability or behavior failed. -- `network` - transport, DNS, VPN, SSH, or service-to-service reach failed. -- `config` - `zerops.yaml`, env vars, setup block, or service settings mismatch. -- `credential` - Zerops, git, SSH, managed-service, or external API credential failed. -- `other` - no known category matched. +- {data.alpine.default} +- selected version of Bun defined in the [base](build-pipeline#base) attribute +- [Zerops command line tool](/references/cli) +- `npm`, `yarn`, `git` and `npx` tools -**Confirmation gate** - an operation that pauses until the user explicitly confirms the named target or consequence. +To install additional packages or tools add one or more prepare commands: -**Destructive import override** - import action that would replace an existing service stack. ZCP MCP refuses first, names affected services, and requires a matching acknowledgement before proceeding. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: bun@latest -## Credentials + # OPTIONAL. Customise the build environment by installing additional packages + # or tools to the base build environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... +``` -**Single-project token** - Zerops token that can access exactly one project. ZCP MCP expects this shape. +When the first build is triggered, Zerops will -**`ZCP_API_KEY`** - single-project Zerops token used by ZCP MCP. +1. create a build container +2. download your application code from your repository +3. run the prepare commands in the defined order -**`GIT_TOKEN`** - git provider credential used by remote git-push delivery when needed. +The application code is available in `/build/source` before the prepare commands are triggered, so you can use any file from your repository in your prepare commands (e.g. a configuration file). The commands themselves run in the `/home/zerops` directory. -**`ZEROPS_TOKEN`** - Zerops token commonly used by GitHub Actions or external CI that runs `zcli`. +:::note +These commands are skipped when using cached environment. Modifying `prepareCommands` will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache invalidation. +::: -**External secret** - third-party credential such as Stripe, OpenAI, Mailgun, or GitHub API access. The agent can wire placeholders and env vars, but the secret value remains your responsibility. +#### Command exit code +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](logs#build-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all prepare commands are finished, your custom build environment is ready for the build phase. ----------------------------------------- +#### Single or separated shell instances -# Zcp > Workflows > Promote To Production +You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). +### buildCommands -Use this after the agent has proved work in development or stage. The production release is the point where authority changes: the agent can prepare proof, source changes, and setup notes, but production execution belongs to Zerops project settings, CI, release tooling, or a deliberate human action with production credentials. +_OPTIONAL._ Defines build commands. -Production should be a separate Zerops project without a `zcp` service. That keeps the development agent out of the production blast radius while still letting verified work reach production. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: bun@latest -## The simple production path + # OPTIONAL. Build your application + buildCommands: + - bun i + - bun run build + ... +``` -There are three different jobs. Two are setup work; one is the repeatable release operation. +Build commands are optional. Zerops triggers each command in the defined order in a dedicated build container, running from the `/build/source` directory. -| Job | How often | Simplest path | -| --- | --- | --- | -| **Create production infrastructure** | Once per production project | Export the verified Zerops project as YAML in the GUI, edit it for production, then import it as a new project. | -| **Connect the production deploy trigger** | Once per production runtime | In the production project, connect the git repository in the Zerops GUI and trigger builds from release tags. | -| **Release an app change** | Every release | Verify in dev/stage, push source to git, then create the release tag or use your team's release process. | -| **Release an app change** | Every release | Verify in dev/stage, push source to git, then create the release tag or use your team's release process. | +Before the build commands are triggered the build container contains: -This page uses the GUI path because it is the clearest path available today. More customized teams can replace the GUI trigger with GitHub Actions or another CI system later. +1. base environment defined by the [base](build-pipeline#base) attribute +2. optional customisation of the base environment defined in the [prepareCommands](build-pipeline#preparecommands) attribute +3. your application code -## 1. Create production infrastructure +#### Run build commands as a single shell instance -Do this once when you need a production project for a verified app. +Use following syntax to run all commands in the same environment context. For example, if one command changes the current directory, the next command continues in that directory. When one command creates an environment variable, the next command can access it. -1. Open the development or staging project that contains the verified runtime. -2. Use **Export project as yaml**. -3. Edit the exported YAML for production. -4. Import the edited YAML as a new Zerops project. +```yaml +buildCommands: + - | + bun i + bun run build +``` -Before import, review the YAML as production infrastructure, not as a blind copy of the development project: +#### Run build commands as a separate shell instances -- remove the `zcp` service, -- remove dev-only runtimes and tools such as Mailpit or Adminer, -- keep the runtime and managed services that production actually needs, -- choose production `mode` values before creation, especially `HA` for databases that need it, -- set production `minContainers`, autoscaling, and core package, -- replace development secrets with production secrets or placeholders, -- plan managed-service data restore or migrations, -- configure production domains, DNS, public access, SMTP, object storage, backups, queues, search, and cache as needed. +When the following syntax is used, each command is triggered in a separate environment context. For example, each shell instance starts in the home directory again. When one command creates an environment variable, it won't be available for the next command. -Before opening production traffic, get familiar with the deeper Zerops production surface: service modes, scaling, deploy pipeline, health checks, backups, public access, and domains. If the app should use a real domain, follow [Public Access Configuration](/references/networking/public-access). +```yaml +buildCommands: + - bun i + - bun run build +``` -Project export/import creates the production infrastructure. Do not rely on it as the code delivery mechanism. The app source should be in git, and the first production code deploy should come through the production deploy trigger. +#### Command exit code -## 2. Connect the production deploy trigger +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](logs#build-log) to troubleshoot the error. If the error log doesn't contain any specific error message, try to run your build with the --verbose option. -Do this once for each production runtime that should build from git. +```yaml +buildCommands: + - bun i --verbose + - bun run build +``` -The simplest path is the Zerops GitHub or GitLab integration in the production project: +If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `buildCommands` are finished, the application build is completed and ready for the deploy phase. -1. Open the production runtime service. -2. Connect the git repository. -3. Choose **New tag** as the production trigger. -4. Add a tag filter if your team uses one, for example `v*`. -5. Keep production env vars and secrets in the production Zerops project. +### deployFiles -For stage, a branch trigger can be convenient. For production, a tag trigger is easier to reason about: a normal source push can update stage, while a deliberate release tag updates production. +_REQUIRED._ Selects which files or folders will be deployed after the build has successfully finished. To filter out specific files or folders, use [`.deployignore`](#deployignore) file. -If your team needs approvals, custom tests, generated artifacts, or stricter audit, use GitHub Actions or another CI system instead. In that setup, store a production-scoped `ZEROPS_TOKEN` in the CI secret store and run the production deploy from CI. +```yaml +# REQUIRED. Select which files / folders to deploy after +# the build has successfully finished +deployFiles: + - dist + - package.json + - node_modules +``` -## 3. Release an app change +Determines files or folders produced by your build, which should be deployed to your runtime service containers. -This is the repeatable operation after production infrastructure and the deploy trigger exist. The exact release command is yours: define it in your repository instructions, agent skill, CI guide, or team release checklist. +The path starts from the **root directory** of your project (the location of `zerops.yaml`). You must enclose the name in quotes if the folder or the file name contains a space. -For example, if production deploys from release tags, the user instruction can be as direct as: +The files/folders will be placed into `/var/www` folder in runtime, e.g. `./src/assets/fonts` would result in `/var/www/src/assets/fonts`. -```text -Create the release tag for production and push it to git. -``` +#### Examples -Use the wording that matches your CI/CD. The release step can be a manual CLI action, a `git push`, a tag push, a pull request, a protected branch merge, or a CI job. That part is your team preference and production setup, not a rule from these docs. +Deploys a folder, and a file from the project root directory: -The important rule is that the agent should name what it pushed and whether that push triggers stage, production, both, or neither. If production release requires a tag, the final answer should say the tag name or the exact tag command. +```yaml +deployFiles: + - dist + - package.json +``` -## What not to carry into production +Deploys the whole content of the build container: -Do not copy these from the development project into production: +```yaml +deployFiles: . +``` -- the `zcp` service, -- development `ZCP_API_KEY`, -- local `.mcp.json`, -- development secrets, -- test data unless it is intentionally migrated, -- dev-only utilities such as Mailpit or Adminer, -- `.zerops.app` preview routing as the final public entry point. +Deploys a folder, and a file in a defined path: -Use production-specific domains, secrets, backup policy, scaling, and release credentials. +```yaml +deployFiles: + - ./path/to/file.txt + - ./path/to/dir/ +``` -## What the agent should hand you +#### How to use a wildcard in the path -A useful release handoff from the agent contains: +Zerops supports the `~` character as a wildcard for one or more folders in the path. -- runtime and project where the change was verified, -- URL, endpoint, UI state, job result, or stored data that proves the requested behavior, -- commit, branch, PR, or suggested release tag, -- whether the git push triggers stage, production, both, or neither, -- services to keep, remove, or change before importing production infrastructure, -- env vars, managed services, migrations, or delivery settings touched, -- external secrets still needed, -- managed-service data that must be restored or migrated, -- production blockers that need a human decision. +Deploys all `file.txt` files that are located in any path that begins with `/path/` and ends with `/to/` -If the answer only says that files were changed, the release handoff is incomplete. Ask for the verification evidence and the exact release artifact. +```yaml +deployFiles: ./path/~/to/file.txt +``` -Production hardening belongs in your team's production checklist. This page only defines the handoff from verified dev or stage work into production authority. +Deploys all folders that are located in any path that begins with `/path/to/` -## Related production references +```yaml +deployFiles: ./path/to/~/ +``` -- [Production boundary](/zcp/security/production-policy) — Why production stays outside the agent loop. -- [Import & Export YAML Configuration](/references/import) — Project export and import reference. -- [Public Access Configuration](/references/networking/public-access) — Custom domains, DNS, SSL, and production public access. +Deploys all folders that are located in any path that begins with `/path/` and ends with `/to/` +```yaml +deployFiles: ./path/~/to/ +``` ----------------------------------------- +:::note Example +By default, `./src/assets/fonts` deploys to `/var/www/src/assets/fonts`, keeping the full path. Adding `~`, like `./src/assets/~fonts`, shortens it to `/var/www/fonts` +::: +#### .deployignore -# Zcp > Workflows > Package Running Service +Add a `.deployignore` file to the root of your project to specify which files and folders Zerops should ignore during deploy. The syntax follows the same pattern format as [`.gitignore`](https://git-scm.com/docs/gitignore#_pattern_format). +To ignore a specific file or directory path, start the pattern with a forward slash (`/`). Without the leading slash, the pattern will match files with that name in any directory. -Use packaging when a verified runtime should become a re-importable Zerops bundle. It is a handoff or reuse task after the app already works, not the normal way to deploy the next change. +:::tip +For consistency, it's recommended to configure both your `.gitignore` and `.deployignore` files with the same patterns. +::: -You can ask for it directly: +Examples: -```text -Package appstage as a buildFromGit import bundle. -Commit it and push it to git. +```yaml title="zerops.yaml" +zerops: + - setup: app + build: + deployFiles: ./ ``` -The result is a single git repo that contains the app source, [`zerops.yaml`](/zerops-yaml/specification), and a project [import file](/references/import) named `zerops-project-import.yaml`. The import file uses `buildFromGit:` so a fresh Zerops project can rebuild the app from the repo instead of carrying source code inside YAML. - -Packaging starts from a deployed Zerops runtime. If important source changes exist only on your laptop, deploy or push them first so the runtime and git repo match what you want to package. - -## When to package +```text title=".deployignore" +/src/file.txt +``` +The example above ignores `file.txt` only in the root src directory. +```text title=".deployignore" +src/file.txt +``` +This example above ignores `file.txt` in ANY directory named `src`, such as: +- `/src/file.txt` +- `/folder2/folder3/src/file.txt` +- `/src/src/file.txt` -Package a runtime when you need: +:::note +`.deployignore` file also works with [`zcli service deploy`](/references/zcli/commands#deploy) command. +::: -- a running runtime and its managed dependencies reproduced in another Zerops project, -- a reusable starter, demo, handoff, customer project, or clean staging baseline, -- a repo commit that carries the Zerops import shape next to the app source, -- the destination project to build from git. +### cache -Do not use packaging for: +_OPTIONAL._ Defines which files or folders will be cached for the next build. -- the next app deploy; use the normal build, deploy, and verify loop, -- the production release; production needs its own infrastructure, credentials, domains, and release trigger, -- moving managed-service data; backups and restores are separate. +```yaml +# OPTIONAL. Which files / folders you want to cache for the next build. +# Next builds will be faster when the cache is used. +cache: file.txt +``` -For production setup, follow [Promote to production](/zcp/workflows/promote-to-production). Packaging can help create a reusable app bundle, but it does not decide production infrastructure or release policy. +The cache attribute helps optimize build times by preserving specified files between builds. -## What the agent prepares +The cache attribute supports the [~ wildcard character](#how-to-use-a-wildcard-in-the-path). -The agent packages **one** runtime. If the project has dev and stage runtimes, it asks which one to use because they can have different env values, start commands, or `setup:` blocks. +Learn more about the [build cache system](/features/build-cache) in Zerops. -Managed services come along as dependencies when the runtime's `zerops.yaml` needs their env references. You do not pick databases, caches, queues, or search services one by one. +### envVariables -The workflow then prepares: +_OPTIONAL._ Defines the environment variables for the build environment. -- `zerops-project-import.yaml` - the project and service shape for the destination project, -- `zerops.yaml` - the runtime build and run configuration, -- a git commit and push when git delivery is configured or explicitly requested. +Enter one or more env variables in following format: -If the runtime has no usable `zerops.yaml` or git remote, the agent has to fix that first. A bundle is only useful when the destination project can pull source and build it from git. +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to build your application ==== + build: + base: bun@latest + … -## Env vars need review + # OPTIONAL. Defines the env variables for the build environment: + envVariables: + NODE_ENV: production + DB_NAME: db + DB_HOST: db + DB_USER: db + DB_PASS: ${db_password} +``` -Project env vars are the main place where the agent may ask you to decide. Each value gets one bucket: +Read more about [environment variables](env-variables) in Zerops. -| Bucket | Use for | Bundle result | -| --- | --- | --- | -| `infrastructure` | Values derived from managed services, such as database or cache references. | Omitted from project envs; the new managed service provides fresh values. | -| `auto-secret` | App-owned signing or encryption keys that can be regenerated. | Fresh generated secret on import. | -| `external-secret` | Third-party credentials such as Stripe, OpenAI, Mailgun, or GitHub. | `REPLACE_ME` placeholder. | -| `plain-config` | Literal non-secret config such as log level, feature flags, or public app settings. | Copied as-is. | -| `plain-config` | Literal non-secret config such as log level, feature flags, or public app settings. | Copied as-is. | +## Runtime configuration -Do not treat this as a key-name guessing game. The agent should inspect source code and ask when classification changes behavior. For example, regenerating a Laravel `APP_KEY`, Django `SECRET_KEY`, or session secret can break existing encrypted state. If state continuity matters, carry the existing value instead of generating a new one. +### base -## What is not included +_OPTIONAL._ Sets the base technology for the runtime environment. +If you don't specify the `run.base` attribute, Zerops keeps the current Bun version for your runtime. -| Not included | What to do instead | -| --- | --- | -| Managed-service data | Restore from [Backup](/features/backup) or another migration path. | -| Real third-party secrets | Fill placeholders in the destination project before deploying. | -| Production domains, scaling, backups, and release triggers | Configure them in the destination project. | -| A repeatable production release process | Use your CI or release workflow; see [Promote to production](/zcp/workflows/promote-to-production). | -| A repeatable production release process | Use your CI or release workflow; see [Promote to production](/zcp/workflows/promote-to-production). | +Following options are available for Bun runtimes: -## Use the bundle +- `bun@1.3.9`, `bun@1.3`, `bun@latest` +- `bun@1.2.2`, `bun@1.2` +- `bun@nightly` +- `bun@canary` +- `bun@1.1.34`, `bun@1.1(Ubuntu only)` -After the bundle is pushed, import `zerops-project-import.yaml` in the destination project through the dashboard or with `zcli project project-import zerops-project-import.yaml`. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: bun@latest + ... -Before opening the new project to users: + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: bun@latest + ... +``` -- fill `REPLACE_ME` values, -- restore or seed data when needed, -- review service scaling and public access, -- run a normal deploy and verification pass in the destination project. +

+ The base runtime environment contains {data.alpine.default}, the + selected major version of Bun, Zerops command line tool, `npm`, `yarn`, `git` and `npx` tools. +

+:::info +You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. +::: ----------------------------------------- +If you need to install more technologies to the runtime environment, set multiple values as a yaml array. For example: -# Zcp > Workflows > Build With Zcp +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: bun@latest + ... + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: + - bun@latest + prepareCommands: + - zsc add go@latest + ... +``` -Use Build and ship for the decisions that shape normal app work. ZCP MCP gives the agent Zerops project state, platform guidance, project-scoped operations, deploy evidence, and recovery rules. You still decide what should be built, where it should run, how strict the acceptance criteria are, and what happens after proof. +See the full list of supported [run base environments](/zerops-yaml/base-list). -```text -Build a task board. -Tasks should stay saved after refresh. -``` +To customise your build environment use the `prepareCommands` attribute. -A prompt can be that short when the outcome is enough. Add detail when it changes behavior, architecture, stack, runtime layout, acceptance criteria, credentials, delivery, packaging, or the production release. +### os -The expected output is a verified running change, not only generated files. The agent should prove the request against a real runtime, real managed services when used, and the logs, events, and checks that explain what happened. +_OPTIONAL._ Sets the operating system for the runtime environment. -## The decisions +Following options are available: -
-
- Product prompt - Build a task board... -
- +- `alpine` +- `ubuntu` -You do not run these steps by hand. They are the parts where your intent changes what the agent should do. If you do not specify a choice, the agent should infer from current project state and ask only when the decision changes cost, credentials, runtime layout, delivery, production risk, or destructive behavior. +Default value is `alpine`. -## 1. Choose the runtime layout {#choose-the-runtime-layout} +We are currently using following os version: -When the app runtime and dependencies are unclear, the workflow prepares the layout before feature work starts. It reads current state, uses existing services when they fit, creates missing runtimes or managed services when needed, and stops when the agent knows where app code belongs. +- {data.alpine.default} +- {data.ubuntu.default} -The main user-facing choice is runtime layout. Let the agent infer it from the project, or name it in the prompt when it matters. +:::caution +The os version is fixed and cannot be customised. +::: -| Runtime layout | Use when | What to tell the agent | -| ------------------------- | ----------------------------------------------------------------------------------------- | ------------------------------------------------------- | -| **Dev** | You want one mutable runtime for fast iteration, experiments, or early app work. | `Build a small Node.js API on dev.` | -| **Dev + stage** | You want a development runtime plus a separate runtime for review or release rehearsal. | `Build a Node.js API with PostgreSQL on dev+stage.` | -| **Stage / linked target** | You work from local files or a single target runtime and want the workflow to use that target. | `Use appstage as the deploy target for this local app.` | -| **Stage / linked target** | You work from local files or a single target runtime and want the workflow to use that target. | `Use appstage as the deploy target for this local app.` | +### ports -The layout is about app runtimes, not where the `zcp` binary runs. Remote setup can use any of these layouts from the `zcp@1` workspace. Local setup usually works from local files into a linked stage or app runtime. +_OPTIONAL._ Specifies one or more internal ports on which your application will listen. -Managed services such as PostgreSQL, Valkey, queues, search, storage, or mail are dependencies. The agent gets their state and wiring patterns, but app code deploys to runtime services. +Projects in Zerops represent a group of one or more services. Services can be of different types (runtime services, databases, message brokers, object storage, etc.). All services of the same project share a **dedicated private network**. To connect to a service within the same project, just use the service hostname and its internal port. -## 2. Development {#develop-with-live-project-context} +For example, to connect to a Bun service with hostname = "app" and port = 3000 from another service of the same project, simply use `app:3000`. Read more about [how to access a Bun service](/features/access). -Development is still a normal coding conversation with the agent. You describe the product behavior, stack constraints, acceptance criteria, and anything the agent must not guess. +Each port has following attributes: -MCP adds the Zerops side of that conversation: current project state, platform knowledge, project-scoped operations, deploy/log evidence, verification checks, recovery rules, and saved work state. Because of that, you usually do not paste service inventory, env wiring, deploy logs, or a "deploy and verify" checklist into the prompt. +| parameter | description | +| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| port | Defines the port number. You can set any port number between _10_ and _65435_. Ports outside this interval are reserved for internal Zerops systems. | +| protocol | **Optional.** Defines the protocol. Allowed values are `TCP` or `UDP`. Default value is `TCP`. | +| httpSupport | **Optional.** `httpSupport = true` is the default setting for TCP protocol. Set `httpSupport = false` if a web server isn't running on the port. Zerops uses this information for the configuration of [public access](/features/access). `httpSupport = true` is available only in combination with the TCP protocol. | +| httpSupport | **Optional.** `httpSupport = true` is the default setting for TCP protocol. Set `httpSupport = false` if a web server isn't running on the port. Zerops uses this information for the configuration of [public access](/features/access). `httpSupport = true` is available only in combination with the TCP protocol. | -The useful things to name are: +### prepareCommands -- the behavior you want and how it should be verified, -- stack, framework, managed-service, or runtime target preferences, -- whether the agent should inspect or continue existing work first, -- approval boundaries for cost, credentials, data, production, or destructive actions. +_OPTIONAL._ Customises the Bun runtime environment by installing additional dependencies or tools to the runtime base environment. -Expect the agent to ask when one of those choices is missing. Otherwise, it should use project context while it works and finish with proof or a blocker. +

+ The base Bun environment contains {data.alpine.default} the selected + major version of Bun, [Zerops command line tool](/references/cli) and `npm`, `yarn`, `git` and `npx` tools. To install + additional packages or tools add one or more prepare commands: +

-## 3. Choose delivery after proof {#choose-delivery-after-proof} +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + ... -Delivery preference is how app work closes after there is a verified result. Include it in the original prompt or set it later. + # ==== how to run your application ==== + run: + # OPTIONAL. Customise the runtime environment by installing additional packages + # or tools to the base Bun runtime environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... +``` -The first functional deploy is still direct so the agent can prove the app runs. Delivery preference decides what happens after that proof and how later sessions should finish similar work. +When the first deploy with a defined prepare attribute is triggered, Zerops will -| Delivery preference | What it means | What to tell the agent | -| ---------------------- | -------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -| **Keep direct deploy** | The agent keeps deploying directly to the target runtime for fast dev/stage iteration. | `Keep direct deploy for now.` | -| **Push to git** | The agent commits and pushes working changes to the configured repository. | `When the app works, push changes to git@github.com:my-org/task-board.git.` | -| **CI / handoff** | A repository integration, GitHub Actions workflow, release process, or human owns the next deploy. | `Set up GitHub Actions delivery for future deploys after the app works.` | -| **CI / handoff** | A repository integration, GitHub Actions workflow, release process, or human owns the next deploy. | `Set up GitHub Actions delivery for future deploys after the app works.` | +1. create a prepare runtime container +2. optionally: [copy selected folders or files from your build container](build-pipeline#copy-folders-or-files-from-your-build-container) +3. run the `prepareCommands` commands in the defined order -The workflow records the delivery choice so later work can follow it. Git credentials, CI secrets, and production credentials are separate from `ZCP_API_KEY`; see [Tokens and credentials](/zcp/security/tokens-and-project-access). +:::note +`run.prepareCommands` run in the `/home/zerops` directory. +::: -## 4. Package a verified runtime {#package-a-verified-runtime} +#### Command exit code -After a runtime is verified, you can ask the agent to prepare it as a re-importable Zerops project bundle. Use this when the app should become a reusable starter, customer handoff, demo project, or clean staging project. +If any command fails, it returns an exit code other than 0 and the deploy is canceled. Read the [prepare runtime log](logs#prepare-runtime-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `prepareCommands` commands are finished, your custom runtime environment is ready for the deploy phase. -The prompt can be one sentence: +#### Cache of your custom runtime environment -```text -Package appstage as a buildFromGit import bundle, commit it, and push it to git so I can import it into a fresh Zerops project. -``` +Some packages or tools can take a long time to install. Therefore, Zerops caches your custom runtime environment after the installation of your custom packages or tools is completed. When the second or following deploy is triggered, Zerops will use the custom runtime cache from the previous deploy if following conditions are met: -The export workflow prepares `zerops-project-import.yaml` and `zerops.yaml` in the same git repo as the app. The import file contains one runtime with `buildFromGit:` pointing back to that repo, plus managed services needed for Zerops env references to resolve when the bundle is imported into a fresh project. +1. Content of the [build.addToRunPrepare](#copy-folders-or-files-from-your-build-container) and `run.prepareCommands` attributes didn't change from the previous deploy +2. The custom runtime cache wasn't invalidated in the Zerops GUI. -The agent may still ask which runtime to package, which half of a dev+stage pair to use, how to classify project env vars, or how to configure git push. Once pushed, the target project can import the bundle from the dashboard or with `zcli project project-import zerops-project-import.yaml`. +To invalidate the custom runtime cache go to `yyy` -Packaging is not the next deploy of the same app. For the next app change, keep using the normal build/deploy/verify loop. Use packaging when the output you want is a git-backed import bundle; see [Package a running service](/zcp/workflows/package-running-service). +When the custom runtime cache is used, Zerops doesn't create a prepare runtime container and executes the deployment of your application directly. -## 5. Prepare the production release {#prepare-production-release} +#### Single or separated shell instances -The production release is where authority changes. The agent prepares verified work and release evidence; production execution belongs to Zerops project settings, CI, release tooling, or a deliberate human action with production credentials. +You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -The useful split is: +### Copy folders or files from your build container -| Job | How often | What happens | -| --- | --- | --- | -| **Production infrastructure** | Once per production project | Export the verified project as YAML in the GUI, edit it for production, then import it as a new project. | -| **Production deploy trigger** | Once per production runtime | Connect the production runtime to git, usually with a tag trigger. | -| **Production release** | Every release | Verify in dev/stage, push source to git, then trigger production through your tag or release process. | -| **Production release** | Every release | Verify in dev/stage, push source to git, then trigger production through your tag or release process. | +

+ The prepare runtime container contains {data.alpine.default}, the selected major version of Bun, [Zerops command line tool](/references/cli) and `npm`, + `yarn`, `git` and `npx` tools. +

-Production should be a separate Zerops project without a `zcp` service. Production credentials are not `ZCP_API_KEY`; keep them in CI or release tooling. For the full release guide, see [Promote to production](/zcp/workflows/promote-to-production). +The prepare runtime container does not contain your application code nor the built application. If you need to copy some folders or files from the build container to the runtime container (e.g. a configuration file) use the `addToRunPrepare` attribute in the [build section](#build-pipeline-configuration). -## What the final answer should contain +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + ... + addToRunPrepare: ./runtime-config.yaml -For a completed app task, the agent should report: + # ==== how to run your application ==== + run: + # OPTIONAL. Customise the runtime environment by installing additional packages + # or tools to the base Bun runtime environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... +``` -- the runtime service it changed, -- the deploy or verification target, -- the URL, endpoint, UI state, job result, or stored data that proves the requested behavior, -- managed services, env vars, or delivery settings it touched, -- the delivery preference, packaging output, or production release state that now applies. +In the example above Zerops will copy the `runtime-config.yaml` file from your build container **after the build has finished** into the new **prepare runtime** container. The copied files and folders will be available in the `/home/zerops` folder in the new prepare runtime container before the prepare commands are triggered. -If the task is incomplete, the final answer should name the blocker, the evidence read, what was tried, and the decision or credential needed from you. +### initCommands +_OPTIONAL._ Defines one or more commands to be run each time a new runtime container is started or a container is restarted. ----------------------------------------- +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -# Zcp > Setup > Local Agent Bridge + # ==== how to run your application ==== + run: + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your Bun application is started. + initCommands: + - rm -rf ./cache +``` +These commands are triggered in the runtime container before your Bun application is started via the [start command](build-pipeline#start). -Local setup installs the `zcp` binary on your machine and runs it from the app directory where your agent works. +:::note +`run.initCommands` run in the `/var/www` directory. +::: -Use it when the agent should work next to local files, local data, your desktop editor, terminal tools, and git credentials. The MCP server limits Zerops operations to one project, but the agent client runs as your local user, so local approvals and filesystem allowlists matter. +Use init commands to clean or initialise your application cache or similar operations. -[Remote setup](/zcp/setup/hosted-workspace) is the safer default when the agent does not need local files or tools. Use local setup when local control is the point. +:::caution +The init commands will delay the start of your application each time a new runtime container is started (including the [horizontal scaling](scaling) or when a runtime container is restarted). -:::warning Local setup maturity -Local setup has more moving parts than remote setup and may change faster. The binary install path, `.mcp.json` shape, and files written by `zcp init` are still settling between releases. +Do not use the init commands for customising your runtime environment. Use the [run:prepareCommands](build-pipeline#preparecommands-1) attribute instead. ::: -## Choose a local starting point - -Pick the folder that should own app work: +#### Command exit code -- **Empty local directory.** Start with no app code yet. The agent can create the app structure and use the MCP tools to select or create Zerops services. -- **Existing app directory.** Use this when app code, local data, editor setup, test fixtures, and git credentials already live on your machine. -- **Recipe prepared for local setup.** Use a recipe to create the Zerops service baseline, then run the agent locally from the directory that should own source changes. +If any of the `initCommands` fails, it returns an exit code other than 0, but deploy is **not** canceled. After all init commands are finished, regardless of the status code, the application is started. Read the [runtime log](logs#runtime-log) to troubleshoot the error. -After that choice, the mechanics are the same: install `zcp`, run `zcp init`, add `ZCP_API_KEY`, start VPN when private service access is needed, and link a runtime when the agent should deploy. +#### Single or separated shell instances -## What local setup gives the agent +You can configure your `initCommands` to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -- **Local files as source.** The agent edits the directory on your machine, and deploys use that working directory. -- **Your editor and terminal.** Framework CLIs, test runners, local data, and local feedback stay under your normal tools. -- **Your git credentials.** Pushes use your local git CLI, SSH agent, or credential helper. -- **Zerops operations.** The MCP tools let the agent discover services, generate env snapshots, deploy to linked runtimes, read logs, and verify. -- **Private service access through VPN.** Your local app and shell reach private service hostnames through `zcli vpn up`. +### envVariables -Security note: local setup cannot protect your laptop from the agent client. Configure approvals as you would for any local coding agent. +_OPTIONAL._ Defines the environment variables for the runtime environment. -## Prerequisites +Enter one or more env variables in following format: -- A Zerops project. Create one from the [Zerops dashboard](https://app.zerops.io/dashboard/project-add), from a [recipe](https://app.zerops.io/recipes), or use an existing development/staging setup. -- [zCLI](/references/cli) installed and authenticated on your machine. -- A compatible local agent client installed and logged in. -- A **single-project Zerops token**. Multi-project tokens are refused at startup. -- A local directory where the agent should run. +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to run your application ==== + run: + # OPTIONAL. Defines the env variables for the runtime environment: + envVariables: + NODE_ENV: production + DB_NAME: db + DB_HOST: db + DB_USER: db + DB_PASS: ${db_password} +``` -You do not need MCP just to develop locally against Zerops services as a human. `zcli vpn up` plus your editor is enough. Add MCP when a local coding agent should also understand and operate Zerops. +Read more about [environment variables](env-variables) in Zerops. -## 1. Get `ZCP_API_KEY` +### start -The MCP server needs a Zerops API token that reaches exactly one project. For normal agent work, use a full-access token; read-only tokens can authenticate but fail on deploys, env changes, lifecycle actions, and other mutations. Token generation, rejected shapes, and rotation are covered in [Tokens and credentials](/zcp/security/tokens-and-project-access). +_REQUIRED._ Defines the start command for your Bun application. -## 2. Install `zcp` +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -```bash -curl -sSfL https://raw.githubusercontent.com/zeropsio/zcp/main/install.sh | sh + # ==== how to run your application ==== + run: + # REQUIRED. Your Bun application start command + start: bun start ``` -The installer downloads the latest release for your platform into `~/.local/bin`, or `/usr/local/bin` when run as root. Verify the install: +We recommend starting your Bun application using `bun start`. -```bash -zcp version -``` +### health check -If your shell cannot find `zcp`, add the install directory to `PATH` and reload the shell. +_OPTIONAL._ Defines a health check. -## 3. Run `zcp init` +`healthCheck` requires either one `httpGet` object or one `exec` object. -From the local directory the agent should operate: +#### httpGet -```bash -zcp init -``` +Configures the health check to request a local URL using a HTTP GET method. -`zcp init` writes local MCP config and agent instructions: +Following attributes are available: -- `.mcp.json` - MCP server config for this directory. -- `CLAUDE.md` - agent instructions for Zerops work. -- `.claude/settings.local.json` - Claude Code per-project settings when that client is used. -- `~/.config/zerops/aliases` plus a shell-rc sourcing line - helper aliases for launching the agent here. -- `.zcp/state/` - workflow state created when MCP first writes local state. + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. +If your application requires a https request, set scheme: https
-Re-running `zcp init` may refresh generated config. `CLAUDE.md` preserves edits outside managed markers, but `.mcp.json` is regenerated from the token-less template. If you rerun it, re-check the `ZCP_API_KEY` block before launching the agent. +**Example:** -## 4. Add `ZCP_API_KEY` +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -`zcp init` writes a token-less `.mcp.json`. Add the project token under the `env` block: + # ==== how to run your application ==== + run: + # REQUIRED. Your Bun application start command + start: bun start -```json -{ - "mcpServers": { - "zerops": { - "command": "zcp", - "args": ["serve"], - "env": { - "ZCP_API_KEY": "" - } - } - } -} + # OPTIONAL. Define a health check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + healthCheck: + httpGet: + port: 80 + path: /status ``` -Add `.mcp.json` to `.gitignore`. It contains a live Zerops credential and should not leave the machine. Each app directory should have its own `.mcp.json` and token. +#### exec -The server name `zerops` is intentional. Do not rename it unless your agent client requires a different name and you understand the prompt/instruction changes. +Configures the health check to run a local command. +Following attributes are available: -## 5. Launch the agent from the app directory +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **command** | Defines a local command to be run. +The command has access to the same [environment variables](create#set-secret-environment-variables) as your Bun application. +A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. | -Start the agent from the directory that contains `.mcp.json`. The client should list `zerops` as an available MCP server. +**Example:** -Sanity check: +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -```text -List the Zerops services through MCP. + # ==== how to run your application ==== + run: + # REQUIRED. Your Bun application start command + start: bun start + + # OPTIONAL. Define a health check with a shell command. + healthCheck: + exec: + command: | + touch grass + rm -rf life + mv /outside/user /home/user ``` -A working connection answers with the runtime and managed services. If not, check the launch directory, token scope, and whether the client loaded `.mcp.json`. +### crontab -## 6. Bring up VPN when private services are needed +_OPTIONAL._ Defines cron jobs. -The MCP server can talk to the Zerops API without VPN. Your local app, shell, tests, database clients, and framework commands need VPN to reach private hostnames such as `db` or `cache`. +Setup cron jobs in the following format: -```bash -zcli vpn up +```yaml +zerops: + # define hostname of your service + - setup: app + + # ==== how to run your application ==== + run: + crontab: + # REQUIRED. Sets the command to execute: + - command: "" + # REQUIRED. Sets the interval time to execute: + timing: "0 * * * *" ``` -VPN setup needs admin or root approval on macOS and Linux. The tools can tell the agent which command is needed, but they cannot approve or start it for you. After the tunnel is up, service hostnames resolve from your machine; rerun the command when local service connections fail. +Read more about setting up [cron](/zerops-yaml/cron) in Zerops. -## 7. Generate local env when needed +## Deploy configuration -When the local app needs service credentials, ask the agent for the app work and let the tools generate the env bridge. For a standalone check: +### readiness check -```text -Generate a .env file for my local app from Zerops env references. -``` +_OPTIONAL._ Defines a readiness check. Read more about how the [readiness check works](deploy-process#readiness-checks) in Zerops. -Env generation needs `zerops.yaml` in the working directory, the runtime or setup the local app should use, a matching `setup:` entry, and non-empty `run.envVariables` under that setup. +`readinessCheck` requires either one `httpGet` object or one `exec` object. -The tools read `run.envVariables`, resolve Zerops references such as `${db_user}`, `${db_password}`, and `${db_hostname}`, and write the resulting values into `.env`. Cross-service references resolve recursively, so a `DATABASE_URL` can land as a complete local connection string. +#### httpGet -If those inputs are missing, the agent should fix `zerops.yaml` or ask for the target runtime/setup. It should not invent env values from service names or dashboard memory. +Configures the readiness check to request a local URL using a http GET method. -The file is a snapshot, not a live sync. Regenerate it after changing env variables in Zerops. VPN is still required for your local app to use private service hostnames from that `.env`. +Following attributes are available: -Keep `.env` out of git. It contains real connection values. + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. +If your application requires a https request, set scheme: https
-## 8. Link a deploy target +**Example:** -Local setup needs a Zerops runtime when the agent should deploy from your working directory. A stage runtime is the usual target because it lets local work prove itself before the production release. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -If there is exactly one runtime, the agent can use it automatically. If multiple runtimes exist, it should ask which one to link: + # ==== how to deploy your application ==== + deploy: + # OPTIONAL. Define a readiness check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + readinessCheck: + httpGet: + port: 80 + path: /status -```text -Link this local directory to appstage for deploys. + # ==== how to run your application ==== + run: ... ``` -Without a linked runtime, the tools can still inspect services and generate env snapshots, but local deploys need a target first. - -## What stays outside +Read more about how the [readiness check works](deploy-process#readiness-checks) in Zerops. -MCP does not replace your local feedback loop. Vite, Valet, Docker Compose, your IDE runner, framework CLIs, local fixtures, and test data stay under your normal tooling. +#### exec -Local setup does not mount Zerops runtime filesystems on your laptop. Remote setup can mount runtime files into the workspace; local setup works from files on your machine. To inspect runtime files from your machine, use [SSH](/references/networking/ssh) directly. +Configures the readiness check to run a local command. +Following attributes are available: -The MCP server does not own your git credentials. In local setup, your local git CLI, SSH agent, or credential helper handles pushes. +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **command** | Defines a local command to be run. +The command has access to the same [environment variables](create#set-secret-environment-variables) as your Bun application. +A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. | -## Local setup checks +**Example:** -- **Launch directory matters.** Start the agent from the folder that contains `.mcp.json`. -- **`zcp init` can remove the token from `.mcp.json`.** Re-add `ZCP_API_KEY` after rerunning init. -- **VPN is separate from MCP auth.** MCP may work while your app still cannot reach `db`. -- **`.env` generation depends on `run.envVariables`.** If generation fails, check that the working directory has `zerops.yaml`, the selected `setup:` exists, and env entries live under `run.envVariables`. -- **`.env` is a credential snapshot.** Regenerate after env changes and keep it out of git. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -## Next steps + # ==== how to deploy your application ==== + deploy: + # OPTIONAL. Define a readiness check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + readinessCheck: + exec: + command: | + touch grass + rm -rf life + mv /outside/user /home/user +``` -- [Build and ship](/zcp/workflows/build-with-zcp) - normal app work after setup. -- [Tokens and credentials](/zcp/security/tokens-and-project-access) - token scope, storage, rotation, and destructive confirmations. +Read more about how the [readiness check works](deploy-process#readiness-checks) in Zerops. ---------------------------------------- -# Zcp > Setup > Hosted Workspace +# Bun > How To > Build Process -A remote workspace puts the agent, terminal, and optional browser IDE inside Zerops, next to private networking and ZCP access. -The `zcp@1` service runs the same `zcp` binary used by local setup, but broad shell permissions and private service access stay in a clean Zerops service instead of on your laptop. +---------------------------------------- -Use remote setup when you want the default workspace, a safer boundary for broad agent permissions, or a preconfigured environment with a bundled coding agent and Browser VS Code. +# Bun > How To > Controls -App code still deploys to your app runtime services. The `zcp` service is the workspace and control surface; it is not the application runtime. -Taking over is straightforward in this setup. You open the same workspace, terminal, files, and workflow status the agent used, then continue, inspect, or stop the work from there. -## What it includes +---------------------------------------- -- **`zcp@1` workspace service.** Runs ZCP inside Zerops and gives the agent project-scoped operations. -- **Platform-injected `ZCP_API_KEY`.** Zerops injects the token into the workspace; you normally do not set it by hand. -- **Bundled coding agent when enabled.** The **Include Coding Agent** option installs and preconfigures one of the supported agents: Claude Code (Anthropic), Codex (OpenAI), Antigravity, or Grok Build. You authenticate with your own subscription login or API credentials. -- **Browser VS Code when enabled.** The **Cloud IDE** option gives you a browser editor, terminal, and a place to supervise or take over the agent session. -- **Private networking.** The workspace can reach managed services by hostname without laptop VPN. -- **Open workspace model.** You can add other agent CLIs, private MCP servers, helper processes, dotfiles, package installs, or a derived team image. +# Bun > How To > Create -For the local alternative, see [Run locally](/zcp/setup/local-agent-bridge). For the tradeoffs, see [Remote or local setup](/zcp/setup/choose-workspace). -## Choose a starting point +Zerops provides a powerful Bun runtime service with extensive build support. The Bun runtime is highly scalable and customizable to suit your development and production needs. With just a few clicks or commands, you can have a production-ready Bun environment up and running in no time. -### First-time trial +## Create a Bun service using Zerops GUI -Use the [Quickstart](/zcp/quickstart) when you want the guided recipe route. It covers the recipe catalog, **AI Agent** environment, coding agent authentication, Browser VS Code, first product prompt, and proof. +First, set up a project in the Zerops GUI. Then go to the project dashboard page and choose **Add new service** in the left menu under the **Services** section. From there, you can add a new Bun service: -After provisioning, continue with a product prompt in [Build and ship](/zcp/workflows/build-with-zcp). +[Video: /vids/services/bun.webm](/vids/services/bun.webm) -### Recipe with AI Agent environment +### Choose a Bun version -Use this when you want a guided stack baseline for development or staging. A recipe with an **AI Agent** environment creates app services, managed services, and the `zcp@1` workspace together. +Zerops supports the following Bun versions: -Keep **Coding Agent** enabled when you want a bundled coding agent. Keep **Cloud IDE** enabled when you want Browser VS Code. +:::info +You can easily [upgrade](upgrade) the major version at any time later. +::: -### New Zerops setup with remote setup enabled +### Set a hostname -Use this when you want blank services or a custom stack. +Enter a unique service identifier like "app", "cache", "gui", etc. Duplicate services with the same name within the same project are not allowed. -1. Open [Add new project](https://app.zerops.io/dashboard/project-add). -2. Enter the project name, region, and tags. -3. Enable the `zcp@1` remote setup service. -4. Keep **Include Coding Agent** enabled if you want a bundled coding agent. -5. Keep **Cloud IDE** enabled if you want browser VS Code. -6. Create the project. +#### Limitations: -This gives you the `zcp@1` workspace. App runtimes and managed services may still be created later by normal ZCP app work. +- Maximum 25 characters +- Must contain only lowercase ASCII letters (a-z) or numbers (0-9) -### Existing development or staging setup +:::caution +The hostname is fixed after the service is created and cannot be changed later. +::: -Use this when runtime or managed services already exist in development or staging. Do not add `zcp` to production; promote verified work through your release process. +### Set secret environment variables -Add a `zcp` service from the dashboard the same way you add another Zerops service. The workspace appears next to the existing services and receives ZCP access from the platform. +Add environment variables with sensitive data, such as passwords, tokens, salts, certificates, etc. These will be securely saved inside Zerops and added to your runtime service upon start. -The agent should still read current state before changing anything. Existing services are context, not instructions for the next task. +Setting secret environment variables is optional. You can always set them later in the Zerops GUI. -## Open the workspace +Read more about the [different types of environment variables](env-variables#service-env-variables) in Zerops. -For a returning remote workspace, open the existing `zcp` service: +## Create a Bun service using zCLI -1. Open the project in the [Zerops dashboard](https://app.zerops.io/). -2. Open the `zcp` service. -3. Use **Browser VS Code** when **Cloud IDE** is enabled. -4. Complete your coding agent login or API-token flow if prompted (Claude Code, Codex, Antigravity, or Grok Build). +zCLI is the Zerops command-line tool. To create a new Bun service via the command line, follow these steps: -After authentication, your coding agent is connected to ZCP and ready to work from the Browser VS Code terminal. If the workspace was already authorized, use the same route to resume, supervise, or take over work. +1. [Install & setup zCLI](/references/cli) +2. [Create a project description file](create#create-a-project-description-file) +3. [Create a project with a Bun and PostgreSQL service](#full-example) -First load can take a minute while the image, Cloud IDE, and bundled agent finish starting. If the page opens before the service is ready, wait until the service is running and reload. +### Create a project description file -## Use your own editor or tools +Zerops uses a YAML format to describe the project infrastructure. -Browser VS Code is the quickest entry point, not the only one. +#### Basic example: -Editors that support remote development can connect to the workspace or runtime services over SSH, depending on how your team wants to work. Common options include VS Code Remote SSH, JetBrains Gateway, Cursor, Zed, and plain SSH. +Create a directory called `my-project`. Inside the `my-project` directory, create a `description.yaml` file with the following content: +```yaml +# basic project data +project: + # project name + name: my-project +# array of project services +services: + - # service name + hostname: app + # service type and version number in Bun@{version} format + type: bun@latest + # defines the minimum number of containers for horizontal autoscaling + minContainers: 1 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 6 + # optional: create env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' +``` -This keeps the agent and private network inside Zerops while letting you use a desktop editor UI. Broader editor patterns live in [Local & Remote Development](/features/local-remote-development#native-ide-over-ssh). +The yaml file describes your future project infrastructure. The project will contain one Bun service with default [auto scaling](scaling) configuration. Hostname will be set to "app", the internal port(s) the service listens on will be defined later in the [zerops.yaml](build-pipeline#ports). Following secret env variables will be configured: -You can also install another agent CLI or additional MCP servers inside the `zcp` service. The bundled agent flow is a convenience, not a closed product boundary. +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" +``` -## Advanced customization guardrails +#### Full example: -Tools installed inside the `zcp` service may see workspace environment variables, private networking, and any runtime files mounted into the workspace. Use trusted and pinned tools. Keep model credentials, git delivery tokens, external API keys, and production credentials out of the workspace unless the current task explicitly needs them. +Create a directory my-project. Create an description.yaml file inside the my-project directory with following content: -## What belongs where +```yaml +# basic project data +project: + # project name + name: my-project + # optional: project description + description: A project with a Bun and PostgreSQL database + # optional: project tags + tags: + - DEMO + - ZEROPS +# array of project services +services: + - # service name + hostname: app + # service type and version number in Bun@{version} format + type: bun@latest + # optional: vertical auto scaling customization + verticalAutoscaling: + cpuMode: DEDICATED + minCpu: 2 + maxCpu: 5 + minRam: 2 + maxRam: 24 + minDisk: 6 + maxDisk: 50 + startCpuCoreCount: 3 + minFreeRamGB: 0.5 + minFreeRamPercent: 20 + # defines the minimum number of containers for horizontal autoscaling. Max value = 6. + minContainers: 2 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 4 + # optional: create env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' + - # second service hostname + hostname: db + # service type and version number in postgresql@{version} format + type: postgresql@12 + # mode of operation "HA"/"non_HA" + mode: NON_HA +``` -| Concern | Where it belongs | -| -------------------- | --------------------------------------------------------------------------------------------------------------------------- | -| Agent workspace | The `zcp@1` service: agent CLI, browser VS Code, shell tools, MCP servers, helper processes, dotfiles. | -| App code deploys | Your app runtime services; not the `zcp` workspace service. | -| `ZCP_API_KEY` | Injected by Zerops into the `zcp` workspace. | -| Agent account | Your agent subscription login or model API credential. Zerops wires the agent to ZCP, but the agent account remains yours. | -| Git credentials | Configured inside the workspace when the agent should commit or push from remote setup. | -| Production release | A separate production project and release process. | -| Production release | A separate production project and release process. | +The yaml file describes your future project infrastructure. The project will contain a Bun service and a [PostgreSQL](/postgresql/overview) service. -## Runtime file access +Bun service with "app" hostname, the internal port(s) the service listens on will be defined later in the [zerops.yaml](build-pipeline#ports). Bun service will run with custom vertical and horizontal scaling. Following secret env variables will be configured: -Remote setup can mount runtime service filesystems into the `zcp` workspace after the first setup pass. Each mounted runtime appears as its own folder. Editing a mounted file changes the file inside that runtime service, with no upload step from your laptop. +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" +``` -Filesystem reach is narrower than network reach. The workspace can reach services over the private network, but it only sees runtime files mounted into it. +The hostname of the PostgreSQL service will be set to "db". The [single container](/features/scaling#single-container-mode) mode will be chosen and the default auto [scaling configuration](/postgresql/how-to/scale#configure-scaling) will be set. -## Make customization persistent +#### Description of description.yaml parameters -The `zcp@1` service is a normal Zerops service. One-off shell installs disappear when the service is rebuilt unless you make them part of the service setup. +The `project:` section is required. Only one project can be defined. -Use these patterns: +| Parameter | Description | Limitations | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| **name** | The name of the new project. Duplicates are allowed. | | +| **description** | **Optional.** Description of the new project. | Maximum 255 characters. | +| **tags** | **Optional.** One or more string tags. Tags do not have a functional meaning, they only provide better orientation in projects. | +| **tags** | **Optional.** One or more string tags. Tags do not have a functional meaning, they only provide better orientation in projects. | -- **Small additions:** put package installs, dotfiles, or bootstrap scripts into service init commands. -- **Team-standard workspace:** build a derived image based on `zcp@1` with required tools already present. -- **Helper processes:** run private helpers next to the agent and editor workspace when your team needs internal integrations. +At least one service in `services:` section is required. You can create a project with multiple services. The example above contains Bun and PostgreSQL services but you can create a `description.yaml` with your own combination of [services](/features/infrastructure). -Keep app runtime build steps with the runtime services. The remote workspace carries the agent, tools, and ZCP access; runtime services own app builds and deploys. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
+ hostname + + The unique service identifier. +
    +
  • duplicate services with the same name in the same project are forbidden
  • +
  • maximum 25 characters
  • +
  • must contain only lowercase ASCII letters (a-z) or numbers (0-9)
  • +
+
+ type + + Specifies the service type and version. -## Next steps + See what [Bun service types](/references/import-yaml/type-list#runtime-services) are currently supported. +
+ verticalAutoscaling + + Optional. Defines [custom vertical auto scaling parameters](/bun/how-to/scaling#configure-scaling). -- [Build and ship](/zcp/workflows/build-with-zcp) - normal app work after setup. -- [Tokens and credentials](/zcp/security/tokens-and-project-access) - how `ZCP_API_KEY`, git credentials, and CI secrets differ. + All verticalAutoscaling attributes are optional. Not specified attributes will be set to their default values. +
+ - cpuMode + + Optional. Accepts `SHARED`, `DEDICATED` values. Default is `SHARED` +
+ - minCpu/maxCpu + + Optional. Set the minCpu or maxCpu in CPU cores (integer). +
+ - minRam/maxRam + + Optional. Set the minRam or maxRam in GB (float). +
+ - minDisk/maxDisk + + Optional. Set the minDisk or maxDisk in GB (float). +
+ minContainers + + Optional. Default = 1. Defines the minimum number of containers + for [horizontal autoscaling](/bun/how-to/scaling#configure-scaling). + Limitations: ----------------------------------------- + Current maximum value = 10. +
+ maxContainers + + Defines the maximum number of containers for [horizontal autoscaling](/bun/how-to/scaling#configure-scaling). -# Zcp > Setup > Choose Workspace + Limitations: + Current maximum value = 10. +
+ envSecrets + + Optional. Defines one or more secret env variables as a key value + map. See env variable [restrictions](env-variables#env-variable-restrictions). +
-Use this page to decide where the agent workspace lives: inside Zerops, or on your machine beside the local app directory. +### Create a project based on the description.yaml -Both setups connect the agent to one Zerops project and the same project-scoped operations. The tradeoff is where the agent works: filesystem ownership, private-service access, credential location, bundled tooling, and shell blast radius. The runtime layout is a separate app-work decision. +When you have your `description.yaml` ready, use the `zcli project project-import` command to create a new project and the service infrastructure. -## What you are choosing +```sh +Usage: + zcli project project-import importYamlPath [flags] -**Remote setup** always includes the `zcp@1` workspace service. If the chosen **runtime layout** has a development runtime, the agent works with that service too. +Flags: + -h, --help Help for the project import command. + --org-id string If you have access to more than one organization, you must specify the org ID for which the + project is to be created. + --working-dir string Sets a custom working directory. Default working directory is the current directory. (default "./") +``` -**Local setup** does not need the workspace service or a separate development runtime. It runs beside your **local source tree** and deploys to the Zerops runtime you choose to link. +Zerops will create a project and one or more services based on the `description.yaml` content. -Remote setup is the **safer default** for broader agent autonomy because the agent shell, private networking, and workspace files stay **inside Zerops** instead of on your machine. Use local setup when local files, data, desktop tools, git credentials, or a **local-only agent client** need to stay local. +Maximum size of the `description.yaml` file is 100 kB. -## Setup comparison +You don't specify the project name in the `zcli project project-import` command, because the project name is defined in the `description.yaml`. -| | Remote setup | Local setup | -| ----------------------- | ------------------------------------------------- | -------------------------------------------- | -| Workspace service | Always has `zcp@1`. | Not required. | -| Development runtime | Only if the runtime layout includes one. | Not required for local work. | -| `zcp` process | Runs in Zerops. | Runs on your machine. | -| Agent process | Runs in the remote workspace. | Runs in your local editor or CLI. | -| Files the agent edits | Workspace files and mounted runtime files. | Files on your machine. | -| Private service access | Private Zerops network from the workspace. | Zerops VPN from your machine. | -| Token storage | Injected into the workspace service. | `.mcp.json` in the local app directory. | -| Git credentials | Configured inside the workspace service. | Your local git credentials. | -| Safety posture | Broad agent shell permissions stay in Zerops. | Agent shell permissions affect your machine. | -| Safety posture | Broad agent shell permissions stay in Zerops. | Agent shell permissions affect your machine. | +If you have access to more than one client, you must specify the client ID for which the project is to be created. The `clientID` is located in the Zerops GUI under the client name on the project dashboard page. -## Starting points +### Add Bun service to an existing project -Remote setup can start from: +#### Example: -- **Recipe with AI Agent environment.** A guided path for a known stack. A recipe creates app services, managed services, and the `zcp@1` workspace together. -- **New Zerops setup with remote setup enabled.** Start from blank services or a custom stack and add the `zcp@1` service during creation. -- **Existing development or staging setup.** Add the `zcp` workspace next to services that already exist. Do not add ZCP to production; promote verified work through your release process instead. +Create a directory `my-project` if it doesn't exist. Create an `import.yaml` file inside the `my-project` directory with following content: -Local setup can start from: +```yaml +# basic project data +project: + # project name + name: my-project +# array of project services +services: + - # service name + hostname: app + # service type and version number in Bun@{version} format + type: bun@latest + # defines the minimum number of containers for horizontal autoscaling + minContainers: 1 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 6 + # optional: create env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' +``` -- **Empty local directory.** The agent creates the app structure from a product request and uses ZCP to select or create Zerops services. -- **Existing app directory.** The app code, editor setup, local data, and git credentials already live on your machine. -- **Recipe prepared for local setup.** The recipe creates the Zerops service baseline, while the agent and files stay local. +The yaml file describes the list of one or more services that you want to add to your existing project. In the example above, one Bun service with default [auto scaling](scaling) configuration will be added to your project. Hostname of the new service will be set to `app`. Following secret env variables will be configured: -## Runtime layout is separate +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" +``` -Remote or local only answers where the agent and `zcp` process run. The project can still use: +The content of the `services:` section of `import.yaml` is identical to the project description file. The `import.yaml` never contains the `project:` section because the project already exists. -- one mutable dev runtime, -- a dev + stage pair, -- a single app runtime, -- local files linked to a stage target. +When you have your `import.yaml` ready, use the `zcli project service-import` command to add one or more services to your existing Zerops project. -That choice belongs to app work: [Build and ship](/zcp/workflows/build-with-zcp#choose-the-runtime-layout). +```sh +Usage: + zcli project service-import importYamlPath [flags] -Stage is not production. Keep production in a separate Zerops project and promote work through your release process; see [Production boundary](/zcp/security/production-policy). +Flags: + -h, --help Help for the project service import command. + -P, --project-id string If you have access to more than one project, you must specify the project ID for which the + command is to be executed. +``` -## Switching later +zCLI commands are interactive, when you press enter after `zcli project service-import importYamlPath`, you will be given a list of your projects to choose from. -Remote and local setup are not permanent, but switching is a handoff between workspaces, not a sync operation. Before switching, make the handoff explicit: +Maximum size of the import.yaml file is 100 kB. -- Preserve the current source tree through git or another explicit copy path. -- Choose one deploy source for the next task: the remote workspace, mounted runtime files, or the local app directory. -- Do not edit mounted runtime files and a local repo in parallel unless you have a merge plan. -- Regenerate local `.env` snapshots after Zerops env changes. -- If the local deploy target changed, have the agent inspect the current local link before deploying. +---------------------------------------- -## Next steps +# Bun > How To > Customize Runtime -- [What remote workspace gives you](/zcp/setup/hosted-workspace) - remote setup, Browser VS Code, bundled agent CLI, and workspace persistence. -- [Run locally](/zcp/setup/local-agent-bridge) - local install, `zcp init`, `.mcp.json`, VPN, env snapshots, and deploy target linking. -- [Trust model](/zcp/security/trust-model) - how the safety boundary changes between remote setup and local setup. ---------------------------------------- -# Zcp > Security > Trust Model +# Bun > How To > Deploy Process -The trust model starts with one rule: one ZCP process operates one Zerops project. `ZCP_API_KEY` decides that boundary at startup, and ZCP refuses tokens that resolve to no project or multiple projects. -That boundary is strong on the Zerops side. It does not make the agent harmless. A valid token can still deploy, change env vars, restart services, read logs, scale services, and change public access when Zerops permissions allow it. Treat it like an operations credential. +---------------------------------------- -## Boundary summary +# Bun > How To > Env Variables -| Question | Answer | -| ------------------------------------ | ------------------------------------------------------------------------------------------- | -| What project can ZCP see? | Exactly one project resolved from `ZCP_API_KEY` at startup. | -| What can ZCP change? | Whatever Zerops RBAC grants that token inside the project. | -| What is outside reach? | Other projects, organization-wide settings, billing, and any operation Zerops RBAC rejects. | -| What network can remote setup reach? | Private services from inside the `zcp` service. | -| What network can local setup reach? | The Zerops API directly, plus private services only when your laptop VPN is up. | -| Who owns the agent login? | You. The agent subscription or model API key is separate from `ZCP_API_KEY`. | -| Who owns the agent login? | You. The agent subscription or model API key is separate from `ZCP_API_KEY`. | -Zerops [RBAC](/features/rbac) remains the authority. ZCP does not bypass platform permissions; it exposes project operations to the agent only through the token it was given. -## Remote and local blast radius +---------------------------------------- -Remote setup and local setup share the same Zerops boundary, but not the same surroundings. +# Bun > How To > Filebrowser -| Area | Remote setup | Local setup | -| -------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------- | -| Agent location | Inside the `zcp@1` service when **Include Coding Agent** is enabled | On your machine through your editor or CLI agent | -| Files visible to the agent | Workspace files and mounted runtime files | Local files and anything your client permits | -| Private service access | Private network without laptop VPN | `zcli vpn up ` from your machine | -| Local machine exposure | No direct access to your laptop | Agent client runs as your local user | -| Best safety posture | Keep ZCP in a development/staging project and avoid mounting unrelated files | Restrict client permissions, shell access, and filesystem scope | -| Best safety posture | Keep ZCP in a development/staging project and avoid mounting unrelated files | Restrict client permissions, shell access, and filesystem scope | -Remote setup is contained inside Zerops by design. Local setup is supervise-the-client by design. Either can be right, but local setup requires more attention to your agent client's local permissions. -## Credential ownership +---------------------------------------- -There are three separate credential surfaces people often mix together: +# Bun > How To > Logs -| Credential | Owner | Purpose | -| ----------------------------------- | ---------------------------- | ------------------------------------------------------ | -| `ZCP_API_KEY` | Zerops token | Lets ZCP operate one Zerops project. | -| Agent subscription or model API key | You / the agent provider | Lets the coding agent run. Zerops does not provide it. | -| Git or CI credentials | You / your repository system | Lets finished work push to git or deploy through CI. | -| Git or CI credentials | You / your repository system | Lets finished work push to git or deploy through CI. | -In both setups, the agent account is still authenticated through the agent's own login flow. For where each credential lives (remote injection vs `.mcp.json`), rotation, rejected token shapes, and `GIT_TOKEN` / `ZEROPS_TOKEN`, see [Tokens and credentials](/zcp/security/tokens-and-project-access). -## What the token lets the agent do +---------------------------------------- -The agent can perform normal operational work when the token has permission: +# Bun > How To > Scaling -- discover runtime and managed services, -- create or adjust services when the task requires it, -- read and write service env vars, -- deploy app code to runtime services, -- read build logs, runtime logs, and service events, -- restart, reload, stop, start, or scale services, -- enable or disable public access, -- prepare delivery such as git push or CI handoff. -This is why development and staging projects are the right place for ZCP. Production should be a separate project without a `zcp` service; see [Production boundary](/zcp/security/production-policy). -## Remote setup specifics +---------------------------------------- -- **`zcp` service is not the app.** It is the workspace and control surface. Deploys target app runtimes, not the `zcp` service. -- **The service has operational reach.** A terminal in the `zcp` service can use the same ZCP access as the agent. Review the dashboard's additional changes before deploying the service; they are what give the workspace its operating surface. -- **Network reach is broader than file reach.** The workspace can reach private services, but it only sees runtime files that are mounted into it. -- **Do not hand-edit `ZCP_API_KEY`.** Remote setup gets the value from Zerops. Manual replacement can break the intended one-project boundary. +# Bun > How To > Trigger Pipeline -## Local setup specifics -- **The agent inherits local reach.** ZCP MCP is limited to one project, but the local agent client can read files, run commands, and use credentials allowed by your client settings. -- **Each local directory has its own config.** `.mcp.json` and `.zcp/state/` belong to one app directory. Launching from the wrong directory can connect the wrong token or no token. -- **VPN is outside MCP authority.** Bringing up Zerops VPN needs your operating-system approval. The tools cannot grant that for the agent. -- **`.env` files are snapshots.** They contain real project credentials and should stay out of git. -## Human confirmation gates +---------------------------------------- -Most project operations do not get an extra ZCP-specific confirmation prompt. Deploys, env changes, restarts, scaling, and public-access changes are normal project operations and are audited through platform evidence. +# Bun > How To > Upgrade -ZCP MCP adds hard gates where the loss is not safely reversible from the conversation: **service deletion** (explicit same-conversation approval by service name; remote setup also blocks deleting the `zcp` service it is running in) and **wholesale service replacement after failed deploy history** (refuse-then-acknowledge with failure evidence first). Approval from an old chat does not carry forward. The full enforcement rules are in [Tokens and credentials → What ZCP enforces for destructive actions](/zcp/security/tokens-and-project-access#what-zcp-enforces-for-destructive-actions). -## Audit evidence -Zerops records platform-side evidence. It does not record the agent's private reasoning, every shell edit, browser-helper action, or prompt history outside your agent client. +---------------------------------------- -When taking over from an agent, read evidence in this order: - -1. service-scoped events, -2. build logs, -3. runtime logs, -4. deploy and verification output, -5. git history when delivery uses git-push. +# Bun > Overview -| Surface | What it proves | What it does not prove | -| -------------- | ------------------------------------------------------------------------- | -------------------------------------------- | -| Service events | Deploy lifecycle, failures, restarts, scaling, and public-access changes. | The exact source edit that caused the event. | -| Build logs | Dependency install, build commands, compile/package failures. | Runtime request behavior after deploy. | -| Runtime logs | Start crashes, port binding, request-time app errors. | Why the build failed. | -| Verify output | Whether reachability and requested behavior passed. | That unrelated app flows work. | -| Git history | Source changes pushed during git-push delivery. | Uncommitted shell edits. | -| Git history | Source changes pushed during git-push delivery. | Uncommitted shell edits. | -Filter by service hostname when possible. Project-level timelines can include unrelated services and older failures. +[Bun ↗](https:/bun.org/en) is an asynchronous event-driven JavaScript runtime, which is designed to build scalable network applications. -## Related security +As said, there is no need for coding yet, we have created a [Github repository ↗](https://github.com/zeropsio/recipe-bun), a **_recipe_**, containing the most simple Bun web application. The repo will be used as a source from which the app will be built. -- [Tokens and credentials](/zcp/security/tokens-and-project-access) - token scope, storage, rotation, and confirmation gates. -- [Remote or local setup](/zcp/setup/choose-workspace) - compare blast radius before setup. -- [Production boundary](/zcp/security/production-policy) - keep production outside the agent loop. +### 🚀 Feel free to deploy the recipe yourself +This is the most bare-bones example of Bun app running in Zerops — as few libraries as possible, + just a simple endpoint with connect, read and write to a Zerops PostgreSQL database. ----------------------------------------- + [Deploy "bun" recipe on Zerops](https://app.zerops.io/recipe/?lf=bun) -# Zcp > Security > Tokens And Project Access +1. Log in/sign up to [Zerops GUI ↗](https://app.zerops.io) +2. In the **Projects** box click on **Import a project** and paste in the following YAML config ([source ↗](https://github.com/zeropsio/recipe-bun/blob/main/zerops-project-import.yaml)): -ZCP uses a Zerops API token to operate exactly one project. The important rule is simple: `ZCP_API_KEY` is the Zerops credential for ZCP, not an agent login, not a git token, and not a general account token. +```yaml +project: + name: recipe-bun + tags: + - zerops-recipe -Remote setup gets `ZCP_API_KEY` from Zerops. Local setup reads it from `.mcp.json`. In both setups, ZCP validates the token at startup and refuses tokens that resolve to no project or multiple projects. +services: + - hostname: api + type: bun@1.1 + enableSubdomainAccess: true + buildFromGit: https://github.com/zeropsio/recipe-bun -## Credential map + - hostname: db + type: postgresql@16 + mode: NON_HA + priority: 1 +``` -| Name | What it authorizes | Where it belongs | -| ---------------------------- | -------------------------------------------- | --------------------------------------------------------------------------- | -| `ZCP_API_KEY` | ZCP against one Zerops project | Remote: `zcp` service env injected by Zerops. Local: `.mcp.json` env block. | -| Agent login or model API key | The coding agent itself | The bundled agent in remote setup, or your local agent client. | -| `GIT_TOKEN` | Git push from remote setup to a git provider | Secret env var on the `zcp` service when remote git-push delivery needs it. | -| `ZEROPS_TOKEN` | `zcli` in GitHub Actions or external CI | Separate Zerops delivery token stored in the CI/release secret store. | -| `ZEROPS_TOKEN` | `zcli` in GitHub Actions or external CI | Separate Zerops delivery token stored in the CI/release secret store. | +3. Click on **Import project** and wait until all pipelines have finished. -Keeping these names separate prevents most setup and delivery failures. +**That's it, your application is now up and running! :star: Let's check it works:** -## Recommended `ZCP_API_KEY` shape +1. A _subdomain_ should have been enabled and visible in the project's **IP addressed & Public Routing Overview** box. Its format should look similar to this `https://api-806-3000.prg1.zerops.app`. +2. Click or the `subdomain` URL to open it in a browser and you should see -Use a Zerops API token with **Custom access per project**, exactly one selected project, and **Full access** for normal agent work. +``` +{"message":"This is a simple, basic Bun application running in Zerops.io,\n each request adds an entry to the PostgreSQL database and returns a count.\n See the source repository (https://github.com/zeropsio/recipe-bun) for more information.","newEntry":"dfd1e873-bfc8-4f36-af07-e32561820b93","count":"1"} +``` -Read-only tokens can authenticate, but they fail as soon as the agent needs to deploy, write env vars, restart services, scale, or change public access. Account-wide or multi-project tokens are refused before the agent can operate. +:::tip +Do you have any questions? Check the step-by-step tutorial, browse the documentation and join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. +::: -To generate the token: +## How to start -1. Open [Settings -> Access Tokens Management](https://app.zerops.io/settings/token-management). -2. Create a token and name it for the project, for example `zcp-`. -3. Choose **Custom access per project**. -4. Add exactly one project. -5. Set that project to **Full access** for normal ZCP MCP work. -6. Create the token and copy the value. Zerops shows it only at creation time. +It doesn't matter whether it's your first curious introduction to Zerops, you have already mastered the basics and are looking for a tiny detail or inspiration. Below, choose a section that fits your needs: -The token's blast radius equals the project and its granted permissions. Other projects, organization settings, and billing stay out of reach. Zerops [Roles & Permissions](/features/rbac#integration-tokens) remain the platform authority. +- [Care for details?](/bun/how-to/create) — Dive in all Zerops has to offer for your Bun application. +- [Bun recipes](https://github.com/zeropsio?q=Bun&type=all&language=&sort=) — Get inspired by already existing repositories, ready to be imported to Zerops. -## Rejected token shapes +## Feature Highlights -ZCP validates token shape at startup. +- [Create Bun service](/bun/how-to/create) — Start with creating a Bun service using GUI or zCLI. +- [Zerops.yaml](/bun/how-to/build-pipeline#add-zeropsyaml-to-your-repository) — See a full example of zerops.yaml file to create your own app. +- [Scaling configuration](/bun/how-to/scaling) — Set up scaling of your Bun application so that it runs smoothly while using only necessary resources. -| Token shape | What happens | Fix | -| ----------------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | -| Account-wide or multi-project token | ZCP refuses to start. | Generate a token scoped to exactly one project. | -| Token with no project access | ZCP refuses to start. | Grant one project or create a new single-project token. | -| Expired or revoked token | ZCP refuses to start or receives HTTP 401. | Replace the token and restart the agent or ZCP process. | -| Read-only project token | Startup may pass, but mutations fail later. | Use full access for normal agent work, or expect read-only behavior. | -| Read-only project token | Startup may pass, but mutations fail later. | Use full access for normal agent work, or expect read-only behavior. | +{" "} -Common messages: +- [Customize build environment](/bun/how-to/build-process#customize-build-environment) +- [Customize runtime environment](/bun/how-to/customize-runtime) -| Message | Meaning | -| -------------------------------------------------------------- | ------------------------------------------------- | -| `Token accesses N projects; use project-scoped token` | The token can see more than one project. | -| `Token has no project access` | The token authenticates but reaches no project. | -| `No authentication found: set ZCP_API_KEY or log in with zcli` | The `zcp` process did not receive a usable token. | -| `AUTH_TOKEN_EXPIRED` or HTTP 401 | The token expired, was revoked, or is invalid. | -| `AUTH_TOKEN_EXPIRED` or HTTP 401 | The token expired, was revoked, or is invalid. | +## When in doubt, reach out -For ZCP MCP setup, provide `ZCP_API_KEY`. `zcli` login is a diagnostic fallback, not the normal agent setup. +Don't know how to start or got stuck during the process? You might not be the first one, visit the FAQ section to find out. -## Where the token lives - remote vs local {#where-the-token-lives--remote-vs-local} +In case you haven't found an answer (and also if you have), we and our community are looking forward to hearing from you on Discord. -ZCP reads `ZCP_API_KEY` from its process environment at startup. It does not write the token somewhere else or exchange it for a derived credential. +Have you build something that others might find useful? Don't hesitate to share your knowledge! -| Setup | Where `ZCP_API_KEY` comes from | Who provisions it | -| -------------------------------------------- | ------------------------------------------------------- | -------------------------------------------------------- | -| [Remote setup](/zcp/setup/hosted-workspace) | The `zcp` service environment | Zerops injects it automatically when the service starts. | -| [Local setup](/zcp/setup/local-agent-bridge) | The `env` block of `.mcp.json` in the app directory | You add it after `zcp init`. | -| [Local setup](/zcp/setup/local-agent-bridge) | The `env` block of `.mcp.json` in the app directory | You add it after `zcp init`. | +- [Discord](https://discord.com/invite/WDvCZ54) — Join our core team and Zerops community on Discord. Ask questions and share your tips with other members. -In remote setup, do not hand-edit `ZCP_API_KEY`. Replace or rotate it through the Zerops-managed surface so the service keeps the intended project boundary. +## Popular Guides -In local setup, `zcp init` writes a token-less `.mcp.json`. Add the token manually: +- [zCLI](/references/cli) — Get even more out of Zerops with the zCLI command line tool. +- [Zerops VPN](/references/networking/vpn) — Connect to your services easily with Zerops VPN. -```json -{ - "mcpServers": { - "zerops": { - "command": "zcp", - "args": ["serve"], - "env": { - "ZCP_API_KEY": "" - } - } - } -} -``` -Add `.mcp.json` to `.gitignore`. Each app directory should have its own file and token. Switching projects means switching directories, not editing one shared credential. +---------------------------------------- -## Agent credentials are separate +# Clickhouse > Overview -The bundled agent in remote setup may ask you to sign in or provide a model API key. That is not `ZCP_API_KEY`. -Zerops wires the agent to ZCP. It does not provide your model subscription, store your agent login, or rotate your agent provider credentials. Treat the agent account exactly as you would outside Zerops. +Zerops provides a fully managed [ClickHouse](https://clickhouse.com/) columnar database optimized for blazing-fast analytical queries on massive datasets, making it ideal for data warehousing and real-time analytics applications. -## Git and CI credentials +## Supported Versions -`GIT_TOKEN` matters only when remote setup pushes to a git remote. It authorizes git provider access from the `zcp` service. In local setup, your local git CLI uses your normal SSH key or credential helper, so ZCP does not need `GIT_TOKEN`. +Currently supported ClickHouse version: -`ZEROPS_TOKEN` is a Zerops API token used by GitHub Actions or another CI system when that system runs `zcli` against Zerops. It is not a GitHub token. Use a separate delivery token so ZCP sessions and CI/release workflows can be named, rotated, and audited independently. +Import configuration version: -For production delivery, `ZEROPS_TOKEN` should reach production only and live only in the production CI or release secret store. +- `clickhouse@25.3` -With GitHub CLI, the secret shape is: +## Service Configuration -```bash -gh secret set ZEROPS_TOKEN -b "$ZEROPS_DELIVERY_TOKEN" -``` +Our ClickHouse implementation features optimized default settings designed for analytical workloads and data warehousing use cases. -Use the GitHub UI or your CI secret manager instead if your team does not allow local CLI secret writes. +### Resource Allocation -## Rotation +Zerops automatically allocates resources to your ClickHouse service based on demand within the limits defined in your [automatic scaling configuration](/features/scaling). -Rotate in the Zerops dashboard, then update the surface that consumes the token. +## High Availability and Deployment Modes -| Surface | Rotation step | -| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -| Remote `ZCP_API_KEY` | Reconfigure or redeploy the remote workspace through the dashboard-managed flow, then restart the `zcp` service so the process gets the new value. | -| Local `ZCP_API_KEY` | Paste the new token into `.mcp.json`, then restart the local agent client. | -| `ZEROPS_TOKEN` in CI | Replace the repository or CI secret. The next workflow run uses the new value. | -| `GIT_TOKEN` | Replace the git-provider credential stored for remote setup. | -| `GIT_TOKEN` | Replace the git-provider credential stored for remote setup. | +:::important +Deployment mode is selected during service creation and cannot be changed later. +::: -Rotation is picked up on the next process start or CI run, not in the middle of a live agent session. +### High-Availability (HA) Setup -## What ZCP enforces for destructive actions +The recommended solution for production workloads and mission-critical analytics: -A valid token does not remove every guardrail. ZCP MCP adds explicit confirmation for operations where the loss is not safely reversible from inside the conversation. +* **3 data nodes** with automatic monitoring, repairs, and replication factor of 3 +* **Default cluster name:** `zerops` (currently 1 shard with 3 replicas) -| Operation | Gate | -| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Service deletion | Requires explicit approval in the same conversation, including the service name. Remote setup also blocks deleting the `zcp` service it is running in. | -| Wholesale service replacement after failed deploy history | The first request refuses, surfaces what would be replaced, and requires the agent to read failure evidence before asking you to confirm. | -| Wholesale service replacement after failed deploy history | The first request refuses, surfaces what would be replaced, and requires the agent to read failure evidence before asking you to confirm. | +#### Replication Configuration -Deploys, env changes, lifecycle actions, restarts, scaling, and public-access changes do not get an additional ZCP-specific confirmation gate. They are normal operations for a full-access token and should be reviewed through service events, logs, verification output, and team policy. +The `Replicated` database engine handles replication automatically, but there are specific requirements you need to follow: -Approval from a previous chat does not carry forward. A new conversation needs a new approval. +**For Database Operations** +Use this configuration when creating/managing databases: -## Evidence before destructive recovery +```sql +CREATE DATABASE uk ON CLUSTER '{cluster}' +ENGINE = Replicated('/clickhouse/databases/{uuid}', '{shard}', '{replica}'); +``` -When a service has recent failure history, ZCP enforces one recovery rule: read the platform evidence before destroying or replacing the service. +**For Table Operations** +Use `ENGINE = ReplicatedMergeTree` when creating tables (without the `ON CLUSTER '{cluster}'` clause): -The agent should inspect service events, build logs, runtime logs, and failure summaries, then either fix the cause or show you the evidence before asking for destructive confirmation. The point is to preserve the failure context the next session needs. +```sql +CREATE TABLE uk.uk_price_paid +( + price UInt32, + date Date, + postcode1 LowCardinality(String), + postcode2 LowCardinality(String), + type Enum8('terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4, 'other' = 0), + is_new UInt8, + duration Enum8('freehold' = 1, 'leasehold' = 2, 'unknown' = 0), + addr1 String, + addr2 String, + street LowCardinality(String), + locality LowCardinality(String), + town LowCardinality(String), + district LowCardinality(String), + county LowCardinality(String) +) ENGINE = ReplicatedMergeTree ORDER BY (postcode1, postcode2, addr1, addr2); +``` -A service waiting for first code deploy is not the same thing as a failed service. The gate is about recorded failure history, not idle state. +For more details see: +- https://clickhouse.com/docs/engines/database-engines/replicated +- https://clickhouse.com/docs/engines/table-engines/mergetree-family/replication +- https://clickhouse.com/docs/sql-reference/distributed-ddl -Threat model and boundaries: [Trust model](/zcp/security/trust-model). +You can use other `Replicated*` engines from the MergeTree family. Replication is only supported for tables in the MergeTree family: -## Credential checks +* `ReplicatedMergeTree` +* `ReplicatedSummingMergeTree` +* `ReplicatedReplacingMergeTree` +* `ReplicatedAggregatingMergeTree` +* `ReplicatedCollapsingMergeTree` +* `ReplicatedVersionedCollapsingMergeTree` +* `ReplicatedGraphiteMergeTree` -- **Account-wide full-access tokens are refused.** ZCP needs one project, not a broad account credential. -- **`zcp init` regenerates `.mcp.json`.** Re-add `ZCP_API_KEY` after rerunning it. -- **`GIT_TOKEN` is not `ZCP_API_KEY`.** One authorizes git provider access; the other authorizes Zerops operations. -- **`ZEROPS_TOKEN` in GitHub Actions is not a GitHub PAT.** It is a Zerops API token for `zcli`. -- **A rotated token needs a restart.** The live ZCP process keeps the old environment value until it starts again. -- **A successful confirmation is still destructive.** Backups, git history, and service events are your recovery evidence; ZCP does not auto-rollback a confirmed deletion or replacement. +User management (users, grants, etc.) is replicated by Keeper by default. The `ON CLUSTER '{cluster}'` clause is not needed when creating/deleting users or changing grants. -## Related pages +The default `` database follows these practices. If you don't follow these recommendations, it is possible you will face issues in case of fail and repair scenario. -- [Trust model](/zcp/security/trust-model) - the access boundary this page enforces. -- [What remote workspace gives you](/zcp/setup/hosted-workspace) - automatic token injection. -- [Run locally](/zcp/setup/local-agent-bridge) - local `.mcp.json` token setup. -- [Production boundary](/zcp/security/production-policy) - why production gets separate credentials. -- [GitHub integration](/references/github-integration) - CI secret usage with Zerops. +### Single Container Installation +Suitable for development and testing environments: ----------------------------------------- +* Consists of 1 ClickHouse node +* Lower resource requirements +* No automatic replication -# Zcp > Security > Production Policy +:::warning +Use for development purposes or non-critical data only. **Make sure to have backups enabled** if using in production, as you can lose your data due to container volatility. +::: +## Network Access & Protocols -Use the MCP setup in development or staging. Keep production in a separate Zerops project without a `zcp` service. Production deploys should come from CI, a release pipeline, or a deliberate human `zcli` push using production credentials. +Zerops automatically configures secure authentication for your ClickHouse service. -Zerops does not prevent you from adding `zcp` to production. The policy exists because ZCP MCP gives a coding agent operational access. In production, that is the wrong blast radius for normal app development. +### Default Database +Zerops creates a default database with the same name as your service hostname (``) during service creation. -The production boundary does not make ZCP output disposable. The intended path is production-shaped dev or stage infrastructure, verified behavior, and then a controlled production release outside the agent loop. +### Default Users -## Recommended project layout +#### `zerops` User +* Created automatically upon service creation +* Has privileges for the default database +* Password available as environment variable `password` -| Project | Contains | Who operates it | -| ----------------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------ | -| Development / staging project | `zcp` service, agent workspace, dev runtime, optional stage runtime, non-production managed services | Agent plus humans | -| Production project | Production runtimes, production managed services, production env values, production backups and scaling | CI/release process plus humans | -| Production project | Production runtimes, production managed services, production env values, production backups and scaling | CI/release process plus humans | +#### `super` User +* Administrative user for cluster management +* Can create new databases, users, and manage permissions +* Password available as environment variable `superUserPassword` -The two projects use different Zerops tokens. A development token cannot reach production. A production token should not be placed in the development `zcp` service or a local `.mcp.json` used by the agent. +### Access Methods -## Why production is a separate project +Services within the same project can access ClickHouse directly using: +``` +: +``` -- **The Zerops project is the security boundary.** ZCP binds to one project at startup. Keeping production separate prevents a development agent from touching it by accident. -- **Secrets stay clean.** Production env values, database credentials, object-storage keys, and third-party secrets stay in the production project. -- **Operational policies can differ.** Production often needs HA services, stronger backup retention, stricter scaling, alerts, and release approvals. Development can stay cheaper and more flexible. -- **Audit trails stay readable.** Development experiments and agent retries do not mix with production deploy evidence. +For HA cluster setups, you can also access specific data nodes: +``` +node-stable-<1..3>.db..zerops: +``` -This separation matters even when the same source repository deploys to both projects. +For external access, use `zcli` VPN to connect using the same connection strings. -## What stage proves +ClickHouse offers multiple interfaces for different use cases: -Stage is the production-like rehearsal inside development or staging. It is where the agent proves the change before the release leaves the ZCP loop. +#### Native TCP Protocol +**Port:** `9000` (Environment variable: `port` or `portNative`) -Use stage to match production where it matters: +Optimal for high-performance applications and ClickHouse-native clients. -- same runtime family and version, -- same managed service types, -- same build and start command pattern, -- same deploy route, -- behavior checks against a real running service. +More about it in [official ClickHouse docs](https://clickhouse.com/docs/interfaces/tcp). -Stage is not production. It should use non-production data and non-production secrets. A green stage means the change is ready for release, not that the agent should deploy to production itself. +#### HTTP/HTTPS Interface +**Port:** `8123` (Environment variable: `portHttp`) -## The release +Ideal for web applications and REST API integrations. -After stage verifies, ZCP's job is done for that change. The production release happens outside the agent loop: +It is also possible to setup HTTPS domain access or enable subdomain for access from outside the project. Then you can access the database using following URL: +- `https://clickhouse.my-awesome-domain.tld` +- JDBC connection string example (use `ssl=true&sslmode=NONE` options): +`jdbc:clickhouse:https://clickhouse.my-awesome-domain.tld:443/?ssl=true&sslmode=NONE` -- CI deploys a merged commit or release tag to the production project. -- A release pipeline runs `zcli push` with a production-scoped `ZEROPS_TOKEN`. -- A human runs `zcli push` against the production project with production credentials. +More about it in [official ClickHouse docs](https://clickhouse.com/docs/interfaces/http). -The agent can prepare the handoff by pushing code, summarizing verification evidence, and naming the runtime and URL it verified. It should not bridge development to production. +#### MySQL Protocol +**Port:** `9004` (Environment variable: `portMysql`) -For the practical workflow, see [Promote to production](/zcp/workflows/promote-to-production). +Enables connectivity from MySQL-compatible tools and applications. -## Credential rules +More about it in [official ClickHouse docs](https://clickhouse.com/docs/interfaces/mysql). -| Credential | Production policy | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------- | -| Development `ZCP_API_KEY` | Never grants production access. Keep it scoped to the development/staging project. | -| Production `ZEROPS_TOKEN` | Store only in the production CI/release secret store. Do not place it in the development `zcp` service. | -| Agent subscription or model API key | May be used by the agent, but it does not grant Zerops production access by itself. | -| Git credentials | May push source changes, but production deploy authority should stay with the release process. | -| Git credentials | May push source changes, but production deploy authority should stay with the release process. | +#### PostgreSQL Protocol +**Port:** `9005` (Environment variable: `portPostgresql`) -If a production deploy fails, investigate in the production project with production logs, events, backups, and CI output. Do not attach the development agent directly to production as a shortcut. +Allows integration with PostgreSQL-compatible clients and ORMs. -## Production separation rules +More about it in [official ClickHouse docs](https://clickhouse.com/docs/interfaces/postgresql). -| Rule | Why it matters | -| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------- | -| Keep the production project without a `zcp` service | Production should not host an agent workspace with operational access. | -| Keep production tokens out of local `.mcp.json` | Local agents should operate development or staging projects, not production. | -| Keep production `ZEROPS_TOKEN` in the release secret store | Development tooling should not deploy to production outside the release process. | -| Treat stage proof as release evidence, not production approval | Stage is the rehearsal; production approval is a separate release decision. | -| Promote through CI, release tooling, or a deliberate human action | Production execution should use production credentials. | -| Promote through CI, release tooling, or a deliberate human action | Production execution should use production credentials. | +## Backup and Recovery -## Acceptable agent involvement +Zerops provides comprehensive backup functionality using ClickHouse's native backup capabilities. -The agent can still help before the production release: +### Backup Process -- make the code change in development, -- deploy and verify dev/stage runtimes, -- produce the URL, endpoint result, or UI proof it verified, -- push or prepare the branch your team uses for review, -- summarize release notes and known blockers for the human or CI handoff. +* Backups are performed using ClickHouse SQL command `BACKUP ALL ...` with `super` user permissions +* All databases are backed up (excluding system databases) +* Backup files are stored as `tar.gz` archives +* Contains the complete folder structure produced by the SQL backup command -ZCP's involvement stops at the handoff. Production execution belongs to the release process. +### Restore Options -## Related security +#### Option 1: Custom S3 Bucket Restore -- [Promote to production](/zcp/workflows/promote-to-production) - practical production release paths after ZCP proof. -- [Trust model](/zcp/security/trust-model) - the boundary that makes this policy enforceable. -- [Tokens and credentials](/zcp/security/tokens-and-project-access) - production and development credentials stay separate. +1. Download backup from Zerops GUI or via API +2. Extract the tar.gz archive and upload to your S3 bucket +3. Restore using ClickHouse SQL commands: +```sql +-- Restore specific table +RESTORE TABLE mydb.mytable AS mydb.mytable2 +FROM S3('https://storage-prg1.zerops.io/mybucket/path/to/dir/with/untarred/backup', + 'my-access-key-id', 'my-secret-key'); ----------------------------------------- +-- Restore all data +RESTORE ALL FROM S3('https://storage-prg1.zerops.io/mybucket/path/to/backup', + 'my-access-key-id', 'my-secret-key'); -# Zcp > Reference > Troubleshooting +-- see https://clickhouse.com/docs/operations/backup#configuring-backuprestore-to-use-an-s3-endpoint +``` +#### Option 2: Support-Assisted Restore -Use troubleshooting when the agent is confused, a session was interrupted, deploy keeps failing, verification does not match the final answer, or you are taking over manually. +Contact Zerops support on Discord, and we'll place the backup on the container's filesystem for restoration using the `File` driver (see [ClickHouse documentation](https://clickhouse.com/docs/operations/backup) for further info). -Start from current state, not chat memory: +:::note +A simple GUI/API action for backup restoration is on our roadmap for future releases. +::: -```text -Read current project status and tell me where things stand before changing anything. -``` +## Troubleshooting -That should make the agent read live services, saved workflow state, recent deploys, logs, events, and verification output before it edits anything else. +### Common Issues -## Find where the run is stuck +#### Connection Problems +* Verify you're using the correct port for your chosen protocol +* Check that your service is running and healthy in the Zerops dashboard +* For HA clusters, try connecting to specific nodes if the main endpoint fails +* Ensure authentication credentials are correct -| Stuck point | Ask for | What you should get | -| ----------- | ------- | ------------------- | -| Agent lost context | Current project status and services in scope. | Runtime target, managed services, last deploy, last verify result, and any saved workflow state. | -| Service setup is unclear | Runtime target and dependency plan. | Which existing services will be used, which missing services are needed, and what needs human approval. | -| Deploy failed | Failure category plus build logs, runtime logs, and recent service events. | A cause or next diagnostic step, not another blind deploy. | -| Runtime is reachable but app behavior fails | The failing behavior check and request-time runtime logs. | Endpoint/UI/job/data evidence tied to the product request. | -| Local app cannot reach services | VPN state, generated `.env`, and selected runtime/setup. | Whether MCP auth works separately from private service access. | -| Delivery is ambiguous | Delivery mode, git-push state, build integration, or handoff note. | What will happen after proof: direct deploy, git push, CI, package, or production handoff. | -| Delivery is ambiguous | Delivery mode, git-push state, build integration, or handoff note. | What will happen after proof: direct deploy, git push, CI, package, or production handoff. | +#### Replication Issues +* Verify you're using `ON CLUSTER '{cluster}'` for database operations +* Confirm tables use `ReplicatedMergeTree` engines -Useful prompt: +## Learn More -```text -Show me the runtime in scope, failure category, evidence read, fixes tried, and the next decision needed. -``` +- [Official ClickHouse Documentation](https://clickhouse.com/docs) - Comprehensive guide to ClickHouse features and SQL syntax +- [ClickHouse Replication Guide](https://clickhouse.com/docs/engines/table-engines/mergetree-family/replication) - Detailed replication concepts +- [Distributed DDL Reference](https://clickhouse.com/docs/sql-reference/distributed-ddl) - Cluster operations documentation -## Evidence order +## Support -The useful evidence depends on the failure category surfaced by deploy or verify tools. +For advanced configurations or custom requirements: +- Join our [Discord community](https://discord.gg/zerops) +- Contact support via [email](mailto:support@zerops.io) -| Category | Read first | Avoid | -| -------- | ---------- | ----- | -| `build` | Build logs, build commands, dependency manifests, deploy file list. | Runtime logs; the runtime did not start yet. | -| `start` | Prepare/runtime logs, start command, ports, env references. | Rebuilding without checking why the process exited. | -| `verify` | Failing check detail, HTTP response, request-time runtime logs, stored state. | Calling a green deploy "done" before behavior passes. | -| `network` | VPN, SSH, DNS, subdomain readiness, service status, transport error. | Editing app code before proving connectivity. | -| `config` | Field-level rejection, `zerops.yaml`, setup name, env references, service settings. | Guessing from service names or dashboard memory. | -| `credential` | The named credential surface: `ZCP_API_KEY`, git, SSH, managed-service, CI, or external API. | Rotating unrelated secrets. | -| `other` | Raw events/logs and the exact phase that failed. | Repeating the same attempt after the same unknown reason. | -| `other` | Raw events/logs and the exact phase that failed. | Repeating the same attempt after the same unknown reason. | +---------------------------------------- -Failure categories come from the deploy/verify evidence surface. They are not a verdict; they tell the agent where the next useful signal is. +# Company > About -## Local setup checks -Local setup has two separate connections: +## Our Story -- MCP uses `ZCP_API_KEY` to talk to the Zerops API. -- Your local app and shell use `zcli vpn up` to reach private service hostnames such as `db` or `cache`. +Zerops, originally founded in 2018, began as an internal project at [vshosting.eu](https://vshosting.eu), one of the largest providers of managed hosting solutions in Central Europe. In June 2024, after a period when the project had been shut down following corporate restructuring, Zerops was re-launched as an independent startup. Now headed by the original development team and backed by strong partners, Zerops continues its mission with renewed focus and independence. -That means MCP can work while the app cannot reach the database. +## Technology & Infrastructure -| Symptom | Check | -| ------- | ----- | -| Agent does not list the `zerops` MCP server. | Relaunch the agent from the directory containing `.mcp.json`. | -| MCP startup says the token reaches multiple projects. | Replace `ZCP_API_KEY` with a single-project token. | -| Re-running `zcp init` made MCP disappear. | Re-add the `ZCP_API_KEY` env block to `.mcp.json` and restart the agent. | -| Local app cannot reach `db`, `cache`, or storage hostnames. | Run `zcli vpn up ` again. | -| Local app reads stale credentials. | Regenerate `.env`; it is a snapshot, not a live sync. | -| `zcp` is not found after install. | Add `~/.local/bin` or the install target to `PATH`, then restart the shell/agent. | -| `zcp` is not found after install. | Add `~/.local/bin` or the install target to `PATH`, then restart the shell/agent. | +Zerops runs on bare metal, with the platform built from the ground up using Golang and [Incus](https://linuxcontainers.org/incus/) containerization. Our servers are currently located in Prague, Czech Republic, leveraging vshosting's state-of-the-art datacenter facilities. -For local setup details, use [Run locally](/zcp/setup/local-agent-bridge). +## Financial Backing & Partners -## Manual takeover +Zerops is financially backed by established venture capital firms: +- [Presto Ventures](https://www.prestoventures.com/) - A leading Central European venture capital firm +- [Gi21 Capital](https://gi21capital.com/) - A technology-focused investment firm -If you take over from the agent, read evidence in this order: +Our primary infrastructure partner is [vshosting.eu](https://vshosting.eu), which itself is part of [Contabo](https://contabo.com/en/), owned by global investment firm [KKR](https://www.kkr.com/). This strategic partnership provides Zerops with enterprise-grade infrastructure stability. -1. Service list and runtime target. -2. Service-scoped events for the runtime in question. -3. Build logs for build failures, runtime logs for start or request failures. -4. Verify output for reachability and requested behavior. -5. Git history only when delivery uses git-push or CI. +## Looking Ahead -Do not inspect every service first. Start with the runtime in scope and expand only when the evidence points to a dependency. +We're committed to continually improving the Zerops platform with a focus on: -## When to stop +- **Multiregional Deployment**: Beginning with built-in CDN capabilities, followed by the ability to run entire projects in different regions +- **Enhanced Performance**: Ongoing optimization of our container orchestration and resource management +- **Developer Experience**: Continuous improvement of our UI, CLI, and API interfaces -Stop the loop when: +## Connect With Us -- the same failure repeats without new evidence, -- the agent needs an external credential, -- the target runtime or stage choice is ambiguous, -- a destructive action would delete or replace a service, -- production release authority is needed, -- the request no longer fits the current project layout. +- [Discord](https://discord.com/invite/WDvCZ54) +- [X.com](https://x.com/zeropsio) +- [LinkedIn](https://www.linkedin.com/company/zerops) +- [Contact Us](mailto:team@zerops.io) -A blocker is acceptable only when it names the runtime in scope, failure category, evidence read, fixes attempted, and the human decision or credential still needed. +---------------------------------------- -Before destructive recovery, read service-scoped events, logs, deploy/verify result, and git history when delivery uses git-push. Token scope and destructive confirmations are covered in [Tokens and credentials](/zcp/security/tokens-and-project-access). +# Company > Branding ----------------------------------------- +# Zerops Brand Assets -# Zcp > Reference > Mcp Operations +Here you can find and download our official logos and badges in various formats. Please follow our brand guidelines when using these assets. +## Download Assets -Most app work should be phrased as an outcome: build this, fix that, deploy and prove it. Operation names matter when you configure agent-client policy, debug an MCP integration, build a custom client, or use ZCP MCP pragmatically as a set of project-scoped Zerops tools. +Below you'll find our official assets available in various formats. Click the download buttons to get the assets in your preferred format. -ZCP MCP is the MCP server exposed by the `zcp` binary. Any MCP-capable client can connect to it and call tools such as `zerops_discover`, `zerops_logs`, `zerops_events`, `zerops_deploy`, or `zerops_verify`. +## Brand Guidelines -## Tool-only use +When using Zerops brand assets, please: -The MCP server exposes operations. It does not, by itself, decide the whole app lifecycle. - -Claude Code with the generated workflow uses its instructions to decide sequencing: inspect state before changing things, choose the runtime target, use existing services or create missing ones, deploy, read failure evidence, verify requested behavior, and stop with proof or a blocker. - -Tool-only use is valid when you want a custom MCP client, script, dashboard, policy-gated agent, or narrow operational task. In that setup, your integration owns the sequencing: +- Don't modify the logos or badges in any way +- Maintain adequate spacing around the assets +- Use the provided color versions (light/dark) as appropriate +- Don't use the Zerops logo or badges in a way that suggests partnership or endorsement without permission +- Don't use the assets as your own branding or as part of your logo -- which project services are in scope, -- when a deploy is allowed, -- what counts as verification, -- which logs or events should be read after failure, -- when to ask a human, -- when to stop. -Tool-level gates still apply. Service deletion requires explicit named approval, and destructive import override requires an acknowledgement of the exact targets. +---------------------------------------- -If you use Claude Code but do not want the generated workflow guidance, keep the MCP connection and remove the ZCP-managed workflow block from `CLAUDE.md`, or keep your own policy outside the ZCP markers. What you lose is the generated instruction layer that makes the agent plan around live state, deploy with bounded retries, verify behavior, and report proof or a concrete blocker. +# Company > Payment -Generated files and workflow state are documented in [Workflows in depth](/zcp/reference/agent-workflow#generated-files-and-state). -## What the tools can do +Zerops provides a transparent credit-based payment system that makes managing your account finances straightforward. You can easily add funds to your account through manual or automatic top-ups, track all your transactions, and download invoices for your records. -| Area | Tools | Typical use | -| ---- | ----- | ----------- | -| Discover | `zerops_discover` | Read services, service metadata, env-var keys, and project topology. | -| Observe | `zerops_logs`, `zerops_events`, `zerops_verify`, `zerops_process` | Diagnose deploys, read runtime/build evidence, run health checks, and watch async processes. | -| Deploy | `zerops_deploy` | Push source through Zerops build/deploy pipeline and return build/deploy evidence. | -| Configure | `zerops_env`, `zerops_subdomain`, `zerops_scale`, `zerops_manage` | Change env vars, public subdomain access, scaling, lifecycle, reload/restart, and storage attachment. | -| Import/export | `zerops_import`, `zerops_export`, `zerops_preprocess` | Import project/service YAML, read export YAML, and expand Zerops preprocessor expressions. | -| Workspace | `zerops_mount` | Mount or unmount runtime filesystems in remote setup. | -| Workflow | `zerops_workflow` | Track, recover, or configure workflow sessions and packaging/export flow. | -| Destructive | `zerops_delete` | Delete one named service after explicit user approval. | -| Destructive | `zerops_delete` | Delete one named service after explicit user approval. | +This page explains how to manage your account balance, set up payment preferences, and access your complete billing history to help you maintain uninterrupted service while keeping your finances organized. -Recipe-authoring and ZCP-internal maintenance operations are intentionally out of scope for this public reference. +## Manual Top-up -## Read-only operations +Manual top-ups give you direct control over your account funding. To add credits to your account immediately: -| Operation | Purpose | -| --------- | ------- | -| `zerops_discover` | Read services, ports, env-var keys, and current state. | -| `zerops_export` | Read platform project/service export YAML and service metadata. | -| `zerops_logs` | Read runtime/build logs filtered by service, severity, time, or search. | -| `zerops_events` | Read service activity, deploys, builds, scaling, and failures. | -| `zerops_verify` | Run service health, recent error log, and HTTP-readiness checks. | -| `zerops_knowledge` | Fetch ZCP MCP guidance or platform knowledge for the current state. | -| `zerops_process` | Check a known async process; cancel is a mutating action. | -| `zerops_process` | Check a known async process; cancel is a mutating action. | +1. Navigate to **Credit & Spend Overview** in the Organization section of the main menu +2. Click on **Top up credit** and fill in the [billing information](#billing-information) +3. Enter your desired top-up amount (minimum $10 VAT excl.) +3. Complete payment using your saved or new payment method -## Mutating operations +## Automatic Top-ups -| Operation | Purpose | -| --------- | ------- | -| `zerops_deploy` | Ship code through the Zerops build and deploy pipeline. | -| `zerops_env` | Read, set, delete, or generate env vars and local `.env` files. | -| `zerops_manage` | Start, stop, restart, reload, or connect storage. | -| `zerops_scale` | Change CPU, RAM, disk, CPU mode, or container autoscaling where supported. `HA`/`NON_HA` is set at service creation. | -| `zerops_subdomain` | Enable or disable public subdomain access. | -| `zerops_delete` | Delete a service. Explicit named approval is required. | -| `zerops_delete` | Delete a service. Explicit named approval is required. | +Automatic top-up ensures your projects continue running without interruption by replenishing your credits when they run low. -## Operational setup +:::note Prerequisites +Automatic top-ups are available once you have made at least one manual top-up, saved a payment method, and provided your [billing information](#billing-information). The saved card is charged off-session, so a valid payment method must stay on file. +::: -| Operation | Purpose | -| --------- | ------- | -| `zerops_workflow` | Track, recover, or configure workflow sessions; also carries the package-running-service export flow. | -| `zerops_import` | Import project/service definitions. Destructive override is gated. | -| `zerops_mount` | Mount or unmount runtime filesystems in remote setup. | -| `zerops_preprocess` | Expand Zerops preprocessor expressions. | -| `zerops_preprocess` | Expand Zerops preprocessor expressions. | +To turn them on, navigate to **Credit & Spend Overview** in the Organization section of the main menu, open the automatic top-up settings, and configure the three values described below. -## Remote and local tool differences +### How Automatic Top-ups Work -The operation names are the same, but the filesystem and network boundary differ. +When enabled, Zerops periodically checks your balance and tops it up by a fixed amount whenever your credit drops below a threshold you choose, up to a limit you set for each calendar month. +Zerops initiates an automatic payment when: -| Area | Remote setup | Local setup | -| ---- | ------------ | ----------- | -| Files | Runtime files through SSHFS or remote containers. | Local working directory. | -| Deploy source | Remote service or batch deploy inside Zerops. | Local `workingDir`. | -| Dev server | Remote setup can run or inspect remote dev processes. | Your local tool owns the dev server. | -| Env bridge | Env vars are already available in Zerops. | `.env` generation resolves Zerops references for local use. | -| Git | Workspace-managed credentials. | User's local git credentials. | -| Git | Workspace-managed credentials. | User's local git credentials. | +- Your combined balance (credit + promo credit) drops **below your threshold** +- You have automatic top-ups enabled +- The top-up wouldn't exceed your **calendar-month limit** -## Confirmation gates +:::note Important notes +- Each top-up charges the **fixed amount** you configured, regardless of how fast you're spending +- Your balance is checked periodically (every few minutes), so a top-up can take a few minutes to appear after you drop below the threshold +- The final automatic top-up of the month is reduced so the month's total lands exactly on your calendar-month limit; after the limit is reached, automatic top-ups pause until the next calendar month +- To avoid repeatedly hitting your payment method (which can get a card flagged or blocked by the payment processor), top-ups are spaced out: after a **successful** top-up Zerops waits **1 hour** before the next one, and after a **failed** top-up it waits **1 day** before trying again +- If a charge fails, Zerops notifies you so you can check the validity and available funds of your saved card. After **3 failed attempts in a row**, automatic top-up is turned off and you're notified by email; re-enable it once your payment method is working again +- Auto top-up limits don't affect manual payments — add any amount manually regardless of automatic settings +::: -Two operations require explicit care: +### Configuration Options -- **Service deletion** requires explicit user approval in the current conversation, by service name. -- **Destructive import override** first refuses and names what would be replaced; a second call must acknowledge the same targets. +#### Threshold +When your combined balance (credit + promo credit) drops below this value, an automatic top-up is triggered. -See [Tokens and credentials](/zcp/security/tokens-and-project-access#what-zcp-enforces-for-destructive-actions) for the user-facing confirmation flow. +#### Top-up Amount +The fixed amount charged to your saved card on each automatic top-up. -## Related reference +- Minimum: $10 (matches the minimum manual payment) +- Maximum: $10,000 per top-up -- [Workflows in depth](/zcp/reference/agent-workflow) - how a generated-workflow run uses these tools. -- [Troubleshooting](/zcp/reference/troubleshooting) - evidence order when a run gets stuck. -- [Tokens and credentials](/zcp/security/tokens-and-project-access) - token scope, storage, and confirmation gates. +#### Calendar-Month Limit +The maximum total that can be automatically charged within a single calendar month (UTC). This safeguards against unexpected costs: once the limit is reached, automatic top-ups pause until the next calendar month. +- Must be at least the top-up amount (so at least one top-up can go through each month) ----------------------------------------- +#### Real-World Example -# Zcp > Reference > Index +**Scenario:** Application with ~$50 weekly operating costs and an initial manual top-up of $100 +**Your Settings:** +- Threshold = $50 +- Top-up amount = $200 +- Calendar-month limit = $500 -Reference pages exist for the moments when an exact label, tool name, or recovery step matters. For day-to-day app work, start in [Build and ship](/zcp/workflows/build-with-zcp); for the loop itself, [How it works](/zcp/concept/how-it-works). +**Expected behavior:** +- When your balance falls below $50, Zerops charges $200 to bring it back up +- Each top-up is exactly $200, no matter how fast you're spending, until you approach the calendar-month limit +- After two top-ups ($400), a full $200 would exceed the $500 limit, so the next top-up is reduced to $100, bringing the month's total to exactly $500 +- Automatic top-ups then pause until the limit resets at the start of the next calendar month (UTC) -- [Workflows in depth](/zcp/reference/agent-workflow) — Catalog of phases, routes, layouts, and labels behind a generated-workflow run. -- [ZCP MCP tools](/zcp/reference/mcp-operations) — Exact tool names and surface for custom MCP clients or agent policy. -- [Troubleshooting](/zcp/reference/troubleshooting) — When the agent is stuck, a session was interrupted, deploys keep failing, or you are taking over manually. -- [Glossary](/zcp/glossary) — Definitions for terms across pages and workflow status (`appdev`, `local-stage`, `delivery mode`, etc.). +## Billing Information -## Common scenarios +You are required to enter billing details for all transactions (manual and automatic top-ups), with one exception: -
+- EU-based users who are not VAT payers with transactions under $350 -
+You can save your billing details by navigating to **Invoices & Billing Settings** in the Organization section of the main menu. -SCENARIO +## Invoices -### Debugging a stuck deploy +Zerops provides easy access to all invoices generated for manual and automatic top-ups within your organization. -[Troubleshooting → Evidence order](/zcp/reference/troubleshooting#evidence-order) names what to read first; [Workflows in depth → Failure categories](/zcp/reference/agent-workflow#failure-categories) maps the labels. +To view and manage your invoices navigate to **Invoices & Billing Settings** in the Organization section of the main menu. -
+## Export Credit Consumption Records -
+Zerops allows you to download monthly reports of your credit consumption history for analysis and record-keeping. -SCENARIO +1. Navigate to **Credit & Spend Overview** in the Organization section +2. Find the **Export Credit Consumption Records** section +3. Click on any month button to download that period's report -### Building a custom MCP client +Reports are available for the past 12 months in TXT format and include: +- Client information and reporting period +- Starting and ending balances +- Itemized resource charges by project and service +- Credit transactions (top-ups, refunds, promotional credits) +- Clear distinction between common (paid) and promotional credits -[ZCP MCP tools](/zcp/reference/mcp-operations) for the tool surface; [Workflows in depth → What drives the workflow](/zcp/reference/agent-workflow#what-drives-the-workflow) for what the generated workflow adds on top of bare tools. +---------------------------------------- -
+# Company > Pricing -
-SCENARIO +Zerops provides a straightforward pricing structure based on your project type and resource usage. -### Auditing a finished run +The total cost of deploying an application includes your project's **core package cost** + the **cost of the resources** of the services inside a project. Additional charges may apply for optional features such as dedicated IPv4, extra egress, object storage, extra backup space and extra build time. -[Workflows in depth → Completion evidence](/zcp/reference/agent-workflow#completion-evidence) for what should be in the final answer; [Trust model → Audit evidence](/zcp/security/trust-model#audit-evidence) for what Zerops records platform-side. +:::note Fair Billing Model +Resources are allocated per service and billed by the minute, though credit is deducted hourly based on actual usage. You're only charged for what you use, calculated down to the minute. +::: -
+Need to add credits to your account? Visit our [Top-up & Billing page](/company/payment) for instructions. -
+## Project Core Plans +Zerops offers two core types to match different needs and budgets. For detailed information on both core types, visit our [Project & Services Structure](/features/infrastructure) page. ----------------------------------------- +### Lightweight Core - Free +Best for development, testing, and smaller workloads with limited redundancy. -# Zcp > Reference > Agent Workflow +**Included resources:** +- **Build Time**: 15 hours per month +- **Backup Storage**: 5 GB +- **Egress Traffic**: 100 GB per month +### Serious Core - $10 / 30 days +Optimized for production workloads with high availability and comprehensive failover protection. -Use this page when you want the process and exact labels behind a run that follows the generated workflow. Normal prompts should still describe outcomes. The workflow exists so the agent can read the project, prepare the right runtime and services, make the app change, deploy, verify, recover from evidence, and stop with proof or a concrete blocker. +**Included resources:** +- **Build Time**: 150 hours per month +- **Backup Storage**: 25 GB +- **Egress Traffic**: 3 TB per month -The useful mental split is: +:::note Storage Limits +All projects have a technical maximum backup storage limit of **1 TiB**. Usage beyond the free tier allocation (5GB or 25GB) is billed according to the [overage costs](#overage-costs) below. +::: -| Phase | What it settles | What should be true when it ends | -| ----- | --------------- | -------------------------------- | -| **Bootstrap** | Where the app should run and which services it depends on. | Runtime target and managed dependencies are known. | -| **Develop** | Code, `zerops.yaml`, env wiring, deploy, verification, recovery, and delivery choice. | The requested behavior is proved, or the blocker is concrete. | -| **Develop** | Code, `zerops.yaml`, env wiring, deploy, verification, recovery, and delivery choice. | The requested behavior is proved, or the blocker is concrete. | +## Resource Pricing -For the loop itself, see [How it works](/zcp/concept/how-it-works). This page catalogs the exact phases, routes, layouts, labels, and gates. +Services in Zerops require computing resources that are billed separately from your project core. These resources are allocated per service and billed by the minute based on actual usage, with credits deducted hourly. -## Session layers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ResourcePriceDescription
Shared CPU$0.60 per CPU / 30 daysEconomical option for most workloads with good performance
Dedicated CPU$6.00 per CPU / 30 daysReserved CPU cores for predictable performance
RAM$0.75 per 0.25 GB / 30 daysMemory allocated to your services
Disk Space$0.05 per 0.5 GB / 30 daysStorage space for your applications and data
-Most workflow mistakes come from confusing these layers: +:::note Daily Spending Control +You can set a daily spending limit in the GUI for your project to keep an eye on costs and avoid unexpected charges. This provides an alternative to configuring automatic resource scaling ranges while keeping your services running optimally. -| Layer | What it is | What changes here | -| ----- | ---------- | ----------------- | -| **Workspace** | Where `zcp` and the agent run: remote `zcp@1` service or local machine. | Agent config, tools, local workflow state. App code should not be deployed to the workspace itself. | -| **Target runtime service** | The app runtime in scope: `appdev`, `appstage`, `app`, or a linked local deploy target. | App files, `zerops.yaml`, deploys, runtime logs, verification target. | -| **Managed services** | Databases, caches, queues, search, storage, mail, and similar dependencies. | Schema/data operations and credentials, never app code deploys. | -| **Managed services** | Databases, caches, queues, search, storage, mail, and similar dependencies. | Schema/data operations and credentials, never app code deploys. | +Reaching the limit does not stop your project - your services keep running. When a project reaches its daily spending limit, Zerops sends you a warning notification (e-mail) so you can decide whether to raise the limit. The limit resets at midnight (UTC). +::: -The `zcp` service is the control surface, not the app runtime. +## Additional Services -## What drives the workflow +Enhance your deployment with these optional services to meet specific requirements for networking, storage, and data transfer. -The generated workflow is made from four pieces: + + + + + + + + + + + + + + + + + + + + +
ServicePriceDescription
Dedicated IPv4$3.00 per 30 daysExclusive IPv4 address for your project (instead of shared)
Object Storage$0.01 per GB / 30 daysScalable storage for files, backups, and static assets
-| Piece | Role | -| ----- | ---- | -| **MCP tools** | Project-scoped Zerops operations: discover, deploy, read logs/events, manage env vars, verify, import/export, and related actions. | -| **Generated instructions** | Agent policy for when to inspect, when to ask, when to deploy, what evidence to read, and what counts as done. | -| **Saved workflow state** | Local metadata about bootstrap sessions, runtime pairing, delivery choice, deploy attempts, verify attempts, and interrupted work. | -| **Live Zerops project** | Source of truth for services, status, env refs, logs, events, deploys, runtime files, and public access. | -| **Live Zerops project** | Source of truth for services, status, env refs, logs, events, deploys, runtime files, and public access. | +## Overage Costs -The workflow does not replace judgment from the user or the agent. It gives the agent a process and evidence surface so app work does not depend on stale chat memory or a pasted runbook. +When you exceed the resources included in your project core plan, the following charges apply: -## Bootstrap + + + + + + + + + + + + + + + + + + + + + + + + + +
ItemPriceDescription
Extra Egress$0.02 per GBData transfer out of your project beyond plan limits
Extra Backup Space$0.50 per 5 GBAdditional storage for automatic, encrypted backups
Extra Build Time$0.50 per 15 hoursAdditional time for building and deploying applications
-Bootstrap starts before app code changes when the workflow needs to understand or prepare the project layout. +## Pricing Calculator -```mermaid -flowchart TD - start(["Read live project state"]) - interrupted{"Interrupted bootstrap -to resume?"} - runtime{"Runtime services -already exist?"} - known{"Request matches -known recipe or stack?"} - resume(["resume"]) - adopt(["adopt"]) - recipe(["recipe"]) - classic(["classic"]) - done(["Runtime target and dependencies known"]) +Use our pricing calculator to estimate your monthly costs based on your specific needs: - start --> interrupted - interrupted -- yes --> resume --> done - interrupted -- no --> runtime - runtime -- yes --> adopt --> done - runtime -- no --> known - known -- yes --> recipe --> done - known -- no --> classic --> done -``` -| Route | Use when | Wrong signal | -| ----- | -------- | ------------ | -| `adopt` | Runtime services already exist, including recipe-created projects. | Recreating services that already fit, or targeting the `zcp` service as the app. | -| `recipe` | The project is empty or only has remote setup, and the request matches a known stack recipe. | Treating an unchanged starter as the finished requested product. | -| `classic` | The project is empty and needs a custom service plan. | Writing app code before service ownership and runtime target are known. | -| `resume` | A previous bootstrap was interrupted. | Starting from scratch without checking live services and saved state. | -| `resume` | A previous bootstrap was interrupted. | Starting from scratch without checking live services and saved state. | +---------------------------------------- -Bootstrap ends when the app runtime target and managed dependencies are known. It should also make visible any choice that needs human judgment: cost, credentials, data, runtime layout, production risk, or destructive behavior. +# Deno > How To > Build Pipeline -## Runtime layouts -Runtime layout describes which app runtime services the workflow should use. Exact layout labels (`standard`, `dev`, `simple`, `local-stage`, `local-only`) and the runtime names they map to live in the [Glossary](/zcp/glossary#runtime-layout). The user-facing three (dev, dev + stage, stage / linked target) are in [Build and ship → Choose the runtime layout](/zcp/workflows/build-with-zcp#choose-the-runtime-layout). Service scaling mode (`HA`/`NON_HA`) is a separate service setting. +Zerops provides a customizable build and runtime environment for your Deno application. -In `standard`, stage is explicit. Work scoped to `appdev` does not silently touch `appstage`; a release or stage verification happens when the user asks for it. +## Add zerops.yaml to your repository -## Develop +Start by adding `zerops.yaml` file to the **root of your repository** and modify it to fit your application: -Develop is the main app-work loop. It begins after bootstrap has a runtime target and dependencies. It closes only when runtime reachability and requested behavior both pass, or when the agent has a blocker that needs a human decision. The loop itself is in [How it works → The work loop](/zcp/concept/how-it-works#the-work-loop). The labeled steps are: +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: deno@latest -1. **Name runtime target.** State which runtime is in scope: `appdev`, `appstage`, `app`, or a linked local target. -2. **Change code and config.** Edit app files, `zerops.yaml`, env references, migrations, seeds, framework config, or local `.env` bridge when needed. -3. **Deploy directly first.** The first verified runtime deploy goes through MCP tools. Git or CI handoff comes after proof. -4. **Start or restart if needed.** Dynamic dev runtimes may need an explicit start or restart after deploy. Built-in webserver runtimes do not need a separate dev-server step unless the framework requires one. -5. **Verify runtime reachability.** Check service status, recent error logs, and HTTP readiness when the runtime is an HTTP service. -6. **Verify requested behavior.** Check endpoint body, UI state, job result, persisted data, or another result tied to the user request. -7. **Fix from evidence.** Read failure category, logs, events, and check output. Repeating the same deploy without new evidence is not progress. + # OPTIONAL. Set the operating system for the build environment. + # os: ubuntu -Reachability and requested behavior are separate gates. A green deploy with a broken route is not done. + # OPTIONAL. Customise the build environment by installing additional packages + # or tools to the base build environment. + # prepareCommands: + # - sudo apt-get something + # - curl something else -## Failure categories + # OPTIONAL. Build your application + buildCommands: + - deno task build -Failure categories (`build`, `start`, `verify`, `network`, `config`, `credential`, `other`) point the agent to the first useful evidence surface. The full read-first / avoid playbook is in [Troubleshooting → Evidence order](/zcp/reference/troubleshooting#evidence-order); the term definitions are in the [Glossary](/zcp/glossary#failure-category). + # REQUIRED. Select which files / folders to deploy after + # the build has successfully finished + deployFiles: + - dist + - deno.jsonc -Categorization is what turns retries into evidence-driven fixes. + # OPTIONAL. Which files / folders you want to cache for the next build. + # Next builds will be faster when the cache is used. + # cache: directory -## Delivery after proof + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: deno@latest -Delivery mode applies after a verified deploy. It does not replace the first proof. + # OPTIONAL. Sets the internal port(s) your app listens on: + ports: + # port number + - port: 3000 -| Exact mode | User-facing choice | Meaning | -| ---------- | ------------------ | ------- | -| `auto` | Keep direct deploy | The agent keeps deploying future changes directly to the target runtime. | -| `git-push` | Push to git | The agent commits and pushes to a configured remote; any resulting build still needs observation and verification. | -| `manual` | External handoff | CI, release process, or a human owns future delivery; the workflow records evidence but does not initiate the next deploy. | -| `manual` | External handoff | CI, release process, or a human owns future delivery; the workflow records evidence but does not initiate the next deploy. | + # OPTIONAL. Customise the runtime Deno environment by installing additional + # dependencies to the base Deno runtime environment. + # prepareCommands: + # - sudo apt-get something + # - curl something else -Git-push capability, delivery mode, and build integration are separate. A project can have git-push configured while still using direct deploy for a given session. + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your Deno application is started. + # initCommands: + # - rm -rf ./cache -Packaging and production release are deliberate handoffs after proof. Packaging turns a verified runtime into a git-backed import bundle. A production release moves verified work into a separate production project through GUI setup, git/CI triggers, or the team's release process. + # REQUIRED. Your Deno application start command + start: deno task start +``` -## Generated files and state +The top-level element is always `zerops`. -Remote setup and `zcp init` create configuration around the MCP server and workflow guidance. +### Setup -| File or directory | Created where | Purpose | -| ----------------- | ------------- | ------- | -| `CLAUDE.md` | Remote workspace or local project directory | Claude Code instruction surface. ZCP MCP writes a managed block between `` and ``. User content outside that block is preserved. | -| `.claude/settings.local.json` | Remote workspace or local project directory | Claude Code per-project settings and ZCP MCP tool permissions for that directory. | -| `.mcp.json` | Local project directory | Project-local MCP server config. It contains the local `zcp` command and the project-scoped `ZCP_API_KEY`; keep it out of git. | -| `~/.claude.json` and SSH config | Remote setup | Workspace-level Claude Code and SSH wiring used inside the Zerops-hosted workspace. | -| `.zcp/state/` | Working directory where the MCP server runs | Workflow state and service metadata for that project directory. | -| `.zcp/state/` | Working directory where the MCP server runs | Workflow state and service metadata for that project directory. | +The first element `setup` contains the **hostname** of your service. A runtime service with the same hostname must exist in Zerops. +Zerops supports the definition of multiple runtime services in a single `zerops.yaml`. This is useful when you use a monorepo. Just add multiple setup elements in your `zerops.yaml`: -The managed `CLAUDE.md` block is refreshed by `zcp init` and by the MCP server when the block already exists. Put durable project instructions outside the ZCP markers. Edits inside the managed block are treated as generated content. +```yaml +zerops: + # definition for app service + - setup: app + # optional + build: ... + # optional + deploy: ... + # required + run: ... -`.zcp/state/` is not application source code and should not be committed. It stores metadata such as known runtime services, local/stage pairing, delivery preference, git-push setup, build integration, first-deploy stamps, workflow sessions, deploy attempts, verify attempts, and local coordination locks. + # definition for api service + - setup: api + # optional + build: ... + # optional + deploy: ... + # required + run: ... +``` -ZCP MCP does not use `.zcp/state/` as a stale copy of the Zerops project. Service status, logs, events, runtime files, env-var values, and current platform configuration are read from Zerops or from the local filesystem when tools run. Local `.env` files are generated separately and may contain secrets. +Each service configuration contains at least the `run` section. Optional `build` and `deploy` sections can be added to further customize your process. -Do not edit `.zcp/state/` by hand during normal work. Use workflow operations to reset, resume, iterate, or reconfigure state. Deleting it intentionally discards local memory of services and delivery setup for that directory; the tools can rediscover live Zerops state, but delivery preferences and workflow history may need to be set again. +## Build pipeline configuration -## Completion evidence +### base -A completed app task should answer: +_REQUIRED._ Sets the base technology for the build environment. -- which bootstrap route was used when setup was needed, -- which runtime target changed, -- which managed services were used or created, -- which deploy passed, -- which reachability check passed, -- which requested behavior passed, -- which URL, endpoint, UI state, worker result, or stored value proves it, -- which delivery choice applies next, -- or which blocker remains and what evidence supports it. +Following options are available for Deno builds: -A clear blocker is acceptable completion only when it names the runtime in scope, failure category, evidence read, fixes tried, and human decision or credential still needed. +- `deno@2.0.0`, `deno@2`, `deno@latest` +- `deno@1.45.5`, `deno@1` -## Confirmation gates +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: deno@latest + ... +``` -Two operations pause because the loss is not safely reversible from inside the conversation: **service deletion** (named approval) and **destructive import override** (refuse-then-acknowledge). See [Tokens and credentials → What ZCP enforces for destructive actions](/zcp/security/tokens-and-project-access#what-zcp-enforces-for-destructive-actions) for the user-facing confirmation flow. +

+ The base build environment contains {data.alpine.default}, the selected + major version of Deno, [Zerops command line tool](/references/cli), `npm`, `yarn`, `git` and `npx` tools. +

-## Auditing a workflow +:::info +You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. +::: -A workflow run is well-shaped if the evidence answers: +If you need to install more technologies to the build environment, set multiple values as a yaml array. For example: -| Question | Evidence | -| -------- | -------- | -| Where did bootstrap start? | Live service list, saved workflow state, and bootstrap route. | -| Where did bootstrap end? | Runtime target, managed dependencies, and any human decisions. | -| Which runtime was developed and deployed? | Runtime target, deploy result, events, and logs. | -| What proved reachability? | Verify output, service status, public URL, or HTTP probe. | -| What proved behavior? | Endpoint, UI flow, job result, database/object state, or other requested proof. | -| What controls future delivery? | Delivery mode, git-push state, build integration, package bundle, or production release handoff note. | -| What controls future delivery? | Delivery mode, git-push state, build integration, package bundle, or production release handoff note. | - -## Related reference - -- [ZCP MCP tools](/zcp/reference/mcp-operations) — operation names and direct tool calls. -- [Troubleshooting](/zcp/reference/troubleshooting) — recovery order when a run gets stuck. -- [Glossary](/zcp/glossary) — exact terms used across the ZCP MCP reference. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: + - deno@latest + prepareCommands: + - zsc add go@latest + ... +``` +See the full list of supported [build base environments](/zerops-yaml/base-list#runtime-services). ----------------------------------------- +To customise your build environment use the [prepareCommands](#preparecommands) attribute. -# Zcp > Concept > How It Works +:::note +Modifying the base technology will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for more details about cache invalidation. +::: +### os -The ZCP MCP setup gives a coding agent a **work loop** for Zerops app work. The agent reads live state, chooses the app runtime and dependencies, changes the app, deploys through Zerops, verifies real behavior, and returns proof or a blocker. +_OPTIONAL._ Sets the operating system for the build environment. -The loop is carried by project-scoped Zerops operations, Zerops-specific knowledge, and instructions for what to inspect, what to change, when to ask, and what counts as done. You describe the product outcome; the agent uses the loop to make its decisions visible while it works. +Following options are available: -The source of truth is the real project: runtimes, managed services, env references, logs, events, and deploy results. A separate preview sandbox is not the source of truth. +- `alpine` +- `ubuntu` -## The work loop +Default value is `alpine`. -```mermaid -flowchart TD - intent["Product intent -Build a task board for my team."] - state["Live state -services, runtime layout, env vars, -logs, events, saved work state"] - scope["Runtime target -which app service changes"] - setup{"Missing or unsuitable -services?"} - provision["Service setup -use existing services or create -missing runtimes/dependencies"] - appwork["App work -code, zerops.yaml, env refs, -migrations, seeds, framework config"] - deploy["Direct deploy through Zerops"] - reachability{"Runtime reachable? -status, logs, HTTP probe"} - behavior{"Requested behavior works? -endpoint, UI flow, worker result, -persisted state"} - evidence["Evidence -build logs, runtime logs, -events, verify output"] - proof["Proof -URL, endpoint result, -UI state, or stored result"] - delivery["Delivery after proof -keep direct deploy, push to git, -or hand off"] - blocker["Blocker -credential, decision, -unsupported fit, -repeated failure"] +We are currently using following os version: - intent --> state --> scope --> setup - setup -->|yes| provision --> appwork - setup -->|no| appwork - appwork --> deploy --> reachability - reachability -->|no, fixable| evidence --> appwork - reachability -->|yes| behavior - behavior -->|no, fixable| evidence - behavior -->|yes| proof --> delivery - setup -->|needs decision| blocker - reachability -->|needs human| blocker - behavior -->|needs human| blocker +- {data.alpine.default} +- {data.ubuntu.default} - classDef user stroke:#2d72d9,stroke-width:1.5px; - classDef zcpbox stroke:#32845a,stroke-width:1.5px; - classDef work stroke:#c47f17,stroke-width:1.5px; - classDef done stroke:#7157d9,stroke-width:1.5px; - classDef stop stroke:#d33f49,stroke-width:1.5px; +:::caution +The os version is fixed and cannot be customised. +::: - class intent user; - class state,scope zcpbox; - class setup,provision,appwork,deploy,reachability,behavior,evidence work; - class proof,delivery done; - class blocker stop; -``` +:::note +Changing the OS setting will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache behavior. +::: -The loop keeps the agent working from evidence instead of a guessed checklist: current state, Zerops wiring rules, deploy evidence, and the distinction between proof and blocker. +### prepareCommands -## What "live state" means +_OPTIONAL._ Customises the build environment by installing additional dependencies or tools to the base build environment. -The MCP tools read Zerops instead of asking you to paste a service inventory into the prompt. Useful state includes: +The base build environment contains: -- runtime services and managed services, -- whether the app has one runtime, a dev+stage pair, or local files linked to a Zerops runtime, -- env-var keys and Zerops references, -- recent build/deploy events, -- build logs, runtime logs, and verification output, -- saved work state after an interrupted session. +- {data.alpine.default} +- selected version of Deno defined in the [base](#base) attribute +- [Zerops command line tool](/references/cli) +- `npm`, `yarn`, `git` and `npx` tools -This is why a short prompt can be enough. The agent can ask what exists, which runtime was last deployed, which checks passed, and where a previous run stopped. +To install additional packages or tools add one or more prepare commands: -Chat history is not the source of truth. If the agent sounds confused, starts from an old assumption, or a session was interrupted, the recovery move is: +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: deno@latest -```text -Read current project status and tell me where this project stands before changing anything. + # OPTIONAL. Customise the build environment by installing additional packages + # or tools to the base build environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... ``` -## What the workflow handles +When the first build is triggered, Zerops will -The workflow handles the things an agent must resolve during app work so you do not have to name them in the prompt. The tools and instructions supply the state, guidance, operations, and verification surface so the agent can work from evidence. +1. create a build container +2. download your application code from your repository +3. run the prepare commands in the defined order -| What the workflow handles | What the agent gets | What that means for you | -| ------------------------- | ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | -| Live state | Services, env-var keys, Zerops references, recent events, logs, verification output, and saved work state. | You do not have to paste a service inventory or reconstruct what happened. | -| Runtime target | Rules for choosing the app runtime that should receive code changes. | The agent can identify where app work belongs before editing or deploying. | -| Managed services | Knowledge and env wiring patterns for database, cache, queue, search, storage, mail, and similar services. | Product intent can imply real dependencies without a manual wiring checklist. | -| Service setup | Operations for using existing services or creating missing runtimes and dependencies. | Runtime layout and dependencies can be established before app work starts. | -| App wiring | Zerops-specific rules for `zerops.yaml`, env references, ports, commands, public access, and build/deploy behavior. | The app is wired for Zerops rather than for a generic cloud template. | -| Deploy evidence | Build logs, runtime logs, platform events, service status, HTTP checks, and structured verification output. | A failed deploy becomes a diagnosis surface instead of guesswork. | -| Behavior proof | The proof gate is the requested behavior, not only a successful build or reachable root URL. | The final answer can point to what was actually checked. | -| Delivery handoff | Direct proof first; then git push, CI, or human handoff when that is the chosen delivery choice. | Shipping setup follows a verified running result. | -| Delivery handoff | Direct proof first; then git push, CI, or human handoff when that is the chosen delivery choice. | Shipping setup follows a verified running result. | +The application code is available in `/build/source` before the prepare commands are triggered, so you can use any file from your repository in your prepare commands (e.g. a configuration file). The commands themselves run in the `/home/zerops` directory. -The exact labels for layouts, delivery modes, and setup routes live in the [Glossary](/zcp/glossary) and [Workflows in depth](/zcp/reference/agent-workflow). +:::note +These commands are skipped when using cached environment. Modifying `prepareCommands` will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache invalidation. +::: -## Service setup prepares the project layout +#### Command exit code -Before app code work starts, the workflow makes three decisions visible: +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/deno/how-to/logs#build-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all prepare commands are finished, your custom build environment is ready for the build phase. -- Which runtime service is the app target? -- Which managed services are dependencies? -- Does the existing project layout fit the request? +#### Single or separated shell instances -If the services already exist, the agent can use them. If a needed runtime or dependency is missing, the tools can create it. If the choice affects cost, product scope, credentials, a destructive action, or which stage/runtime should be used, the agent should stop and ask. +You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -Service setup is finished when the app runtime and dependencies are known. It is the layout that lets app work happen in the right place. +### buildCommands -## App work changes code and platform wiring together +_OPTIONAL._ Defines build commands. -After the runtime target is known, the agent gets the platform knowledge needed to make the application change. In practice this often spans both source code and Zerops wiring: +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: deno@latest -- app files, -- `zerops.yaml` build and run setup, -- env references to managed services, -- migrations, seeds, and framework config, -- start commands, ports, and public HTTP support, -- local `.env` generation when using local setup. + # OPTIONAL. Build your application + buildCommands: + - deno task build + ... +``` -That guidance matters because Zerops is its own platform. Service references, build/deploy behavior, public access, scaling, and env resolution do not follow Docker Compose or Kubernetes conventions. +Build commands are optional. Zerops triggers each command in the defined order in a dedicated build container, running from the `/build/source` directory. -The first functional deploy goes directly through MCP so the agent has a running result to verify. A repository push or CI handoff can follow, but it should not replace the first proof. +Before the build commands are triggered the build container contains: -## Recovery is evidence-driven +1. base environment defined by the [base](#base) attribute +2. optional customisation of the base environment defined in the [prepareCommands](#preparecommands) attribute +3. your application code -When something fails, the workflow puts the agent on the matching evidence surface — build logs for build failures, prepare/runtime logs for start failures, verify output and request-time logs for behavior failures, transport surfaces for network failures, field-level rejection for config, and the named credential surface for credential failures. The full categories, what to read first, and what to avoid live in [Troubleshooting](/zcp/reference/troubleshooting). +#### Run build commands as a single shell instance -Retrying the same deploy without new evidence is not progress. The loop pushes toward one of three outcomes: fix from a cause, ask for the missing decision, or report a blocker with the category, evidence read, and attempts made. +Use following syntax to run all commands in the same environment context. For example, if one command changes the current directory, the next command continues in that directory. When one command creates an environment variable, the next command can access it. -## Verification has two layers +```yaml +buildCommands: + - | + deno test + deno task build +``` -A successful deploy proves that Zerops accepted the build and started the runtime. Reachability checks prove the service is running and reachable. They still do not prove the product request. +#### Run build commands as a separate shell instances -For a task-board app, useful behavior proof might be: +When the following syntax is used, each command is triggered in a separate environment context. For example, each shell instance starts in the home directory again. When one command creates an environment variable, it won't be available for the next command. -- create a task, -- move it between columns, -- refresh the page, -- confirm the task is still there. +```yaml +buildCommands: + - deno task build +``` -For an API task, proof might be a JSON response from the requested endpoint and stored data behind it. For a worker task, proof might be a processed job and the resulting database or object-storage state. For a staging request, proof belongs on the stage runtime, not only on dev. +#### Command exit code -The final answer should make proof inspectable: runtime name, URL or endpoint, behavior checked, and delivery choice if one was set. +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/deno/how-to/logs#build-log) to troubleshoot the error. If the error log doesn't contain any specific error message, try to run your build with the --verbose option. -## Delivery happens after proof +```yaml +buildCommands: + - npm i --verbose + - npm run build +``` -Delivery choice controls how future changes ship after a verified runtime exists: keep direct deploy, push to git, or hand off to CI/release/human action. The user-facing version of this choice and what to tell the agent for each option lives in [Build and ship → Choose delivery after proof](/zcp/workflows/build-with-zcp#choose-delivery-after-proof). +If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `buildCommands` are finished, the application build is completed and ready for the deploy phase. -Packaging a running service turns a deployed runtime into a re-importable bundle for another Zerops project. It is useful for handoff or reuse after proof, not for deploying the next app change; see [Package a running service](/zcp/workflows/package-running-service). +### deployFiles -## Remote and local setup use the same loop +_REQUIRED._ Selects which files or folders will be deployed after the build has successfully finished. To filter out specific files or folders, use [`.deployignore`](#deployignore) file. -The same `zcp` binary can run in two places. The control loop stays the same; filesystem and network access change. A human can take over from the same evidence either way: files, runtime target, logs, events, verification result, and delivery state. +```yaml +# REQUIRED. Select which files / folders to deploy after +# the build has successfully finished +deployFiles: + - dist + - package.json + - node_modules +``` -| Setup | What runs where | Practical effect | -| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Remote setup | A `zcp@1` service runs the `zcp` binary inside Zerops. **Include Coding Agent** adds the bundled agent CLI; **Cloud IDE** adds Browser VS Code. | Work happens inside the remote workspace, with private networking and runtime file mounts. | -| Local setup | The `zcp` binary runs on your laptop after `zcp init`, and your local editor or CLI agent talks to it. | App files, deploy source, and git credentials stay local. Managed services are reached over Zerops VPN, and `.env` generation bridges credentials into your local app. | -| Local setup | The `zcp` binary runs on your laptop after `zcp init`, and your local editor or CLI agent talks to it. | App files, deploy source, and git credentials stay local. Managed services are reached over Zerops VPN, and `.env` generation bridges credentials into your local app. | +Determines files or folders produced by your build, which should be deployed to your runtime service containers. -Choose setup by where the agent and filesystem should live: [Remote or local setup](/zcp/setup/choose-workspace). +The path starts from the **root directory** of your project (the location of `zerops.yaml`). You must enclose the name in quotes if the folder or the file name contains a space. -## Signs of a healthy run +The files/folders will be placed into `/var/www` folder in runtime, e.g. `./src/assets/fonts` would result in `/var/www/src/assets/fonts`. -A well-shaped run should: +#### Examples -- name the runtime target before editing or deploying, -- use existing services when they fit, -- create missing services only before app work starts, -- read logs, events, and verify output when failure occurs, -- distinguish runtime reachability from requested behavior, -- stop before destructive actions, ambiguous runtime/stage choices, or missing credentials, -- end with proof or a blocker. +Deploys a folder, and a file from the project root directory: -That is the practical difference between "the agent wrote code" and "the app task is done". +```yaml +deployFiles: + - dist + - package.json +``` -## Next steps +Deploys the whole content of the build container: -- [Build and ship](/zcp/workflows/build-with-zcp) — normal app work after setup. -- [Workflows in depth](/zcp/reference/agent-workflow) — process gates, generated files, runtime layouts, delivery labels, and completion evidence. +```yaml +deployFiles: . +``` +Deploys a folder, and a file in a defined path: ----------------------------------------- +```yaml +deployFiles: + - ./path/to/file.txt + - ./path/to/dir/ +``` -# Valkey > Overview +#### How to use a wildcard in the path +Zerops supports the `~` character as a wildcard for one or more folders in the path. -Valkey is a powerful, open-source alternative to Redis, offering full compatibility with Redis clients while providing an independent development path focused on community-driven innovation. Deploy and manage Valkey in Zerops' fully managed infrastructure to get instant access to high-performance in-memory data storage. +Deploys all `file.txt` files that are located in any path that begins with `/path/` and ends with `/to/` -:::tip -Valkey is our recommended Redis alternative as KeyDB's development has slowed significantly in recent times. -::: +```yaml +deployFiles: ./path/~/to/file.txt +``` -## Supported Versions +Deploys all folders that are located in any path that begins with `/path/to/` -Currently supported Valkey versions: +```yaml +deployFiles: ./path/to/~/ +``` -Import configuration version: +Deploys all folders that are located in any path that begins with `/path/` and ends with `/to/` -- `valkey@7.2` +```yaml +deployFiles: ./path/~/to/ +``` -## Service Configuration +:::note Example +By default, `./src/assets/fonts` deploys to `/var/www/src/assets/fonts`, keeping the full path. Adding `~`, like `./src/assets/~fonts`, shortens it to `/var/www/fonts` +::: +#### .deployignore -Zerops offers Valkey in two deployment configurations to meet different availability requirements. +Add a `.deployignore` file to the root of your project to specify which files and folders Zerops should ignore during deploy. The syntax follows the same pattern format as [`.gitignore`](https://git-scm.com/docs/gitignore#_pattern_format). -### Single Setup -- Single node deployment on port `6379` (non-TLS) and `6380` (TLS) -- Suitable for development or non-critical workloads +To ignore a specific file or directory path, start the pattern with a forward slash (`/`). Without the leading slash, the pattern will match files with that name in any directory. -See [Persistence](#persistence) for how data is stored and recovered. +:::tip +For consistency, it's recommended to configure both your `.gitignore` and `.deployignore` files with the same patterns. +::: -### HA (High Availability) Setup +Examples: -The HA deployment is a 3-node cluster with automatic failover, fronted by an HAProxy load balancer on every node. +```yaml title="zerops.yaml" +zerops: + - setup: app + build: + deployFiles: ./ +``` -- 3-node configuration: 1 primary + 2 replicas -- Client-facing ports (available on every node): - - `6379` — read/write (non-TLS), routed to the current primary - - `6380` — read/write over TLS, routed to the current primary - - `7000` — read-only (non-TLS), load-balanced across replicas - - `7001` — read-only over TLS, load-balanced across replicas -- Failover is handled by a built-in [Sentinel](https://valkey.io/topics/sentinel/) cluster. When the primary becomes unreachable, a replica is promoted automatically and HAProxy starts routing writes to it. -- TLS is terminated at HAProxy. -- Connect your application to the standard ports — the address never changes when the primary moves. +```text title=".deployignore" +/src/file.txt +``` +The example above ignores `file.txt` only in the root src directory. +```text title=".deployignore" +src/file.txt +``` +This example above ignores `file.txt` in ANY directory named `src`, such as: +- `/src/file.txt` +- `/folder2/folder3/src/file.txt` +- `/src/src/file.txt` :::note -Replica reads (ports `7000`/`7001`) can lag slightly behind the primary due to asynchronous replication. +`.deployignore` file also works with [`zcli service deploy`](/references/zcli/commands#deploy) command. ::: -**Failover client impact:** expect roughly 10–15 seconds of write unavailability while a new primary is elected and HAProxy reconverges. Read traffic on surviving replicas is unaffected. +### cache -:::tip Trusting the TLS certificate -The certificates served on the TLS ports (`6380` and `7001`) are signed by the Zerops Certificate Authority. To verify them from outside Zerops, download and trust the [Zerops CA](/references/networking/zerops-ca) — e.g. `redis-cli --tls --cacert ./zerops-ca.pem -h -p 6380 -a `. -::: +_OPTIONAL._ Defines which files or folders will be cached for the next build. -## Connecting +```yaml +# OPTIONAL. Which files / folders you want to cache for the next build. +# Next builds will be faster when the cache is used. +cache: file.txt +``` -Zerops generates the connection details as environment variables on the Valkey service. Reference them from another service in the same project as `${_}` — for a service named `db`, the connection string is `${db_connectionString}`. The examples below assume the hostname `db`. +The cache attribute helps optimize build times by preserving specified files between builds. -| Variable | Example value | Notes | -|---|---|---| -| `hostname` | `db` | Service hostname; reachable as `db.zerops` inside the project | -| `port` | `6379` | Plain (non-TLS) port | -| `portTls` | `6380` | TLS port | -| `password` | *(generated)* | Password for the `default` user (sensitive) | -| `connectionString` | `redis://default:@db.zerops:6379` | Ready-to-use non-TLS URL | -| `connectionTlsString` | `rediss://default:@db.zerops:6380` | Ready-to-use TLS URL | -| `connectionTlsString` | `rediss://default:@db.zerops:6380` | Ready-to-use TLS URL | +The cache attribute supports the [~ wildcard character](#how-to-use-a-wildcard-in-the-path). -In **HA mode** four additional variables expose the read-only replica endpoints (load-balanced across replicas): +Learn more about the [build cache system](/features/build-cache) in Zerops. -| Variable | Example value | Notes | -|---|---|---| -| `portReplicas` | `7000` | Read-only plain port | -| `portTlsReplicas` | `7001` | Read-only TLS port | -| `connectionStringReplicas` | `redis://default:@db.zerops:7000` | Read-only non-TLS URL | -| `connectionTlsStringReplicas` | `rediss://default:@db.zerops:7001` | Read-only TLS URL | -| `connectionTlsStringReplicas` | `rediss://default:@db.zerops:7001` | Read-only TLS URL | +### envVariables -The connection string format is `redis://default:@.zerops:` (or `rediss://` for TLS). The username is always `default`. +_OPTIONAL._ Defines the environment variables for the build environment. -:::note Authentication -Valkey requires a password. It is generated automatically, exposed as the sensitive `${db_password}` variable, and already embedded in the `connectionString` variables above. Connect with it directly — e.g. `redis-cli -h db.zerops -p 6379 -a "$db_password"`. +Enter one or more env variables in following format: -Services created **without** a `password` variable (older deployments) keep working without authentication and are unaffected. **All deployments created since this release require the password.** -::: +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to build your application ==== + build: + base: deno@latest + … -### Idle connection timeout + # OPTIONAL. Defines the env variables for the build environment: + envVariables: + NODE_ENV: production + DB_NAME: db + DB_HOST: db + DB_USER: db + DB_PASS: ${db_password} +``` -Valkey closes connections that stay **idle for 5 minutes** (`timeout 300`). This is intentional on the managed instances — we avoid keeping infinite idle connections open. Older Valkey services ran with no timeout (`timeout 0`); if you connected before this change, your connections used to stay open indefinitely. +Read more about [environment variables](/deno/how-to/env-variables) in Zerops. -"Idle" means **no commands sent on the connection** — the server resets the timer on every command, so a busy connection is never closed. The connections most likely to be affected are long-lived ones that sit waiting rather than sending commands, typically **pub/sub subscribers** and **blocking reads** (`BLPOP`, `XREAD`, …). Most clients reconnect automatically, so you may only see log lines such as `Redis subscriber socket closed; reconnecting if possible.` — but the reconnect churn can drop pub/sub messages published in the gap. +## Runtime configuration -To keep idle connections open, send an application-level **`PING` on an interval shorter than 300s**. A TCP keep-alive alone is **not** enough — keepalive packets live below the application layer and don't count as Valkey commands, so they don't reset the idle timer. +### base -Many clients have a built-in option for this. For example, [node-redis](https://github.com/redis/node-redis): +_OPTIONAL._ Sets the base technology for the runtime environment. +If you don't specify the `run.base` attribute, Zerops keeps the current Deno version for your runtime. -```js -const redisClient = createClient({ - url: redisURL, - pingInterval: 10000, // send PING every 10s; keeps the connection under the 300s idle limit -}); -``` +Following options are available for Deno builds: -If your client has no equivalent option, run your own heartbeat on every long-lived connection: +- `2.0` +- `1.45` -```js -const heartbeat = setInterval(() => { - publisher.ping().catch(() => {}); - subscriber.ping().catch(() => {}); -}, 60000); // any interval under 300s +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: deno@latest + ... + + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: deno@latest + ... ``` -For ordinary request/response traffic, a [connection pool](https://valkey.io/topics/clients/) that recycles connections handles this transparently. +

+ The base runtime environment contains {data.alpine.default}, the + selected major version of Deno, Zerops command line tool, `npm`, `yarn`, `git` and `npx` tools. +

-## Persistence +:::info +You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. +::: -Valkey persists data to disk with **AOF (append-only file)**, so the dataset survives restarts and is rebuilt automatically on startup. +If you need to install more technologies to the runtime environment, set multiple values as a yaml array. For example: -- **AOF is enabled** (`appendonly yes`) and synced to disk **every second** (`appendfsync everysec`). After an unclean crash you lose at most ~1 second of the most recent writes. -- **RDB snapshots are disabled** (`save ""`) — durability relies on AOF, not periodic snapshots. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: deno@latest + ... -**Durability by mode:** -- **Single:** the AOF lives on the node's local disk. Data survives service restarts but is lost if the underlying hardware node fails and no backup exists. -- **HA:** writes are additionally replicated to two replicas, so the dataset survives the loss of any single node via automatic failover. + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: + - deno@latest + prepareCommands: + - zsc add go@latest + ... +``` -:::note Backups -Platform-managed encrypted backups are available for both Single and HA setups. They are **disabled by default** — enable them on the service if you need point-in-time recovery beyond AOF and replication. -::: +See the full list of supported [run base environments](/zerops-yaml/base-list). -## Memory and Autoscaling +To customise your build environment use the `prepareCommands` attribute. -You don't set `maxmemory` directly. Zerops sizes it at **80% of the container's available RAM** — precisely 80% of the *smaller* of your configured maximum RAM and the cgroup-allocated RAM. It is re-evaluated and adjusted automatically about every 30 seconds, so `maxmemory` tracks the container as it scales vertically. The remaining 20% covers Valkey's internal overhead (fork on AOF rewrite / replica sync, fragmentation) and the OS. +### os -:::warning Keep minimum free RAM above 20% when customizing autoscaling -If you edit the autoscaling configuration, keep the **minimum free RAM above 20%**. Zerops caps `maxmemory` at 80% of available RAM, so the dataset alone can never push free RAM below 20%. If your minimum free RAM threshold is at or below 20%, the scale-up trigger may **never fire at all** — free RAM never crosses it, so the service stays stuck at its current size and starts evicting keys (or rejecting writes under `noeviction`) instead of scaling up. Setting the threshold above 20% lets the dataset's growth toward the 80% cap cross the trigger, so the service scales up in time and keeps headroom for the fork during an AOF rewrite or replica sync. The built-in profiles all keep this threshold above 20%. -::: +_OPTIONAL._ Sets the operating system for the runtime environment. -:::note Check the logs for OOM events -Watch the service's runtime logs for out-of-memory events — typically the kernel OOM-killer terminating and restarting Valkey when a fork during an AOF rewrite or replica sync briefly inflates memory. Recurring OOMs mean the reserved headroom isn't enough for your workload's peaks. Raise the **minimum free RAM** (more headroom) or the **minimum RAM** (a higher floor) until they stop. -::: +Following options are available: -## Tunable Parameters +- `alpine` +- `ubuntu` -The `maxmemory-policy` Valkey setting is exposed as an **autoscaling profile override**. In the GUI, open the service's **Automatic scaling configuration**, click **Adjust scaling** and set them under **Overrides**. Zerops applies the change live — **no service restart**, no client reconnect. In HA mode the change is rolled out to every node. +Default value is `alpine`. -To set the parameters at creation time, use `profileOverrides` in your import YAML (a `profile` must be selected to use overrides — available profiles are `hobby`, `staging` and `production`): +We are currently using following os version: -```yaml -services: - - hostname: redis - type: valkey:ha@7.2 - profile: staging - profileOverrides: - maxmemory-policy: noeviction -``` +- {data.alpine.default} +- {data.ubuntu.default} -:::note Migrating from environment variables -Services created before profile overrides existed configure this setting via the `VALKEY_MAXMEMORY_POLICY` environment variable. It keeps working, but once a profile override is set it takes precedence over the environment variable. +:::caution +The os version is fixed and cannot be customised. ::: -### `maxmemory-policy` +### ports -Default: `allkeys-lru`. Controls what Valkey does when the dataset reaches `maxmemory`. +_OPTIONAL._ Specifies one or more internal ports on which your application will listen. -| Value | Behavior | When to use | -|---|---|---| -| `noeviction` | Reject writes with an OOM error | Datasets where every key must be preserved (session storage without TTL, job queues). Requires careful capacity planning. | -| `allkeys-lru` | Evict least-recently-used keys | General-purpose caching — the safe default | -| `allkeys-lfu` | Evict least-frequently-used keys | Hot/cold workloads where access frequency matters more than recency | -| `allkeys-random` | Evict random keys | Uniform access patterns (rare) | -| `volatile-lru` | Evict LRU keys *with a TTL set* | Mixed workloads: persistent keys without TTL are protected, cache keys with TTL are evictable | -| `volatile-lfu` | Evict LFU keys with a TTL | Same as `volatile-lru`, frequency-based | -| `volatile-random` | Evict random keys with a TTL | Rarely appropriate | -| `volatile-ttl` | Evict keys with the shortest remaining TTL | When TTL reflects priority | -| `volatile-ttl` | Evict keys with the shortest remaining TTL | When TTL reflects priority | +Projects in Zerops represent a group of one or more services. Services can be of different types (runtime services, databases, message brokers, object storage, etc.). All services of the same project share a **dedicated private network**. To connect to a service within the same project, just use the service hostname and its internal port. -:::warning `noeviction` and memory pressure -With `noeviction`, Valkey cannot free memory on its own — once the dataset reaches `maxmemory`, writes fail with OOM errors until the service scales up or keys are deleted. Make sure your autoscaling limits (maximum RAM) leave enough room for the dataset's growth. -::: +For example, to connect to a Deno service with hostname = "app" and port = 3000 from another service of the same project, simply use `app:3000`. Read more about [how to access a Deno service](/references/networking/internal-access#basic-service-communication). -## Metrics +Each port has following attributes: -Prometheus-compatible metrics are exported by default for scraping, on the port given by the `ZEROPS_PROMETHEUS_PORT` variable (`db:9121`). +| parameter | description | +| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| port | Defines the port number. You can set any port number between _10_ and _65435_. Ports outside this interval are reserved for internal Zerops systems. | +| protocol | **Optional.** Defines the protocol. Allowed values are `TCP` or `UDP`. Default value is `TCP`. | +| httpSupport | **Optional.** `httpSupport = true` is the default setting for TCP protocol. Set `httpSupport = false` if a web server isn't running on the port. Zerops uses this information for the configuration of [public access](/features/access). `httpSupport = true` is available only in combination with the TCP protocol. | +| httpSupport | **Optional.** `httpSupport = true` is the default setting for TCP protocol. Set `httpSupport = false` if a web server isn't running on the port. Zerops uses this information for the configuration of [public access](/features/access). `httpSupport = true` is available only in combination with the TCP protocol. | -## Learn More +### prepareCommands -- [Official Valkey Documentation](https://valkey.io/docs) - Comprehensive guide to Valkey features +_OPTIONAL._ Customises the Deno runtime environment by installing additional dependencies or tools to the runtime base environment. -## Support +

+ The base Deno environment contains {data.alpine.default} the selected + major version of Deno, [Zerops command line tool](/references/cli) and `npm`, `yarn`, `git` and `npx` tools. To install + additional packages or tools add one or more prepare commands: +

-For advanced configurations or custom requirements: -- Join our [Discord community](https://discord.gg/zeropsio) -- Contact support via [email](mailto:support@zerops.io) +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + ... ----------------------------------------- + # ==== how to run your application ==== + run: + # OPTIONAL. Customise the runtime environment by installing additional packages + # or tools to the base Deno runtime environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... +``` -# Ubuntu > Overview +When the first deploy with a defined prepare attribute is triggered, Zerops will +1. create a prepare runtime container +2. optionally: [copy selected folders or files from your build container](#copy-folders-or-files-from-your-build-container) +3. run the `prepareCommands` commands in the defined order -[Ubuntu ↗](https://ubuntu.com/) is a popular Linux distribution based on Debian, widely used for servers, cloud computing, and containerized applications. +:::note +`run.prepareCommands` run in the `/home/zerops` directory. +::: -Ubuntu services in Zerops provide a flexible base environment for running applications built with technologies that aren't officially supported by Zerops, or for custom setups requiring full control over the runtime environment. +#### Command exit code -:::tip -Do you have any questions? Check the step-by-step tutorial, browse the documentation and join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. -::: +If any command fails, it returns an exit code other than 0 and the deploy is canceled. Read the [prepare runtime log](/deno/how-to/logs#prepare-runtime-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `prepareCommands` commands are finished, your custom runtime environment is ready for the deploy phase. -## Feature Highlights +#### Cache of your custom runtime environment -- [Create Ubuntu service](/ubuntu/how-to/create) — Start with creating an Ubuntu service using GUI or zCLI. -- [zerops.yaml](/ubuntu/how-to/build-pipeline#add-zeropsyaml-to-your-repository) — See a full example of zerops.yaml file to configure your own app. -- [Scaling configuration](/ubuntu/how-to/scaling) — Set up scaling of your Ubuntu service so that it runs smoothly while using only necessary resources. +Some packages or tools can take a long time to install. Therefore, Zerops caches your custom runtime environment after the installation of your custom packages or tools is completed. When the second or following deploy is triggered, Zerops will use the custom runtime cache from the previous deploy if following conditions are met: -{" "} +1. Content of the [build.addToRunPrepare](#copy-folders-or-files-from-your-build-container) and `run.prepareCommands` attributes didn't change from the previous deploy +2. The custom runtime cache wasn't invalidated in the Zerops GUI. -- [Customize build environment](/ubuntu/how-to/build-process#customize-build-environment) -- [Customize runtime environment](/ubuntu/how-to/customize-runtime) +To invalidate the custom runtime cache go to `yyy` -## When in doubt, reach out +When the custom runtime cache is used, Zerops doesn't create a prepare runtime container and executes the deployment of your application directly. -Don't know how to start or got stuck during the process? You might not be the first one, visit the FAQ section to find out. +#### Single or separated shell instances -In case you haven't found an answer (and also if you have), we and our community are looking forward to hearing from you on Discord. +You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -Have you built something that others might find useful? Don't hesitate to share your knowledge! +### Copy folders or files from your build container -- [FAQ](/ubuntu/faq) — Most common questions in one place. -- [Discord](https://discord.com/invite/WDvCZ54) — Join our core team and Zerops community on Discord. Ask questions and share your tips with other members. +

+ The prepare runtime container contains {data.alpine.default}, the + selected major version of Deno, [Zerops command line tool](/references/cli) and `npm`, `yarn`, `git` and `npx` tools. +

-## Popular Guides +The prepare runtime container does not contain your application code nor the built application. If you need to copy some folders or files from the build container to the runtime container (e.g. a configuration file) use the `addToRunPrepare` attribute in the [build section](#build-pipeline-configuration). -- [zCLI](/references/cli) — Get even more out of Zerops with the zCLI command line tool. -- [Zerops VPN](/references/networking/vpn) — Connect to your services easily with Zerops VPN. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + ... + addToRunPrepare: ./runtime-config.yaml + # ==== how to run your application ==== + run: + # OPTIONAL. Customise the runtime environment by installing additional packages + # or tools to the base Deno runtime environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... +``` ----------------------------------------- +In the example above Zerops will copy the `runtime-config.yaml` file from your build container **after the build has finished** into the new **prepare runtime** container. The copied files and folders will be available in the `/home/zerops` folder in the new prepare runtime container before the prepare commands are triggered. -# Ubuntu > How To > Upgrade +### initCommands +_OPTIONAL._ Defines one or more commands to be run each time a new runtime container is started or a container is restarted. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... ----------------------------------------- + # ==== how to run your application ==== + run: + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your Deno application is started. + initCommands: + - rm -rf ./cache +``` -# Ubuntu > How To > Trigger Pipeline +These commands are triggered in the runtime container before your Deno application is started via the [start command](#start). +:::note +`run.initCommands` run in the `/var/www` directory. +::: +Use init commands to clean or initialise your application cache or similar operations. ----------------------------------------- +:::caution +The init commands will delay the start of your application each time a new runtime container is started (including the horizontal [scaling](/deno/how-to/scaling) or when a runtime container is restarted). -# Ubuntu > How To > Scaling +Do not use the init commands for customising your runtime environment. Use the [run:prepareCommands](#preparecommands-1) attribute instead. +::: +#### Command exit code +If any of the `initCommands` fails, it returns an exit code other than 0, but deploy is **not** canceled. After all init commands are finished, regardless of the status code, the application is started. Read the [runtime log](/deno/how-to/logs#runtime-log) to troubleshoot the error. ----------------------------------------- +#### Single or separated shell instances -# Ubuntu > How To > Logs +You can configure your `initCommands` to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). +### envVariables +_OPTIONAL._ Defines the environment variables for the runtime environment. ----------------------------------------- +Enter one or more env variables in following format: -# Ubuntu > How To > Filebrowser +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to run your application ==== + run: + # OPTIONAL. Defines the env variables for the runtime environment: + envVariables: + NODE_ENV: production + DB_NAME: db + DB_HOST: db + DB_USER: db + DB_PASS: ${db_password} +``` +Read more about [environment variables](/deno/how-to/env-variables) in Zerops. +### start ----------------------------------------- +_REQUIRED._ Defines the start command for your Deno application. -# Ubuntu > How To > Env Variables +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... + # ==== how to run your application ==== + run: + # REQUIRED. Your Deno application start command + start: deno task start +``` +We recommend starting your Deno application using `deno task start`. ----------------------------------------- +### health check -# Ubuntu > How To > Deploy Process +_OPTIONAL._ Defines a health check. +`healthCheck` requires either one `httpGet` object or one `exec` object. +#### httpGet ----------------------------------------- +Configures the health check to request a local URL using a HTTP GET method. -# Ubuntu > How To > Customize Runtime +Following attributes are available: + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. +If your application requires a https request, set scheme: https
-## Build Custom Runtime Images +**Example:** -Zerops allows you to build custom runtime images (CRI) when the default base runtime images don't meet your application's requirements. This is an optional phase in the [build and deploy pipeline](/features/pipeline#runtime-prepare-phase-optional). +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -Ubuntu is a versatile base for running anything not explicitly offered as a dedicated Zerops runtime. You can install any packages and tools you need, treating it as a clean OS to customize however you want. + # ==== how to run your application ==== + run: + # REQUIRED. Your Deno application start command + start: deno task start -It is also a great option when you need a specific version of a technology (like Go, Node.js, or PHP) that Zerops doesn't support by default—whether it's an older version for legacy projects or a newer release not yet available. + # OPTIONAL. Define a health check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + healthCheck: + httpGet: + port: 80 + path: /status +``` -## Configuration +#### exec -### Default Runtime Environment +Configures the health check to run a local command. +Following attributes are available: -The default runtime environment contains: +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **command** | Defines a local command to be run. +The command has access to the same [environment variables](/deno/how-to/create#set-secret-environment-variables) as your Deno application. +A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. | -- {data.ubuntu.default} -- [zCLI](/references/cli) -- +**Example:** -### When You Need a Custom Runtime Image +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -Since Ubuntu serves as a general-purpose base, you'll likely want to customize it for your specific use case. Common scenarios include: + # ==== how to run your application ==== + run: + # REQUIRED. Your Deno application start command + start: deno task start -:::important -You should not include your application code in the custom runtime image, as your built/packaged code is deployed automatically into fresh containers. -::: + # OPTIONAL. Define a health check with a shell command. + healthCheck: + exec: + command: | + touch grass + rm -rf life + mv /outside/user /home/user +``` -Here are examples of configuring custom runtime images in your `zerops.yml`: +### crontab -### Basic Setup +_OPTIONAL._ Defines cron jobs. -### Using Build Files in Runtime Preparation +Setup cron jobs in the following format: -For complete configuration details, see the [runtime prepare phase configuration guide](/features/pipeline#configuration). +```yaml +zerops: + # define hostname of your service + - setup: app -## Process and Caching + # ==== how to run your application ==== + run: + crontab: + # REQUIRED. Sets the command to execute: + - command: "" + # REQUIRED. Sets the interval time to execute: + timing: "0 * * * *" +``` -### How Runtime Prepare Works -The runtime prepare process follows the same steps for all runtimes. See [how runtime prepare works](/features/pipeline#how-it-works) for the complete process details. +Read more about setting up [cron](/zerops-yaml/cron) in Zerops. -### Caching Behavior -Zerops caches custom runtime images to optimize deployment times. Learn about [custom runtime image caching](/features/pipeline#custom-runtime-image-caching) including when images are cached and reused. +## Deploy configuration -### Build Management -For information about managing builds and deployments, see [managing builds and deployments](/features/pipeline#manage-builds-and-deployments). +### readiness check -:::warning -Local Storage volumes are not available during the runtime prepare phase, and start commands (such as a SeaweedFS mount) do not run there. -::: +_OPTIONAL._ Defines a readiness check. Read more about how the [readiness check works](/deno/how-to/deploy-process#readiness-checks) in Zerops. -## Troubleshooting +`readinessCheck` requires either one `httpGet` object or one `exec` object. -If your `prepareCommands` fail, check the for specific error messages. +#### httpGet ----------------------------------------- +Configures the readiness check to request a local URL using a http GET method. -# Ubuntu > How To > Create +Following attributes are available: + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. +If your application requires a https request, set scheme: https
-Zerops provides a Ubuntu runtime service with extensive build support. Ubuntu runtime is highly scalable and customisable to suit both development and production. +**Example:** -## Create Ubuntu service using Zerops GUI +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -First, set up a project in Zerops GUI. Then go to the project dashboard page and choose **Add new service** in the left menu in the **Services** block. Then add a new Ubuntu service: + # ==== how to deploy your application ==== + deploy: + # OPTIONAL. Define a readiness check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + readinessCheck: + httpGet: + port: 80 + path: /status -[Video: /vids/services/golang.webm](/vids/services/golang.webm) + # ==== how to run your application ==== + run: ... +``` -### Choose Ubuntu version +Read more about how the [readiness check works](/deno/how-to/deploy-process#readiness-checks) in Zerops. -Following Ubuntu versions are currently supported: +#### exec -:::info -You can [change](/ubuntu/how-to/upgrade) the major version at any time later. -::: +Configures the readiness check to run a local command. +Following attributes are available: -### Set a hostname +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **command** | Defines a local command to be run. +The command has access to the same [environment variables](/deno/how-to/create#set-secret-environment-variables) as your Deno application. +A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. | -Enter a unique service identifier like "app","cache", "gui" etc. Duplicate services with the same name in the same project are forbidden. +**Example:** -#### Limitations: +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -- maximum 25 characters -- must contain only lowercase ASCII letters (a-z) or numbers (0-9) + # ==== how to deploy your application ==== + deploy: + # OPTIONAL. Define a readiness check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + readinessCheck: + exec: + command: | + touch grass + rm -rf life + mv /outside/user /home/user +``` -:::caution -The hostname is fixed after the service is created. It can't be changed later. -::: +Read more about how the [readiness check works](/deno/how-to/deploy-process#readiness-checks) in Zerops. -### Set secret environment variables -Add environment variables with sensitive data, such as password, tokens, salts, certificates etc. These will be securely saved inside Zerops and added to your runtime service upon start. +---------------------------------------- -Setting the secret environment variables is optional. You can set them later in Zerops GUI. +# Deno > How To > Build Process -Read more about [different types of env variables](/ubuntu/how-to/env-variables#service-env-variables) in Zerops. -## Create Ubuntu service using zCLI +## Build process overview -zCLI is the Zerops command-line tool. To create a new Ubuntu service via the command-line, follow these steps: +Zerops starts a temporary build container and performs the following actions: -1. [Install & setup zCLI](/references/cli) -2. [Create a project description file](/ubuntu/how-to/create#create-a-project-description-file) -3. [Create a project with a Ubuntu and PostgreSQL service](#full-example) +1. **Installs the build environment** - Sets up base system and Deno runtime +2. **Downloads your application source code** - From [GitHub ↗](https://www.github.com), [GitLab ↗](https://www.gitlab.com) or via [Zerops CLI](/references/cli) +3. **Optionally customizes the build environment** - Runs prepare commands if configured +4. **Runs the build commands** - Executes your build process +5. **Uploads the application artifact** - Stores build output to internal Zerops storage +6. **Caches selected files** - Preserves specified files for faster future builds -### Create a project description file +The build container is automatically deleted after the build has finished or failed. -Zerops uses a yaml format to describe the project infrastructure. +## Build configuration -#### Basic example: +Configure your Deno build process in your `zerops.yaml` file according to the [full build & deploy Deno pipeline guide](/deno/how-to/build-pipeline). -Create a directory `my-project`. Create an `description.yaml` file inside the `my-project` directory with following content: +## Build environment -```yaml -# basic project data -project: - # project name - name: my-project -# array of project services -services: - - # service name - hostname: app - # service type and version number in ubuntu@{version} format - type: ubuntu@26.04 - # defines the minimum number of containers for horizontal autoscaling - minContainers: 1 - # defines the maximum number of containers for horizontal autoscaling. Max value = 6. - maxContainers: 6 - # optional: create env variables - envSecrets: - S3_ACCESS_KEY_ID: 'P8cX1vVVb' - S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' -``` +### Default Deno build environment -The yaml file describes your future project infrastructure. The project will contain one Ubuntu service with default [auto scaling](/ubuntu/how-to/scaling) configuration. Hostname will be set to "app", the internal port(s) the service listens on will be defined later in the [zerops.yaml](/ubuntu/how-to/build-pipeline#ports). Following secret env variables will be configured: +The default Deno build environment contains: -```env -S3_ACCESS_KEY_ID="P8cX1vVVb" -S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" -``` +- {data.ubuntu.default} +- Selected version of Deno defined in `zerops.yaml` [build.base](/deno/how-to/build-pipeline#base) parameter +- [zCLI](/references/cli), Zerops command line tool +- Deno and Git -#### Full example: +### Customize build environment -Create a directory my-project. Create an description.yaml file inside the my-project directory with following content: +To install additional packages or tools, add one or more [build.prepareCommands](/deno/how-to/build-pipeline#preparecommands) to your `zerops.yaml`. -```yaml -# basic project data -project: - # project name - name: my-project - # optional: project description - description: A project with a Ubuntu and PostgreSQL database +:::info +The application code is available in the `/build/source` folder in your build container before the prepare commands are triggered. This allows you to use any file from your application code in your prepare commands (e.g. a configuration file). +::: + +### Build hardware resources + +All runtime services use the same hardware resources for build containers: + + + + + + + + + + + + + + + + + + + + + + + + + + +
HW resourceMinimumMaximum
CPU cores15
RAM8 GB8 GB
Disk1 GB100 GB
+ +Build containers start with minimum resources and scale vertically up to maximum capacity as needed. + +:::info +Build container resources are not charged separately. Limited build time is included in your [project core plan](/company/pricing#project-core-plans), with additional build time available if needed. +::: + +### Build time limit + +The time limit for the whole build pipeline is **1 hour**. After 1 hour, Zerops will terminate the build pipeline and delete the build container. + +## Troubleshooting Deno builds + +### Build command failures + +If any [build command](/deno/how-to/build-pipeline#buildcommands) fails (returns non-zero exit code), the build is canceled. Check the [build log](/deno/how-to/logs#build-log) to troubleshoot the error. + +For Deno, if the error log doesn't contain specific error messages, try running your build with verbose output: + +```yaml +buildCommands: + - deno cache main.ts + - deno compile --allow-net --allow-read main.ts +``` + +### Prepare command failures + +If any [prepare command](/deno/how-to/build-pipeline#preparecommands) fails, check the [build log](/deno/how-to/logs#build-log) for specific error messages. Common issues include: + +- Missing permissions in Deno commands (add --allow-net, --allow-read, etc.) +- Ubuntu package installation failures (use sudo apt-get update first) +- Deno cache directory permissions + +### Build cache issues + +If you encounter unexpected build behavior or dependency issues, the problem might be related to [cached build data](/features/build-cache). While Zerops maintains the build cache to speed up deployments, sometimes you may need to start fresh. + +To invalidate the build cache: + +1. Go to your service detail in Zerops GUI +2. Choose **Pipelines & CI/CD Settings** from the left menu +3. Click on the **Invalidate build cache** button + +This will force Zerops to run the next build clean, including all prepare commands. Learn more about [build cache behavior](/features/build-cache). + +:::tip Advanced troubleshooting +For complex build issues that require investigation, you can enable [debug mode](/features/debug-mode) to pause the build process at specific points and inspect the build container state interactively. +::: + +## More resources + +For more details about the build and deploy pipeline, including how to cancel builds and manage application versions, see the [general pipeline documentation](/features/pipeline). + +## Next steps + +- Understand the [deployment process](/deno/how-to/deploy-process) +- Learn how to [customize the runtime environment](/deno/how-to/customize-runtime) +- Explore [build and runtime logs](/deno/how-to/logs) + +---------------------------------------- + +# Deno > How To > Controls + + + +---------------------------------------- + +# Deno > How To > Create + + +Zerops provides a powerful Deno runtime service with extensive build support. The Deno runtime is highly scalable and customizable to suit your development and production needs. With just a few clicks or commands, you can have a production-ready Deno environment up and running in no time. + +## Create a Deno service using Zerops GUI + +First, set up a project in the Zerops GUI. Then go to the project dashboard page and choose **Add new service** in the left menu under the **Services** section. From there, you can add a new Deno service: + +[Video: /vids/services/deno.webm](/vids/services/deno.webm) + +### Choose a Deno version + +Zerops supports the following Deno versions: + +:::info +You can easily [upgrade](/deno/how-to/upgrade) the major version at any time later. +::: + +### Set a hostname + +Enter a unique service identifier like "app", "cache", "gui", etc. Duplicate services with the same name within the same project are not allowed. + +#### Limitations: + +- Maximum 25 characters +- Must contain only lowercase ASCII letters (a-z) or numbers (0-9) + +:::caution +The hostname is fixed after the service is created and cannot be changed later. +::: + +### Set secret environment variables + +Add environment variables with sensitive data, such as passwords, tokens, salts, certificates, etc. These will be securely saved inside Zerops and added to your runtime service upon start. + +Setting secret environment variables is optional. You can always set them later in the Zerops GUI. + +Read more about the [different types of environment variables](/deno/how-to/env-variables#service-env-variables) in Zerops. + +## Create a Deno service using zCLI + +zCLI is the Zerops command-line tool. To create a new Deno service via the command line, follow these steps: + +1. [Install & setup zCLI](/references/cli) +2. [Create a project description file](/deno/how-to/create#create-a-project-description-file) +3. [Create a project with a Deno and PostgreSQL service](#full-example) + +### Create a project description file + +Zerops uses a YAML format to describe the project infrastructure. + +#### Basic example: + +Create a directory called `my-project`. Inside the `my-project` directory, create a `description.yaml` file with the following content: +```yaml +# basic project data +project: + # project name + name: my-project +# array of project services +services: + - # service name + hostname: app + # service type and version number in deno@{version} format + type: deno@latest + # defines the minimum number of containers for horizontal autoscaling + minContainers: 1 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 6 + # optional: create env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' +``` + +The yaml file describes your future project infrastructure. The project will contain one Deno version 20 service with default [auto scaling](/deno/how-to/scaling) configuration. Hostname will be set to "app", the internal port(s) the service listens on will be defined later in the [zerops.yaml](/deno/how-to/build-pipeline#ports). Following secret env variables will be configured: + +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" +``` + +#### Full example: + +Create a directory my-project. Create an description.yaml file inside the my-project directory with following content: + +```yaml +# basic project data +project: + # project name + name: my-project + # optional: project description + description: A project with a Deno and PostgreSQL database # optional: project tags tags: - DEMO @@ -3758,8 +4640,8 @@ project: services: - # service name hostname: app - # service type and version number in ubuntu@{version} format - type: ubuntu@26.04 + # service type and version number in deno@{version} format + type: deno@latest # optional: vertical auto scaling customization verticalAutoscaling: cpuMode: DEDICATED @@ -3776,7 +4658,7 @@ services: minContainers: 2 # defines the maximum number of containers for horizontal autoscaling. Max value = 6. maxContainers: 4 - # optional: create secret env variables + # optional: create env variables envSecrets: S3_ACCESS_KEY_ID: 'P8cX1vVVb' S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' @@ -3788,9 +4670,9 @@ services: mode: NON_HA ``` -The yaml file describes your future project infrastructure. The project will contain a Ubuntu service and a [PostgreSQL](/postgresql/overview) service. +The yaml file describes your future project infrastructure. The project will contain a Deno service and a [PostgreSQL](/postgresql/overview) service. -Ubuntu service with "app" hostname, the internal port(s) the service listens on will be defined later in the zerops.yaml. Ubuntu service will run with a custom vertical and horizontal scaling. Following secret env variables will be configured: +Deno service with "app" hostname, the internal port(s) the service listens on will be defined later in the [zerops.yaml](/deno/how-to/build-pipeline#ports). Deno service will run on version 20 with a custom vertical and horizontal scaling. Following secret env variables will be configured: ```env S3_ACCESS_KEY_ID="P8cX1vVVb" @@ -3803,22 +4685,29 @@ The hostname of the PostgreSQL service will be set to "db". The [single containe The `project:` section is required. Only one project can be defined. +| Parameter | Description | Limitations | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| **name** | The name of the new project. Duplicates are allowed. | | +| **description** | **Optional.** Description of the new project. | Maximum 255 characters. | +| **tags** | **Optional.** One or more string tags. Tags do not have a functional meaning, they only provide better orientation in projects. | +| **tags** | **Optional.** One or more string tags. Tags do not have a functional meaning, they only provide better orientation in projects. | + +At least one service in `services:` section is required. You can create a project with multiple services. The example above contains Deno and PostgreSQL services but you can create a `description.yaml` with your own combination of [services](/features/infrastructure). + - - + + - + - + - + - + - + - + - + - + - + - + @@ -3918,7 +4828,7 @@ You don't specify the project name in the `zcli project project-import` command, If you have access to more than one client, you must specify the client ID for which the project is to be created. The `clientID` is located in the Zerops GUI under the client name on the project dashboard page. -### Add Ubuntu service to an existing project +### Add Deno service to an existing project #### Example: @@ -3933,8 +4843,8 @@ project: services: - # service name hostname: app - # service type and version number in ubuntu@{version} format - type: ubuntu@26.04 + # service type and version number in deno@{version} format + type: deno@latest # defines the minimum number of containers for horizontal autoscaling minContainers: 1 # defines the maximum number of containers for horizontal autoscaling. Max value = 6. @@ -3945,7 +4855,7 @@ services: S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' ``` -The yaml file describes the list of one or more services that you want to add to your existing project. In the example above, one Ubuntu service version 1 with default [auto scaling](/ubuntu/how-to/scaling) configuration will be added to your project. Hostname of the new service will be set to `app`. Following secret env variables will be configured: +The yaml file describes the list of one or more services that you want to add to your existing project. In the example above, one Deno service version 20 with default [auto scaling](/deno/how-to/scaling) configuration will be added to your project. Hostname of the new service will be set to `app`. Following secret env variables will be configured: ```env S3_ACCESS_KEY_ID="P8cX1vVVb" @@ -3973,207 +4883,573 @@ Maximum size of the import.yaml file is 100 kB. ---------------------------------------- -# Ubuntu > How To > Controls +# Deno > How To > Customize Runtime +## Build Custom Runtime Images ----------------------------------------- +Zerops allows you to build custom runtime images (CRI) when the default base runtime images don't meet your Deno application's requirements. This is an optional phase in the [build and deploy pipeline](/features/pipeline#runtime-prepare-phase-optional). -# Ubuntu > How To > Build Process +:::important +You should not include your application code in the custom runtime image, as your built/packaged code is deployed automatically into fresh containers. +::: +## Configuration -## Build process overview +### Default Deno Runtime Environment -Zerops starts a temporary build container and performs the following actions: +The default Deno runtime environment contains: -1. **Installs the build environment** - Sets up base system and runtime -2. **Downloads your application source code** - From [GitHub ↗](https://www.github.com), [GitLab ↗](https://www.gitlab.com) or via [Zerops CLI](/references/cli) -3. **Optionally customizes the build environment** - Runs prepare commands if configured -4. **Runs the build commands** - Executes your build process -5. **Uploads the application artifact** - Stores build output to internal Zerops storage -6. **Caches selected files** - Preserves specified files for faster future builds +- {data.ubuntu.default} +- Selected version of Deno when the runtime service was created +- [zCLI](/references/cli) +- Deno and Git -The build container is automatically deleted after the build has finished or failed. +### When You Need a Custom Runtime Image -## Build configuration +If your Deno application needs more than what's included in the default environment, you'll need to build a custom runtime image. Common scenarios include: -Configure your build process in your `zerops.yaml` file according to the pipeline guide. +- **System packages for processing**: When your app processes images, videos, or files (requiring packages like `sudo apt-get install -y imagemagick`) +- **Global Deno tools**: When you need CLI tools or utilities available system-wide +- **Native dependencies**: When your Deno modules require system libraries that aren't in the default environment -## Build environment +Here are Deno-specific examples of configuring custom runtime images in your `zerops.yml`: -### Default build environment +### Basic Deno Setup -The default build environment contains: +### Using Build Files in Runtime Preparation -- {data.ubuntu.default} -- [zCLI](/references/cli), Zerops command line tool -- +```yaml +build: + addToRunPrepare: + - deno.json + - import_map.json +run: + prepareCommands: + - sudo apt-get update + - sudo apt-get install -y imagemagick + - deno cache deps.ts +``` -### Customize build environment +For complete configuration details, see the [runtime prepare phase configuration guide](/features/pipeline#configuration). -To install additional packages or tools, add one or more to your `zerops.yaml`. +## Process and Caching -:::info -The application code is available in the `/build/source` folder in your build container before the prepare commands are triggered. This allows you to use any file from your application code in your prepare commands (e.g. a configuration file). +### How Runtime Prepare Works +The runtime prepare process follows the same steps for all runtimes. See [how runtime prepare works](/features/pipeline#how-it-works) for the complete process details. + +### Caching Behavior +Zerops caches custom runtime images to optimize deployment times. Learn about [custom runtime image caching](/features/pipeline#custom-runtime-image-caching) including when images are cached and reused. + +### Build Management +For information about managing builds and deployments, see [managing builds and deployments](/features/pipeline#manage-builds-and-deployments). + +:::warning +Local Storage volumes are not available during the runtime prepare phase, and start commands (such as a SeaweedFS mount) do not run there. ::: -### Build hardware resources +## Troubleshooting -All runtime services use the same hardware resources for build containers: +If your `prepareCommands` fail, check the [prepare runtime log](/deno/how-to/logs#prepare-runtime-log) for specific error messages. -
ParameterDescriptionParameterDescription
hostname + hostname + The unique service identifier. - - The hostname of the new database will be set to the `hostname` value. - - Limitations:
  • duplicate services with the same name in the same project are forbidden
  • maximum 25 characters
  • @@ -3827,69 +4716,90 @@ The `project:` section is required. Only one project can be defined.
type + type + Specifies the service type and version. - See what [Ubuntu service types](/references/import-yaml/type-list#runtime-services) are currently supported. + See what [Deno service types](/references/import-yaml/type-list#runtime-services) are currently supported.
verticalAutoscaling - Optional. Defines [custom vertical auto scaling parameters](/ubuntu/how-to/create#set-auto-scaling-configuration). + verticalAutoscaling + + Optional. Defines [custom vertical auto scaling parameters](/deno/how-to/create#set-auto-scaling-configuration). - All verticalAutoscaling attributes are optional. Not specified attributes will be set to their default values. + All verticalAutoscaling attributes are optional. Not specified + attributes will be set to their default values.
- cpuMode - Optional. Accepts `SHARED`, `DEDICATED` values. Default is `SHARED` + - cpuMode + + Optional. Accepts `SHARED`, `DEDICATED` values. Default is `SHARED`
- minCpu/maxCpu - Optional. Set the minCpu or maxCpu in CPU cores (integer). + - minCpu/maxCpu + + Optional. Set the minCpu or maxCpu in CPU cores (integer).
- minRam/maxRam - Optional. Set the minRam or maxRam in GB (float). + - minRam/maxRam + + Optional. Set the minRam or maxRam in GB (float).
- minDisk/maxDisk - Optional. Set the minDisk or maxDisk in GB (float). + - minDisk/maxDisk + + Optional. Set the minDisk or maxDisk in GB (float).
minContainers - Optional. Default = 1. Defines the minimum number of containers for [horizontal autoscaling](/ubuntu/how-to/create#horizontal-auto-scaling). + minContainers + + Optional. Default = 1. Defines the minimum number of containers + for [horizontal autoscaling](/deno/how-to/create#horizontal-auto-scaling). - Limitations: + Limitations: Current maximum value = 10.
maxContainers - Defines the maximum number of containers for [horizontal autoscaling](/ubuntu/how-to/create#horizontal-auto-scaling). + maxContainers + + Defines the maximum number of containers for [horizontal autoscaling](/deno/how-to/create#horizontal-auto-scaling). - Limitations: + Limitations: Current maximum value = 10.
envSecrets - Optional. Defines one or more secret env variables as a key value map. See env variable [restrictions](/ubuntu/how-to/env-variables#env-variable-restrictions). + envSecrets + + Optional. Defines one or more secret env variables as a key value + map. See env variable [restrictions](/deno/how-to/env-variables#env-variable-restrictions).
- - - - - - - - - - - - - - - - - - - - - - - - -
HW resourceMinimumMaximum
CPU cores15
RAM8 GB8 GB
Disk1 GB100 GB
+---------------------------------------- -Build containers start with minimum resources and scale vertically up to maximum capacity as needed. +# Deno > How To > Deploy Process -### Build time limit -The time limit for the whole build pipeline is **1 hour**. After 1 hour, Zerops will terminate the build pipeline and delete the build container. -:::info -Build container resources are not charged separately. Limited build time is included in your [project core plan](/company/pricing#project-core-plans), with additional build time available if needed. -::: +---------------------------------------- -## Troubleshooting builds +# Deno > How To > Env Variables -:::tip Advanced troubleshooting -For complex build issues that require investigation, you can enable [debug mode](/features/debug-mode) to pause the build process at specific points and inspect the build container state interactively. -::: -### Build and prepare command failures -If any or fails (returns non-zero exit code), the build is canceled. Check the to troubleshoot the error. +---------------------------------------- -### Build cache issues +# Deno > How To > Filebrowser -If you encounter unexpected build behavior or dependency issues, the problem might be related to cached build data. While Zerops maintains the build cache to speed up deployments, sometimes you may need to start fresh. -To invalidate the build cache: -1. Go to your service detail in Zerops GUI -2. Choose **Pipelines & CI/CD Settings** from the left menu -3. Click on the **Invalidate build cache** button +---------------------------------------- -This will force Zerops to run the next build clean, including all prepare commands. +# Deno > How To > Logs -Learn more about [build cache behavior](/features/build-cache). -## More resources -For more details about the build and deploy pipeline, including how to cancel builds and manage application versions, see the [general pipeline documentation](/features/pipeline). +---------------------------------------- + +# Deno > How To > Scaling -## Next steps -- Understand the -- Learn how to -- Explore ---------------------------------------- -# Ubuntu > How To > Build Pipeline +# Deno > How To > Trigger Pipeline -Zerops provides a customizable build and runtime environment for your Ubuntu application. -## Add zerops.yaml to your repository +---------------------------------------- -Start by adding `zerops.yaml` file to the **root of your repository** and modify it to fit your application: +# Deno > How To > Upgrade -```yaml -zerops: - # define hostname of your service - - setup: app - # ==== how to build your application ==== - build: - # REQUIRED. Set the base technology for the build environment: - base: ubuntu@26.04 - # OPTIONAL. Customize the build environment by installing additional packages - # or tools to the base build environment. - prepareCommands: - - sudo apt-get something - - curl something else - # OPTIONAL. Build your application, e.g. with not officially supported version of your favourite technology - buildCommands: - - go build -o app main.go - # REQUIRED. Select which files / folders to deploy after - # the build has successfully finished - deployFiles: app +---------------------------------------- - # OPTIONAL. Which files / folders you want to cache for the next build. - # Next builds will be faster when the cache is used. - cache: some_file +# Deno > Overview - # ==== how to run your application ==== - run: - # OPTIONAL. Sets the base technology for the runtime environment: - base: ubuntu@26.04 - # OPTIONAL. Sets the internal port(s) your app listens on: - ports: - # port number - - port: 8080 +[Deno ↗](https://deno.org/en) is an asynchronous event-driven JavaScript runtime, which is designed to build scalable network applications. - # OPTIONAL. Customize the runtime Ubuntu environment by installing additional - # dependencies to the base Ubuntu runtime environment. - prepareCommands: - - sudo apt-get something - - curl something else +:::tip +Have you got any additional question? Join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. +::: - # OPTIONAL. Run one or more commands each time a new runtime container - # is started or restarted. These commands are triggered before - # your Ubuntu application is started. - initCommands: - - rm -rf ./cache +As said, there is no need for coding yet, we have created a [Github repository ↗](https://github.com/zeropsio/recipe-deno), a **_recipe_**, containing the most simple Deno web application. The repo will be used as a source from which the app will be built. - # REQUIRED. Your Ubuntu application start command - start: ./app -``` +### 🚀 No Fuss, Just Deploy with Speed! -The top-level element is always `zerops`. +This is the most bare-bones example of Deno app running in Zerops — as few libraries as possible, + just a simple endpoint with connect, read and write to a Zerops PostgreSQL database. -### Setup + [Deploy "deno" recipe on Zerops](https://app.zerops.io/recipe/?lf=deno) -The first element `setup` contains the **hostname** of your service. A runtime service with the same hostname must exist in Zerops. -Zerops supports the definition of multiple runtime services in a single `zerops.yaml`. This is useful when you use a monorepo. Just add multiple setup elements in your `zerops.yaml`: +1. Log in/sign up to [Zerops GUI ↗](https://app.zerops.io) -```yaml -zerops: - # definition for app service - - setup: app - # optional - build: ... - # optional - deploy: ... - # required - run: ... +2. In the **Projects** box click on **Import a project** and paste in the following YAML config ([source ↗](https://github.com/zeropsio/recipe-deno/blob/main/zerops-project-import.yaml)): - # definition for api service +```yaml +project: + name: recipe-deno + tags: + - zerops-recipe + +services: + - hostname: api + type: deno@1 + buildFromGit: https://github.com/zeropsio/recipe-deno + enableSubdomainAccess: true + + - hostname: db + type: postgresql@16 + mode: NON_HA + priority: 1 +``` + +3. Click on **Import project** and wait until all pipelines have finished. + +**That's it, your application is now up and running! :star: Let's check it works:** + +1. A _subdomain_ should have been enabled and visible in the project's **IP addressed & Public Routing Overview** box. Its format should look similar to this `https://api-7f6-8000.prg1.zerops.app`. +2. Click or the `subdomain` URL to open it in a browser and you should see + +``` +{"message":"This is a simple, basic Deno / Oak application running in Zerops.io,\n each request adds an entry to the PostgreSQL database and returns a count.\n See the source repository (https://github.com/zeropsio/recipe-deno) for more information.","newEntry":"274b0cc1-5b6d-4351-b8ec-53cf82bd9d0f","count":1} +``` + +:::tip +Do you have any questions? Check the step-by-step tutorial, browse the documentation and join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. +::: + +## How to start + +It doesn't matter whether it's your first curious introduction to Zerops, you have already mastered the basics and are looking for a tiny detail or inspiration. Below, choose a section that fits your needs: + +- [Care for details?](/deno/how-to/create) — Dive in all Zerops has to offer for your Deno application. +- [Deno recipes](https://github.com/zeropsio?q=deno&type=all&language=&sort=) — Get inspired by already existing repositories, ready to be imported to Zerops. + +## Feature Highlights + +- [Create Deno service](/deno/how-to/create) — Start with creating a Deno service using GUI or zCLI. +- [Zerops.yaml](/deno/how-to/build-pipeline#add-zeropsyaml-to-your-repository) — See a full example of zerops.yaml file to create your own app. +- [Scaling configuration](/deno/how-to/scaling) — Set up scaling of your Deno application so that it runs smoothly while using only necessary resources. + +{" "} + +- [Customize build environment](/deno/how-to/build-process#customize-build-environment) +- [Customize runtime environment](/deno/how-to/customize-runtime) + +## When in doubt, reach out + +Don't know how to start or got stuck during the process? You might not be the first one, visit the FAQ section to find out. + +In case you haven't found an answer (and also if you have), we and our community are looking forward to hearing from you on Discord. + +Have you build something that others might find useful? Don't hesitate to share your knowledge! + +- [Discord](https://discord.com/invite/WDvCZ54) — Join our core team and Zerops community on Discord. Ask questions and share your tips with other members. + +## Popular Guides + +- [zCLI](/references/cli) — Get even more out of Zerops with the zCLI command line tool. +- [Zerops VPN](/references/networking/vpn) — Connect to your services easily with Zerops VPN. + + +---------------------------------------- + +# Docker > Overview + + +Zerops provides Docker support through dedicated Virtual Machine (VM) environments, ensuring maximum compatibility and isolation while maintaining integration with the broader Zerops ecosystem. This guide explains how to effectively use Docker services in Zerops, including best practices and important considerations. + +## Why VMs + +While Zerops primarily uses native Linux containers for optimal performance, this VM-based approach allows you to run virtually any Docker container while maintaining Zerops' robust infrastructure management. + +You can learn more about [differences](/features/container-vs-vm) between Containers and Virtual Machines in Zerops. + +Before using Docker services, consider these important aspects: + +### Virtual Machine Environment + +Docker services in Zerops operate in a full VM environment, which has several implications: + +- **Slower Boot Times**: VMs require more time to initialize due to full kernel boot +- **Higher Resource Usage**: VMs include additional system overhead compared to native containers +- **Scaling Limitations**: + - Vertical scaling requires VM restart + - Resources must be set as fixed values (no min-max ranges) + - Zerops automatically restarts the VM when resource values are changed in UI +- **Storage Management**: Disk space can only be increased, not decreased without recreation +- **Build Phase Limitations**: Build phase runs in containers, not in the VM environment + +### Advantages + +Despite these limitations, Docker services offer some benefits: + +- **Broad Compatibility**: Run almost any Docker container with minimal modification +- **Familiar Environment**: Standard Docker runtime environment + +## Configuration Guide + +### Supported Version + +Currently supported Docker versions: + +### Basic Structure + +Docker services in Zerops are configured through the `zerops.yaml` file. Here's a typical configuration pattern: + +```yaml title="zerops.yaml" +zerops: + - setup: app + run: + base: docker@latest + prepareCommands: + - docker image pull : # Always use specific version tags + start: docker run --network=host : + ports: + - port: + httpSupport: true +``` + +:::important +Always use specific version tags (like `1.0.0`) instead of `:latest`. Zerops caches the `prepareCommands` output, which means a new `:latest` image won't be automatically pulled on subsequent deployments unless the cache is manually cleared or the commands change. +::: + +Refer to the [Docker recipe repository](https://github.com/zeropsio/recipe-docker) for an example configuration. + +:::note +We are actively working on improving the speed of image caching after `run.prepareCommands` and reducing the startup time of runtime VMs. These improvements will be released in future updates. +::: + +### Network Configuration + +Docker services require the `--network=host` flag for proper integration with Zerops: + +- **Direct Port Management**: Ports are managed through `zerops.yaml` +- **Simplified Configuration**: Avoids double port exposure in Docker and Zerops +- **Native Performance**: Direct access to host networking + +### Docker Compose Support + +For projects using Docker Compose, additional configuration is required: + +1. **File Deployment**: + ```yaml title="zerops.yaml" + build: + # base cannot be docker — build phase runs in containers, not VMs + deployFiles: ./docker-compose.yaml + addToRunPrepare: ./docker-compose.yaml + ``` + +2. **Network Mode**: + ```yaml title="docker-compose.yaml" + services: + your-service: + image: your-image:1.0.0 + network_mode: host + ``` + +3. **Start Command**: + ```yaml title="zerops.yaml" + run: + start: docker compose up --force-recreate + ``` + +### Environment Variables + +When using Docker services, there's an additional layer to consider since environment variables defined in Zerops must be explicitly passed to your Docker containers. + +#### 1. Defining Variables in Zerops + +Define your environment variables in the `run.envVariables` section of your `zerops.yaml` (example uses [referenced](/features/env-variables#referencing-variables) variables): + +```yaml title="zerops.yaml" +zerops: + - setup: app + run: + base: docker@latest + envVariables: + DB_HOST: ${db_hostname} + DB_PORT: ${db_port} +``` + +#### 2. Passing Variables to Docker Containers + +For single containers, pass variables using the `-e` flag: + +```yaml title="zerops.yaml" +run: + base: docker@latest + prepareCommands: + - docker image pull my-application:1.0.0 # Use specific version tags, not :latest + start: docker run -e DB_HOST -e DB_PORT --network=host my-application:1.0.0 +``` + +:::important +Always use specific version tags (like `1.0.0`) instead of `:latest`. Zerops caches the `prepareCommands` output, which means a new `:latest` image won't be automatically pulled on subsequent deployments unless the cache is manually cleared or the commands change. +::: + +For Docker Compose setups, pass environment variables in your `docker-compose.yaml`: + +```yaml title="docker-compose.yaml" +services: + api: + image: my-application:1.0.0 + network_mode: host + environment: + - DB_HOST + - DB_PORT +``` + +## Implementation Examples + +### Single Container + +```yaml title="zerops.yaml" +zerops: + - setup: app + run: + base: docker@latest + prepareCommands: + - docker image pull crccheck/hello-world:1.0.0 # Always use specific version tags + start: docker run --network=host crccheck/hello-world:1.0.0 + ports: + - port: 8000 + httpSupport: true +``` + +:::important +Always use specific version tags (like `1.0.0`) instead of `:latest`. Zerops caches the `prepareCommands` output, which means a new `:latest` image won't be automatically pulled on subsequent deployments unless the cache is manually cleared or the commands change. +::: + +### Single Service with Docker Compose + +```yaml title="zerops.yaml" +zerops: + - setup: api + build: + # base cannot be docker — build phase runs in containers, not VMs + deployFiles: ./docker-compose.yaml + addToRunPrepare: ./docker-compose.yaml + run: + base: docker@latest + prepareCommands: + - docker compose pull api + start: docker compose up api --force-recreate + ports: + - port: 8000 + httpSupport: true +``` + +```yaml title="docker-compose.yaml (excerpt)" +services: + api: + image: your-image:1.0.0 + network_mode: host + # other configuration... +``` + +### Multiple Services with Docker Compose + +```yaml title="zerops.yaml" +zerops: + - setup: apps + build: + # base cannot be docker — build phase runs in containers, not VMs + deployFiles: ./docker-compose.yaml + addToRunPrepare: ./docker-compose.yaml + run: + base: docker@latest + prepareCommands: + - docker compose pull + start: docker compose up --force-recreate + ports: + - port: 8000 + httpSupport: true +``` + +```yaml title="docker-compose.yaml (excerpt)" +services: + web: + image: web-image:1.0.0 + network_mode: host + # other configuration... + + api: + image: api-image:1.0.0 + network_mode: host + # other configuration... +``` + +## Best Practices + +#### Image Management +- **Always use specific version tags** instead of `:latest` - This prevents caching issues as Zerops caches `prepareCommands` output + +#### Resource Planning +- Account for VM overhead in resource allocation +- Plan for longer initialization times +- Consider the impact on scaling operations + +#### Migration Consideration +- Evaluate if your workload could run on native containers +- Consider gradual migration for complex applications +- Balance development effort against operational benefits + +## Limitations and Workarounds + +### Build Phase + +Since the build phase runs in containers rather than VMs: + +- Use `run.prepareCommands` for Docker-specific build steps +- Consider external CI/CD for complex Docker builds +- Leverage pre-built images when possible + +### Scaling Operations + +Docker services in Zerops have specific scaling characteristics that differ from native containers: + +#### Vertical Scaling +- Resources must be defined with **fixed** values instead of min-max ranges +- CPU, RAM, and disk are specified as single values: + ```yaml + verticalAutoscaling: + cpu: 3 + ram: 2 + disk: 20 + ``` +- Any change to these values through the UI triggers an automatic VM restart +- Plan your resource allocation carefully to minimize scaling operations + +#### Horizontal Scaling +- Still supports multiple containers through `minContainers` and `maxContainers` +- Consider breaking large services into smaller components +- Implement proper health checks for reliable scaling +- Use horizontal scaling when possible to avoid VM restarts + +---------------------------------------- + +# Dotnet > How To > Build Pipeline + + +Zerops provides a customizable build and runtime environment for your .NET application. + +## Add zerops.yaml to your repository + +Start by adding `zerops.yaml` file to the **root of your repository** and modify it to fit your application: + +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: dotnet@6 + + # OPTIONAL. Set the operating system for the build environment. + # os: ubuntu + + # OPTIONAL. Customize the build environment by installing additional packages + # or tools to the base build environment. + # prepareCommands: + # - sudo apt-get something + # - curl something else + + # OPTIONAL. Build your application + buildCommands: + - npm i + - npm run build + + # REQUIRED. Select which files / folders to deploy after + # the build has successfully finished + deployFiles: + - dist + - package.json + - node_modules + + # OPTIONAL. Which files / folders you want to cache for the next build. + # Next builds will be faster when the cache is used. + cache: node_modules + + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: dotnet@latest + + # OPTIONAL. Sets the internal port(s) your app listens on: + ports: + # port number + - port: 5000 + + # OPTIONAL. Customize the runtime .NET environment by installing additional + # dependencies to the base .NET runtime environment. + # prepareCommands: + # - sudo apt-get something + # - curl something else + + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your .NET application is started. + # initCommands: + # - rm -rf ./cache + + # REQUIRED. Your .NET application start command + start: npm start +``` + +The top-level element is always `zerops`. + +### Setup + +The first element `setup` contains the **hostname** of your service. A runtime service with the same hostname must exist in Zerops. +Zerops supports the definition of multiple runtime services in a single `zerops.yaml`. This is useful when you use a monorepo. Just add multiple setup elements in your `zerops.yaml`: + +```yaml +zerops: + # definition for app service + - setup: app + # optional + build: ... + # optional + deploy: ... + # required + run: ... + + # definition for api service - setup: api # optional build: ... @@ -4191,11 +5467,13 @@ Each service configuration contains at least the `run` section. Optional `build` _REQUIRED._ Sets the base technology for the build environment. -Following options are available for Ubuntu builds: +Following options are available for .NET builds: -- `ubuntu@26.04` -- `ubuntu@24.04` -- `ubuntu@22.04`, `ubuntu@latest` +- `dotnet@10`, `dotnet@latest` +- `dotnet@9` +- `dotnet@8` +- `dotnet@7` +- `dotnet@6` ```yaml zerops: @@ -4204,12 +5482,13 @@ zerops: # ==== how to build your application ==== build: # REQUIRED. Sets the base technology for the build environment: - base: ubuntu@26.04 + base: dotnet@6 ... ```

- The base build environment contains {data.ubuntu.default}, [Zerops command line tool](/references/cli), `git` and `wget`. + The base build environment contains {data.alpine.default}, the selected + major version of .NET, [Zerops command line tool](/references/cli), `ASP .NET` and `git`.

:::info @@ -4226,9 +5505,9 @@ zerops: build: # REQUIRED. Sets the base technology for the build environment: base: - - ubuntu@26.04 + - dotnet@6 prepareCommands: - - zsc add nodejs@latest + - zsc add go@latest ... ``` @@ -4240,15 +5519,40 @@ To customize your build environment use the [prepareCommands](#preparecommands) Modifying the base technology will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for more details about cache invalidation. ::: +### os + +_OPTIONAL._ Sets the operating system for the build environment. + +Following options are available: + +- `alpine` +- `ubuntu` + +Default value is `alpine`. + +We are currently using following os version: + +- {data.alpine.default} +- {data.ubuntu.default} + +:::caution +The os version is fixed and cannot be customized. +::: + +:::note +Changing the OS setting will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache behavior. +::: + ### prepareCommands _OPTIONAL._ Customizes the build environment by installing additional dependencies or tools to the base build environment. The base build environment contains: -- {data.ubuntu.default} +- {data.alpine.default} +- selected version of .NET defined in the [base](#base) attribute - [Zerops command line tool](/references/cli) -- `git` and `wget` +- `ASP .NET` and `git` To install additional packages or tools add one or more prepare commands: @@ -4259,7 +5563,7 @@ zerops: # ==== how to build your application ==== build: # REQUIRED. Set the base technology for the build environment: - base: ubuntu@26.04 + base: dotnet@6 # OPTIONAL. Customize the build environment by installing additional packages # or tools to the base build environment. @@ -4283,7 +5587,7 @@ These commands are skipped when using cached environment. Modifying `prepareComm #### Command exit code -If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/ubuntu/how-to/logs#build-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all prepare commands are finished, your custom build environment is ready for the build phase. +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/dotnet/how-to/logs#build-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all prepare commands are finished, your custom build environment is ready for the build phase. #### Single or separated shell instances @@ -4300,11 +5604,11 @@ zerops: # ==== how to build your application ==== build: # REQUIRED. Set the base technology for the build environment: - base: ubuntu@26.04 + base: dotnet@6 # OPTIONAL. Build your application buildCommands: - - + - dotnet build -o app ... ``` @@ -4316,28 +5620,58 @@ Before the build commands are triggered the build container contains: 2. optional customisation of the base environment defined in the [prepareCommands](#preparecommands) attribute 3. your application code -For detailed information about build commands, including how to run commands in single or separate shell instances and command exit code handling, refer to the documentation for your specific technology (e.g., [Node.js](/nodejs/how-to/build-pipeline), [Go](/ubuntu/how-to/build-pipeline), [Python](/python/how-to/build-pipeline), etc.). - -### deployFiles +#### Run build commands as a single shell instance -_REQUIRED._ Selects which files or folders will be deployed after the build has successfully finished. To filter out specific files or folders, use [`.deployignore`](#deployignore) file. +Use following syntax to run all commands in the same environment context. For example, if one command changes the current directory, the next command continues in that directory. When one command creates an environment variable, the next command can access it. ```yaml -# REQUIRED. Select which files / folders to deploy after -# the build has successfully finished -deployFiles: - - app +buildCommands: + - | + sudo apt-get -y install dotnet-runtime-6.0 aspnetcore-runtime-6.0 dotnet-sdk-6.0 # already installed for .NET service + dotnet build -o app ``` -Determines files or folders produced by your build, which should be deployed to your runtime service containers. - -The path starts from the **root directory** of your project (the location of `zerops.yaml`). You must enclose the name in quotes if the folder or the file name contains a space. - -The files/folders will be placed into `/var/www` folder in runtime, e.g. `./src/assets/fonts` would result in `/var/www/src/assets/fonts`. - -#### Examples +#### Run build commands as a separate shell instances -Deploys a folder, and a file from the project root directory: +When the following syntax is used, each command is triggered in a separate environment context. For example, each shell instance starts in the home directory again. When one command creates an environment variable, it won't be available for the next command. + +```yaml +buildCommands: + - sudo apt-get -y install dotnet-runtime-6.0 aspnetcore-runtime-6.0 dotnet-sdk-6.0 # already installed for .NET service + - dotnet build -o app +``` + +#### Command exit code + +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/dotnet/how-to/logs#build-log) to troubleshoot the error. If the error log doesn't contain any specific error message, try to run your build with the `--verbosity ` option. + +```yaml +buildCommands: + - dotnet build --verbosity detailed +``` + +If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `buildCommands` are finished, the application build is completed and ready for the deploy phase. + +### deployFiles + +_REQUIRED._ Selects which files or folders will be deployed after the build has successfully finished. To filter out specific files or folders, use [`.deployignore`](#deployignore) file. + +```yaml +# REQUIRED. Select which files / folders to deploy after +# the build has successfully finished +deployFiles: + - app +``` + +Determines files or folders produced by your build, which should be deployed to your runtime service containers. + +The path starts from the **root directory** of your project (the location of `zerops.yaml`). You must enclose the name in quotes if the folder or the file name contains a space. + +The files/folders will be placed into `/var/www` folder in runtime, e.g. `./src/assets/fonts` would result in `/var/www/src/assets/fonts`. + +#### Examples + +Deploys a folder, and a file from the project root directory: ```yaml deployFiles: @@ -4384,7 +5718,6 @@ deployFiles: ./path/~/to/ :::note Example By default, `./src/assets/fonts` deploys to `/var/www/src/assets/fonts`, keeping the full path. Adding `~`, like `./src/assets/~fonts`, shortens it to `/var/www/fonts` ::: - #### .deployignore Add a `.deployignore` file to the root of your project to specify which files and folders Zerops should ignore during deploy. The syntax follows the same pattern format as [`.gitignore`](https://git-scm.com/docs/gitignore#_pattern_format). @@ -4448,32 +5781,34 @@ zerops: - setup: app # ==== how to build your application ==== build: - base: ubuntu@26.04 + base: dotnet@6 … # OPTIONAL. Defines the env variables for the build environment: envVariables: - MODE: production + DOTNET_ENV: production DB_NAME: db DB_HOST: db DB_USER: db DB_PASS: ${db_password} ``` -Read more about [environment variables](/ubuntu/how-to/env-variables) in Zerops. +Read more about [environment variables](/dotnet/how-to/env-variables) in Zerops. ## Runtime configuration ### base _OPTIONAL._ Sets the base technology for the runtime environment. -If you don't specify the `run.base` attribute, Zerops keeps the current Ubuntu version for your runtime. +If you don't specify the `run.base` attribute, Zerops keeps the current .NET version for your runtime. -Following options are available for Ubuntu builds: +Following options are available for .NET builds: -- `ubuntu@26.04` -- `ubuntu@24.04` -- `ubuntu@22.04`, `ubuntu@latest` +- `dotnet@10`, `dotnet@latest` +- `dotnet@9` +- `dotnet@8` +- `dotnet@7` +- `dotnet@6` ```yaml zerops: @@ -4482,18 +5817,19 @@ zerops: # ==== how to build your application ==== build: # REQUIRED. Sets the base technology for the build environment: - base: ubuntu@26.04 + base: dotnet@6 ... # ==== how to run your application ==== run: # OPTIONAL. Sets the base technology for the runtime environment: - base: ubuntu@26.04 + base: dotnet@6 ... ```

- The base runtime environment contains {data.ubuntu.default}, Zerops command line tool, `git` and `wget`. + The base runtime environment contains {data.alpine.default}, the + selected major version of .NET, [Zerops command line tool](/references/cli) and `ASP .NET` and `git`.

:::info @@ -4509,16 +5845,16 @@ zerops: # ==== how to build your application ==== build: # REQUIRED. Sets the base technology for the build environment: - base: ubuntu@26.04 + base: dotnet@6 ... # ==== how to run your application ==== run: # OPTIONAL. Sets the base technology for the runtime environment: base: - - ubuntu@26.04 + - dotnet@6 prepareCommands: - - zsc add nodejs@latest + - zsc add go@latest ... ``` @@ -4526,13 +5862,33 @@ See the full list of supported [run base environments](/zerops-yaml/base-list). To customise your build environment use the `prepareCommands` attribute. +### os + +_OPTIONAL._ Sets the operating system for the runtime environment. + +Following options are available: + +- `alpine` +- `ubuntu` + +Default value is `alpine`. + +We are currently using following os version: + +- {data.alpine.default} +- {data.ubuntu.default} + +:::caution +The os version is fixed and cannot be customised. +::: + ### ports _OPTIONAL._ Specifies one or more internal ports on which your application will listen. Projects in Zerops represent a group of one or more services. Services can be of different types (runtime services, databases, message brokers, object storage, etc.). All services of the same project share a **dedicated private network**. To connect to a service within the same project, just use the service hostname and its internal port. -For example, to connect to a Ubuntu service with hostname = "app" and port = 8080 from another service of the same project, simply use `app:8080`. Read more about [how to access a Ubuntu service](/references/networking/internal-access#basic-service-communication). +For example, to connect to a .NET service with hostname = "app" and port = 5000 from another service of the same project, simply use `app:5000`. Read more about [how to access a .NET service](/references/networking/internal-access#basic-service-communication). Each port has following attributes: @@ -4561,10 +5917,12 @@ Each port has following attributes: ### prepareCommands -_OPTIONAL._ Customises the Ubuntu runtime environment by installing additional dependencies or tools to the runtime base environment. +_OPTIONAL._ Customises the .NET runtime environment by installing additional dependencies or tools to the runtime base environment.

- The base Ubuntu environment contains {data.ubuntu.default}, [Zerops command line tool](/references/cli) and `git` and `wget`. To install additional packages or tools add one or more prepare commands: + The base .NET environment contains {data.alpine.default}, the selected + major version of .NET, [Zerops command line tool](/references/cli) and `ASP .NET` and `git`. To install additional packages + or tools add one or more prepare commands:

```yaml @@ -4578,7 +5936,7 @@ zerops: # ==== how to run your application ==== run: # OPTIONAL. Customise the runtime environment by installing additional packages - # or tools to the base Ubuntu runtime environment. + # or tools to the base .NET runtime environment. prepareCommands: - sudo apt-get something - curl something else @@ -4597,7 +5955,7 @@ When the first deploy with a defined prepare attribute is triggered, Zerops will #### Command exit code -If any command fails, it returns an exit code other than 0 and the deploy is canceled. Read the [prepare runtime log](/ubuntu/how-to/logs#prepare-runtime-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `prepareCommands` commands are finished, your custom runtime environment is ready for the deploy phase. +If any command fails, it returns an exit code other than 0 and the deploy is canceled. Read the [prepare runtime log](/dotnet/how-to/logs#prepare-runtime-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `prepareCommands` commands are finished, your custom runtime environment is ready for the deploy phase. #### Cache of your custom runtime environment @@ -4617,7 +5975,10 @@ You can configure your prepare commands to be run in a single shell instance or ### Copy folders or files from your build container

- The prepare runtime container contains {data.ubuntu.default}, [Zerops command line tool](/references/cli) and `git` and `wget`. + The prepare runtime container contains {data.alpine.default}, the + selected major version of .NET, + [Zerops command line tool](/references/cli) and + `ASP .NET` and `git`.

The prepare runtime container does not contain your application code nor the built application. If you need to copy some folders or files from the build container to the runtime container (e.g. a configuration file) use the `addToRunPrepare` attribute in the [build section](#build-pipeline-configuration). @@ -4634,7 +5995,7 @@ zerops: # ==== how to run your application ==== run: # OPTIONAL. Customise the runtime environment by installing additional packages - # or tools to the base Ubuntu runtime environment. + # or tools to the base .NET runtime environment. prepareCommands: - sudo apt-get something - curl something else @@ -4658,12 +6019,12 @@ zerops: run: # OPTIONAL. Run one or more commands each time a new runtime container # is started or restarted. These commands are triggered before - # your Ubuntu application is started. + # your .NET application is started. initCommands: - rm -rf ./cache ``` -These commands are triggered in the runtime container before your Ubuntu application is started via the [start command](#start). +These commands are triggered in the runtime container before your .NET application is started via the [start command](#start). :::note `run.initCommands` run in the `/var/www` directory. @@ -4672,14 +6033,14 @@ These commands are triggered in the runtime container before your Ubuntu applica Use init commands to clean or initialise your application cache or similar operations. :::caution -The init commands will delay the start of your application each time a new runtime container is started (including the horizontal [scaling](/ubuntu/how-to/scaling) or when a runtime container is restarted). +The init commands will delay the start of your application each time a new runtime container is started (including the horizontal [scaling](/dotnet/how-to/scaling) or when a runtime container is restarted). Do not use the init commands for customising your runtime environment. Use the [run:prepareCommands](#preparecommands-1) attribute instead. ::: #### Command exit code -If any of the `initCommands` fails, it returns an exit code other than 0, but deploy is **not** canceled. After all init commands are finished, regardless of the status code, the application is started. Read the [runtime log](/ubuntu/how-to/logs#runtime-log) to troubleshoot the error. +If any of the `initCommands` fails, it returns an exit code other than 0, but deploy is **not** canceled. After all init commands are finished, regardless of the status code, the application is started. Read the [runtime log](/dotnet/how-to/logs#runtime-log) to troubleshoot the error. #### Single or separated shell instances @@ -4699,18 +6060,18 @@ zerops: run: # OPTIONAL. Defines the env variables for the runtime environment: envVariables: - MODE: production + DOTNET_ENV: production DB_NAME: db DB_HOST: db DB_USER: db DB_PASS: ${db_password} ``` -Read more about [environment variables](/ubuntu/how-to/env-variables) in Zerops. +Read more about [environment variables](/dotnet/how-to/env-variables) in Zerops. ### start -_OPTIONAL._ Defines the start command for your Ubuntu application. +_REQUIRED._ Defines the start command for your .NET application. ```yaml zerops: @@ -4721,8 +6082,8 @@ zerops: # ==== how to run your application ==== run: - # OPTIONAL. Your Ubuntu application start command - start: ./app + # REQUIRED. Your .NET application start command + start: cd app && dotnet dnet.dll ``` ### health check @@ -4778,8 +6139,8 @@ zerops: # ==== how to run your application ==== run: - # OPTIONAL. Your Ubuntu application start command - start: ./app + # REQUIRED. Your .NET application start command + start: cd app && dotnet dnet.dll # OPTIONAL. Define a health check with a HTTP GET request option. # Configures the check on http://127.0.0.1:80/status @@ -4807,7 +6168,7 @@ Following attributes are available: Defines a local command to be run. - The command has access to the same [environment variables](/ubuntu/how-to/create#set-secret-environment-variables) as your Ubuntu application. + The command has access to the same [environment variables](/dotnet/how-to/create#set-secret-environment-variables) as your .NET application. A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. @@ -4826,8 +6187,8 @@ zerops: # ==== how to run your application ==== run: - # REQUIRED. Your Ubuntu application start command - start: ./app + # REQUIRED. Your .NET application start command + start: cd app && dotnet dnet.dll # OPTIONAL. Define a health check with a shell command. healthCheck: @@ -4864,7 +6225,7 @@ Read more about setting up [cron](/zerops-yaml/cron) in Zerops. ### readiness check -_OPTIONAL._ Defines a readiness check. Read more about how the [readiness check works](/ubuntu/how-to/deploy-process#readiness-checks) in Zerops. +_OPTIONAL._ Defines a readiness check. Read more about how the [readiness check works](/dotnet/how-to/deploy-process#readiness-checks) in Zerops. `readinessCheck` requires either one `httpGet` object or one `exec` object. @@ -4926,7 +6287,7 @@ zerops: run: ... ``` -Read more about how the [readiness check works](/ubuntu/how-to/deploy-process#readiness-checks) in Zerops. +Read more about how the [readiness check works](/dotnet/how-to/deploy-process#readiness-checks) in Zerops. #### exec @@ -4946,7 +6307,7 @@ Following attributes are available: Defines a local command to be run. - The command has access to the same [environment variables](/ubuntu/how-to/create#set-secret-environment-variables) as your Ubuntu application. + The command has access to the same [environment variables](/dotnet/how-to/create#set-secret-environment-variables) as your .NET application. A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. @@ -4975,1367 +6336,1573 @@ zerops: mv /outside/user /home/user ``` -Read more about how the [readiness check works](/ubuntu/how-to/deploy-process#readiness-checks) in Zerops. +Read more about how the [readiness check works](/dotnet/how-to/deploy-process#readiness-checks) in Zerops. ---------------------------------------- -# Typesense > Overview +# Dotnet > How To > Build Process -Zerops provides a fully managed [Typesense search engine](https://typesense.org/) service that combines developer productivity with enterprise-grade reliability. The platform handles infrastructure complexity through automated deployment, scaling, and maintenance while providing developers full access to Typesense's native capabilities. -## Supported Versions +---------------------------------------- -Currently supported Typesense version: +# Dotnet > How To > Controls -Import configuration version: -- `typesense@27.1` -## Service Configuration +---------------------------------------- -Our Typesense implementation comes with carefully tuned defaults that diverge from the [standard Typesense configuration](https://typesense.org/docs/27.1/api/server-configuration.html#using-command-line-arguments) in the following ways: +# Dotnet > How To > Create -```yaml -thread-pool-size: 16 -num-collections-parallel-load: 8 -``` -These defaults are optimized for most common use cases and managed by the platform. If you need to adjust these settings, please contact us through our [support channels](#support). +Zerops provides a .NET runtime service with extensive build support. .NET runtime is highly scalable and customisable to suit both development and production. -### Data Persistence +## Create .NET service using Zerops GUI -Typesense data is automatically persisted to disk at `/var/lib/typesense`. +First, set up a project in Zerops GUI. Then go to the project dashboard page and choose **Add new service** in the left menu in the **Services** block. Then add a new .NET service: -This ensures that data remains intact during service restarts (Typesense automatically reloads the persisted data into memory upon startup). +[Video: /vids/services/dotnet.webm](/vids/services/dotnet.webm) -This persistence mechanism works in both HA and non-HA deployment modes, though with different reliability guarantees as detailed below. +### Choose .NET version -### Deployment Modes +Following .NET versions are currently supported: -:::warning -The choice between HA and non-HA mode must be made during service creation and cannot be changed later. Make sure to carefully consider your requirements before deploying. +:::info +You can [change](/dotnet/how-to/upgrade) the major version at any time later. ::: -#### Non-HA Mode -- Suitable for development and testing -- Data persistence not guaranteed during node failures -- Lower resource requirements +### Set a hostname -#### HA Mode -- Implements Typesense's native [**Raft consensus**](https://typesense.org/docs/guide/high-availability.html) mechanism for data replication -- Deploys as a **3-node cluster by default** for optimal reliability - - Scaling configuration of 3-5 or 3-7 nodes for higher workloads is possible upon request (contact [support](#support) to configure custom node ranges) -- Includes **built-in data synchronization** across all nodes -- Features **automatic leader election** to maintain cluster availability - - Recovery typically takes up to 1 minute during node failures or leader transitions - - During these periods, requests may temporarily receive `503 Not Ready or Lagging` or `500 Could not find a leader` responses - - These states automatically resolve once consensus is reestablished +Enter a unique service identifier like "app","cache", "gui" etc. Duplicate services with the same name in the same project are forbidden. -### API Key Management +#### Limitations: -The master API key is automatically generated and managed by the platform. You can access it through: -- The service access details in the Zerops GUI -- The `apiKey` environment variable in your service configuration +- maximum 25 characters +- must contain only lowercase ASCII letters (a-z) or numbers (0-9) -:::warning -Currently, as a security-focused design decision, the master API key cannot be modified after generation. +:::caution +The hostname is fixed after the service is created. It can't be changed later. ::: -### CORS Configuration - -Your Typesense instance comes with CORS enabled by default, ensuring seamless integration with frontend applications. Browser-based clients can directly access the instance by providing the `X-Typesense-Api-Key` header, maintaining security while enabling straightforward client-side implementation. - -## Network Architecture & Access Patterns - -### Access Methods - -#### HTTPS Access +### Set secret environment variables -When using HTTPS access (either through Zerops subdomain or custom domain), traffic is distributed across nodes via our integrated Nginx proxy layer. This provides a single access point that handles load balancing automatically. +Add environment variables with sensitive data, such as password, tokens, salts, certificates etc. These will be securely saved inside Zerops and added to your runtime service upon start. -For enabling HTTPS access: -1. Configure through the [Zerops access documentation](/features/access) -2. Or use `enableSubdomainAccess: true` when [importing](/references/import#service-configuration) a Typesense service +Setting the secret environment variables is optional. You can set them later in Zerops GUI. -#### Direct Node Access +Read more about [different types of env variables](/dotnet/how-to/env-variables#service-env-variables) in Zerops. -Allows to access individual nodes using internal DNS: -1. **Via [Zerops VPN](/references/networking/vpn)** -2. **Internal Project Access** - services within the same project can reach nodes directly +## Create .NET service using zCLI -Node addressing patterns: -##### Standard format -**Format:**```node{n}.db.{hostname}.zerops``` -- e.g. `node1.db.typesenseha.zerops`, `node2.db.typesenseha.zerops` -##### Stable DNS records -**Format:**```node-stable-{n}.db.{hostname}.zerops``` -- **maintain consistent IP mapping** until node retirement (scaling down or failure events) -- e.g. `node-stable-1.db.typesenseha.zerops`, `node-stable-2.db.typesenseha.zerops` +zCLI is the Zerops command-line tool. To create a new .NET service via the command-line, follow these steps: -## Quick Start Example +1. [Install & setup zCLI](/references/cli) +2. [Create a project description file](/dotnet/how-to/create#create-a-project-description-file) +3. [Create a project with a .NET and PostgreSQL service](#full-example) -Here's a simple example of using Typesense with the JavaScript client: +### Create a project description file -```javascript +Zerops uses a yaml format to describe the project infrastructure. -const client = new TypesenseClient({ - nodes: [{ - host: 'your-service.zerops.dev', // Your Zerops subdomain - port: '443', - protocol: 'https' - }], - apiKey: process.env.TYPESENSE_API_KEY, - connectionTimeoutSeconds: 2 -}) +#### Basic example: -// Create a collection -await client.collections().create({ - name: 'companies', - fields: [ - { name: 'company_name', type: 'string' }, - { name: 'num_employees', type: 'int32' }, - { name: 'country', type: 'string', facet: true } - ], - default_sorting_field: 'num_employees' -}) +Create a directory `my-project`. Create an `description.yaml` file inside the `my-project` directory with following content: -// Example search query -const searchResults = await client.collections('companies') - .documents() - .search({ - q: 'tech', - query_by: 'company_name', - filter_by: 'country:=USA', - sort_by: 'num_employees:desc' - }) +```yaml +# basic project data +project: + # project name + name: my-project +# array of project services +services: + - # service name + hostname: app + # service type and version number in dotnet@6 format + type: dotnet@6 + # defines the minimum number of containers for horizontal autoscaling + minContainers: 1 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 6 + # optional: create env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' ``` -## Best Practices - -#### API Key Security -- Never expose the master API key in client-side code -- Generate scoped search-only API keys for frontend applications -- Rotate API keys periodically through your service configuration - -#### High Availability -- Implement retry logic in clients for handling temporary unavailability -- Use stable DNS records for direct node access when needed - -#### Performance Optimization -- Utilize batch operations for bulk updates -- Configure appropriate timeout values based on your use case -- Consider data volume when designing collection schemas - -## Support - -For advanced configurations or custom requirements: -- Join our [Discord community](https://discord.gg/zeropsio) -- Contact support via [email](mailto:support@zerops.io) +The yaml file describes your future project infrastructure. The project will contain one .NET version 6 service with default [auto scaling](/dotnet/how-to/scaling) configuration. Hostname will be set to "app", the internal port(s) the service listens on will be defined later in the [zerops.yaml](/dotnet/how-to/build-pipeline#ports). Following secret env variables will be configured: ----------------------------------------- +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" +``` -# Storage > Overview +#### Full example: +Create a directory my-project. Create an description.yaml file inside the my-project directory with following content: -Runtime containers on Zerops are **volatile**. Anything your application needs to keep must live outside the container — in a [managed database](/postgresql/overview), or in one of the storage services described on this page. +```yaml +# basic project data +project: + # project name + name: my-project + # optional: project description + description: A project with a .NET and PostgreSQL database + # optional: project tags + tags: + - DEMO + - ZEROPS +# array of project services +services: + - # service name + hostname: app + # service type and version number in dotnet@6 format + type: dotnet@6 + # optional: vertical auto scaling customization + verticalAutoscaling: + cpuMode: DEDICATED + minCpu: 2 + maxCpu: 5 + minRam: 2 + maxRam: 24 + minDisk: 6 + maxDisk: 50 + startCpuCoreCount: 3 + minFreeRamGB: 0.5 + minFreeRamPercent: 20 + # defines the minimum number of containers for horizontal autoscaling. Max value = 6. + minContainers: 2 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 4 + # optional: create secret env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' + - # second service hostname + hostname: db + # service type and version number in postgresql@{version} format + type: postgresql@12 + # mode of operation "HA"/"non_HA" + mode: NON_HA +``` -## Container filesystem is volatile +The yaml file describes your future project infrastructure. The project will contain a .NET service and a [PostgreSQL](/postgresql/overview) service. -The filesystem of a runtime container survives a restart, a reload, and a stop and start, but that is all: +.NET service with "app" hostname, the internal port(s) the service listens on will be defined later in the [zerops.yaml](/dotnet/how-to/build-pipeline#ports). .NET service will run on version 6 with a custom vertical and horizontal scaling. Following secret env variables will be configured: -- **Every deploy replaces the containers.** The new containers contain only the [`deployFiles`](/zerops-yaml/specification#deployfiles-) of the new build; whatever the previous containers wrote to disk is gone. -- **Containers are replaced when the service scales.** Scaling horizontally creates and removes containers, each with its own disk. -- **Containers do not share a filesystem.** A file written in one container is not visible in the others of the same service. +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" +``` -Use the container disk for temporary and scratch files only. Everything else — uploads, generated files, application state, anything shared between containers — belongs in a storage service or a database. +The hostname of the PostgreSQL service will be set to "db". The [single container](/features/scaling#single-container-mode) mode will be chosen and the default auto [scaling configuration](/postgresql/how-to/scale#configure-scaling) will be set. -## Storage services +#### Description of description.yaml parameters -Zerops offers three storage services. The first word of each name tells you the access model: +The `project:` section is required. Only one project can be defined. - - - - + + + - - - - + + + - - - - + + + - - - - + + +
ServiceAccess modelSemanticsHAParameterDescriptionLimitations
[Object Storage](/object-storage/overview)S3 API over the networkObject semantics; best price and durability for uploads, media, and backupsYesnameThe name of the new project. Duplicates are allowed.
[Local Storage](/local-storage/overview)Locally attached disk, single machineFull single-kernel POSIX: locking, mmap, inotify across all connected containersNot yetdescriptionOptional. Description of the new project.Maximum 255 characters.
[SeaweedFS](/seaweedfs/overview)Network filesystem, mounted or accessed over HTTP by your servicesPOSIX-like with network filesystem caveats (per-mount locks, write amplification)YestagsOptional. One or more string tags. Tags do not have a functional meaning, they only provide better orientation in projects.
-## Which one to use +At least one service in `services:` section is required. You can create a project with multiple services. The example above contains .NET and PostgreSQL services but you can create a `description.yaml` with your own combination of [services](/features/infrastructure). -- **Uploads, media, backups, logs, exports** — [Object Storage](/object-storage/overview). Highly available, cheapest per GB, and independent of any runtime service; the default for most application data. -- **Anything that needs a real filesystem** — [Local Storage](/local-storage/overview). SQLite and other embedded databases, single-node stateful apps such as Prometheus or Gitea, and filesystem state shared between services (certificates, caches). It is the only storage type where lock-dependent workloads are safe; see its [trade-offs](/local-storage/overview#key-trade-offs). -- **Files shared between containers over the network, with high availability** — [SeaweedFS](/seaweedfs/overview). Zerops runs the managed cluster, your services mount it with `weed mount` from their start commands or talk to its filer HTTP API. Not for databases, see its [storage engine behavior](/seaweedfs/overview#storage-engine-behavior). -- **Existing Shared Storage setups** — the service is already a SeaweedFS service. Take over the mount with the [SeaweedFS migration guide](/seaweedfs/how-to/migrate-from-shared-storage), or move the data to Local Storage with [its guide](/local-storage/how-to/migrate-from-shared-storage). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
hostname + The unique service identifier. -For structured data, use a [managed database](/postgresql/overview) rather than files on any storage. + The hostname of the new database will be set to the `hostname` value. -- [Object Storage](/object-storage/overview) — S3 compatible storage for uploads, media, and backups. -- [Local Storage](/local-storage/overview) — Persistent local disk volume with full POSIX semantics. -- [SeaweedFS](/seaweedfs/overview) — Managed distributed filesystem you mount from your services. + Limitations: +
    +
  • duplicate services with the same name in the same project are forbidden
  • +
  • maximum 25 characters
  • +
  • must contain only lowercase ASCII letters (a-z) or numbers (0-9)
  • +
+
type + Specifies the service type and version. -## Need help? + See what [.NET service types](/references/import-yaml/type-list#runtime-services) are currently supported. +
verticalAutoscaling + Optional. Defines [custom vertical auto scaling parameters](/dotnet/how-to/create#set-auto-scaling-configuration). -Stuck, or want to share what you built? Our core team and community are on Discord. + All verticalAutoscaling attributes are optional. Not specified attributes will be set to their default values. +
- cpuMode + Optional. Accepts `SHARED`, `DEDICATED` values. Default is `SHARED` +
- minCpu/maxCpu + Optional. Set the minCpu or maxCpu in CPU cores (integer). +
- minRam/maxRam + Optional. Set the minRam or maxRam in GB (float). +
- minDisk/maxDisk + Optional. Set the minDisk or maxDisk in GB (float). +
minContainers + Optional. Default = 1. Defines the minimum number of containers for [horizontal autoscaling](/dotnet/how-to/create#horizontal-auto-scaling). -- [Discord](https://discord.com/invite/WDvCZ54) — Join the Zerops community on Discord. Ask questions and share your tips. -- [zCLI](/references/cli) — Get more out of Zerops with the command-line tool. + Limitations: + Current maximum value = 10. +
maxContainers + Defines the maximum number of containers for [horizontal autoscaling](/dotnet/how-to/create#horizontal-auto-scaling). ----------------------------------------- + Limitations: -# Static > Overview + Current maximum value = 10. +
envSecrets + Optional. Defines one or more secret env variables as a key value map. See env variable [restrictions](/dotnet/how-to/env-variables#env-variable-restrictions). +
+### Create a project based on the description.yaml -The Static service serves static files (HTML, CSS, JavaScript, images, the build output of any frontend framework) through a pre-configured Nginx. You describe redirects, headers and CORS declaratively in `zerops.yaml` and Zerops generates the Nginx configuration for you. +When you have your `description.yaml` ready, use the `zcli project project-import` command to create a new project and the service infrastructure. -### Experience the simplicity of Zerops +```sh +Usage: + zcli project project-import importYamlPath [flags] -Deploy an Analog app with static hosting in seconds. All you need is a Zerops account. +Flags: + -h, --help Help for the project import command. + --org-id string If you have access to more than one organization, you must specify the org ID for which the + project is to be created. + --working-dir string Sets a custom working directory. Default working directory is the current directory. (default "./") +``` - [Deploy "analog" recipe on Zerops](https://app.zerops.io/recipe/?lf=analog) +Zerops will create a project and one or more services based on the `description.yaml` content. -## Static or Nginx service? +Maximum size of the `description.yaml` file is 100 kB. -Zerops offers two services for static content. Both run Nginx, but they are configured differently and support different `zerops.yaml` attributes: +You don't specify the project name in the `zcli project project-import` command, because the project name is defined in the `description.yaml`. -| | Static service | [Nginx service](/nginx/overview) | -|---|---|---| -| `run.base` | `alpine/static` or `ubuntu/static` | `alpine/nginx@latest` or `ubuntu/nginx@latest` | -| Nginx configuration | Generated from `run.routing` | Built-in default, or your own file via `run.siteConfigPath` | -| Redirects, custom headers, CORS | Declarative `run.routing` | Written by you in the Nginx configuration | -| Fallback for missing paths | `/index.html` (SPA friendly), plus extensionless `.html` pages | `/index.html` | -| Prerender.io for crawlers | Built in, enabled by `PRERENDER_TOKEN` | Not built in | -| Reverse proxy (`proxy_pass`), caching, rate limiting, other ports | Not available | Anything Nginx can do, in your own configuration | -| Document root | `run.routing.root` | `run.documentRoot` | -| Document root | `run.routing.root` | `run.documentRoot` | +If you have access to more than one client, you must specify the client ID for which the project is to be created. The `clientID` is located in the Zerops GUI under the client name on the project dashboard page. -Choose **Static** when you deploy framework build output or plain files and need at most redirects, headers and CORS. Choose **Nginx** when you need Nginx directives that `routing` cannot express, typically proxying to another service, response caching, or listening on additional ports. +### Add .NET service to an existing project -:::caution Attributes are not interchangeable -- `run.routing` is read only by the Static service. On any other service, including Nginx, it is silently ignored. -- `run.documentRoot` is ignored by the Static service. Use `run.routing.root` instead. -::: +#### Example: -:::tip Sending paths to another service -You do not need an Nginx service just to send `/api` to a backend. [Domain access routing](/references/networking/public-access#http-routing-setup) on the project's L7 balancer maps public paths to services and ports, so a Static frontend and an API can share one domain. -::: +Create a directory `my-project` if it doesn't exist. Create an `import.yaml` file inside the `my-project` directory with following content: -## Quick Start +```yaml +# basic project data +project: + # project name + name: my-project +# array of project services +services: + - # service name + hostname: app + # service type and version number in dotnet@6 format + type: dotnet@6 + # defines the minimum number of containers for horizontal autoscaling + minContainers: 1 + # defines the maximum number of containers for horizontal autoscaling. Max value = 6. + maxContainers: 6 + # optional: create env variables + envSecrets: + S3_ACCESS_KEY_ID: 'P8cX1vVVb' + S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' +``` -Build your frontend with any runtime and hand the output to the Static service: +The yaml file describes the list of one or more services that you want to add to your existing project. In the example above, one .NET service version 6 with default [auto scaling](/dotnet/how-to/scaling) configuration will be added to your project. Hostname of the new service will be set to `app`. Following secret env variables will be configured: -```yaml title="zerops.yaml" -zerops: - - setup: app - build: - base: nodejs@latest - buildCommands: - - npm i - - npm run build - deployFiles: - - dist/~ # deploy the *contents* of dist to /var/www - run: - base: alpine/static +```env +S3_ACCESS_KEY_ID="P8cX1vVVb" +S3_ACCESS_SECRET="ogFthuiLYki8XoL73opSCQ" ``` -The `~` in `dist/~` deploys the contents of `dist` directly into `/var/www`, so `index.html` ends up at the document root. If you deploy the folder as a whole (`deployFiles: - dist`), point the service at it with [`routing.root: dist`](#document-root). - -If your files are already built, skip the `build` section and [deploy them with zCLI](/references/cli). +The content of the `services:` section of `import.yaml` is identical to the project description file. The `import.yaml` never contains the `project:` section because the project already exists. -The base carries the operating system: `alpine/static` or `ubuntu/static`. The bare shorthand `static` is accepted and means `alpine/static`. +When you have your `import.yaml` ready, use the `zcli project service-import` command to add one or more services to your existing Zerops project. -## How requests are served +```sh +Usage: + zcli project service-import importYamlPath [flags] -The generated configuration serves files from the [document root](#document-root) and resolves every request in this order: +Flags: + -h, --help Help for the project service import command. + -P, --project-id string If you have access to more than one project, you must specify the project ID for which the + command is to be executed. +``` -1. The exact path (`$uri`) -2. The path with `.html` appended (`$uri.html`), so `/about` serves `about.html` -3. `index.html` inside the directory (`$uri/index.html`), so `/docs` serves `docs/index.html` -4. `/index.html`, which makes client-side routing of Single Page Applications work -5. HTTP 404 if `/index.html` does not exist either +zCLI commands are interactive, when you press enter after `zcli project service-import importYamlPath`, you will be given a list of your projects to choose from. -Other built-in behavior: +Maximum size of the import.yaml file is 100 kB. -- The service listens on port 80 only. HTTPS is terminated on the Zerops balancer and forwarded as plain HTTP. -- Everything under `/.git` returns 404. -- Gzip compression is enabled for text-based content types. -- Prerender.io is wired in and becomes active once `PRERENDER_TOKEN` is set, see [SEO with Prerender](#seo-with-prerender). -:::important SPAs -Single Page Applications work out of the box. No redirects are needed for client-side routing. A consequence of the fallback is that a request for a nonexistent path returns `/index.html` with status 200, not 404. -::: +---------------------------------------- -## Document root +# Dotnet > How To > Customize Runtime -By default files are served from `/var/www`, the folder your `deployFiles` land in. To serve a subfolder, set `run.routing.root`. The path is relative to `/var/www`: -```yaml title="zerops.yaml" -run: - base: alpine/static - routing: - root: dist # serves /var/www/dist -``` -:::caution -`run.documentRoot` has no effect on the Static service. It is only used by the [Nginx](/nginx/how-to/build-pipeline#documentroot) and PHP services (and inside a [custom `.tmpl` configuration](#custom-nginx-configuration)). -::: +---------------------------------------- -## Routing & Configuration +# Dotnet > How To > Deploy Process -Configure redirects, headers and CORS in the `run.routing` section of your `zerops.yaml`: -```yaml title="zerops.yaml" -run: - base: alpine/static - routing: - root: dist - cors: "*" - redirects: - - from: /special-path/* - to: /specific-landing-page - status: 302 - headers: - - for: "/*" - values: - X-Frame-Options: "'DENY'" -``` -Zerops turns this into `location` blocks inside the generated Nginx configuration. Every deploy regenerates the configuration, so `routing` changes take effect on the next deploy. +---------------------------------------- -### Path matching +# Dotnet > How To > Env Variables -The `from` field of a redirect and the `for` field of a header rule use the same matching rules: -- **Without a wildcard** (`/about`) the rule matches that exact path only. `/about?x=1` matches (the query string is not part of the path), `/about/` and `/about/team` do not. -- **With a trailing `*`** (`/blog/*`) the rule matches the path prefix. `/blog/`, `/blog/post` and `/blog/2024/post.html` all match. `/blog` without the trailing slash does not. -- `*` is only supported at the end of a path. Patterns such as `/*.html` or `/*/edit` are not supported. -- When several rules match, an exact rule wins over a prefix rule, and the longest matching prefix wins among prefix rules. -- Path rules apply to paths only. Redirects between domains use [absolute redirects](#absolute-redirects), which are evaluated before any path rule. -`/*` matches everything and is the rule to use when you want a header on all responses. +---------------------------------------- -### Redirects +# Dotnet > How To > Filebrowser -#### Relative Redirects -:::note -Remember that SPA routing is already built into the default behavior. You don't need to add any custom redirects for client-side routing to work. -::: -When both `from` and `to` are paths, the redirect is relative. Omitting `status` creates a **masked redirect**: the content of the target is served while the URL in the browser stays the same. With a `status`, the browser receives an HTTP redirect to the target: +---------------------------------------- -```yaml title="zerops.yaml" -routing: - redirects: - # Masked redirect - URL stays the same but shows content from about-us - - from: /about - to: /about-us +# Dotnet > How To > Logs - # Standard redirect with status code - - from: /old-page - to: /new-page - status: 301 - # Preserve the path when redirecting between directories - - from: /blog/* - to: /articles/ - preservePath: true - status: 302 - # Preserve both path and query parameters - - from: /posts/* - to: /blog/ - preservePath: true - preserveQuery: true - status: 302 -``` +---------------------------------------- -- `status` can be any redirect code, typically `301`, `302`, `307` or `308`. -- `preservePath` appends the part of the path after the wildcard to `to`. `/blog/*` to `/articles/` redirects `/blog/hello.html` to `/articles/hello.html`. End `to` with a `/`, otherwise the result is `/articleshello.html`. -- `preserveQuery` appends the original query string. Without it the query string is dropped. -- A masked redirect serves the target through the [default rules](#how-requests-are-served), so `to: /about-us` may resolve to `about-us.html` or `about-us/index.html`. -- `preservePath` and `preserveQuery` are not allowed on masked redirects. Setting them fails the deploy with `Preserve path must not be set for masked redirects`. A masked redirect for a prefix (`from: /legacy/*`) simply serves the same `to` for every matching path. +# Dotnet > How To > Scaling -#### Absolute Redirects -Use absolute URLs (`http://` or `https://`) to redirect between domains or to an external site. Absolute redirects require a `status`. -A redirect with an **absolute `to`** and a path `from` works like a relative redirect, only the destination is external. Any status code is allowed: +---------------------------------------- -```yaml title="zerops.yaml" -routing: - redirects: - # /docs/getting-started -> https://docs.example.com/getting-started - - from: /docs/* - to: https://docs.example.com/ - status: 301 - preservePath: true -``` +# Dotnet > How To > Trigger Pipeline -A redirect with an **absolute `from`** matches on the domain of the request, which is why it only makes sense for domains that are [pointed at this service](/references/networking/public-access#custom-domain-access). It is evaluated before any path rule and supports `status` `301` or `302` only: -```yaml title="zerops.yaml" -routing: - redirects: - # Redirect an old domain to a new one, keeping the query string - - from: https://old-domain.com/* - to: https://new-domain.com - status: 301 - preserveQuery: true - # Redirect with path preservation: https://old-site.com/blog/x -> https://new-site.com/blog/x - - from: https://old-site.com/* - to: https://new-site.com - status: 301 - preservePath: true -``` +---------------------------------------- -- With an absolute `from`, `preservePath` appends the complete request path (it always starts with `/`), so do **not** end `to` with a `/`. -- The domain match is a case-insensitive substring match on `host + path`. `https://old-domain.com/*` therefore also matches `www.old-domain.com` and every other subdomain of `old-domain.com`. -- `https://*.old-domain.com/*` matches subdomains of `old-domain.com` only, not `old-domain.com` itself. -- `https://old-domain.com/` without the trailing `*` matches the root path of that domain only. +# Dotnet > How To > Upgrade -#### Wildcard Matching -Use `*` as a wildcard: -- **At the end of a path** it matches the path prefix, see [path matching](#path-matching). -- **At the start of a domain** in an absolute `from` (`https://*.domain.com/*`) it matches all subdomains. -Example of domain management: +---------------------------------------- -```yaml title="zerops.yaml" -run: - routing: - redirects: - # Redirect a specific domain (and its subdomains) to an article - - from: https://promo-domain.com/* - to: https://main-site.com/special-offer - status: 302 +# Dotnet > Overview - # Redirect only subdomains of old-domain.com to the main site - - from: https://*.old-domain.com/* - to: https://main-site.com - status: 302 -``` -#### Matching Priority +[.NET ↗](https://dotnet.microsoft.com/en-us/) is the free, open-source, cross-platform framework for building modern apps and powerful cloud services.. -Rules are matched in this order: +As said, there is no need for coding yet, we have created a [Github repository ↗](https://github.com/zeropsio/recipe-dotnet-hello-world), a **_recipe_**, containing the most simple .NET web application. The repo will be used as a source from which the app will be built. -1. Absolute redirects (matched on the request domain) -2. Exact path rules (`from` without a wildcard) -3. Prefix rules (`from` ending with `*`), longest prefix first -4. The [default behavior](#how-requests-are-served) for everything else +### 🚀 Feel free to deploy the recipe yourself -For example: +This is the most bare-bones example of .NET running in Zerops — as few libraries as possible, + just a simple endpoint with connect, read and write to a Zerops PostgreSQL database. -```yaml title="zerops.yaml" -routing: - redirects: - # Exact match for homepage - standard redirect - - from: / - to: /home - status: 302 + [Deploy "dotnet" recipe on Zerops](https://app.zerops.io/recipe/?lf=dotnet) - # Exact match - masked redirect - - from: /about - to: /about-us +1. Log in/sign up to [Zerops GUI ↗](https://app.zerops.io) +2. In the **Projects** box click on **Import a project** and paste in the following YAML config ([source ↗](https://github.com/zeropsio/recipe-dotnet-hello-world/blob/main/import-project/description.yaml)): - # Prefix match with path preservation - - from: /blog/* - to: /articles/ - preservePath: true - status: 302 +```yaml +project: + name: my-first-project +services: + - hostname: helloworld + type: dotnet@latest + minContainers: 1 + maxContainers: 3 + buildFromGit: https://github.com/zeropsio/recipe-dotnet-hello-world@main + enableSubdomainAccess: true ``` -In this configuration: -- `/` redirects to `/home` with a 302 status -- `/about` shows content from `/about-us` but keeps the URL as `/about` -- `/about/` and `/about/team` do not match the exact rule and use the default behavior -- `/blog/post-123.html` redirects to `/articles/post-123.html` -- Any other path uses the [default behavior](#how-requests-are-served) +3. Click on **Import project** and wait until all pipelines have finished. -#### Common Redirect Patterns +**That's it, your application is now up and running! :star: Let's check it works:** + +1. A _subdomain_ should have been enabled and visible in the project's **IP addressed & Public Routing Overview** box. Its format should look similar to this `https://helloworld-24-8080.prg1.zerops.app`. +2. Click or the `subdomain` URL to open it in a browser and you should see -**Domain Migration** -```yaml title="zerops.yaml" -routing: - redirects: - - from: https://old-domain.com/* - to: https://new-domain.com - status: 301 - preservePath: true - preserveQuery: true ``` -Use permanent (301) redirects when permanently moving content to maintain SEO value. Both `preservePath` and `preserveQuery` keep the visitor on the same page of the new domain. +Hello, World! +``` -**Multiple Domain Management** -```yaml title="zerops.yaml" -run: - routing: - redirects: - # Product-specific domain - - from: https://product-promo.com/* - to: https://main-site.com/products - status: 302 +:::tip +Do you have any questions? Check the step-by-step tutorial, browse the documentation and join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. +::: - # Campaign domain - - from: https://special-offer.com/* - to: https://main-site.com/campaign - status: 302 +## How to start - # Legacy subdomains - - from: https://*.legacy-domain.com/* - to: https://main-site.com - status: 302 -``` +- [Care for details?](/dotnet/how-to/create) — Dive in all Zerops has to offer for your .NET application. -**Moving a section of the site** -```yaml title="zerops.yaml" -routing: - redirects: - - from: /blog/* - to: /articles/ - status: 301 - preservePath: true - preserveQuery: true -``` +## Feature Highlights -### CORS Configuration +- [Create .NET service](/dotnet/how-to/create) — Start with creating a .NET service using GUI or zCLI. +- [zerops.yaml](/dotnet/how-to/build-pipeline#add-zeropsyaml-to-your-repository) — See a full example of zerops.yaml file to create your own app. +- [Scaling configuration](/dotnet/how-to/scaling) — Set up scaling of your .NET application so that it runs smoothly while using only necessary resources. -You can enable CORS for your static service by adding a `cors` directive: +{" "} -```yaml title="zerops.yaml" -run: - routing: - # Simple case - automatically converted to '*' - cors: "*" +- [Customize build environment](/dotnet/how-to/build-process#customize-build-environment) +- [Customize runtime environment](/dotnet/how-to/customize-runtime) - # Full syntax with proper quoting - cors: "'*' always" -``` +## When in doubt, reach out -The `cors` directive sets the following headers on every response, including redirects: -- `Access-Control-Allow-Origin` -- `Access-Control-Allow-Methods` -- `Access-Control-Allow-Headers` -- `Access-Control-Expose-Headers` +Don't know how to start or got stuck during the process? You might not be the first one, visit the FAQ section to find out. -All four headers receive the same value. If you need different values per header, set them individually with the [`headers`](#custom-headers) directive instead. +In case you haven't found an answer (and also if you have), we and our community are looking forward to hearing from you on Discord. -:::note -The `cors` directive has a special case: if you specify just `"*"`, it's automatically converted to `'*'`. For any other values, you need to include the proper Nginx syntax including quotes. -::: +Have you build something that others might find useful? Don't hesitate to share your knowledge! -### Custom Headers +- [FAQ](/dotnet/faq) — Most common questions in one place. +- [Discord](https://discord.com/invite/WDvCZ54) — Join our core team and Zerops community on Discord. Ask questions and share your tips with other members. -For more control over HTTP headers, use the `headers` directive. The `for` field uses the same [path matching](#path-matching) as redirects, so use `"/*"` to cover the whole site. `"/"` alone would match the homepage only: +## Popular Guides -```yaml title="zerops.yaml" -run: - routing: - headers: - - for: "/*" - values: - # All values need proper quoting since they're inserted directly into Nginx - X-Frame-Options: "'DENY'" +- [zCLI](/references/cli) — Get even more out of Zerops with the zCLI command line tool. +- [Zerops VPN](/references/networking/vpn) — Connect to your services easily with Zerops VPN. - # Values with internal quotes need proper YAML escaping - Content-Security-Policy: '"default-src ''self''"' -``` -:::important -Header values are inserted directly into the Nginx configuration **without** additional quotes, which means: +---------------------------------------- -1. **All values must include their own quotes** (typically single quotes) -2. If you need single quotes inside your header value, you must escape them in YAML (using double single quotes) -3. To include the `always` directive, add it after your quoted value -4. For complex values, you can use YAML's block scalar notation (`>-`) for better readability -::: +# Elasticsearch > Overview -Here are examples for different header scenarios: -```yaml title="zerops.yaml" -headers: - - for: "/*" - values: - # Simple header with proper quoting - X-Frame-Options: "'DENY'" +Deploy [Elasticsearch](https://www.elastic.co/elasticsearch/) instances in Zerops with flexible scaling options, from standalone nodes to highly available clusters. - # Header with 'always' directive - X-XSS-Protection: "'1; mode=block' always" +## Supported Versions - # Header with internal single quotes - need double single quotes for escaping - Content-Security-Policy: '"default-src ''self'' https://cdn.example.com"' +Currently supported Elasticsearch versions: - # Complex header with block scalar notation for better readability - Content-Security-Policy: >- - "default-src 'self' https://cdn.example.com; - script-src 'self' 'unsafe-inline'; - img-src * data:" always -``` +Import configuration version: -When this configuration is processed, it translates to the following Nginx directives: +- `elasticsearch@9.2` +- `elasticsearch@8.16` -``` -add_header X-Frame-Options 'DENY'; -add_header X-XSS-Protection '1; mode=block' always; -add_header Content-Security-Policy "default-src 'self' https://cdn.example.com"; -add_header Content-Security-Policy "default-src 'self' https://cdn.example.com; script-src 'self' 'unsafe-inline'; img-src * data:" always; +## Connection Details + +- **Port**: 9200 +- **Protocol**: HTTP only +- **Internal Access**: `http://{hostname}:9200` +- **Basic auth security** + - **User**: `elastic` + - **Password**: randomly generated during service creation, find under **Access Details** in service detail + +#### Example +```sh +curl -u elastic:generatedpassword http://elasticsearch:9200 ``` -:::important Path Handling -Headers are attached to the matched location, and only the single best-matching rule applies to a request. Rules are not merged: +## Configuration Options -- A request for `/docs/page` with rules for `/*` and `/docs/*` receives only the `/docs/*` headers. Repeat the site-wide headers in the more specific rule if you need both. -- A redirect defined in `redirects` does not pick up headers from a broader rule such as `/*`, only the [`cors`](#cors-configuration) headers. To add headers to a redirect response, add a header rule with the same `for` path as the redirect's `from`. The two are merged. -- A header rule for a path without a redirect serves files with the same [default behavior](#how-requests-are-served) as the rest of the site. -- Without `always`, Nginx adds a header only to 2xx, 3xx and 304 responses, so use `always` for headers that must be present on error pages too. -::: +### Plugin Management -### Combining CORS and Custom Headers +You can configure Elasticsearch plugins using a comma-separated list in your environment secrets: -You can use both CORS and custom headers together: +```yaml +envSecrets: + PLUGINS: "analysis-icu,ingest-attachment" +``` -```yaml title="zerops.yaml" -run: - routing: - cors: "'*' always" - headers: - - for: "/*" - values: - X-Frame-Options: "'DENY'" +**Plugin Configuration Details:** +- Defines plugins to install at service startup +- **Format**: `plugin1,plugin2,...` +- Service automatically installs specified plugins during initialization +- Removing a plugin from this list triggers uninstallation on service restart + +### JVM Heap Allocation + +Control the JVM heap size as a percentage of container memory: + +```yaml +envSecrets: + HEAP_PERCENT: "75" ``` -The `cors` directive sets default Access-Control headers for all routes, while the `headers` directive allows you to set additional headers for specific paths. +**Heap Configuration Details:** +- Value represents the percentage of container memory allocated to JVM heap +- **Default**: 50% of available container memory +- **Valid range**: 1-100 +- To increase available memory, adjust the service's RAM allocation in scaling configuration -:::important -If you specify Access-Control headers in the `headers` directive, they will override the ones set by `cors` for that specific path. +:::note Requires Restart +Changes to HEAP_PERCENT require a service restart to take effect. ::: -## SEO with Prerender +## Example Configuration -Single Page Applications render content with JavaScript, which most crawlers can't process—they see an empty page instead of your content. This affects traditional search engines, social media platforms, and AI tools like ChatGPT, Perplexity, and Claude. +```yaml +services: + - hostname: elasticsearch + type: elasticsearch@8.16 + mode: HA + envSecrets: + PLUGINS: "analysis-icu,ingest-attachment" + HEAP_PERCENT: "75" +``` -The Static service includes built-in support for [Prerender.io](https://prerender.io), which automatically detects crawlers (search engines, social media link previews, SEO tools and AI bots) and serves them pre-rendered HTML while your users get the full interactive experience. Requests for assets such as scripts, styles and images are never prerendered. +## Related Resources -### Setup +- [Elasticsearch Official Documentation](https://www.elastic.co/guide/index.html) +- [Available Elasticsearch Plugins](https://www.elastic.co/guide/en/elasticsearch/plugins/current/index.html) -1. Set the `PRERENDER_TOKEN` [secret variable](/features/env-variables) with your Prerender.io token -2. Restart the service (or trigger a new deploy). The Nginx configuration is generated when a container starts, so it picks the token up on the next start +---------------------------------------- -No changes to `zerops.yaml` are needed. +# Elixir > How To > Build Pipeline -### Custom Prerender Host -If you're using a custom Prerender host, add it to environment variables in `zerops.yaml`: - -```yaml title="zerops.yaml" -run: - envVariables: - PRERENDER_HOST: your.prerender.host -``` - -:::note Default -The default host is `service.prerender.io` if not specified. -::: +Zerops provides a customizable build and runtime environment for your Elixir application. -## Framework Integration +## Add zerops.yaml to your repository -The Static service handles static builds from any modern framework. Here's the typical deployment pattern: +Start by adding `zerops.yaml` file to the **root of your repository** and modify it to fit your application: -```yaml title="zerops.yaml" +```yaml zerops: + # define hostname of your service - setup: app + # ==== how to build your application ==== build: - base: nodejs@20 - buildCommands: - - npm install - - npm run build - deployFiles: - - dist/~ # Your framework's output directory - run: - base: alpine/static -``` + # REQUIRED. Set the base technology for the build environment: + base: elixir@latest -The key is pointing `deployFiles` to wherever your framework outputs its built files (`dist/`, `build/`, `.output/public/`, etc.). The trailing `/~` deploys the folder's contents to the document root. + # OPTIONAL. Set the operating system for the build environment. + # os: ubuntu -This configuration: -1. Uses Node.js for building the application -2. Installs dependencies and builds the application -3. Deploys the resulting static files to the Static service + # OPTIONAL. Customise the build environment by installing additional packages + # or tools to the base build environment. + # prepareCommands: + # - sudo apt-get something + # - curl something else -You can enhance this basic setup with: -- Custom redirects for URL management -- Prerender.io integration for SEO -- Additional routing rules as needed + # OPTIONAL. Build your application + buildCommands: + - mix deps.get --only prod + - mix compile + - mix release -For framework-specific examples, check out our [recipe collection](https://github.com/zeropsio/recipe-analog-static). + # REQUIRED. Select which files / folders to deploy after + # the build has successfully finished + deployFiles: _build/prod/rel/app/ -## Advanced Topics + # OPTIONAL. Which files / folders you want to cache for the next build. + # Next builds will be faster when the cache is used. + cache: node_modules -### Custom Nginx configuration + # ==== how to run your application ==== + run: + # OPTIONAL. Sets the base technology for the runtime environment: + base: elixir@latest -The Static service also accepts your own Nginx configuration through `run.siteConfigPath`, the same attribute the [Nginx service](/nginx/how-to/customize-web-server) uses. The configuration is chosen with this precedence: + # OPTIONAL. Sets the internal port(s) your app listens on: + ports: + # port number + - port: 3000 -1. `run.routing` is set: the configuration is generated from it and `siteConfigPath` is ignored -2. Only `run.siteConfigPath` is set: your file is used as the complete `server` configuration -3. Neither is set: the generated default configuration is used + # OPTIONAL. Customise the runtime Elixir environment by installing additional + # dependencies to the base Elixir runtime environment. + # prepareCommands: + # - sudo apt-get something + # - curl something else -A `.tmpl` file is rendered as a Go template with `{{.DocumentRoot}}` (the value of `run.documentRoot`, `/var/www` when unset) and `{{.Environment.NAME}}` for environment variables. Any other extension is copied verbatim. See the [Nginx service guide](/nginx/how-to/customize-web-server#customize-nginx-configuration) for the requirements a custom configuration must meet. + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your Elixir application is started. + # initCommands: + # - rm -rf ./cache -:::tip -If you find yourself writing a custom configuration, consider switching to the [Nginx service](/nginx/overview). It is the same Nginx with `documentRoot` and `siteConfigPath` as first-class options, and it is what the rest of the documentation assumes for hand-written configurations. -::: + # REQUIRED. Your Elixir application start command + start: npm start +``` -### Switching to Full Nginx +The top-level element is always `zerops`. -If you need more control over your Nginx configuration: +### Setup -1. Go to your Static service overview in the UI -2. Click the three vertical dots in the left panel -3. Select **Need to switch to full Nginx service?** -4. Copy the generated Nginx configuration -5. Use this configuration as a starting point for a full Nginx service +The first element `setup` contains the **hostname** of your service. A runtime service with the same hostname must exist in Zerops. +Zerops supports the definition of multiple runtime services in a single `zerops.yaml`. This is useful when you use a monorepo. Just add multiple setup elements in your `zerops.yaml`: -The same file is available inside any running container of the service at `/etc/nginx/sites-enabled/default.site`, for example over [SSH](/references/networking/ssh). +```yaml +zerops: + # definition for app service + - setup: app + # optional + build: ... + # optional + deploy: ... + # required + run: ... -To migrate, change `run.base` to `alpine/nginx@latest` (or `ubuntu/nginx@latest`), replace `run.routing` with `run.siteConfigPath` pointing at the copied configuration (with the `root` directive adjusted or replaced by `{{.DocumentRoot}}`), and remove `routing`, since the Nginx service ignores it. Prerender.io support is part of the generated configuration and will be carried over with it. + # definition for api service + - setup: api + # optional + build: ... + # optional + deploy: ... + # required + run: ... +``` -:::tip -This allows you to move to a more customizable setup while maintaining your existing routing logic. -::: +Each service configuration contains at least the `run` section. Optional `build` and `deploy` sections can be added to further customize your process. -### Complex Multi-Domain Setups +## Build pipeline configuration -For advanced scenarios involving multiple domains and complex routing: +### base -```yaml title="zerops.yaml" -run: - routing: - redirects: - # Product-specific domain - - from: https://product-promo.com/* - to: https://main-site.com/products - status: 302 +_REQUIRED._ Sets the base technology for the build environment. - # Campaign domain - - from: https://special-offer.com/* - to: https://main-site.com/campaign - status: 302 +Following options are available for Elixir builds: - # Legacy subdomains - - from: https://*.legacy-domain.com/* - to: https://main-site.com - status: 302 +- `1.16` + +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: elixir@latest + ... ``` -## Complete Examples +

+ The base build environment contains {data.alpine.default}, the selected + major version of Elixir, [Zerops command line tool](/references/cli), `npm`, `yarn`, `git` and `npx` tools. +

-### Development Setup +:::info +You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. +::: -Configuration for a development environment with CORS and an API on another domain: +If you need to install more technologies to the build environment, set multiple values as a yaml array. For example: -```yaml title="zerops.yaml" -run: - routing: - # CORS with proper quoting - cors: "'*' always" - redirects: - # Send browsers calling /api/... to the API domain - - from: /api/* - to: https://api.your-domain.com/ - status: 307 - preservePath: true - preserveQuery: true +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: + - elixir@latest + prepareCommands: + - zsc add go@latest + ... ``` +See the full list of supported [build base environments](/zerops-yaml/base-list#runtime-services). + +To customise your build environment use the [prepareCommands](#preparecommands) attribute. + :::note -This is a browser redirect, not a reverse proxy. The Static service cannot proxy requests. To serve an API under the same domain as the frontend, use [domain access routing](/references/networking/public-access#http-routing-setup) or the [Nginx service](/nginx/overview) with a `proxy_pass` configuration. +Modifying the base technology will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for more details about cache invalidation. ::: -### Production Setup with Security +### os -Security-enhanced configuration for production environments: +_OPTIONAL._ Sets the operating system for the build environment. -```yaml title="zerops.yaml" -run: - routing: - headers: - # Custom headers for the whole site - - for: "/*" - values: - X-Frame-Options: "'DENY' always" - X-Content-Type-Options: "'nosniff' always" - # Note the proper escaping of single quotes - Content-Security-Policy: '"default-src ''self''" always' -``` +Following options are available: +- `alpine` +- `ubuntu` ----------------------------------------- +Default value is `alpine`. -# Shared Storage > Overview +We are currently using following os version: +- {data.alpine.default} +- {data.ubuntu.default} -:::warning Shared Storage is deprecated -Shared Storage, the SeaweedFS cluster that Zerops mounted into your runtime containers through the **Shared storage connections** page and the `mount:` import field, is no longer offered. The service type has been retired (the old `shared-storage:ha` / `shared-storage:single` type names still work in imports and create a SeaweedFS service), the `mount:` field is rejected on import, and the connections page is gone from the GUI. +:::caution +The os version is fixed and cannot be customised. ::: -**Every existing Shared Storage service has been converted in place into a [SeaweedFS](/seaweedfs/overview) service.** Same containers, same data, same hostname, no action was needed on your side. The mounts your runtime services had keep working for now through the `zeropsSharedStorageMounts` environment variable, on a best-effort basis and with a deprecation warning in the runtime log. Take over the mount in your own `zerops.yaml` with the [migration guide](/seaweedfs/how-to/migrate-from-shared-storage) before the managed mounts are removed. +:::note +Changing the OS setting will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache behavior. +::: -For new projects, pick by workload: +### prepareCommands -- **Files shared between containers and services** over the network - [SeaweedFS](/seaweedfs/overview). The same managed cluster as before, you mount it or use its filer API yourself. -- **A real filesystem** with correct locking, for SQLite and other filesystem-based databases or single-node stateful apps - [Local Storage](/local-storage/overview). -- **Uploads, media, backups** - [Object Storage](/object-storage/overview). +_OPTIONAL._ Customises the build environment by installing additional dependencies or tools to the base build environment. -See [Storage on Zerops](/storage/overview) for the full comparison. +The base build environment contains: -- [Migrate to SeaweedFS](/seaweedfs/how-to/migrate-from-shared-storage) — Take over the mount in your zerops.yaml, no data moves. -- [Migrate to Local Storage](/local-storage/how-to/migrate-from-shared-storage) — Copy the data to a Local Storage volume. -- [Storage on Zerops](/storage/overview) — Compare the storage services and pick the right one. +- {data.alpine.default} +- selected version of Elixir defined in the [base](#base) attribute +- [Zerops command line tool](/references/cli) +- `npm`, `yarn`, `git` and `npx` tools +To install additional packages or tools add one or more prepare commands: ----------------------------------------- +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: elixir@latest -# Seaweedfs > Overview + # OPTIONAL. Customise the build environment by installing additional packages + # or tools to the base build environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... +``` +When the first build is triggered, Zerops will -[SeaweedFS ↗](https://github.com/seaweedfs/seaweedfs) is a distributed filesystem built for high volumes of files. Zerops runs the SeaweedFS cluster for you - master, volume servers and filer, in a single container or in a replicated highly available pair, with monitoring, autoscaling and backups. +1. create a build container +2. download your application code from your repository +3. run the prepare commands in the defined order -What Zerops does **not** do is decide how your application talks to it. The service exposes the SeaweedFS **filer** on the project network, and you pick the client: a FUSE mount started from your `zerops.yaml`, the filer HTTP API, or any other SeaweedFS client. This replaces the deprecated [Shared Storage](/shared-storage/overview), which mounted the same cluster into your containers with one fixed set of mount options. If you have a Shared Storage service, see the [migration guide](/seaweedfs/how-to/migrate-from-shared-storage). +The application code is available in `/build/source` before the prepare commands are triggered, so you can use any file from your repository in your prepare commands (e.g. a configuration file). The commands themselves run in the `/home/zerops` directory. -:::tip Is SeaweedFS the right storage? -SeaweedFS is a network filesystem: files are visible from every container that mounts it, but locks are enforced per mount and the store is append-only. That makes it a good fit for **files shared between containers and services** and a bad fit for databases. For a real POSIX filesystem with correct locking use [Local Storage](/local-storage/overview), for uploads, media and backups use [Object Storage](/object-storage/overview). See [Storage on Zerops](/storage/overview) for the comparison. +:::note +These commands are skipped when using cached environment. Modifying `prepareCommands` will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache invalidation. ::: -## Supported Versions +#### Command exit code -Currently supported SeaweedFS versions: +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/elixir/how-to/logs#build-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all prepare commands are finished, your custom build environment is ready for the build phase. -Import configuration version: +#### Single or separated shell instances -- `seaweedfs:single@3.85`, `seaweedfs:ha@3.85` +You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -The legacy `shared-storage:ha` and `shared-storage:single` type names are accepted as aliases and create a SeaweedFS service. +### buildCommands -## Service Configuration +_OPTIONAL._ Defines build commands. -Zerops offers SeaweedFS in two deployment modes. The mode is part of the service type and is fixed for the life of the service. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Set the base technology for the build environment: + base: elixir@latest -### Single Setup + # OPTIONAL. Build your application + buildCommands: + - npm i + - npm run build + ... +``` -- One container running master, volume server and filer -- No redundancy, all data is lost if the container fails -- Suitable for development or non-critical data +Build commands are optional. Zerops triggers each command in the defined order in a dedicated build container, running from the `/build/source` directory. -### HA (High Availability) Setup +Before the build commands are triggered the build container contains: -- Two containers, each running its own volume server and filer, the master runs on the first one -- File data and filer metadata are replicated 1:1 across both containers (SeaweedFS replication `001`) -- When a container fails, a new one replaces it and the data is replicated onto it automatically. While the master container is being replaced, the cluster is unavailable for roughly 30 seconds until the new master starts -- Recommended for production +1. base environment defined by the [base](#base) attribute +2. optional customisation of the base environment defined in the [prepareCommands](#preparecommands) attribute +3. your application code -### Creating the service +#### Run build commands as a single shell instance -Add the service in the Zerops GUI (**Add new service** → **SeaweedFS**), or import it: +Use following syntax to run all commands in the same environment context. For example, if one command changes the current directory, the next command continues in that directory. When one command creates an environment variable, the next command can access it. -```yaml title="zerops-import.yaml" -services: - - hostname: storage - type: seaweedfs:ha@3.85 +```yaml +buildCommands: + - | + npm i + npm run build ``` -Use `seaweedfs:single@3.85` for the single container mode. Import the file with the [zCLI](/references/cli): +#### Run build commands as a separate shell instances -```sh -zcli project service-import zerops-import.yaml -``` +When the following syntax is used, each command is triggered in a separate environment context. For example, each shell instance starts in the home directory again. When one command creates an environment variable, it won't be available for the next command. -## Connecting +```yaml +buildCommands: + - npm i + - npm run build +``` -The service exposes only the filer, the component every client talks to. Master and volume servers are internal to the cluster and clients reach them through the filer on their own. +#### Command exit code -| Endpoint | Address | Notes | -|---|---|---| -| Filer HTTP API | `http://.zerops:8888` | File upload, download and listing over HTTP, and the Filer UI | -| Filer gRPC | `.zerops:18888` | Used by `weed mount` and other native SeaweedFS clients (always HTTP port + 10000) | -| Filer of one container | `node-stable-.db..zerops:8888` | Pin a client to a specific container, `n` is `1` or `2` | -| Filer of one container | `node-stable-.db..zerops:8888` | Pin a client to a specific container, `n` is `1` or `2` | +If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/elixir/how-to/logs#build-log) to troubleshoot the error. If the error log doesn't contain any specific error message, try to run your build with the --verbose option. -The generated environment variables are `hostname` and `port` (`8888`). Reference them from another service in the same project as `${storage_hostname}` and `${storage_port}` for a service named `storage`. +```yaml +buildCommands: + - npm i --verbose + - npm run build +``` -The filer is not authenticated. It is reachable only inside the project's private network and over the [Zerops VPN](/references/networking/vpn), and it cannot be exposed through public HTTP routing or subdomain access. +If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `buildCommands` are finished, the application build is completed and ready for the deploy phase. -### Mounting from a runtime service +### deployFiles -The SeaweedFS binary that ships in every Zerops runtime container (`/opt/zerops/bin/weed-3-85`) contains `weed mount`, a FUSE client that presents the filer as a directory. Run it as one of your [`startCommands`](/zerops-yaml/specification#startcommands-), next to your application: +_REQUIRED._ Selects which files or folders will be deployed after the build has successfully finished. To filter out specific files or folders, use [`.deployignore`](#deployignore) file. -```yaml title="zerops.yaml" -zerops: - - setup: app - run: - base: nodejs@22 - startCommands: - - name: app - command: npm start - - name: storage - initCommands: - - sudo mkdir -p /mnt/storage - - sudo chown zerops:zerops /mnt/storage - command: sudo /opt/zerops/bin/weed-3-85 mount -filer=node-stable-1.db.storage.zerops:8888 -dir=/mnt/storage +```yaml +# REQUIRED. Select which files / folders to deploy after +# the build has successfully finished +deployFiles: + - dist + - package.json + - node_modules ``` -- `weed mount` runs in the foreground and keeps the directory mounted for the lifetime of the container. Zerops restarts it like any other start command if it exits. -- `-filer` points at the filer of one container. In HA mode both containers run a filer with the same metadata, so a second service can mount `node-stable-2` to spread the load. -- The mount needs `sudo`, both Ubuntu and Alpine runtime images allow it without a password. -- Every container of the service gets its own mount, and every mount sees the same files. -- A bare `weed mount` favours throughput and caches reads locally, so the mount process can grow to hundreds of MB under load. Cap it with `-cacheCapacityMB`, `-concurrentWriters` and `-chunkSizeLimitMB` if RAM matters more, see the [`weed mount` options ↗](https://github.com/seaweedfs/seaweedfs/wiki/FUSE-Mount). -- The mount is only available while the container runs, not during the build or the [runtime prepare](/features/pipeline#runtime-prepare-phase-optional) phase. +Determines files or folders produced by your build, which should be deployed to your runtime service containers. -:::note Shortcut: `zsc shared-storage mount` -`zsc shared-storage mount ` does the same thing with a RAM-lean tuning baked in: it creates `/mnt/`, gives it to the `zerops` user and mounts the filer of the first container (`node-stable-1.db..zerops:8888`) there, passing `-volumeServerAccess=direct -cacheCapacityMB=0 -concurrentWriters=1 -chunkSizeLimitMB=1` so the mount process stays around 100-150 MB at the cost of throughput. It exists for backwards compatibility with the deprecated Shared Storage and stays available, see the [zsc reference](/references/zsc#shared-storage). -::: +The path starts from the **root directory** of your project (the location of `zerops.yaml`). You must enclose the name in quotes if the folder or the file name contains a space. -### Mounting in init commands +The files/folders will be placed into `/var/www` folder in runtime, e.g. `./src/assets/fonts` would result in `/var/www/src/assets/fonts`. -A start command only runs after the [`initCommands`](/zerops-yaml/specification#initcommands-), so if an init command needs the storage (a certificate that lives there, a config it has to write, a migration over shared files), mount it there instead, in the background: +#### Examples -```yaml title="zerops.yaml" -zerops: - - setup: app - run: - base: nodejs@22 - initCommands: - - sudo zsc shared-storage mount storage --background - - cp /mnt/storage/certs/app.pem /var/www/app.pem - start: npm start -``` +Deploys a folder, and a file from the project root directory: -`--background` mounts `/mnt/` the same way as the foreground form (same filer, same tuning), leaves a detached `weed mount` process behind and returns once the mount is ready. Init commands run on every container start, and the command cleans up a stale mount before mounting, so a restart mounts again. +```yaml +deployFiles: + - dist + - package.json +``` -The raw equivalent, for a custom path or options, is `weed fuse`: it takes every `weed mount` flag as an `-o` option and detaches the same way: +Deploys the whole content of the build container: ```yaml - initCommands: - - sudo mkdir -p /mnt/certs && sudo chown zerops:zerops /mnt/certs - - sudo /opt/zerops/bin/weed-3-85 fuse /mnt/certs -o "filer=node-stable-1.db.storage.zerops:8888,filer.path=/certs,readOnly=true" +deployFiles: . ``` -:::caution Nothing supervises a background mount -A mount started from an init command is not restarted if its process dies, unlike a start command. Zerops replaces a container whose health check fails, but a lost mount alone does not fail the health check. If the storage is part of what your application serves, prefer the start command form, or add a [health check](/zerops-yaml/specification#healthcheck-) that touches a file on the mount. -::: - -### Useful mount options +Deploys a folder, and a file in a defined path: -These apply to `weed mount` as flags (`-filer.path=/certs`) and to `weed fuse` as `-o` options (`filer.path=/certs`): +```yaml +deployFiles: + - ./path/to/file.txt + - ./path/to/dir/ +``` -| Option | What it does | -|---|---| -| `filer=:8888,:8888` | Comma-separated list of filers. In HA mode you can list both containers (`node-stable-1.db..zerops:8888,node-stable-2.db..zerops:8888`) instead of pinning the mount to one of them. | -| `filer.path=/some/dir` | Mounts only that directory of the storage, so different services can get different subtrees of one storage. The directory is created if missing. | -| `readOnly=true` | Read-only mount, writes fail with `Read-only file system`. | -| `cacheCapacityMB`, `concurrentWriters`, `chunkSizeLimitMB` | Memory vs. throughput trade-offs. The `zsc` shortcut sets them to `0`, `1` and `1` to keep the mount process RAM-lean. | -| `allowOthers=false` | Restricts the mount to the user that mounted it (root when started with `sudo`), the default `true` lets the `zerops` user in. | -| `allowOthers=false` | Restricts the mount to the user that mounted it (root when started with `sudo`), the default `true` lets the `zerops` user in. | +#### How to use a wildcard in the path -See the [FUSE mount documentation ↗](https://github.com/seaweedfs/seaweedfs/wiki/FUSE-Mount) for the full list. +Zerops supports the `~` character as a wildcard for one or more folders in the path. -### Filer HTTP API +Deploys all `file.txt` files that are located in any path that begins with `/path/` and ends with `/to/` -Any HTTP client can read and write files without a mount, which suits build steps, one-off jobs and languages with an HTTP client but no FUSE: +```yaml +deployFiles: ./path/~/to/file.txt +``` -```sh -# upload (creates the directories on the way) -curl -F "file=@report.pdf" http://storage.zerops:8888/reports/2026/ +Deploys all folders that are located in any path that begins with `/path/to/` -# download -curl -o report.pdf http://storage.zerops:8888/reports/2026/report.pdf +```yaml +deployFiles: ./path/to/~/ +``` -# list a directory as JSON -curl -H "Accept: application/json" http://storage.zerops:8888/reports/2026/ +Deploys all folders that are located in any path that begins with `/path/` and ends with `/to/` -# delete -curl -X DELETE http://storage.zerops:8888/reports/2026/report.pdf +```yaml +deployFiles: ./path/~/to/ ``` -Uploads through the HTTP API are limited to **64 MB per file**. Files written through a mount are chunked and have no such limit. See the [filer server API ↗](https://github.com/seaweedfs/seaweedfs/wiki/Filer-Server-API) for the full interface. - -### Web interfaces +:::note Example +By default, `./src/assets/fonts` deploys to `/var/www/src/assets/fonts`, keeping the full path. Adding `~`, like `./src/assets/~fonts`, shortens it to `/var/www/fonts` +::: +#### .deployignore -Over the [Zerops VPN](/references/networking/vpn) you can open the SeaweedFS UIs in a browser: +Add a `.deployignore` file to the root of your project to specify which files and folders Zerops should ignore during deploy. The syntax follows the same pattern format as [`.gitignore`](https://git-scm.com/docs/gitignore#_pattern_format). -- **Filer UI** - `http://.zerops:8888` - browse, upload and download files -- **Master UI** - `http://node-stable-1.db..zerops:9333` - cluster topology, volume servers, health -- **Volume UI** - `http://node-stable-.db..zerops:8080/ui/index.html` - volume status and disk usage of one container +To ignore a specific file or directory path, start the pattern with a forward slash (`/`). Without the leading slash, the pattern will match files with that name in any directory. -## Storage engine behavior +:::tip +For consistency, it's recommended to configure both your `.gitignore` and `.deployignore` files with the same patterns. +::: -SeaweedFS stores file data in append-only volumes. Files are split into chunks, and when a file is modified new chunks are written while the old ones stay on disk until a vacuum reclaims them. Zerops triggers the automatic vacuum when deleted content exceeds 15% of a volume (the SeaweedFS default is 30%). +Examples: -The consequences for your workload: +```yaml title="zerops.yaml" +zerops: + - setup: app + build: + deployFiles: ./ +``` -- **Frequent small modifications of existing files** cause heavy write amplification. Batch writes where possible and avoid huge trees of tiny files. -- **File locks are per mount.** `flock` and POSIX locks are enforced only inside the container that holds the mount, a process in another container can write to the locked file freely. -- **Latency is higher** than on a local disk, every operation crosses the network. +```text title=".deployignore" +/src/file.txt +``` +The example above ignores `file.txt` only in the root src directory. +```text title=".deployignore" +src/file.txt +``` +This example above ignores `file.txt` in ANY directory named `src`, such as: +- `/src/file.txt` +- `/folder2/folder3/src/file.txt` +- `/src/src/file.txt` -:::caution Not suitable for databases -Do not run SQLite, Prometheus TSDB or any other filesystem-based database on SeaweedFS. Per-mount locks lead to corruption as soon as two containers touch the database, and the append-only store amplifies every small write. Use a [managed database](/postgresql/overview), or [Local Storage](/local-storage/overview) for embedded databases. +:::note +`.deployignore` file also works with [`zcli service deploy`](/references/zcli/commands#deploy) command. ::: -## Capacity - -A SeaweedFS service holds at most **60 GB of data** regardless of the disk resource in autoscaling. The disk gives the storage engine working space for the vacuum process and metadata, raising it in autoscaling does not raise the data capacity. If you need more, contact support. - -- Maximum file size: no fixed limit through a mount, up to the available capacity -- Maximum upload size through the filer HTTP API and UI: 64 MB per file -- `df` inside a mount reports the filer's view and can be misleading, use the service detail page in the GUI for accurate usage - -## Auto Scaling Configuration - -Zerops scales the containers vertically. The default configuration is: - -The number of containers is fixed by the deployment mode. If you need to limit the cost of the service, lower the maximum resources, Zerops never scales above them. If the storage feels slow, raise the minimum resources, Zerops never scales below them. The parameters can be changed at any time. - -## Health Monitoring - -Zerops checks the volume server (`/status`) and the filer of every container, plus the master (`/cluster/healthz`) on the container that runs it, and shows the result on the service detail page. The SeaweedFS logs of every component are in the service's **Runtime Logs**, the logs of a mount process are in the runtime logs of the service that runs it, under the name of the start command. - -## Backup and Recovery - -Zerops takes automated encrypted backups of the whole filesystem. For configuration, scheduling, retention, tagging, quotas and CLI tools see [Zerops Backups](/features/backup). - -- **Format**: `.tar.gz` archive of the filesystem contents -- **Storage**: encrypted, in isolated object storage - -### Restoring backups +### cache -1. Download the backup archive from the Zerops GUI. -2. Transfer it into a runtime service that has the storage [mounted](#mounting-from-a-runtime-service), for example over the [Zerops VPN](/references/networking/vpn). -3. Extract it into the mount directory: +_OPTIONAL._ Defines which files or folders will be cached for the next build. -```sh -tar -xzf backup.tar.gz -C /mnt/storage +```yaml +# OPTIONAL. Which files / folders you want to cache for the next build. +# Next builds will be faster when the cache is used. +cache: file.txt ``` -Extract through a mount rather than uploading through the Filer UI, whose 64 MB per-file limit would reject larger files. - -## Support - -- Ask in the Zerops [Discord](https://discord.com/invite/WDvCZ54) -- SeaweedFS [wiki ↗](https://github.com/seaweedfs/seaweedfs/wiki) for client options and the filer API +The cache attribute helps optimize build times by preserving specified files between builds. +The cache attribute supports the [~ wildcard character](#how-to-use-a-wildcard-in-the-path). ----------------------------------------- +Learn more about the [build cache system](/features/build-cache) in Zerops. -# Seaweedfs > How To > Migrate From Shared Storage +### envVariables +_OPTIONAL._ Defines the environment variables for the build environment. -[Shared Storage](/shared-storage/overview) is deprecated. Every existing Shared Storage service has already been converted in place into a [SeaweedFS](/seaweedfs/overview) service: same containers, same data, same hostname. What changes is who mounts it. Zerops used to mount the storage into your runtime containers through the **Shared storage connections** page and the `mount:` import field. Now your service mounts it itself, from its `zerops.yaml`. +Enter one or more env variables in following format: -Until you do that, the old mounts keep working: the connection lives on as the `zeropsSharedStorageMounts` environment variable of the runtime service, Zerops still mounts every hostname listed in it at `/mnt/` on container start, and logs a deprecation warning into the runtime log each time. The managed mount is best-effort from now on and will be removed in a later release, so plan the switch. +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to build your application ==== + build: + base: elixir@latest + … -The migration in short: + # OPTIONAL. Defines the env variables for the build environment: + envVariables: + NODE_ENV: production + DB_NAME: db + DB_HOST: db + DB_USER: db + DB_PASS: ${db_password} +``` -1. Add a `weed mount` start command to the `zerops.yaml` of every service that uses the storage. -2. Delete the `zeropsSharedStorageMounts` variable of that service. -3. Deploy. -4. Update your import files. +Read more about [environment variables](/elixir/how-to/env-variables) in Zerops. -Throughout the guide, `storage` is the hostname of the storage service and `app` the runtime service that mounts it. Replace them with your own. +## Runtime configuration -## Before you start +### base -- The storage service now shows up as **SeaweedFS** in the GUI and has a `port` variable (`8888`, the filer). Nothing on it needs changing, and there is no **Shared storage connections** page anymore. -- Take a fresh [backup](/seaweedfs/overview#backup-and-recovery) of the storage before you touch the mounts. -- If you would rather move the data off SeaweedFS altogether, the [Local Storage migration guide](/local-storage/how-to/migrate-from-shared-storage) covers copying it to a Local Storage volume. +_OPTIONAL._ Sets the base technology for the runtime environment. +If you don't specify the `run.base` attribute, Zerops keeps the current Elixir version for your runtime. -## 1. Mount the storage from zerops.yaml +Following options are available for Elixir builds: -Add a second entry to [`startCommands`](/zerops-yaml/specification#startcommands-) that runs `weed mount`. Keep the mount path the storage was at, `/mnt/`, so the application does not change. If your `zerops.yaml` uses a single `start` command, convert it into the first `startCommands` entry: +- `1.16` -```yaml title="zerops.yaml" +```yaml zerops: + # hostname of your service - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: elixir@latest + ... + + # ==== how to run your application ==== run: - base: nodejs@22 - # start: npm start - startCommands: - - name: app - command: npm start - - name: storage - initCommands: - - sudo mkdir -p /mnt/storage - - sudo chown zerops:zerops /mnt/storage - command: sudo /opt/zerops/bin/weed-3-85 mount -filer=node-stable-1.db.storage.zerops:8888 -dir=/mnt/storage + # OPTIONAL. Sets the base technology for the runtime environment: + base: elixir@latest + ... ``` -The `-filer` address is `node-stable-1.db..zerops:8888`, where `storage` is the **hostname of your SeaweedFS service** (the former Shared Storage service, its hostname did not change) and `8888` is the filer port. `node-stable-1.db..zerops` is the fixed name of the service's first container, which is where the managed mount always connected. In HA mode the second container is `node-stable-2.db..zerops`, and `.zerops:8888` alone resolves to the filer HTTP API too. A service that mounted several storages gets one such entry per storage. +

+ The base runtime environment contains {data.alpine.default}, the + selected major version of Elixir, Zerops command line tool, `npm`, `yarn`, `git` and `npx` tools. +

-:::note How the managed mount is tuned -The managed mount (and `zsc shared-storage mount`) runs `weed mount` with `-volumeServerAccess=direct -cacheCapacityMB=0 -concurrentWriters=1 -chunkSizeLimitMB=1`: no local read cache and minimal write buffers, so the mount process stays around 100-150 MB of RAM at the cost of throughput. A bare `weed mount` favours speed and can grow well beyond that under load - tune the flags to your own workload, see [Mounting from a runtime service](/seaweedfs/overview#mounting-from-a-runtime-service). +:::info +You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. ::: -The equivalent one-liner is `zsc shared-storage mount storage`, which stays available as a [shortcut](/references/zsc#shared-storage). It runs exactly what the managed mount ran: the filer address above, the mount at `/mnt/` owned by the `zerops` user, and the tuning flags from the note above: +If you need to install more technologies to the runtime environment, set multiple values as a yaml array. For example: ```yaml - - name: storage - command: sudo zsc shared-storage mount storage -``` - -### Alternative: mount in init commands - -If your `initCommands` already use the storage (they read a certificate from it, write a config into it, run a migration over shared files), a start command comes too late, it only runs after the init commands. Mount in the background from the init commands instead: - -```yaml title="zerops.yaml" zerops: + # hostname of your service - setup: app + # ==== how to build your application ==== + build: + # REQUIRED. Sets the base technology for the build environment: + base: elixir@latest + ... + + # ==== how to run your application ==== run: - base: nodejs@22 - initCommands: - - sudo zsc shared-storage mount storage --background - - cp /mnt/storage/certs/app.pem /var/www/app.pem - start: npm start + # OPTIONAL. Sets the base technology for the runtime environment: + base: + - elixir@latest + prepareCommands: + - zsc add go@latest + ... ``` -The mount lands at the same `/mnt/storage`, with the same filer and tuning, and stays mounted after the init commands finish. Init commands run on every container start, so restarts mount again. The difference to the start command form: nothing restarts the mount process if it dies. See [Mounting in init commands](/seaweedfs/overview#mounting-in-init-commands) for the raw `weed fuse` equivalent and the options it accepts (sub-path, read-only, both HA filers). - -## 2. Delete the `zeropsSharedStorageMounts` variable - -Open the runtime service's **Environment variables** page and delete `zeropsSharedStorageMounts`. If the service mounts several storages and you are switching them one at a time, edit the variable and remove only the hostname you have taken over (the value is a `|`-separated list of hostnames). - -The change is applied live: the managed mount of that storage is unmounted from the running containers right away, and it is not recreated on the next container start. Your application loses the storage until step 3 completes, so do steps 2 and 3 back to back, or during a maintenance window. +See the full list of supported [run base environments](/zerops-yaml/base-list). -:::caution Do it before the deploy, not after -The managed mount and your `weed mount` target the same directory. Deploying first would start your mount on top of the managed one in the new containers, delete the variable first so only your mount runs. -::: +To customise your build environment use the `prepareCommands` attribute. -## 3. Deploy +### os -Deploy the service with the changed `zerops.yaml` (`zcli push`, or trigger your pipeline). The new containers mount the storage from the start command, at the same path as before. +_OPTIONAL._ Sets the operating system for the runtime environment. -Check the runtime log: the `storage` start command logs the mount, and the deprecation warning that used to appear on container start is gone. +Following options are available: -## 4. Update your import files +- `alpine` +- `ubuntu` -- Replace the `mount:` field of runtime services in `zerops-import.yaml` files and templates by the `startCommands` entry above, `mount:` is rejected by the import now (`yamlMountDeprecated`). -- The `shared-storage:ha` and `shared-storage:single` type names still work and create a SeaweedFS service, but prefer `seaweedfs:ha@3.85` and `seaweedfs:single@3.85`. +Default value is `alpine`. -## Rollback +We are currently using following os version: -Put the hostname back into `zeropsSharedStorageMounts` (or recreate the variable with the hostname as its value), remove the `weed mount` start command and deploy. Zerops mounts the storage on the next container start as before. +- {data.alpine.default} +- {data.ubuntu.default} +:::caution +The os version is fixed and cannot be customised. +::: ----------------------------------------- +### ports -# Rust > Overview +_OPTIONAL._ Specifies one or more internal ports on which your application will listen. +Projects in Zerops represent a group of one or more services. Services can be of different types (runtime services, databases, message brokers, object storage, etc.). All services of the same project share a **dedicated private network**. To connect to a service within the same project, just use the service hostname and its internal port. -[Rust ↗](https://www.rust-lang.org/) - a language empowering everyone to build reliable and efficient software. +For example, to connect to a Elixir service with hostname = "app" and port = 3000 from another service of the same project, simply use `app:3000`. Read more about [how to access a Elixir service](/references/networking/internal-access#basic-service-communication). -As said, there is no need for coding yet, we have created a [Github repository ↗](https://github.com/zeropsio/recipe-rust-hello-world), a **_recipe_**, containing the most simple Rust web application. The repo will be used as a source from which the app will be built. +Each port has following attributes: -### 🚀 Feel free to deploy the recipe yourself +| parameter | description | +| ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| port | Defines the port number. You can set any port number between _10_ and _65435_. Ports outside this interval are reserved for internal Zerops systems. | +| protocol | **Optional.** Defines the protocol. Allowed values are `TCP` or `UDP`. Default value is `TCP`. | +| httpSupport | **Optional.** `httpSupport = true` is the default setting for TCP protocol. Set `httpSupport = false` if a web server isn't running on the port. Zerops uses this information for the configuration of [public access](/features/access). `httpSupport = true` is available only in combination with the TCP protocol. | +| httpSupport | **Optional.** `httpSupport = true` is the default setting for TCP protocol. Set `httpSupport = false` if a web server isn't running on the port. Zerops uses this information for the configuration of [public access](/features/access). `httpSupport = true` is available only in combination with the TCP protocol. | -This is the most bare-bones example of Rust running in Zerops — as few libraries as possible, - just a simple endpoint with connect, read and write to a Zerops PostgreSQL database. +### prepareCommands - [Deploy "rust" recipe on Zerops](https://app.zerops.io/recipe/?lf=rust) +_OPTIONAL._ Customises the Elixir runtime environment by installing additional dependencies or tools to the runtime base environment. -1. Log in/sign up to [Zerops GUI ↗](https://app.zerops.io) -2. In the **Projects** box click on **Import a project** and paste in the following YAML config ([source ↗](https://github.com/zeropsio/recipe-rust-hello-world/blob/main/import-project/description.yaml)): +

+ The base Elixir environment contains {data.alpine.default} the selected + major version of Elixir, [Zerops command line tool](/references/cli) and `npm`, `yarn`, `git` and `npx` tools. To install + additional packages or tools add one or more prepare commands: +

```yaml -project: - name: my-first-project -services: - - hostname: helloworld - type: rust@latest - minContainers: 1 - maxContainers: 3 - buildFromGit: https://github.com/zeropsio/recipe-rust-hello-world@main - enableSubdomainAccess: true -``` - -3. Click on **Import project** and wait until all pipelines have finished. +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + ... -**That's it, your application is now up and running! :star: Let's check it works:** + # ==== how to run your application ==== + run: + # OPTIONAL. Customise the runtime environment by installing additional packages + # or tools to the base Elixir runtime environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... +``` -1. A _subdomain_ should have been enabled and visible in the project's **IP addressed & Public Routing Overview** box. Its format should look similar to this `https://helloworld-24-8080.prg1.zerops.app`. -2. Click or the `subdomain` URL to open it in a browser and you should see +When the first deploy with a defined prepare attribute is triggered, Zerops will -``` -Hello, World! -``` +1. create a prepare runtime container +2. optionally: [copy selected folders or files from your build container](#copy-folders-or-files-from-your-build-container) +3. run the `prepareCommands` commands in the defined order -:::tip -Do you have any questions? Check the step-by-step tutorial, browse the documentation and join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. +:::note +`run.prepareCommands` run in the `/home/zerops` directory. ::: -## How to start +#### Command exit code -- [Care for details?](/rust/how-to/create) — Dive in all Zerops has to offer for your Rust application. +If any command fails, it returns an exit code other than 0 and the deploy is canceled. Read the [prepare runtime log](/elixir/how-to/logs#prepare-runtime-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `prepareCommands` commands are finished, your custom runtime environment is ready for the deploy phase. -## Feature Highlights +#### Cache of your custom runtime environment -- [Create Rust service](/rust/how-to/create) — Start with creating a Rust service using GUI or zCLI. -- [zerops.yaml](/rust/how-to/build-pipeline#add-zeropsyaml-to-your-repository) — See a full example of zerops.yaml file to create your own app. -- [Scaling configuration](/rust/how-to/scaling) — Set up scaling of your Rust application so that it runs smoothly while using only necessary resources. +Some packages or tools can take a long time to install. Therefore, Zerops caches your custom runtime environment after the installation of your custom packages or tools is completed. When the second or following deploy is triggered, Zerops will use the custom runtime cache from the previous deploy if following conditions are met: -{" "} +1. Content of the [build.addToRunPrepare](#copy-folders-or-files-from-your-build-container) and `run.prepareCommands` attributes didn't change from the previous deploy +2. The custom runtime cache wasn't invalidated in the Zerops GUI. -- [Customize build environment](/rust/how-to/build-process#customize-build-environment) -- [Customize runtime environment](/rust/how-to/customize-runtime) +To invalidate the custom runtime cache go to `yyy` -## When in doubt, reach out +When the custom runtime cache is used, Zerops doesn't create a prepare runtime container and executes the deployment of your application directly. -Don't know how to start or got stuck during the process? You might not be the first one, visit the FAQ section to find out. +#### Single or separated shell instances -In case you haven't found an answer (and also if you have), we and our community are looking forward to hearing from you on Discord. +You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). -Have you build something that others might find useful? Don't hesitate to share your knowledge! +### Copy folders or files from your build container -- [FAQ](/rust/faq) — Most common questions in one place. -- [Discord](https://discord.com/invite/WDvCZ54) — Join our core team and Zerops community on Discord. Ask questions and share your tips with other members. +

+ The prepare runtime container contains {data.alpine.default}, the + selected major version of Elixir, [Zerops command line tool](/references/cli) and `npm`, `yarn`, `git` and `npx` tools. +

-## Popular Guides +The prepare runtime container does not contain your application code nor the built application. If you need to copy some folders or files from the build container to the runtime container (e.g. a configuration file) use the `addToRunPrepare` attribute in the [build section](#build-pipeline-configuration). -- [zCLI](/references/cli) — Get even more out of Zerops with the zCLI command line tool. -- [Zerops VPN](/references/networking/vpn) — Connect to your services easily with Zerops VPN. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: + ... + addToRunPrepare: ./runtime-config.yaml + # ==== how to run your application ==== + run: + # OPTIONAL. Customise the runtime environment by installing additional packages + # or tools to the base Elixir runtime environment. + prepareCommands: + - sudo apt-get something + - curl something else + ... +``` ----------------------------------------- +In the example above Zerops will copy the `runtime-config.yaml` file from your build container **after the build has finished** into the new **prepare runtime** container. The copied files and folders will be available in the `/home/zerops` folder in the new prepare runtime container before the prepare commands are triggered. -# Rust > How To > Upgrade +### initCommands +_OPTIONAL._ Defines one or more commands to be run each time a new runtime container is started or a container is restarted. +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... ----------------------------------------- + # ==== how to run your application ==== + run: + # OPTIONAL. Run one or more commands each time a new runtime container + # is started or restarted. These commands are triggered before + # your Elixir application is started. + initCommands: + - rm -rf ./cache +``` -# Rust > How To > Trigger Pipeline +These commands are triggered in the runtime container before your Elixir application is started via the [start command](#start). +:::note +`run.initCommands` run in the `/var/www` directory. +::: +Use init commands to clean or initialise your application cache or similar operations. ----------------------------------------- +:::caution +The init commands will delay the start of your application each time a new runtime container is started (including the horizontal [scaling](/elixir/how-to/scaling) or when a runtime container is restarted). -# Rust > How To > Scaling +Do not use the init commands for customising your runtime environment. Use the [run:prepareCommands](#preparecommands-1) attribute instead. +::: +#### Command exit code +If any of the `initCommands` fails, it returns an exit code other than 0, but deploy is **not** canceled. After all init commands are finished, regardless of the status code, the application is started. Read the [runtime log](/elixir/how-to/logs#runtime-log) to troubleshoot the error. ----------------------------------------- +#### Single or separated shell instances -# Rust > How To > Logs +You can configure your `initCommands` to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). +### envVariables +_OPTIONAL._ Defines the environment variables for the runtime environment. ----------------------------------------- +Enter one or more env variables in following format: -# Rust > How To > Filebrowser +```yaml +zerops: + # define hostname of your service + - setup: app + # ==== how to run your application ==== + run: + # OPTIONAL. Defines the env variables for the runtime environment: + envVariables: + NODE_ENV: production + DB_NAME: db + DB_HOST: db + DB_USER: db + DB_PASS: ${db_password} +``` +Read more about [environment variables](/elixir/how-to/env-variables) in Zerops. +### start ----------------------------------------- +_REQUIRED._ Defines the start command for your Elixir application. -# Rust > How To > Env Variables +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... + # ==== how to run your application ==== + run: + # REQUIRED. Your Elixir application start command + start: npm start +``` +We recommend starting your Elixir application using `npm start`. ----------------------------------------- +### health check -# Rust > How To > Deploy Process +_OPTIONAL._ Defines a health check. +`healthCheck` requires either one `httpGet` object or one `exec` object. +#### httpGet ----------------------------------------- +Configures the health check to request a local URL using a HTTP GET method. -# Rust > How To > Customize Runtime +Following attributes are available: + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. +If your application requires a https request, set scheme: https
+**Example:** ----------------------------------------- +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -# Rust > How To > Create + # ==== how to run your application ==== + run: + # REQUIRED. Your Elixir application start command + start: npm start + # OPTIONAL. Define a health check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + healthCheck: + httpGet: + port: 80 + path: /status +``` -Zerops provides a Rust runtime service with extensive build support. Rust runtime is highly scalable and customisable to suit both development and production. +#### exec -## Create Rust service using Zerops GUI +Configures the health check to run a local command. +Following attributes are available: -First, set up a project in Zerops GUI. Then go to the project dashboard page and choose **Add new service** in the left menu in the **Services** block. Then add a new Rust service: +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **command** | Defines a local command to be run. +The command has access to the same [environment variables](/elixir/how-to/create#set-secret-environment-variables) as your Elixir application. +A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. | -[Video: /vids/services/rust.webm](/vids/services/rust.webm) +**Example:** -### Choose Rust version +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... -Following Rust versions are currently supported: + # ==== how to run your application ==== + run: + # REQUIRED. Your Elixir application start command + start: npm start -:::info -You can [change](/rust/how-to/upgrade) the major version at any time later. -::: + # OPTIONAL. Define a health check with a shell command. + healthCheck: + exec: + command: | + touch grass + rm -rf life + mv /outside/user /home/user +``` -### Set a hostname +### crontab -Enter a unique service identifier like "app","cache", "gui" etc. Duplicate services with the same name in the same project are forbidden. +_OPTIONAL._ Defines cron jobs. -#### Limitations: +Setup cron jobs in the following format: -- maximum 25 characters -- must contain only lowercase ASCII letters (a-z) or numbers (0-9) +```yaml +zerops: + # define hostname of your service + - setup: app -:::caution -The hostname is fixed after the service is created. It can't be changed later. -::: + # ==== how to run your application ==== + run: + crontab: + # REQUIRED. Sets the command to execute: + - command: "" + # REQUIRED. Sets the interval time to execute: + timing: "0 * * * *" +``` -### Set secret environment variables +Read more about setting up [cron](/zerops-yaml/cron) in Zerops. -Add environment variables with sensitive data, such as password, tokens, salts, certificates etc. These will be securely saved inside Zerops and added to your runtime service upon start. +## Deploy configuration -Setting the secret environment variables is optional. You can set them later in Zerops GUI. +### readiness check -Read more about [different types of env variables](/rust/how-to/env-variables#service-env-variables) in Zerops. +_OPTIONAL._ Defines a readiness check. Read more about how the [readiness check works](/elixir/how-to/deploy-process#readiness-checks) in Zerops. -## Create Rust service using zCLI +`readinessCheck` requires either one `httpGet` object or one `exec` object. -zCLI is the Zerops command-line tool. To create a new Rust service via the command-line, follow these steps: +#### httpGet -1. [Install & setup zCLI](/references/cli) -2. [Create a project description file](/rust/how-to/create#create-a-project-description-file) -3. [Create a project with a Rust and PostgreSQL service](#full-example) +Configures the readiness check to request a local URL using a http GET method. -### Create a project description file +Following attributes are available: -Zerops uses a yaml format to describe the project infrastructure. + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescription
portDefines the port of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. +The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. +If your application requires a https request, set scheme: https
-#### Basic example: +**Example:** -Create a directory `my-project`. Create an `description.yaml` file inside the `my-project` directory with following content: +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... + + # ==== how to deploy your application ==== + deploy: + # OPTIONAL. Define a readiness check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + readinessCheck: + httpGet: + port: 80 + path: /status + + # ==== how to run your application ==== + run: ... +``` + +Read more about how the [readiness check works](/elixir/how-to/deploy-process#readiness-checks) in Zerops. + +#### exec + +Configures the readiness check to run a local command. +Following attributes are available: + +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **command** | Defines a local command to be run. +The command has access to the same [environment variables](/elixir/how-to/create#set-secret-environment-variables) as your Elixir application. +A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. | + +**Example:** + +```yaml +zerops: + # hostname of your service + - setup: app + # ==== how to build your application ==== + build: ... + + # ==== how to deploy your application ==== + deploy: + # OPTIONAL. Define a readiness check with a HTTP GET request option. + # Configures the check on http://127.0.0.1:80/status + readinessCheck: + exec: + command: | + touch grass + rm -rf life + mv /outside/user /home/user +``` + +Read more about how the [readiness check works](/elixir/how-to/deploy-process#readiness-checks) in Zerops. + + +---------------------------------------- + +# Elixir > How To > Build Process + + + +---------------------------------------- + +# Elixir > How To > Controls + + + +---------------------------------------- + +# Elixir > How To > Create + + +Zerops provides a powerful Elixir runtime service with extensive build support. The Elixir runtime is highly scalable and customizable to suit your development and production needs. With just a few clicks or commands, you can have a production-ready Elixir environment up and running in no time. + +## Create a Elixir service using Zerops GUI + +First, set up a project in the Zerops GUI. Then go to the project dashboard page and choose **Add new service** in the left menu under the **Services** section. From there, you can add a new Elixir service: + +[Video: /vids/services/elixir.webm](/vids/services/elixir.webm) + +### Choose a Elixir version + +Zerops supports the following Elixir versions: + +:::info +You can easily [upgrade](/elixir/how-to/upgrade) the major version at any time later. +::: + +### Set a hostname + +Enter a unique service identifier like "app", "cache", "gui", etc. Duplicate services with the same name within the same project are not allowed. + +#### Limitations: + +- Maximum 25 characters +- Must contain only lowercase ASCII letters (a-z) or numbers (0-9) + +:::caution +The hostname is fixed after the service is created and cannot be changed later. +::: + +### Set secret environment variables + +Add environment variables with sensitive data, such as passwords, tokens, salts, certificates, etc. These will be securely saved inside Zerops and added to your runtime service upon start. + +Setting secret environment variables is optional. You can always set them later in the Zerops GUI. + +Read more about the [different types of environment variables](/elixir/how-to/env-variables#service-env-variables) in Zerops. + +## Create a Elixir service using zCLI +zCLI is the Zerops command-line tool. To create a new Elixir service via the command line, follow these steps: + +1. [Install & setup zCLI](/references/cli) +2. [Create a project description file](/elixir/how-to/create#create-a-project-description-file) +3. [Create a project with a Elixir and PostgreSQL service](#full-example) + +### Create a project description file + +Zerops uses a YAML format to describe the project infrastructure. + +#### Basic example: + +Create a directory called `my-project`. Inside the `my-project` directory, create a `description.yaml` file with the following content: ```yaml # basic project data project: @@ -6345,8 +7912,8 @@ project: services: - # service name hostname: app - # service type and version number in rust@{version} format - type: rust@latest + # service type and version number in elixir@{version} format + type: elixir@latest # defines the minimum number of containers for horizontal autoscaling minContainers: 1 # defines the maximum number of containers for horizontal autoscaling. Max value = 6. @@ -6357,7 +7924,7 @@ services: S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' ``` -The yaml file describes your future project infrastructure. The project will contain one Rust version 18 service with default [auto scaling](/rust/how-to/scaling) configuration. Hostname will be set to "app", the internal port(s) the service listens on will be defined later in the [zerops.yaml](/rust/how-to/build-pipeline#ports). Following secret env variables will be configured: +The yaml file describes your future project infrastructure. The project will contain one Elixir version 20 service with default [auto scaling](/elixir/how-to/scaling) configuration. Hostname will be set to "app", the internal port(s) the service listens on will be defined later in the [zerops.yaml](/elixir/how-to/build-pipeline#ports). Following secret env variables will be configured: ```env S3_ACCESS_KEY_ID="P8cX1vVVb" @@ -6374,7 +7941,7 @@ project: # project name name: my-project # optional: project description - description: A project with a Rust and PostgreSQL database + description: A project with a Elixir and PostgreSQL database # optional: project tags tags: - DEMO @@ -6383,8 +7950,8 @@ project: services: - # service name hostname: app - # service type and version number in rust@{version} format - type: rust@latest + # service type and version number in elixir@{version} format + type: elixir@latest # optional: vertical auto scaling customization verticalAutoscaling: cpuMode: DEDICATED @@ -6401,7 +7968,7 @@ services: minContainers: 2 # defines the maximum number of containers for horizontal autoscaling. Max value = 6. maxContainers: 4 - # optional: create secret env variables + # optional: create env variables envSecrets: S3_ACCESS_KEY_ID: 'P8cX1vVVb' S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' @@ -6413,9 +7980,9 @@ services: mode: NON_HA ``` -The yaml file describes your future project infrastructure. The project will contain a Rust service and a [PostgreSQL](/postgresql/overview) service. +The yaml file describes your future project infrastructure. The project will contain a Elixir service and a [PostgreSQL](/postgresql/overview) service. -Rust service with "app" hostname, the internal port(s) the service listens on will be defined later in the [zerops.yaml](/rust/how-to/build-pipeline#ports). Rust service will run on version 18 with a custom vertical and horizontal scaling. Following secret env variables will be configured: +Elixir service with "app" hostname, the internal port(s) the service listens on will be defined later in the [zerops.yaml](/elixir/how-to/build-pipeline#ports). Elixir service will run on version 20 with a custom vertical and horizontal scaling. Following secret env variables will be configured: ```env S3_ACCESS_KEY_ID="P8cX1vVVb" @@ -6428,34 +7995,14 @@ The hostname of the PostgreSQL service will be set to "db". The [single containe The `project:` section is required. Only one project can be defined. - - - - - - - - - - - - - - - - - - - - - - - - - -
ParameterDescriptionLimitations
nameThe name of the new project. Duplicates are allowed.
descriptionOptional. Description of the new project.Maximum 255 characters.
tagsOptional. One or more string tags. Tags do not have a functional meaning, they only provide better orientation in projects.
+| Parameter | Description | Limitations | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------- | +| **name** | The name of the new project. Duplicates are allowed. | | +| **description** | **Optional.** Description of the new project. | Maximum 255 characters. | +| **tags** | **Optional.** One or more string tags. Tags do not have a functional meaning, they only provide better orientation in projects. | +| **tags** | **Optional.** One or more string tags. Tags do not have a functional meaning, they only provide better orientation in projects. | -At least one service in `services:` section is required. You can create a project with multiple services. The example above contains Rust and PostgreSQL services but you can create a `description.yaml` with your own combination of [services](/features/infrastructure). +At least one service in `services:` section is required. You can create a project with multiple services. The example above contains Elixir and PostgreSQL services but you can create a `description.yaml` with your own combination of [services](/features/infrastructure). @@ -6485,7 +8032,7 @@ At least one service in `services:` section is required. You can create a projec @@ -6493,7 +8040,7 @@ At least one service in `services:` section is required. You can create a projec verticalAutoscaling @@ -6591,7 +8138,7 @@ You don't specify the project name in the `zcli project project-import` command, If you have access to more than one client, you must specify the client ID for which the project is to be created. The `clientID` is located in the Zerops GUI under the client name on the project dashboard page. -### Add Rust service to an existing project +### Add Elixir service to an existing project #### Example: @@ -6606,8 +8153,8 @@ project: services: - # service name hostname: app - # service type and version number in rust@{version} format - type: rust@latest + # service type and version number in elixir@{version} format + type: elixir@latest # defines the minimum number of containers for horizontal autoscaling minContainers: 1 # defines the maximum number of containers for horizontal autoscaling. Max value = 6. @@ -6618,7 +8165,7 @@ services: S3_ACCESS_SECRET: 'ogFthuiLYki8XoL73opSCQ' ``` -The yaml file describes the list of one or more services that you want to add to your existing project. In the example above, one Rust service version 18 with default [auto scaling](/rust/how-to/scaling) configuration will be added to your project. Hostname of the new service will be set to `app`. Following secret env variables will be configured: +The yaml file describes the list of one or more services that you want to add to your existing project. In the example above, one Elixir service version 20 with default [auto scaling](/elixir/how-to/scaling) configuration will be added to your project. Hostname of the new service will be set to `app`. Following secret env variables will be configured: ```env S3_ACCESS_KEY_ID="P8cX1vVVb" @@ -6646,10398 +8193,9417 @@ Maximum size of the import.yaml file is 100 kB. ---------------------------------------- -# Rust > How To > Controls +# Elixir > How To > Customize Runtime ---------------------------------------- -# Rust > How To > Build Process +# Elixir > How To > Deploy Process ---------------------------------------- -# Rust > How To > Build Pipeline +# Elixir > How To > Env Variables -Zerops provides a customizable build and runtime environment for your Rust application. -## Add zerops.yaml to your repository +---------------------------------------- -Start by adding `zerops.yaml` file to the **root of your repository** and modify it to fit your application: +# Elixir > How To > Filebrowser -```yaml -zerops: - # define hostname of your service - - setup: app - # ==== how to build your application ==== - build: - # REQUIRED. Set the base technology for the build environment: - base: rust@latest - # OPTIONAL. Set the operating system for the build environment. - # os: ubuntu - # OPTIONAL. Customize the build environment by installing additional packages - # or tools to the base build environment. - # prepareCommands: - # - sudo apt-get something - # - curl something else +---------------------------------------- - # OPTIONAL. Build your application - buildCommands: - - cargo b --release +# Elixir > How To > Logs - # REQUIRED. Select which files / folders to deploy after - # the build has successfully finished - deployFiles: - - target/release/~app - # OPTIONAL. Which files / folders you want to cache for the next build. - # Next builds will be faster when the cache is used. - # cache: file.txt - # ==== how to run your application ==== - run: - # OPTIONAL. Sets the base technology for the runtime environment: - base: rust@latest +---------------------------------------- - # OPTIONAL. Sets the internal port(s) your app listens on: - ports: - # port number - - port: 8080 +# Elixir > How To > Scaling - # OPTIONAL. Customize the runtime Rust environment by installing additional - # dependencies to the base Rust runtime environment. - # prepareCommands: - # - sudo apt-get something - # - curl something else - # OPTIONAL. Run one or more commands each time a new runtime container - # is started or restarted. These commands are triggered before - # your Rust application is started. - # initCommands: - # - rm -rf ./cache - # REQUIRED. Your Rust application start command - start: ./app -``` +---------------------------------------- -The top-level element is always `zerops`. +# Elixir > How To > Trigger Pipeline -### Setup -The first element `setup` contains the **hostname** of your service. A runtime service with the same hostname must exist in Zerops. -Zerops supports the definition of multiple runtime services in a single `zerops.yaml`. This is useful when you use a monorepo. Just add multiple setup elements in your `zerops.yaml`: -```yaml -zerops: - # definition for app service - - setup: app - # optional - build: ... - # optional - deploy: ... - # required - run: ... +---------------------------------------- - # definition for api service - - setup: api - # optional - build: ... - # optional - deploy: ... - # required - run: ... -``` +# Elixir > How To > Upgrade -Each service configuration contains at least the `run` section. Optional `build` and `deploy` sections can be added to further customize your process. -## Build pipeline configuration -### base +---------------------------------------- -_REQUIRED._ Sets the base technology for the build environment. +# Elixir > Overview -Following options are available for Rust builds: -- `rust@1`, `rust@latest`, `rust@stable` -- `rust@1.86` -- `rust@1.80` -- `rust@1.78` -- `rust@nightly` +[Elixir ↗](https://elixir.org/en) is an asynchronous event-driven JavaScript runtime, which is designed to build scalable network applications. -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: - # REQUIRED. Sets the base technology for the build environment: - base: rust@latest - ... -``` +As said, there is no need for coding yet, we have created a [Github repository ↗](https://github.com/zeropsio/recipe-elixir), a **_recipe_**, containing the most simple Elixir web application. The repo will be used as a source from which the app will be built. -

- The base build environment contains {data.alpine.default}, the selected - major version of Rust, [Zerops command line tool](/references/cli), `npm` , `yarn`, `git` and `npx` tools. -

+### 🚀 Feel free to deploy the recipe yourself -:::info -You can change the base environment when you need to. Just simply modify the `zerops.yaml` in your repository. -::: +This is the most bare-bones example of Elixir app running in Zerops — as few libraries as possible, + just a simple endpoint with connect, read and write to a Zerops PostgreSQL database. -If you need to install more technologies to the build environment, set multiple values as a yaml array. For example: + [Deploy "elixir" recipe on Zerops](https://app.zerops.io/recipe/?lf=elixir) + +1. Log in/sign up to [Zerops GUI ↗](https://app.zerops.io) + +2. In the **Projects** box click on **Import a project** and paste in the following YAML config ([source ↗](https://github.com/zeropsio/recipe-elixir/blob/main/zerops-project-import.yaml)): ```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: - # REQUIRED. Sets the base technology for the build environment: - base: - - rust@latest - prepareCommands: - - zsc add go@latest - ... +project: + name: recipe-elixir + tags: + - zerops-recipe + +services: + - hostname: api + type: elixir@1.16 + enableSubdomainAccess: true + buildFromGit: https://github.com/zeropsio/recipe-elixir + + - hostname: db + type: postgresql@16 + mode: NON_HA + priority: 1 ``` -See the full list of supported [build base environments](/zerops-yaml/base-list#runtime-services). +3. Click on **Import project** and wait until all pipelines have finished. -To customize your build environment use the [prepareCommands](#preparecommands) attribute. +**That's it, your application is now up and running! :star: Let's check it works:** -:::note -Modifying the base technology will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for more details about cache invalidation. +1. A _subdomain_ should have been enabled and visible in the project's **IP addressed & Public Routing Overview** box. Its format should look similar to this `https://api-808-4000.prg1.zerops.app`. +2. Click or the `subdomain` URL to open it in a browser and you should see + +``` +{"message":"This is a simple Elixir application running in Zerops.io, each request adds an entry to the PostgreSQL database and returns a count. See the source repository (https://github.com/zeropsio/recipe-elixir) for more information.","newEntry":"e64be640-d6c2-4be8-93ac-d1e40e56fa06","count":1} +``` + +:::tip +Do you have any questions? Check the step-by-step tutorial, browse the documentation and join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. ::: -### os +## How to start -_OPTIONAL._ Sets the operating system for the build environment. +It doesn't matter whether it's your first curious introduction to Zerops, you have already mastered the basics and are looking for a tiny detail or inspiration. Below, choose a section that fits your needs: -Following options are available: +- [Care for details?](/elixir/how-to/create) — Dive in all Zerops has to offer for your Elixir application. +- [Elixir recipes](https://github.com/zeropsio?q=elixir&type=all&language=&sort=) — Get inspired by already existing repositories, ready to be imported to Zerops. -- `alpine` -- `ubuntu` +## Feature Highlights -Default value is `alpine`. +- [Create Elixir service](/elixir/how-to/create) — Start with creating a Elixir service using GUI or zCLI. +- [Zerops.yaml](/elixir/how-to/build-pipeline#add-zeropsyaml-to-your-repository) — See a full example of zerops.yaml file to create your own app. +- [Scaling configuration](/elixir/how-to/scaling) — Set up scaling of your Elixir application so that it runs smoothly while using only necessary resources. -We are currently using following os version: +{" "} -- {data.alpine.default} -- {data.ubuntu.default} +- [Customize build environment](/elixir/how-to/build-process#customize-build-environment) +- [Customize runtime environment](/elixir/how-to/customize-runtime) -:::caution -The os version is fixed and cannot be customized. -::: +## When in doubt, reach out -:::note -Modifying the OS will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for more details about cache invalidation. -::: +Don't know how to start or got stuck during the process? You might not be the first one, visit the FAQ section to find out. -### prepareCommands +In case you haven't found an answer (and also if you have), we and our community are looking forward to hearing from you on Discord. -_OPTIONAL._ Customizes the build environment by installing additional dependencies or tools to the base build environment. +Have you build something that others might find useful? Don't hesitate to share your knowledge! -The base build environment contains: +- [FAQ](/elixir/faq) — Most common questions in one place. +- [Discord](https://discord.com/invite/WDvCZ54) — Join our core team and Zerops community on Discord. Ask questions and share your tips with other members. -- {data.alpine.default} -- selected version of Rust defined in the [base](#base) attribute -- [Zerops command line tool](/references/cli) -- `npm`, `yarn`, `git` and `npx` tools +## Popular Guides -To install additional packages or tools add one or more prepare commands: +- [zCLI](/references/cli) — Get even more out of Zerops with the zCLI command line tool. +- [Zerops VPN](/references/networking/vpn) — Connect to your services easily with Zerops VPN. -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: - # REQUIRED. Set the base technology for the build environment: - base: rust@latest - # OPTIONAL. Customize the build environment by installing additional packages - # or tools to the base build environment. - prepareCommands: - - cargo b --release - ... -``` +---------------------------------------- -When the first build is triggered, Zerops will +# Features > Access -1. create a build container -2. download your application code from your repository -3. run the prepare commands in the defined order -The application code is available in `/build/source` before the prepare commands are triggered, so you can use any file from your repository in your prepare commands (e.g. a configuration file). The commands themselves run in the `/home/zerops` directory. +Zerops provides multiple ways to access your services, whether you need internal communication between services, secure access from your development machine, or public access from the internet. :::note -These commands are skipped when using cached environment. Modifying `prepareCommands` will invalidate your build cache. See our [Build Cache Documentation](/features/build-cache) for details about cache invalidation. +By default, your services are not publicly accessible until you configure external access. Internal communication between services within the same project works automatically. ::: -#### Command exit code +## How Zerops Networking Works -If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/rust/how-to/logs#build-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all prepare commands are finished, your custom build environment is ready for the build phase. +Every Zerops project includes a **shared networking infrastructure** that handles all access methods: -#### Single or separated shell instances +**Private Project Network:** +- All services within a project share a dedicated private network +- Services communicate directly using hostnames and internal ports +- Traffic stays isolated within your project -You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). +**Public Access Infrastructure:** +- **Core (L3) Balancer** manages IP addresses and direct port access +- **L7 HTTP Balancer** handles domain routing and SSL termination + - Can be extensively configured for advanced routing, performance optimization, and custom behaviors + - See the [L7 Balancer Configuration Guide](/references/networking/l7-balancer-config) for detailed options +- Both are shared across all services in your project -### buildCommands +**Secure External Access:** +- **Built-in VPN** provides secure tunnel access to your project's private network +- Useful for development, debugging, and administration -_OPTIONAL._ Defines build commands. +## Internal Access -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: - # REQUIRED. Set the base technology for the build environment: - base: rust@latest +:::tip Complete Internal Access Setup +See the [Internal access reference guide](/references/networking/internal-access). +::: - # OPTIONAL. Build your application - buildCommands: - - cargo b --release - ... +Services within the same project can communicate directly using hostnames and internal ports. No additional configuration required. + +**Example:** Connect to your `api` service on port 3000: +``` +http://api:3000 ``` -Build commands are optional. Zerops triggers each command in the defined order in a dedicated build container, running from the `/build/source` directory. +**Key points:** +- Use service hostname as the address +- Use HTTP (not HTTPS) for internal communication +- Access internal ports defined in your service configuration +- Communication is automatically isolated from other projects -Before the build commands are triggered the build container contains: +### Environment Variables -1. base environment defined by the [base](#base) attribute -2. optional customisation of the base environment defined in the [prepareCommands](#preparecommands) attribute -3. your application code +Zerops automatically creates environment variables to help with internal connections between services. -#### Run build commands as a single shell instance +## VPN Access +:::tip Complete VPN Setup +See the [VPN reference guide](/references/networking/vpn). +::: -Use following syntax to run all commands in the same environment context. For example, if one command changes the current directory, the next command continues in that directory. When one command creates an environment variable, the next command can access it. +Connect securely to your project's internal network from your local machine: -```yaml -buildCommands: - - | - cargo b --release +```bash +# Connect to your project +zcli vpn up + +# Access services using internal hostnames +curl http://api:3000/health + +# Disconnect when done +zcli vpn down ``` -#### Run build commands as a separate shell instances +## Public Access -When the following syntax is used, each command is triggered in a separate environment context. For example, each shell instance starts in the home directory again. When one command creates an environment variable, it won't be available for the next command. +:::tip Complete Public Access Setup +See the [Public access reference guide](/references/networking/public-access). +::: -```yaml -buildCommands: - - cargo b --release -``` +Make your services accessible from the internet using one of three methods: -#### Command exit code +### Zerops Subdomain +**Best for:** Development and testing -If any command fails, it returns an exit code other than 0 and the build is canceled. Read the [build log](/rust/how-to/logs#build-log) to troubleshoot the error. If the error log doesn't contain any specific error message, try to run your build with the --verbose option. +- Quick setup with automatic `.zerops.app` subdomains +- Each service gets its own unique subdomain +- Automatic SSL certificate management +- Shared infrastructure (has limitations for production use) -```yaml -buildCommands: - - cargo b --release -``` +### Custom Domain +**Best for:** Production deployments -If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `buildCommands` are finished, the application build is completed and ready for the deploy phase. +- Use your own domain names +- Better performance with dedicated balancer +- Full control over SSL and routing +- Requires DNS configuration -### deployFiles +### Direct Port Access +**Best for:** Non-HTTP protocols and specialized use cases -_REQUIRED._ Selects which files or folders will be deployed after the build has successfully finished. To filter out specific files or folders, use [`.deployignore`](#deployignore) file. +- Direct access to specific ports on your services +- Supports any protocol (TCP/UDP) +- Optional firewall configuration +- Uses your project's IP addresses -```yaml -# REQUIRED. Select which files / folders to deploy after -# the build has successfully finished -deployFiles: - - target/release/~app -``` +## Next Steps -Determines files or folders produced by your build, which should be deployed to your runtime service containers. +- **Internal access setup:** [Internal Access Reference Guide](/references/networking/internal-access) +- **Public access configuration:** [Public Access Reference Guide](/references/networking/public-access) +- **VPN setup and troubleshooting:** [VPN Reference Guide](/references/networking/vpn) +- **Advanced routing and SSL:** [L7 Balancer Configuration Guide](/references/networking/l7-balancer-config) -The path starts from the **root directory** of your project (the location of `zerops.yaml`). You must enclose the name in quotes if the folder or the file name contains a space. +---------------------------------------- -The files/folders will be placed into `/var/www` folder in runtime, e.g. `./src/assets/fonts` would result in `/var/www/src/assets/fonts`. +# Features > Backup -#### Examples -Deploys a folder, and a file from the project root directory: +Zerops provides an automated, secure backup system for supported services. This guide covers how to configure, manage, and restore your backups. -```yaml -deployFiles: - - target/release/~app -``` +## Supported Services -Deploys the whole content of the build container: +Zerops provides automated backup functionality for the following services. For specific backup format details and restore instructions, visit each service's documentation: [MariaDB](/mariadb/how-to/backup), [PostgreSQL](/postgresql/how-to/manage#backups), [Qdrant](/qdrant/overview), [NATS](/nats/overview), [Meilisearch](/meilisearch/overview), [Local Storage](/local-storage/how-to/manage#backups), and [SeaweedFS](/seaweedfs/overview#backup-and-recovery). -```yaml -deployFiles: . -``` +## Managing Backups in the UI -Deploys a folder, and a file in a defined path: +By default, your data is backed up automatically **every day** between 00:00:00 UTC and 01:00:00 UTC, unless you update your settings. -```yaml -deployFiles: - - ./path/to/file.txt - - ./path/to/dir/ -``` +To manage backups, go to the service detail and choose **Backups List & Configuration** in the left menu. -#### How to use a wildcard in the path +From this section, you can: +- Create a one-time backup +- Change the frequency/disable of automatic backups +- Configure retention policies and limits -Zerops supports the `~` character as a wildcard for one or more folders in the path. +### Backup Frequency Options -Deploys all `file.txt` files that are located in any path that begins with `/path/` and ends with `/to/` +Available schedules: +- **No backups**: Disable automatic backups (not recommended) +- **Once a day**: Daily backups at a specified time +- **Once a week**: Weekly backups on a specific day and time +- **Once a month**: Monthly backups on a specific day and time +- **Custom CRON**: Define a custom schedule using CRON syntax -```yaml -deployFiles: ./path/~/to/file.txt -``` +For the Custom CRON option, you can use the following syntax: -Deploys all folders that are located in any path that begins with `/path/to/` +
Specifies the service type and version. - See what [Rust service types](/references/import-yaml/type-list#runtime-services) are currently supported. + See what [Elixir service types](/references/import-yaml/type-list#runtime-services) are currently supported.
- Optional. Defines [custom vertical auto scaling parameters](/rust/how-to/create#set-auto-scaling-configuration). + Optional. Defines [custom vertical auto scaling parameters](/elixir/how-to/create#set-auto-scaling-configuration). All verticalAutoscaling attributes are optional. Not specified attributes will be set to their default values. @@ -6537,7 +8084,7 @@ At least one service in `services:` section is required. You can create a projec Optional. Default = 1. Defines the minimum number of containers - for [horizontal autoscaling](/rust/how-to/create#horizontal-auto-scaling). + for [horizontal autoscaling](/elixir/how-to/create#horizontal-auto-scaling). Limitations: @@ -6549,7 +8096,7 @@ At least one service in `services:` section is required. You can create a projec maxContainers - Defines the maximum number of containers for [horizontal autoscaling](/rust/how-to/create#horizontal-auto-scaling). + Defines the maximum number of containers for [horizontal autoscaling](/elixir/how-to/create#horizontal-auto-scaling). Limitations: @@ -6562,7 +8109,7 @@ At least one service in `services:` section is required. You can create a projec Optional. Defines one or more secret env variables as a key value - map. See env variable [restrictions](/rust/how-to/env-variables#env-variable-restrictions). + map. See env variable [restrictions](/elixir/how-to/env-variables#env-variable-restrictions).
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field nameAllowed values
Minute0-59
Hour0-23
Day1-31
Month1-12
Week Day0–7; both 0 and 7 represent Sunday
-```yaml -deployFiles: ./path/to/~/ -``` +Examples: +- `0 2 * * *` - Every day at 2:00 AM +- `0 4 * * 0` - Every Sunday at 4:00 AM +- `0 0 1 * *` - First day of every month at midnight +- `0 */6 * * *` - Every 6 hours -Deploys all folders that are located in any path that begins with `/path/` and ends with `/to/` +### Backup Tagging -```yaml -deployFiles: ./path/~/to/ -``` -:::note Example -By default, `./src/assets/fonts` deploys to `/var/www/src/assets/fonts`, keeping the full path. Adding `~`, like `./src/assets/~fonts`, shortens it to `/var/www/fonts` -::: +Zerops uses tags to categorize and manage backups: -#### .deployignore +**Time-Based Tags** (assigned automatically): +- `daily`: Every automatic backup +- `weekly`: First backup of each week (Monday UTC) +- `monthly`: First backup of each month (1st UTC) -Add a `.deployignore` file to the root of your project to specify which files and folders Zerops should ignore during deploy. The syntax follows the same pattern format as [`.gitignore`](https://git-scm.com/docs/gitignore#_pattern_format). +**User Tags** (custom labels you create): +- Used for organization and identification (e.g., `v2.1-release`, `before-migration`, `monthly-snapshot`) +- Add when creating manual backups - up to 24 characters (letters, numbers, `:-_`) -To ignore a specific file or directory path, start the pattern with a forward slash (`/`). Without the leading slash, the pattern will match files with that name in any directory. +**Protected Tags** (configured in retention policy): +- Backups with these tag names are exempt from automatic deletion, regardless of storage limits +- Define in the backup retention configuration section of the UI and add when creating manual backups -:::tip -For consistency, it's recommended to configure both your `.gitignore` and `.deployignore` files with the same patterns. +:::important +Manual backups don't get automatic time-based tags. Always add a protected tag to preserve critical manual backups. ::: -Examples: - -```yaml title="zerops.yaml" -zerops: - - setup: app - build: - deployFiles: ./ -``` +### View and Manage Backup Files -```text title=".deployignore" -/src/file.txt -``` -The example above ignores `file.txt` only in the root src directory. -```text title=".deployignore" -src/file.txt -``` -This example above ignores `file.txt` in ANY directory named `src`, such as: -- `/src/file.txt` -- `/folder2/folder3/src/file.txt` -- `/src/src/file.txt` +In this section, you can: +- Create manual backups +- View all backups with their timestamps and sizes +- Download backups +- Delete backups :::note -`.deployignore` file also works with [`zcli service deploy`](/references/zcli/commands#deploy) command. +When creating manual backups via the UI, you'll see immediate feedback. If the backup takes longer than 10 seconds, the process continues in the background. You can verify completion by refreshing the backup list or checking service logs. ::: -### cache - -_OPTIONAL._ Defines which files or folders will be cached for the next build. +## Storage and Limits -```yaml -# OPTIONAL. Which files / folders you want to cache for the next build. -# Next builds will be faster when the cache is used. -cache: file.txt -``` +### Project Storage Quotas -The cache attribute helps optimize build times by preserving specified files between builds. +Each Zerops project has a **technical maximum backup storage limit of 1 TiB**: +- Only full backups are stored +- If a backup would exceed the storage limit, it will not be stored +- This quota is shared across all service backups within the project -The cache attribute supports the [~ wildcard character](#how-to-use-a-wildcard-in-the-path). +### Billing +- **Lightweight Project Core**: 5 GB backup storage and 100 GB egress included +- **Serious Project Core**: 25 GB backup storage and 3 TB egress included -Learn more about the [build cache system](/features/build-cache) in Zerops. +When you exceed your plan's free limits, **additional charges apply** according to our [pricing](/company/pricing#overage-costs). -### envVariables +### Retention Policy and Configuration -_OPTIONAL._ Defines the environment variables for the build environment. +Zerops manages which backups are kept using a retention policy that you can customize through the UI: -Enter one or more env variables in following format: +**Default Time-Based Retention** (minimums): +- At least 7 daily backups +- At least 4 weekly backups +- At least 3 monthly backups -```yaml -zerops: - # define hostname of your service - - setup: app - # ==== how to build your application ==== - build: - base: rust@latest - … +**Default Resource Limits** (maximums): +- Max 50 total backups per service +- Storage limited to your project's 1 TiB technical maximum (with billing for usage beyond free tier) - # OPTIONAL. Defines the env variables for the build environment: - envVariables: - RUST_ENV: production - DB_NAME: db - DB_HOST: db - DB_USER: db - DB_PASS: ${db_password} -``` +**Customization Options:** +You can modify these defaults in the backup retention configuration interface: +- **Set Protected Tags**: Define tag names that prevent automatic deletion of backups +- **Configure Maximum Limits**: Adjust total number of backups and storage size limits per service +- **Customize Minimum Retention**: Change how many daily, weekly, and monthly backups to keep +- **Set Type-Specific Limits**: Control maximum backups for each type (0 means unlimited, subject to total limits) -Read more about [environment variables](/rust/how-to/env-variables) in Zerops. +:::important +Backups with [protected tags](#backup-tagging) and the minimum required time-based backups will always be kept, even if they exceed the limits above. This ensures your critical recovery points are preserved. +::: -## Runtime configuration +If you need more storage space, contact our support team. -### base +### When Deleting Services or Projects -_OPTIONAL._ Sets the base technology for the runtime environment. -If you don't specify the `run.base` attribute, Zerops keeps the current Rust version for your runtime. +Deleted services/projects have their backups kept for a 7-day grace period before final removal. -Following options are available for Rust builds: +## Command Line Interface -- `rust@1`, `rust@latest`, `rust@stable` -- `rust@1.86` -- `rust@1.80` -- `rust@1.78` -- `rust@nightly` +You can also manage backups using the Zerops CLI (zCLI): -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: - # REQUIRED. Sets the base technology for the build environment: - base: rust@latest - ... +```bash +# Create a backup +zcli backup create myServiceName - # ==== how to run your application ==== - run: - # OPTIONAL. Sets the base technology for the runtime environment: - base: rust@latest - ... +# Create a backup with tags (including protection) +zcli backup create myServiceName --tags pre-deploy,protected ``` -

- The base runtime environment contains {data.alpine.default}, the - selected major version of Rust, Zerops command line tool, npm, yarn, git and - npx tools. -

+Check `zcli backup --help` for current commands. -:::info -You can change the base environment when you need to. Just simply modify the zerops.yaml in your repository. +:::note +zCLI currently focuses on creation; listing/deletion/tag management is primarily via UI. ::: -If you need to install more technologies to the runtime environment, set multiple values as a yaml array. For example: +## Restoring Backups -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: - # REQUIRED. Sets the base technology for the build environment: - base: rust@latest - ... +Restoration involves downloading backups and using service-specific methods. Zerops facilitates the backup creation and download; the restore action uses service-specific tools and APIs. - # ==== how to run your application ==== - run: - # OPTIONAL. Sets the base technology for the runtime environment: - base: - - rust@latest - prepareCommands: - - zsc add go@latest - ... -``` +1. **Download**: Find the backup in the UI (by date/tag) and download it +2. **Prepare**: Set up your target environment (clean existing data or use a new instance) +3. **Restore**: Use service-specific tools via Zerops VPN, run the restore during deployment, or use the service API if available. For service-specific restore instructions, see each service's documentation linked in the [Supported Services](#supported-services) section above. -See the full list of supported [run base environments](/zerops-yaml/base-list). +:::info Continuous Improvement +We're working on enhancing the restore experience, potentially including more automated options in the future. +::: -To customize your build environment use the `prepareCommands` attribute. +For assistance with restoration, contact Zerops support. -### os +## High Availability (HA) -_OPTIONAL._ Sets the operating system for the runtime environment. +For multi-node HA services: +- **Automatic Backups**: Run on a randomly selected healthy node +- **Manual Backups**: Typically run on the primary/designated node (check logs) +- **Cluster State**: Other nodes stay operational -Following options are available: +## Security -- `alpine` -- `ubuntu` +Backups are protected with end-to-end encryption: -Default value is `alpine`. +- **Unique Encryption**: Each project gets its own encryption key (X25519) +- **Secure Process**: Data is encrypted immediately as backups are created +- **Zero-Trust**: Even Zerops staff cannot access your raw backup data +- **Isolated Storage**: Backups are stored separately from your regular data +- **Secure Download**: Backups are only decrypted when you download them -We are currently using following os version: +:::important +When a project is deleted, the encryption key is permanently destroyed after 7 days, making the backup data unrecoverable. +::: -- {data.alpine.default} -- {data.ubuntu.default} +## Best Practices -:::caution -The os version is fixed and cannot be customised. -::: +1. **Create backups before major changes**: + - Always create a manual backup with a protected tag before database migrations, deployments, or large data operations + - Use descriptive tags like `pre-migration` or `pre-release-v2` -### ports +2. **Manage storage efficiently**: + - Regularly check usage in the Project Overview & Service Backup tabs to monitor free tier usage and stay within the 1 TiB technical limit + - Remove unnecessary backups, especially those with [protected tags](#backup-tagging) + - Adjust [retention policies](#retention-policy-and-configuration) based on your recovery needs + - Regularly review and clean up old backups to optimize storage usage and minimize overage costs -_OPTIONAL._ Specifies one or more internal ports on which your application will listen. +3. **Test your restore process** periodically in a non-production environment to ensure you can recover when needed -Projects in Zerops represent a group of one or more services. Services can be of different types (runtime services, databases, message brokers, object storage, etc.). All services of the same project share a **dedicated private network**. To connect to a service within the same project, just use the service hostname and its internal port. +## Troubleshooting -For example, to connect to a Rust service with hostname = "app" and port = 8080 from another service of the same project, simply use `app:8080`. Read more about [how to access a Rust service](/references/networking/internal-access#basic-service-communication). +### Storage Quota Issues +**Cause**: High backup frequency, long retention periods, or many protected tags can lead to exceeding free tier limits or approaching technical maximums. -Each port has following attributes: +**Solutions**: +1. **Review & Prune**: Delete unnecessary manual backups or remove protected status from older backups +2. **Adjust Retention Policy**: Reduce minimum retention counts if your recovery requirements allow +3. **Optimize Schedule**: Reduce backup frequency if daily backups aren't essential +4. **Monitor Costs**: Check usage against your free tier (5GB/25GB) to avoid unexpected overage charges +5. **Contact Support**: If you need assistance managing storage - - - - - - - - - - - - - - - - - - - - - -
ParameterDescription
portDefines the port number. You can set any port number between 10 and 65435. Ports outside this interval are reserved for internal Zerops systems.
protocolOptional. Defines the protocol. Allowed values are TCP or UDP. Default value is TCP.
httpSupportOptional. httpSupport = true is the default setting for TCP protocol. Set httpSupport = false if a web server isn't running on the port. Zerops uses this information for the configuration of [public access](/features/access). httpSupport = true is available only in combination with the TCP protocol.
+### Backup Failures +**Cause**: Service health issues, resource exhaustion, or platform problems. -### prepareCommands +**Solutions**: +1. **Check Service Logs**: Look for error messages around the scheduled backup time +2. **Verify Service Health**: Ensure the service is running properly with adequate resources +3. **Check Platform Status**: Visit status.zerops.io for any ongoing incidents +4. **Contact Support**: If issues persist, reach out with service name, failure time, and relevant logs -_OPTIONAL._ Customises the Rust runtime environment by installing additional dependencies or tools to the runtime base environment. +---------------------------------------- -

- The base Rust environment contains {data.alpine.default}, the selected - major version of Rust, [Zerops command line tool](/references/cli) and `npm` , `yarn`, `git` and `npx` tools. To install additional packages or tools add one or - more prepare commands: -

+# Features > Build Cache -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: - ... - # ==== how to run your application ==== - run: - # OPTIONAL. Customise the runtime environment by installing additional packages - # or tools to the base Rust runtime environment. - prepareCommands: - - sudo apt-get something - - curl something else - ... -``` +> Zerops implements a sophisticated two-layer caching strategy that optimizes build times while maintaining complete control over the build environment. This documentation explores the architecture, configuration patterns, and practical implementation of the build cache system. -When the first deploy with a defined prepare attribute is triggered, Zerops will +## Architecture Overview -1. create a prepare runtime container -2. optionally: [copy selected folders or files from your build container](#copy-folders-or-files-from-your-build-container) -3. run the `prepareCommands` commands in the defined order +The build cache operates through two distinct layers: -:::note -`run.prepareCommands` run in the `/home/zerops` directory. -::: +1. **Base Layer**: Comprises the OS, installed dependencies, and prepare commands +2. **Build Layer**: Contains the state after executing build commands -#### Command exit code +The layers work together to create an efficient and predictable build environment, though they are currently coupled in their cache invalidation behavior (invalidating one layer affects the other). -If any command fails, it returns an exit code other than 0 and the deploy is canceled. Read the [prepare runtime log](/rust/how-to/logs#prepare-runtime-log) to troubleshoot the error. If the command ends successfully, it returns the exit code 0 and Zerops triggers the following command. When all `prepareCommands` commands are finished, your custom runtime environment is ready for the deploy phase. +### Cache Implementation -#### Cache of your custom runtime environment +The caching mechanism is implemented through an efficient file movement strategy. This approach ensures near-instantaneous cache operations through simple directory relocation within the container, implementing the following characteristics: -Some packages or tools can take a long time to install. Therefore, Zerops caches your custom runtime environment after the installation of your custom packages or tools is completed. When the second or following deploy is triggered, Zerops will use the custom runtime cache from the previous deploy if following conditions are met: +- Files are moved between `/build/source` and `/build/cache` using container-level rename operations +- No packaging, compression, or network transfer is involved +- Cache preservation is achieved through simple directory relocation within the container +- Files maintain their original state and permissions throughout the process -1. Content of the [build.addToRunPrepare](#copy-folders-or-files-from-your-build-container) and `run.prepareCommands` attributes didn't change from the previous deploy -2. The custom runtime cache wasn't invalidated in the Zerops GUI. +:::note +See detailed [build process lifecycle](#build-process-lifecycle). +::: -To invalidate the Zerops runtime cache go to your service detail in Zerops GUI, choose **Service dashboard & runtime containers** from the left menu and click on the **Open pipeline detail** button. Then click on the **Clear runtime prepare cache** button. +## Configuration Guide -When the prepare cache is used, Zerops doesn't create a prepare runtime container and executes the deployment of your application directly. +### Essential zerops.yaml Fields -#### Single or separated shell instances +The following fields in `zerops.yaml` affect build cache behavior: -You can configure your prepare commands to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). +**Direct Cache Configuration**: +- `build.cache`: Explicitly defines what should be cached through paths or patterns -### Copy folders or files from your build container +**Cache Invalidation Triggers**: +These parameters trigger cache invalidation when modified: +- `build.os`: Base operating system selection +- `build.base`: Pre-installed software stacks and runtimes +- `build.prepareCommands`: System preparation and dependency installation +- `build.cache`: Changes to cache configuration -

- The prepare runtime container contains {data.alpine.default}, the - selected major version of Rust, [Zerops command line tool](/references/cli) and `npm`, `yarn`, `git` and `npx` tools. -

+**Build Artifact Generation**: +- `build.buildCommands`: Generates the build artifact that will be deployed. -The prepare runtime container does not contain your application code nor the built application. If you need to copy some folders or files from the build container to the runtime container (e.g. a configuration file) use the `addToRunPrepare` attribute in the [build section](#build-pipeline-configuration). +## Cache Configuration Patterns +### Pattern 1: System-Wide Cache Control ```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: - ... - addToRunPrepare: ./runtime-config.yaml - - # ==== how to run your application ==== - run: - # OPTIONAL. Customise the runtime environment by installing additional packages - # or tools to the base Rust runtime environment. - prepareCommands: - - sudo apt-get something - - curl something else - ... +build: + cache: true # Cache everything + # OR + cache: false # Intended to disable all caching ``` -In the example above Zerops will copy the `runtime-config.yaml` file from your build container **after the build has finished** into the new **prepare runtime** container. The copied files and folders will be available in the `/home/zerops` folder in the new prepare runtime container before the prepare commands are triggered. +The boolean values provide system-wide cache control: -### initCommands +`cache: true`: +- Preserves the entire build container state +- Maintains system-level package installations +- Ideal for globally installed packages (Python/PHP packages, Go modules) -_OPTIONAL._ Defines one or more commands to be run each time a new runtime container is started or a container is restarted. +`cache: false`: +- Intended to disable all caching +- Currently, due to layer coupling, only files within `/build/source` are not cached +- Everything outside `/build/source` remains cached (see [Common Pitfalls: Layer Coupling](#current-pitfalls)) +### Pattern 2: Path-Specific Caching ```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: ... +# Single path +build: + cache: node_modules - # ==== how to run your application ==== - run: - # OPTIONAL. Run one or more commands each time a new runtime container - # is started or restarted. These commands are triggered before - # your Rust application is started. - initCommands: - - rm -rf ./cache +# Multiple paths +build: + cache: + - node_modules + - package-lock.json + - .build ``` -These commands are triggered in the runtime container before your Rust application is started via the [start command](#start). - -:::note -`run.initCommands` run in the `/var/www` directory. -::: - -Use init commands to clean or initialise your application cache or similar operations. - -:::caution -The init commands will delay the start of your application each time a new runtime container is started (including the horizontal [scaling](/rust/how-to/scaling) or when a runtime container is restarted). +Execution flow: +1. Source code extraction to `/build/source` +2. Build command execution +3. Specified path preservation in `/build/cache` +4. Cached content restoration (no-clobber mode - source files take precedence) -Do not use the init commands for customising your runtime environment. Use the [run:prepareCommands](#preparecommands-1) attribute instead. +:::tip +Ideal for non-versioned dependencies in your working directory (e.g., `node_modules`, `vendor`, `.venv`). ::: -#### Command exit code - -If any of the `initCommands` fails, it returns an exit code other than 0, but deploy is **not** canceled. After all init commands are finished, regardless of the status code, the application is started. Read the [runtime log](/rust/how-to/logs#runtime-log) to troubleshoot the error. - -#### Single or separated shell instances - -You can configure your `initCommands` to be run in a single shell instance or multiple shell instances. The format is identical to [build commands](#buildcommands). - -### envVariables +## Path Pattern Reference -_OPTIONAL._ Defines the environment variables for the runtime environment. +Zerops supports [Go's filepath.Match](https://pkg.go.dev/path/filepath#Match) syntax. Consider this example structure: -Enter one or more env variables in following format: +``` +├── node_modules/ +├── package.json +├── package-lock.json +└── subdir/ + ├── file1.txt + ├── file2.txt + └── file3.md +``` +Pattern examples and matches: ```yaml -zerops: - # define hostname of your service - - setup: app - # ==== how to run your application ==== - run: - # OPTIONAL. Defines the env variables for the runtime environment: - envVariables: - RUST_ENV: production - DB_NAME: db - DB_HOST: db - DB_USER: db - DB_PASS: ${db_password} +build: + cache: + - "subdir/*.txt" # Matches: subdir/file1.txt, subdir/file2.txt + - "package*" # Matches: package.json, package-lock.json + - "node_modules" # Matches: entire node_modules directory recursively ``` -Read more about [environment variables](/rust/how-to/env-variables) in Zerops. - -### start +:::note +All patterns resolve relative to `/build/source`. Path variations like `./node_modules`, `node_modules`, and `node_modules/` are treated identically. +::: -_REQUIRED._ Defines the start command for your Rust application. +## Build Process Lifecycle -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: ... +1. **Initialization Phase** + - Build container startup + - Builder process launch + - Source code loading into `/build/source` - # ==== how to run your application ==== - run: - # REQUIRED. Your Rust application start command - start: ./app -``` +2. **Cache Restoration Phase** + - Cached file movement to `/build/source` (no-clobber mode) + - Source file precedence handling + - Conflict logging (no build interruption) + - Cache directory cleanup -### health check +3. **Build Execution Phase** + - Build command processing + - Artifact packaging (`build.deployFiles`) -_OPTIONAL._ Defines a health check. +4. **Cache Preservation Phase** + - Specific cache files movement outside `/build/source` + - `/build/source` directory cleanup + - Container termination -`healthCheck` requires either one `httpGet` object or one `exec` object. +## Cache Invalidation Reference -#### httpGet +The build cache invalidates under these conditions: -Configures the health check to request a local URL using a HTTP GET method. +1. **Manual Triggers** + - API call: `DELETE /service-stack/{id}/build-cache` + - GUI: Manual cache clear action -Following attributes are available: +2. **Version Management** + - Backup app version activation via `PUT /app-version/{id}/deploy` - - - - - - - - - - - - - - - - - - - - - - - - - -
ParameterDescription
portDefines the port of the HTTP GET request. -The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
pathDefines the URL path of the HTTP GET request. -The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. -If your application requires a https request, set scheme: https
+3. **Configuration Changes** + Any modifications to: + ```yaml + build.os + build.base + build.prepareCommands + build.cache + ``` -**Example:** +### Current Pitfalls -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: ... +The current implementation has some important characteristics: - # ==== how to run your application ==== - run: - # REQUIRED. Your Rust application start command - start: ./app +1. **Layer Coupling** + ```yaml + build: + base: go@1 + prepareCommands: + - sudo apk update + - sudo apk add sqlite + buildCommands: + - go build -o app main.go + cache: false + ``` + Even with `cache: false`, Go modules outside `/build/source` remain cached. - # OPTIONAL. Define a health check with a HTTP GET request option. - # Configures the check on http://127.0.0.1:80/status - healthCheck: - httpGet: - port: 80 - path: /status -``` +2. **Cascade Invalidation** + ```yaml + build: + base: node@22 + prepareCommands: + - sudo apk update + - sudo apk add sqlite vim # Adding 'vim' invalidates everything + buildCommands: + - npm install + - npm build + cache: + - node_modules + ``` + Modifying `prepareCommands` invalidates both layers, including cached `node_modules`. -#### exec +## Real-World Implementation Examples -Configures the health check to run a local command. -Following attributes are available: +### Node.js Project with TypeScript +```yaml +build: + base: node@22 + buildCommands: + - npm ci + - npm run build + cache: + - node_modules + - .next + - .turbo + - package-lock.json +``` - - - - - - - - - - - - - -
ParameterDescription
command - Defines a local command to be run. +### Go Project with Multiple Dependencies +```yaml +build: + base: go@1 + prepareCommands: + - sudo apk add build-base + buildCommands: + - go mod download + - go build -o bin/app cmd/main.go + cache: true # Caches entire Go modules directory +``` - The command has access to the same [environment variables](/rust/how-to/create#set-secret-environment-variables) as your Rust application. +### PHP/Laravel Project +```yaml +build: + base: php@8.3 + buildCommands: + - composer install --no-dev + - php artisan optimize + cache: + - vendor + - composer.lock +``` - A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. -
+## Debugging and Monitoring -**Example:** +* **Build Logs** + - Cache operations are detailed in build logs + - File conflicts during restoration are logged + - Cache preservation status is visible -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: ... +## Implementation Best Practices - # ==== how to run your application ==== - run: - # REQUIRED. Your Rust application start command - start: ./app +### Cache Strategy Optimization - # OPTIONAL. Define a health check with a shell command. - healthCheck: - exec: - command: | - touch grass - rm -rf life - mv /outside/user /home/user -``` +1. **Layer Management** + - Maintain stable `prepareCommands` to prevent cache invalidation + - Group related prepare commands logically -### crontab +2. **Performance Optimization**: + - Cache package manager lock files alongside dependency directories + - Use system-wide caching (`cache: true`) for languages with global package managers -_OPTIONAL._ Defines cron jobs. +3. **Performance Tuning** + - Leverage system-wide caching for complex builds + - Monitor build logs for cache operations and potential conflicts + - Use explicit patterns for precise control + - Don't over-optimize – the system handles large caches efficiently -Setup cron jobs in the following format: +## Future Development -```yaml -zerops: - # define hostname of your service - - setup: app +Planned system enhancements include: +- Layer independence implementation +- Granular cache control mechanisms +- Enhanced layer management capabilities +- Improved cache invalidation patterns - # ==== how to run your application ==== - run: - crontab: - # REQUIRED. Sets the command to execute: - - command: "" - # REQUIRED. Sets the interval time to execute: - timing: "0 * * * *" -``` -Read more about setting up [cron](/zerops-yaml/cron) in Zerops. +---------------------------------------- -## Deploy configuration +# Features > Cdn -### readiness check -_OPTIONAL._ Defines a readiness check. Read more about how the [readiness check works](/rust/how-to/deploy-process#readiness-checks) in Zerops. +Zerops CDN is a global content delivery network that brings your static content closer to your users, resulting in faster load times and improved user experience. Built on Nginx and Cloudflare geo-steering technology, our CDN automatically routes users to the nearest server location based on their DNS request. -`readinessCheck` requires either one `httpGet` object or one `exec` object. +## Key Benefits -#### httpGet +- **Global Reach**: Serve content from strategic locations across the world +- **Reduced Latency**: Content is delivered from the server closest to your users +- **Simple Integration**: No complex configuration required -Configures the readiness check to request a local URL using a http GET method. +## Global CDN Infrastructure -Following attributes are available: +Zerops CDN operates across **6 strategic regions** to ensure your content is always delivered from a location close to your users: - +
- - + + + - - + + + + - - + + - - + + + - - + + + - + + + + + + + + + + +
ParameterDescriptionRegionLocationCoverage Area
portDefines the port of the HTTP GET request. -The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}EUCZPrague, Czech RepublicPrimary European coverage + failover for all regions
pathDefines the URL path of the HTTP GET request. -The readiness check will trigger a GET request on {'http://127.0.0.1:{port}/{path}'}DEFalkenstein, Germany
hostOptional. The readiness check is triggered from inside of your runtime container so it always uses the localhost 127.0.0.1. If you need to add a host to the request header, specify it in the host attribute.UKLondon, United KingdomUK and surrounding areas
schemeOptional. The readiness check is triggered from inside of your runtime container so no https is required. -If your application requires a https request, set scheme: httpsAUSydney, AustraliaAustralia and Oceania
SGSingapore, SingaporeSoutheast Asia
CABeauharnois, CanadaNorth America
-**Example:** +### Geo-Steering Technology +Zerops CDN's geo-steering technology automatically routes users to the server location closest to them. Here's how it works: -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: ... +* **Automatic routing**: Users are directed to the optimal CDN node based on their geographic location +* **Quick failover**: The DNS TTL is set to just 30 seconds, allowing fast recovery if a node fails +* **Redundancy**: If any node becomes unavailable, Cloudflare automatically redirects traffic to the next closest node +* **Reliable backup**: The EU region serves as the ultimate fallback - if all other nodes go down, EU will always be served in DNS - # ==== how to deploy your application ==== - deploy: - # OPTIONAL. Define a readiness check with a HTTP GET request option. - # Configures the check on http://127.0.0.1:80/status - readinessCheck: - httpGet: - port: 80 - path: /status +## CDN Modes and Implementation - # ==== how to run your application ==== - run: ... -``` +Zerops CDN currently supports two distinct usage modes (with a third mode coming soon), each designed for specific content delivery needs. -Read more about how the [readiness check works](/rust/how-to/deploy-process#readiness-checks) in Zerops. +### Object Storage Mode -#### exec +Perfect for efficiently delivering media files, documents, and other static assets stored in Zerops [Object Storage](/object-storage/overview) to users across different geographical regions. -Configures the readiness check to run a local command. -Following attributes are available: +**Setup process:** +1. Create an Object Storage service or select an existing one +2. Enable the CDN option for this service +3. Set appropriate public read access policies for objects you want to serve via CDN - - - - - - - - - - - - - -
ParameterDescription
command - Defines a local command to be run. +**Accessing content:** +```txt +https://storage.cdn.zerops.app/your-bucket/path/to/file +``` - The command has access to the same [environment variables](/rust/how-to/create#set-secret-environment-variables) as your Rust application. +:::tip +Access the storage CDN URL via the `storageCdnUrl` **project** environment variable `${storageCdnUrl}/your-bucket/path/to/file`. +::: - A single string is required. If you need to run multiple commands create a shell script or, use a multiline format as in the example below. -
+### Static Mode -**Example:** +Ideal for caching and delivering static website assets like HTML, CSS, JavaScript, and images served from your custom domains. -```yaml -zerops: - # hostname of your service - - setup: app - # ==== how to build your application ==== - build: ... +**Setup process:** +1. Configure domain access for your service through the L7 HTTP Balancer section +2. Access domain settings via the **three dots menu** or **gear icon** next to your domain entry +3. In the "Project Domain Access Modification" dialog, enable the **"Enable CDN for static files"** toggle +4. Optionally enable "Automatically install SSL Certificates" if not already configured - # ==== how to deploy your application ==== - deploy: - # OPTIONAL. Define a readiness check with a HTTP GET request option. - # Configures the check on http://127.0.0.1:80/status - readinessCheck: - exec: - command: | - touch grass - rm -rf life - mv /outside/user /home/user +**Accessing content:** +```txt +https://static.cdn.zerops.app/your-domain.com/path/to/file ``` -Read more about how the [readiness check works](/rust/how-to/deploy-process#readiness-checks) in Zerops. +:::tip +Access the static CDN URL via the `staticCdnUrl` **project** environment variable `${staticCdnUrl}/your-domain.com/path/to/file`. +::: +:::warning Wildcard Domains Not Supported +Static CDN cannot be activated for wildcard domains (e.g., *.example.com). You must use specific domain names. +::: ----------------------------------------- +### API Mode *(Coming Soon)* -# Ruby > Overview +Designed for caching API responses to reduce load on your backend services and deliver faster responses to clients. +**Environment variable:** Once available, you'll be able to access the API CDN URL via the `apiCdnUrl` **project** environment variable. -[Ruby ↗](https://www.ruby-lang.org/en/) is a dynamic, object-oriented programming language with a focus on simplicity and programmer happiness. +:::warning +API Mode is currently under development and will be available in a future release. +::: -As said, there is no need for coding yet, we have created a [Github repository ↗](https://github.com/zerops-recipe-apps/ruby-hello-world-app), a **_recipe_**, containing a simple Ruby (Sinatra) web application served by Puma. The repo will be used as a source from which the app will be built. +### HTML Implementation Examples -1. Log in/sign up to [Zerops GUI ↗](https://app.zerops.io) +Here's how to integrate CDN URLs in your HTML code: -2. In the **Projects** box click on **Import a project** and paste in the following YAML config: +```html + + -```yaml -project: - name: recipe-ruby - tags: - - zerops-recipe + -services: - - hostname: app - type: ubuntu/ruby@4.0 - zeropsSetup: prod - enableSubdomainAccess: true - buildFromGit: https://github.com/zerops-recipe-apps/ruby-hello-world-app + - - hostname: db - type: postgresql@16 - mode: NON_HA - priority: 1 -``` + + + -3. Click on **Import project** and wait until all pipelines have finished. + + +``` -**That's it, your application is now up and running! :star: Let's check it works:** +### Testing Specific CDN Nodes -1. A _subdomain_ should have been enabled and visible in the project's **IP addressed & Public Routing Overview** box. Its format should look similar to this `https://app-808-8080.prg1.zerops.app`. -2. Click or the `subdomain` URL to open it in a browser and you should see +For testing or debugging purposes, you can bypass the automatic geo-steering and access a specific CDN node directly: ``` -{"type":"ruby","greeting":"Hello from Zerops!","status":{"database":"OK"}} +https://{region}-{mode}.cdn.zerops.app/path/to/content ``` -:::tip -Do you have any questions? Check the step-by-step tutorial, browse the documentation and join our **[Discord](https://discord.com/invite/WDvCZ54)** community to get help from our team and other members. -::: - -## How to start - -It doesn't matter whether it's your first curious introduction to Zerops, you have already mastered the basics and are looking for a tiny detail or inspiration. Below, choose a section that fits your needs: - -- [Care for details?](/ruby/how-to/create) — Dive in all Zerops has to offer for your Ruby application. -- [Ruby recipes](https://github.com/zeropsio?q=ruby&type=all&language=&sort=) — Get inspired by already existing repositories, ready to be imported to Zerops. - -## Feature Highlights - -- [Create Ruby service](/ruby/how-to/create) — Start with creating a Ruby service using GUI or zCLI. -- [Zerops.yaml](/ruby/how-to/build-pipeline#add-zeropsyaml-to-your-repository) — See a full example of zerops.yaml file to create your own app. -- [Scaling configuration](/ruby/how-to/scaling) — Set up scaling of your Ruby application so that it runs smoothly while using only necessary resources. - -{" "} +Available region prefixes: `cz`, `de`, `au`, `sg`, `uk`, and `ca` -- [Customize build environment](/ruby/how-to/build-process#customize-build-environment) -- [Customize runtime environment](/ruby/how-to/customize-runtime) +**Examples:** +- Test Australia node: `https://au-storage.cdn.zerops.app/my-bucket/test.jpg` +- Test UK node: `https://uk-static.cdn.zerops.app/my-domain.com/index.html` -## When in doubt, reach out +## Managing CDN Content -Don't know how to start or got stuck during the process? You might not be the first one, visit the FAQ section to find out. +### Cache Lifecycle -In case you haven't found an answer (and also if you have), we and our community are looking forward to hearing from you on Discord. +Content served through Zerops CDN follows this lifecycle: -Have you build something that others might find useful? Don't hesitate to share your knowledge! +1. **First Request**: When a user requests content not yet in the CDN cache, the request goes to the origin server (your Zerops service), and the response is cached at the CDN node +2. **Subsequent Requests**: Further requests for the same content are served directly from the CDN cache, reducing latency and origin server load +3. **Cache Expiration**: By default, content remains cached for 30 days unless explicitly purged +4. **Automatic Management**: When CDN storage reaches capacity, the least recently used content is automatically removed -- [FAQ](/ruby/faq) — Most common questions in one place. -- [Discord](https://discord.com/invite/WDvCZ54) — Join our core team and Zerops community on Discord. Ask questions and share your tips with other members. +:::note Important Cache Behavior +Zerops CDN implements a fixed 30-day TTL policy. Currently, HTTP caching headers such as `Cache-Control`, `Expires`, `Pragma`, etc. do not influence CDN caching behavior. To refresh content sooner than the 30-day period, use the [purge API](#api-reference). -## Popular Guides +Your `Cache-Control` headers will still affect browser caching behavior. +::: -- [zCLI](/references/cli) — Get even more out of Zerops with the zCLI command line tool. -- [Zerops VPN](/references/networking/vpn) — Connect to your services easily with Zerops VPN. +### When to Purge Cache +You should consider purging cached content when: ----------------------------------------- +- **Content Updates**: You've updated content but kept the same URL (e.g., updated images, CSS files) +- **Deployment Rollouts**: You've deployed a new version of your application +- **Emergency Removal**: You need to immediately remove content that was accidentally made public +- **Testing Changes**: You want to ensure users see the latest version during testing -# Ruby > How To > Upgrade +### Purging Cached Content +Zerops provides multiple ways to manage and purge cached content before its normal expiration: +- **Command Line**: Use the `zsc cdn purge` [command](/references/zsc#cdn) available in all Zerops containers: + ```sh + # Purge all content for a domain + zsc cdn purge example.com + # Purge all content (wildcard) + zsc cdn purge example.com "/*" + # Purge specific file + zsc cdn purge example.com "/path/to/my-file$" + ``` ----------------------------------------- + :::important + - This command must be executed in any container within the project that has the CDN-enabled domain active + - Currently only works for [Static Mode](#static-mode) CDN + ::: -# Ruby > How To > Trigger Pipeline +- **API Endpoints**: For programmatic control, use the [API endpoints](#api-reference). Here are ready-to-use curl examples for quickly purging content in your scripts: + ```sh + # Static mode: Purge all content for a domain + curl --location --request PUT "https://api.app-prg1.zerops.io/api/rest/public/project/$PROJECT_ID/purge-cdn/static/$DOMAIN/*" \ + --header "Authorization: Bearer $USER_OR_ACCESS_TOKEN" + ``` + ```sh + # Storage mode: Purge all content for object storage + curl --location --request PUT "https://api.app-prg1.zerops.io/api/rest/public/service-stack/$OBJECT_STORAGE_SERVICE_ID/purge-cdn/*" \ + --header "Authorization: Bearer $USER_OR_ACCESS_TOKEN" + ``` ----------------------------------------- +#### Purge Pattern Examples -# Ruby > How To > Scaling + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PatternDescriptionExample
`/*`Purges all contentUseful after major updates
`/images/*`Purges all content in a directoryClear all cached images
`/css/main.css$`Purges a specific fileUpdate a single CSS file
`/2023*`Purges content starting with patternClear content with date prefix
+:::warning Pattern Rules +- Wildcards (`*`) must be at the end of the pattern +- Specific files must include `$` at the end +- Nested wildcards (e.g., `/dir/*.jpg`) are not supported +::: +## API Reference ----------------------------------------- +Zerops provides a comprehensive set of API endpoints to manage your CDN configuration and content. For complete information about base URLs, authorization, and general API usage, please refer to our [API specification](/references/api). -# Ruby > How To > Logs +The endpoint links below will take you to the Swagger documentation with detailed request/response schemas and examples: +### CDN Management API +- **[Enable CDN for Storage ↗](https://api.app-prg1.zerops.io/api/rest/public/swagger/#/PublicServiceStack/EnableStorageCdn)** `PUT /api/rest/public/service-stack/{id}/cdn` +- **[Disable CDN for Storage ↗](https://api.app-prg1.zerops.io/api/rest/public/swagger/#/PublicServiceStack/DisableStorageCdn)** `DELETE /api/rest/public/service-stack/{id}/cdn` +- **[Create Object Storage with CDN ↗](https://api.app-prg1.zerops.io/api/rest/public/swagger/#/PublicServiceStackObjectStorage/CreateObjectStorageV1)** `POST /api/rest/public/service-stack/object_storage_v1` +- **[Create Domain Routing with CDN ↗](https://api.app-prg1.zerops.io/api/rest/public/swagger/#/PublicPublicHttpRouting/CreatePublicHttpRouting)** `POST /api/public/public-http-routing` +- **[Update Domain Routing with CDN ↗](https://api.app-prg1.zerops.io/api/rest/public/swagger/#/PublicPublicHttpRouting/UpdatePublicHttpRouting)** `PUT /api/public/public-http-routing/{id}` ----------------------------------------- +### Cache Purge API -# Ruby > How To > Filebrowser +- **[Purge Storage Mode Cache ↗](https://api.app-prg1.zerops.io/api/rest/public/swagger/#/PublicServiceStack/PurgeStorageCdn)** `PUT /api/rest/public/service-stack/{id}/purge-cdn/{path}` +- **[Purge Static Mode Cache ↗](https://api.app-prg1.zerops.io/api/rest/public/swagger/#/PublicProject/PurgeStaticCdn)** `PUT /api/rest/public/project/{id}/purge-cdn/static/{domain}/{path}` +- **Purge Api Mode Cache *(Coming soon)*** +## Troubleshooting +Having issues with your CDN? Here are solutions to the most common problems: ----------------------------------------- +#### Content Not Updated After Changes +* **Issue:** You've updated content, but users still see the old version. +* **Possible Cause:** The CDN cache is continuing to serve the previously cached version. +* **Solution:** + - Use the [purge API](#api-reference) with the specific content path + - For immediate changes, use versioned file names (e.g., `style.v2.css` instead of just `style.css`) -# Ruby > How To > Env Variables +#### Content Not Being Cached +* **Issue:** Your content isn't being cached by the CDN. +* **Possible Cause:** Missing public read permissions on objects. +* **Solution:** + - For object storage: Check bucket and object access policies + - Verify the object is accessible directly before attempting CDN access +:::note +Remember that only publicly accessible objects will be cached by the CDN. Private objects will always be fetched directly from the origin. +::: +#### Environment Variables Not Available +* **Issue:** You can't access the new CDN-related project level environment variables in your containers. +* **Possible Cause:** When new environment variables are created, existing services need to be restarted to access them. Services created before the CDN feature release require special handling. +* **Solution:** + - For services created after CDN release: Restart the service to apply the new environment variables + - For services created before CDN release: Add and then remove a dummy environment variable in the project settings adn restart the service ----------------------------------------- +#### Unexpected 404 Errors +* **Issue:** Users receive 404 errors when accessing content via CDN. +* **Possible Cause:** Incorrect CDN URL formatting or missing content at origin. +* **Solution:** + - Double-check your [URL structure](#) (pay attention to domain names and paths) + - Verify content exists at the origin before attempting CDN access + - Test accessing the content directly from origin first -# Ruby > How To > Deploy Process +**Correct URL patterns:** +- Object Storage: `https://storage.cdn.zerops.app/your-bucket/path/to/file` +- Static Mode: `https://static.cdn.zerops.app/your-domain.com/path/to/file` +--- +*Need help implementing CDN in your project? Join our [Discord community](https://discord.gg/zeropsio) where our team and other Zerops users can assist you!* ---------------------------------------- -# Ruby > How To > Customize Runtime +# Features > Coding Agents +Zerops was built on the idea of **environment parity** — giving developers the full development lifecycle, from remote development to highly available production, with the observability and developer tools for maximum flexibility, and sensible defaults so the configs stay reasonable. Turns out that's **exactly what coding agents need** to produce and iterate on production-ready applications. ----------------------------------------- +
+