Only this pageAll pages
Powered by GitBook
1 of 62

dyrector.io docs

Loading...

Basics

Loading...

Loading...

Loading...

Loading...

Loading...

Tutorials

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Features

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Self-managed

Loading...

Loading...

Loading...

Loading...

Loading...

Learn more

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Who is it for?

In short: developers and DevOps engineers. But there's always a bit more nuanced answer.

Developers / Software Engineers / Programmers

If you enjoy developing software more than configuring the containerized app you just created, dyrector.io is for you.

The platform helps you to spark up your containerized stack on any infra hassle-free, so you can spend more time doing things you like.

DevOps Engineers / SysAdmins

Imagine the platform as a hub where all the components of your infrastructure can be accessed, and containers can be started, shut down or restarted.

This hub not only grants you access to these resources, but also enables your teammates to interact with your applications in a self-service manner. You'll be only needed to help them with deployments and troubleshooting when necessary.

Indiehackers / Self-hosters

Tinkering with stuff is your passion, and we're here to help you with that. If a project you'd like to use has an OCI compatible image, you can set it up on your local machine, on-premises server or cloud infrastructure.

Tip for self-hosting enthusiasts: you can dyrector.io for free, unlimited, forever.

Startups / Organizations tired of vendor lock-ins

dyrector.io is the right platform for startups eyeing containerization. The platform's release management capabilities help you spend your funds on meaningful stuff instead of wasting valuable engineering hours on repeated, mundane tasks.

As an organization, you might already have invested in some type of infrastructure. Moving your services from that infrastructure is painful and resource-heavy. With the platform, it's completely unnecessary, because the platform can be used with your infrastructure right away. And in case you decide to leave the platform, you can do so by exporting YAML-files to avoid losing your data.

Add your Registry

Registries are where the images you'd like to deploy are collected. While there are multiple registries explicitly supported, all OCI registries are supported. You can add registries from the following sources:

GitHub
  • GitLab

  • Google

  • Unchecked

  • V2 compatible registries
    Docker Hub
    self-manage

    Welcome 👋

    What is dyrector.io?

    It's an open-source continuous delivery platform offering self-service deployment and configuration management capabilities via a GUI and API to any cloud or on-premises infrastructure.

    You can find the project's repository on GitHub.

    Demo (2 mins)

    When to use the platform

    • You already have a Kubernetes cluster and want to manage it with ease.

    • Multiple users on your team need to have access to your containers for management.

    • You'd like to configure versions once, without repetition.

    • Your team needs self-service deployments for QA or sales purposes.

    Platform introduction

    UI & API for container management

    A delivery platform that helps you by substituting Docker and Kubernetes command line interactions with abstractions. You're able to configure any OCI compatible containers with a configuration screen, and in a JSON-editor, as well.

    You can use the platform by installing its agents on your infrastructure. The agent will communicate with the platform to conduct interactions with containers running on your infra.

    Cloud provider & technology agnostic platform

    The platform is ready to interact with your already existing infrastructure and clusters right away. The platform interacts with any existing cloud & on-premises infrastructure, as we don't offer infra. You can deploy images from any registry you have access to.

    The platform can be used without moving your services to a brand new infrastructure. To provide quick setup, we don't offer any infrastructure to our users.

    Integrations to the most popular tools

    Chat notifications on Discord, Slack, and Teams let you and your team know about newly made deployments and versions to increase collaboration.

    How it works

    dyrector.io consists of 2 major components:

    • an agent that's installed on your environment where you want to deploy images – crane is the agent that communicates with Kubernetes API and dagent is the agent for communication with Docker API, both written in Go –,

    • and a platform (UI developed in React.js, Next.js. Backend developed in Node.js, Nest.js). Communication between the agents and the platform takes place in gRPC with TLS encryption. The data is managed in a PostgreSQL database mapped by Prisma ORM.

    dyrector.io cloud (alpha access)

    Alpha is suggested for non-production purposes. If you want to use it for production, reach out to us at .

    Self-managed

    Self-hosted dyrector.io is free and will always be, without feature and usage restrictions.

    Getting started

    Give the platform a quick try with this guide.

    Self-managed guide

    Spark up your self-managed platform for 100% free.

    Who is it for?

    Find out how it can help you.

    Cover
    Cover
    Cover
    [email protected]

    Audit log

    Keep track of the actions your teammates execute. This way if a malfunction occurs, you can understand if it was due to a specific action or an outside factor.

    We track user ID, time and unsensitive data related to actions on the platform. Audit logging on our platform only monitors actions executed by users via the platform.

    We don't get access to self-managed team logs.

    Components

    To better understand how you’ll be able to manage your applications on the platform, there are certain components – entities and concepts – within the platform that need to be cleared.

    Team

    A group of users working on the same project. Without an invite to a team, on your first login you must define a team. Later you can invite others to your team, they will have access to every data and components, including configurations and secrets that belong to the team. To limit access to the data of one team, create a new team that'll have its own components.

    Teams can have multiple Nodes, Projects and Registries.

    Node

    Nodes are the deployment target environments where either of the agents are installed. A node can be any cloud or on-premises infrastructure. Without registering a node, your team can't use the platform. We suggest to be the first step you do after creating your team.

    dyrector.io doesn't provide infrastructure. You can use the platform with your already existing infra.

    Node setups require admin or root privilege. Without that, it's not possible to the platform's agent on your node.

    If you're curious about the install scripts of the agent, you can check them out at the link below:

    Registry

    Container registries where the images that you plan to deploy are stored. You can use any Docker Registry API V2 compatible registry with the platform, including Docker Hub, GitHub, GitLab, Google, Azure registries. Unchecked sources are supported, too, as long as they're V2 compatible. Docker Hub Library is available to every user by default.

    Project

    Projects are the fundamental building blocks of dyrector.io, as these are the deployable units that contains the images with the corresponding configuration. These are the stacks you’ll manage in dyrector.io. There are two types of Projects, as seen below.

    Versioned Project
    Versioned Project
    Versionless Project
    • Versionless Project: these projects have only one hidden version and cannot be rolled back. These are mostly useful for testing purposes.

    • Versioned Project: versioned projects can have multiple versions. The different versions can have different configuration and images. Semantic versioning is suggested.

    Deployment

    Deployment is the process of delivering the images that make up a project to the environment you added as a node by installing an agent on it. You can assign environment and configuration variables to the deployments, and also edit deployments depending on the type of project you want to set up on your node.

    Each deployed project comes with a prefix. Prefixes are alphanumeric strings in the container names to signal the deployment of a version to a node. Prefixes are comprehended within nodes.

    The purpose of this is to avoid duplications of a stack on an environment.

    Versioned project deployment

    • Rolling version

    Rolling versions have one deployment per version on each node, because a new deployment will overwrite the existing stack on the node. These type of versions can have multiple deployment prefixes since you can deploy them to multiple nodes. Only In progress deployments of rolling versions aren't mutable and deletable. Once the deployment of a rolling version is complete, you can't adjust or delete that.

    • Incremental version

    You can deploy multiple incremental versions of the same project to a node, therefore different incremental versions can have the same deployment prefix. The first deployment of an incremental version is mutable as long as it's not In progress. Incremental versions can have multiple deployments with the same prefix, but only one of them can have Preparing status. Only In progress deployments can't be deleted. After deploying an incremental version, the deployment will get one of the two statuses below:

    Successful: successful deployments remain immutable. After successful deployments, you can roll back the previous version with the corresponding database.

    New successful deployments turn previous ones that belong to older versions obsolete. When a previous version gets rolled back, the deployment that belongs to it turns all the deployments coming after downgraded.

    Failed: if a deployment comes back failed, it can be mutable.

    Versionless project deployment

    Versionless projects come without a version. The purpose of versionless projects is to reduce infrastructure maintenance overhead.

    Use cases:

    • Messaging queues: RabbitMQ, MQTT, etc.

    • Proxies: Traefik, NGINX, etc.

    • Databases: Postgres, MySQL, etc.

    Protected deployments

    There are protected deployments that prevent you from overwriting your deployments from another project. This is a helpful measure when you manage dozens or hundreds of environments, and a misplaced click can hurt your users by an outage.

    • Rolling versions: You can't deploy it if a protected deployment exists with the same prefix on the node.

    Audit log

    Audit logs collect team activity. It lists executed actions, the users who initiated them and the time of when the actions happened.

    Logs are assigned to teams.

    Profile

    Your user profile. One profile can belong to multiple teams.

    Create a Rolling Version

    Rolling versions are similar to versionless project in a way that they come with a version that can't be rolled back. They’re always mutable but contrary to incremental versions, they aren’t hierarchic and lack a version number.

    Step 1: After picking the Rolling tag, click ‘Save’. You’ll be directed to the Project tab. Select the project again.

    Step 2: Click ‘Add version’.

    Step 3: Enter the rolling version's name and specify a changelog.

    Step 4: Click 'Save'. You'll be directed to the board of versions of your versioned project.

    Step 5: Click 'Images' button in the card that belongs to the version you'd like to assemble.

    Add V2 Registry

    V2 Registries are Docker Registry HTTP API V2 compatible. Both private and public registries are supported.

    Add a private registry

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Step 2: Enter your registry’s name and select an icon.

    Configuration bundle

    You can create configuration bundles which you're able to apply to deployments later. These are templatized key-value pairs for environment variables.

    • Configuration bundles are shared between the members of a team.

    • Configuration bundles act as .env files.

    • Multiple bundles can be applied to a deployment.

    Pricing

    The platform is currently in the making, and so is its pricing. The public alpha hosted by us is completely free. If you want to give the platform a try , you can do it, free of charge, forever.

    Our plan with pricing is to have one, limited free package, and multiple paid plans with different usage caps. Paid users will have access to prioritized support compared to free users, and they're going to be able to manage more nodes, projects, and deployments in the platform.

    Gitea

    is a painless self-hosted Git service. It is similar to GitHub, Bitbucket, and GitLab. Image is available with latest tag on dyrector.io.

    After the Node where you'd like to run Gitea is , you can set it up by following the steps of deployments as documented .

    Once the deployment is successful, Gitea is ready to use at by default, as seen below.

    Roadmap

    Find out what's in the works on , or check out coming features and integrations we have in mind at the links below.

    Keys can't conflict between bundles applied to a deployment.

  • Values of a bundle can be overwritten manually when you set up the deployment. This won't impact the value stored in the bundle.

  • Bundles and the deployments of incremental version

    In the case of an incremental version's successful deployment, all the values of the applied bundles are copied to the deployment but connection between the bundles and the deployment are terminated. The purpose of this is when a bundle is modified, it won't interfere with the values specified for an existing deployment.

    hosted by yourself
    Send a feature request to [email protected] or drop a line on our Discord server.
    GitHub
    Features in progress
    Integrations in progress
    Gitea
    registered
    here
    http://localhost:3000/

    Inject Files to a Container

    You can inject files into a container using S3 storages by following the steps below.

    What you'll need:

    • An S3 API compatible storage available

    Add your storage to the platform

    Step 1: Navigate to Storage on the platform and click the Add button at the top right corner.

    Step 2: Enter the following information to their respective fields:

    • Name

    • Your storage's URL

    • Access key

    • Secret key

    Step 3: Click Save.

    Add a bucket in your storage to a container

    Step 1: Navigate to your projects and select the project that has the container you'd like to inject files to.

    When the container is under a versioned project version's, there's an extra step you'll need to take by selecting the version you desire to deploy.

    Step 2: Click on the gear icon on the right side of the container.

    Step 3: If it's turned off, turn on the Storage filter in the sub filters.

    Step 4: Select the storage you'd like to inject files from, and enter the bucket path.

    You can specify a folder within a bucket, too. (Example: "bucket/folder/sub-folder")

    Add a version to your Versioned Project

    If you’ve created a versioned project, you’ll need to add a version to it. This version could be a rolling or an incremental version.

    Step 1: Open Projects page on the left and select the project you want to set a version to.

    Step 2: Click ‘Add version’ on the top right.

    Step 3: Define a name for your project’s version in the name field.

    Step 4: Enter a changelog if you’d like to.

    Step 5: Select if you’d like to make this a rolling or an incremental version. Click here for more details on the difference between the two.

    Step 6: Select if you’d like to turn this into a default version all the future versions will automatically inherit images and their configurations.

    Step 7: Click ‘Save’ on top right.

    Container configuration

    Container routing

    Container routing is available for nodes where Traefik is enabled on node install.

    Expose strategy of the container you wish to be exposed should be set to HTTP or HTTPS, instead of none. In the routing section of the configuration screen, you need to specify a domain and a port. The additional variables are optional.

    When a path is specified, the Traefik container will exclusively route requests with URLs containing that designated path prefix.

    Enabling path stripping will result in forwarding the request without including the specified path.

    The generated Traefik router's name will be automatically generated as "prefix + name."

    If the router uses HTTPS, all necessary Let's Encrypt labels will also be added. It's important to note that middlewares can only be applied by adding them as custom Docker labels.

    Docker labels

    If you have Docker labels set for your container, you can specify them as key-value pairs in the config screen under the Docker labels section.

    Vaultwarden

    Vaultwarden is an unofficial self-hosted Bitwarden implementation. Image is available with latest tag as a template.

    After the Node where you'd like to run Vaultwarden is registered, you can set it up by following the steps of deployments as documented here.

    Once the deployment is successful, self-managed Vaultwarden is ready to use at localhost:80 by default.

    Previous version is overwritten

    Image and configuration inheritance

    ❌

    Ideal for

    Nightly Versions

    Production

    Testing, Single-container stacks

    Incremental versions: You can't deploy it if a protected deployment exists of a different version with the same prefix on the node.

    Version Type

    Rolling

    Incremental

    ❌

    Rollbacks

    ❌

    ✅

    ❌

    registering a node
    install
    Docker
    Kubernetes

    History

    Step 6: Click 'Add image'.

    Step 7: Select the Registry you want to add images from.

    Step 8: Type the image’s name to filter images. Select the image by clicking on the checkbox next to it.

    Step 9: Click ‘Add’.

    Step 10: Pick the ‘Tag’ icon next to the bin icon in the actions column to pick a version of the image you selected in the previous step.

    Now you can define environment configurations to the selected image. For further adjustments, click on the JSON tab where you can define other variables. Copy and paste it to another image when necessary. Learn more about Configuration management here.

    Step 11: Click ‘Add Image’ to add another image. Repeat until you have all the desired images included in your product.

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select V2 Registry and switch the toggle under the URL field to ‘Private’.

    Step 4: In the corresponding fields, enter:

    • URL of your registry without the /v2 suffix,

    • username, and

    • the token or password which you use to access it.

    Step 5: Click ‘Save’ button on the top right.

    Add a public registry

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Step 2: Enter your registry’s name and select an Icon below.

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select V2 Registry type and switch the toggle under the URL field to ‘Public’.

    Step 4: Enter the URL of your registry without the /v2 suffix.

    Step 5: Click ‘Save’ button on the top right.

    Create a versionless project

    Versionless projects have only one abstracted-away version and cannot be rolled back. These are mostly useful for testing purposes or single-container stacks.

    Step 1: On the Project tab, click ‘Add’ on top right.

    Step 2: Enter the project’s name.

    Tip: You can write a description so your teammates can understand what’s the purpose of this project.

    Step 3: Select the versionless type under the description.

    Step 4: Click ‘Save’. You’ll be directed to the Project tab. Select the project you just created.

    Step 5: Click ‘Add Image’.

    Step 6: Select the Registry you want to filter images from.

    Step 7: Type the image’s name to filter images. Select the image by clicking on the checkbox next to it.

    Step 8: Click ‘Add’.

    Step 9: Click on the ‘Tag’ icon under the actions column left to the bin icon. This will allow you to select a version of the image you picked in the previous step.

    You can define environment configurations to the selected image by clicking on the gear icon on the right. For further adjustments, click on the JSON tab where you can define other variables. Copy and paste it to another image when necessary. Learn more about Configuration management .

    Step 10: Click ‘Add Image’ to add another image. Repeat until you have all the desired images included in your product.

    Getting started

    This is an extremely compressed guide to new users who would like to give cloud-hosted dyrector.io a look as quick as possible.

    Having access to a target environment (Docker or Kubernetes) is a requirement. More details here.

    1. Go to sign up or login.

      • If you just signed up, check the inbox of the e-mail address you added for confirmation e-mail and verify your account with the link.

    2. Create a team.

    3. On the nodes page a new Docker or Kubernetes orchestrated node.

    4. to the platform. Docker Hub is available by default. Bypass this step and step 5 by saving one of the as a project.

    5. .

    6. to your project.

    7. the images if needed.

    8. Deploy. 🎬

    Continuous Deployment

    Function is still in the works, anomalies might occur.

    How it works?

    After the CI/CD pipeline builds and pushes the image to a container registry, the pipeline triggers the deployment on the platform. The platform automatically signals to the agent that it should pull and start the image with the tag that already exists on the node.

    Generate CD token

    Step 1. a versioned project.

    Step 2. Add a rolling version to the project.

    Step 3. Add images to the version.

    Step 4. a deployment to the version.

    Step 5. Click Create in the Deployment token card.

    Step 6. Enter a name for your deployment token and set its expiration time, then click Create. You'll need to generate a new one when the token expires.

    Step 7. Save the token somewhere secure as you won't be able to retrieve it later. Click Close when you're done.

    Step 8. Paste the curl command into the pipeline.

    Never store your token in your git repository. Use pipeline secrets instead.

    How to revoke token?

    You can revoke the token by clicking on the Revoke token button in the Deployment token card.

    Add Unchecked Registry

    Unchecked means image availibility checking is disabled. Any HTTP API V2 compatible registry can be added this way, but images and their tags cannot be browsed when assembling a project. You can add an image to a project from an unchecked registry by entering the image's exact name and when needed, the tag.

    When you add images from an unchecked registry to a project, and the image's name doesn't match, the deployment will fail.

    How to add an unchecked registry?

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Step 2: Enter your registry’s name and select an icon.

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select Unchecked Registry and switch the toggle under the URL field to ‘Private’.

    Step 4: In the corresponding fields, enter the registry's URL.

    Step 5: Click ‘Save’ button on the top right.

    Add GitHub Registry

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Step 2: Enter your registry’s name and select an icon.

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select GitHub Registry type.

    Step 4: Select if you'd like to add an organization or a user.

    Step 5: In the corresponding fields, enter:

    • Your GitHub user name,

    • Personal access token generated in GitHub with the steps documented . Select the repo and read:packages scopes. Repo scope is required due to GitHub's limitations. You're still able to add public GitHub registries, too.

    • And your organization’s or your user's GitHub name.

    Only classic tokens are supported. Fine-grained tokens aren't supported yet.

    Step 6: Click ‘Save’ button on the top right.

    WordPress

    WordPress is the most popular CMS. More than 43% of all websites are managed with it. You can quickly set it up wherever you'd like to manage your content with WordPress. Image is available with latest tag.

    After the Node where you'd like to run WordPress is registered, you can setup WordPress by following the steps of deployments as documented here.

    Once the deployment is successful, WordPress is ready to use at localhost:4444 by default, as seen below.

    Environment variables

    dyrectorio/.env.example

    dyrectorio/web/crux/.env.example

    dyrectorio/web/crux-ui/.env.example

    dyrectorio/golang/cmd/crane.env.example

    dyrectorio/golang/cmd/dagent.env.example

    Monitoring

    Monitoring allows you to get instant feedback whether a deployment was successful or not, as seen below.

    Besides deployment feedback, the platform is useful when you need to check up on your infrastructure and all you need to do is check the platform to get logs.

    Add your Node

    Nodes are the environments that'll be the target of your deployments.

    Node setups require admin or root privilege. Without that, it's not possible to dyrector.io's agent on your node in the case of both Docker and Kubernetes.

    If you're curious about the install scripts of the agent, you can check them out at the links below:

    Use cases

    Self-service container management

    The platform abstracts away interactions with containers. You can deploy images, start, restart, and delete containers with the platform. Logs and container inspection allows you to dig deeper into a container's operation when needed.

    Add Google Registry

    Add a Private Google Registry

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Step 2: Enter your registry’s name and select an icon.

    Quick start

    Self-managed setup is only supported in Docker as of now, Kubernetes support is in the works.

    Production

    Use .

    Pilot

    Deploy your Project

    Deployment is the key feature of the platform. It's the process of setting up the images on your node.

    Deployment workflows are similar for each type and version of projects but there's difference between the capabilities. You can find out more about the differences of deployment capabilities between versionless and versioned projects .

    Step 1: Open the project or version you would like to deploy. To demonstrate the process, we used a versionless project.

    Step 2: Click 'Add deployment'.

    Step 3: Select the node in the 'Add deployment' block. After that, click 'Add' on the top right corner of the block.

    Create your Project

    Projects are the deployable units made up of images and their configuration you're going to manage through the platform.

    Versioned Project
    Versioned Project
    Versionless Project

    Core functionality

    Features

    • Deployment – Initiate deployments to a single or multiple deployment environments called nodes. A node can be in any cloud, VPN, or on-premises environment.

    Strapi

    is a CMF that allows developers to build APIs in Node.js. It's mainly used to build content-driven applications or websites. You can quickly set it up on your infrastructure. Both images of Strapi are available with latest tag.

    After the Node where you'd like to run Strapi is , you can setup Strapi by following the steps of deployments as documented .

    Once the deployment is successful, Strapi is ready to use at by default, as seen below.

    Create Chat Notifications

    Chat notifications help you to get informed about your team's activity in an instant. As of now 3 platforms are supported:

    • Discord,

    • Slack,

    • and Microsoft Teams.

    You can get notifications about 4 events:

    Self-signed certificates

    It is possible to use container registries with self-signed (private) certificates. Be warned, it is an advanced, less convenient matter.

    API

    You can opt for using unchecked registries, that means images are not checked at all, image URLs are passed to the agent straight away. This way you can skip setting up certificates for the API.

    The environment variable is NODE_EXTRA_CA_CERTS, the process expects a concatenated list of your certificates. More info:

    Concatenating pem files to a single file: cat *.cert.pem > node_extra_ca_certs

    Google Microservices Demo

    is used to how to build and deploy microservices-based applications using Google Cloud Provider (GCP). Google Microservices Demo allows users to demonstrate use of technologies like Kubernetes/GKE, Istio, Stackdriver, gRPC and OpenCensus. Users can quickly set Google Microservices Demo up on your infrastructure.

    All images are available with 0.4.1 tag in the template.

    After the Node where you'd like to run Google Microservices Demo is , you can set it up by following the steps of deployments as documented .

    Once the deployment is successful, Google Microservices Demo is ready to use at

    Minecraft Server

    Minecraft needs no introduction. You can setup a Minecraft Server by following the steps of deployments as documented . Image is available with latest tag as a template.

    Once the deployment is successful, the server is ready to use at by default.

    Community

    Join our community to discuss DevOps, Kubernetes or anything on our public .

    You can find the project's GitHub repository . Feel free to contribute!

    Check our to read posts written by our team of DevOps specialists to improve your processes.

    Follow us on , , and to stay updated about the latest developments.

    If you got any question or feedback, let us know at .

    Add Docker Hub Registry

    Docker Hub is a public image library. You can add registries from Docker Hub with the following steps.

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Step 2: Enter your registry’s name and select an icon.

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select Docker Hub type.

    Release & Configuration management –
    One-time configuration for releases in a configuration screen or a JSON. Configure releases in real time with your teammates.
    In progress:
    Specify bundled configuration variables instead of going through them one-by-one, repeatedly.
  • Instant test environments – Spark up your stack in an instant on your local machine after adding it as a node without assistance.

  • Monitoring – Check container and deployment statuses via the platform and interfere when required.

  • Audit log – Audit log allows teams to trace back activity that might have caused an anomaly.

  • Chat notifications – Automated chat messages on Discord, Slack, and Teams when a teammates makes an action on the platform, so they don't have to go out of their way to let others know about completed tasks.

  • Features in progress

    • Changelogs – You're able to create changelogs at ease based on commit messages with the help of Conventional Commits, so your team understands the purpose of new versions. This simplifies communication between departments who work on the product and outsiders, for example decision-makers. The generated changelogs can be sent out via e-mail or any chatbot integration.

    • Secret management – Store and manage sensitive data with our Vault integration powered by HashiCorp.

    • RBAC – Role based access control lets you distribute privileges based on their responsibilities to your teammates. This is important to prevent any wrongdoing in case a user profile gets corrupted.

    • ChatOps solutions – Interact with the platform and your stack via chat messages on the chat platform your team uses.

    add
    Add a registry
    Templates
    Create a project
    Add a deployment
    Configure

    The docker-compose below is only designed for demoing the platform, we don't suggest using it for any other use.

    Use docker-compose.http-only.yaml.

    Development

    Use CLI.

    System Recommendations

    • 1 CPUs

    • 8 GB RAM

    • Docker or Podman installed

    Disabling Sign Up

    We don't have an option to disable signup, but you can restart the Kratos container with the following variables in the docker-compose:

    SELFSERVICE_FLOWS_REGISTRATION_ENABLED=false

    It should disable the registration flow and the platform will throw an error on the registration page.

    More details in Kratos documentation.

    Why it's worth it

    Self-managed dyrector.io is free, unlimited, forever.

    This freedom comes with a trade-off. While we'll still offer support on our Discord server, we take no responsibility for maintaining your own instance of the platform and we won't prioritize giving support over other users. Make sure you use the latest version for a consistent experience.

    While we won't put a cap on the number of nodes, deployments, projects you manage with your self-managed instance, as with every self-managed software, environment or database related problems might occur, which we take no responsibility for. For a seamless experience, give the cloud-hosted platform a look.

    docker-compose.yaml
    here
    http://localhost:25565/
    Discord
    here
    blog
    Twitter
    LinkedIn
    Instagram
    [email protected]
    here
    After Step 3 this is how UI should look like.
    Strapi
    registered
    here
    localhost:1337
    Create
    Add
    here

    ✅

    ❌

    History

    Previous version overwritten

    Image and configuration inheritance

    ❌

    Ideal for

    Nightly Versions

    Production

    Testing, Single-container stacks

    The different project types have different deployment capabilities. For more details about the differences, check out the Components section.

    Versionless project

    Versionless projects have one abstracted-away version and cannot be rolled back. These are mostly useful for testing purposes.

    Versioned project

    Versioned projects have two types of versions: rolling and incremental. You can define one version per versioned project as default. That'll be the version future versioned projects will inherit images and configurations later until you set another one as default.

    Rolling Version

    Rolling versions are similar to simple projects except they’re perfect for continuous delivery. They’re always mutable but contrary to incremental projects they aren’t hierarchic and lack a version number.

    Incremental Version

    Incremental versions are hierarchical. They can have a child version and once a deployment is successful, the deployed versions, the environment variables, and the deployed images can never be modified. This guarantees you’re able to roll back the deployed version and reinstate the last functional one if any error occurs to avoid downtime.

    Versioned projects can have both rolling and incremental versions.

    Version Type

    Rolling

    Incremental

    ❌

    Rollbacks

    ❌

    Mount the generated file using and provide the environment variable.

    Agent

    The two supported target nodes require different approaches.

    dagent

    Assumed the host already trusts the CA, when adding a node the install script is visible, you can use this script also to add extra behavior, if it is not explicitly implemented in the UI. The component allows us to provide additional CA files using the SSL_CERT_FILE variable, it expects one crt file that you have to mount from the host.

    The last command of the script will be extended with two lines:

    Make sure you use the correct values.

    crane

    Using Kubernetes, you have to make sure that nodes already trust your CA: example.

    You have to modify the install script to mount the crt file to crane.

    You can create a secret from a file using this one liner, make sure it is in the dyrectorio namespace.

    https://nodejs.org/api/cli.html#cli_node_extra_ca_certs_file
     -e SSL_CERT_FILE=/path/to/ssl/ca.crt
     -p /host/cert/path/ca.crt:/path/to/ssl/ca.crt
    kubectl create secret generic my-cert --from-file=path/to/bar

    Docker

  • Kubernetes

  • Step 1: Open Nodes on the left and click ‘Add’ on top right.

    Step 2: Enter your node’s name and select its icon.

    Tip: You can write a description so others on your team can understand what’s the purpose of this node.

    Step 3: Click ‘Save’ and select the type of technology your node uses. You can select

    • Docker Host,

    • and Kubernetes Cluster.

    Docker Host requirements are the following:

    • a Linux host/VPS,

    • Docker or Podman installed on host,

    • ability to execute the script on host.

    Kubernetes Cluster requirements are the following:

    • a Kubernetes cluster,

    • kubectl authenticated, active context selected,

    • ability to run these commands.

    Users are able to opt-in to install Traefik, as well. In that case they need to add an ACME email address where they'll be updated when their certification expires.

    Traefik's Docker instance is only supported on Linux. Further details about it at the official Docker documentation.

    Step 4: Depending on your node's OS, select whether you'd like to generate a shell or a powershell script. Shell scripts are supported on Linux nodes, powershell scripts are designed to be used with Windows nodes.

    Step 5: After picking the technology and the script's type, click the ‘Generate script’ button to generate a one-liner script.

    Step 6: Run the one-liner in sh or bash.

    The one-liner will generate a script that’ll set the platform’s agent up on your node.

    Information and status of your node will show on the node's page, so you can see if the setup is successful right away.

    Now you're ready to setup your product and one step closer deploy your application.

    install
    Self-hosted stacks for indie hackers

    If you're passionate about self-hosting the tools you use every day, you can add all of your environments to the platform as nodes, where you can manage all the containers you run. Instead of setting up dashboards and adding each service individually, you can interact with all of your ecosystem through one GUI.

    Pro tip: you can self-manage dyrector.io, too.

    Multi-Instance Deployments

    The key purpose of multi-instance deployments is to avoid repetitive tasks when the same stack needs to be deployed to dozens or hundreds of deployment targets. After configuring the stack once, you're able to select all the nodes where you'd like to set it up.

    Below you can see a flowchart that illustrates how you can deploy the same stack to multiple environments at the same time.

    Another scenario is when a 3rd-party redistributes the business application your organization develops. In the flowchart below you can see how this process differs from direct distribution as described above.

    In progress: Bundled configurations enable your team to assign templatized configurations through the whole process.

    Instant test environments

    QA, PMs and salespeople can spark up your stack instantly on their own by deploying the stack to their local machine or a demo environment as a project.

    And more, including

    • Installing Next.js apps with NGINX to a VPS or a Kubernetes cluster

    • Installing single images (like RabbitMQ or a database)

    • Checking server/cluster status

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select Google Registry and switch the toggle under the URL field to ‘Private’.

    Step 4: In the corresponding fields, enter the organization name. Upload the JSON key file you can generate as documented here. In the Google Cloud documentation you only need to follow instructions until the 2nd part.

    Step 5: Click ‘Save’ button on the top right.

    Add a Public Google Registry

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Step 2: Enter your registry’s name and select an icon below.

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select Google Registry type and switch the toggle under the URL field to ‘Public’.

    Step 4: Enter the Organization name.

    Step 5: Click ‘Save’ button on the top right.

    Step 4: The images of the project will be listed. By clicking on the gear icon, you are able to define and adjust configuration variables. Learn more about Configuration management here.

    Step 5: Click 'Deploy'. If everything goes right, deployment status should switch from 'Preparing' to 'In progress'. When deployment's complete the status should turn 'Successful'.

    You can see status change for each image on the 2nd picture below.

    Protected deployments

    There are protected deployments that prevent you from overwriting your deployments from another project. This is a helpful measure when you manage dozens or hundreds of environments, and a misplaced click can hurt your users by an outage.

    • Rolling versions: You can't deploy it if a protected deployment exists with the same prefix on the node.

    • Incremental versions: You can't deploy it if a protected deployment exists of a different version with the same prefix on the node.

    Deployment deletion

    Deleting a deployment will only remove the containers from the platform. Infrastructure related data, including volumes and networks, will remain stored on the node.

    Troubleshooting

    When you can't deploy a version or a project because node status turns outdated, you should navigate to your node's edit page and update the agent by clicking the Update button.

    here
    • new Node added,

    • new Version created,

    • successful and failed deployments,

    • new teammate invited.

    Tutorial

    Before you start creating your Notifications, make sure you have the webhook ready. You can find how to create a webhook for Discord, Slack, and Microsoft Teams in their official documentations.

    Step 1: Click 'Notifications' on the left side.

    Step 2: Select one of the 3 supported chat platforms.

    Step 3: Enter the following data:

    • name of your notification,

    • webhook URL.

    Step 4: Set the toggle for 'Active' or 'Inactive' notifications. You can change this later to activate or inactivate the notifications.

    Step 5: Click 'Save' on the top right.

    To test your notification, head to Notifications on the left, select the Notification you'd like to test and press the Test webhook message button.

    by default, as seen below.
    Google Microservices Demo
    registered
    here
    localhost:65534

    Step 4: Enter the registry’s name or your username in Docker Hub in the ‘Organization name or username’ field.

    Step 5: Click ‘Save’ button on the top right.

    Self-managed GitLab

    Self-managed GitLab is an open-source version of GitLab to manage your code. It's key advantage is that users can configure GitLab to their needs. You can quickly set it up on your infrastructure. Image comes with latest tag in the template.

    After the Node where you'd like to run GitLab is registered, you can set it up by following the steps of deployments as documented here.

    Once the deployment is successful, self-managed GitLab is ready to use at localhost:21080 by default.

    Create an Incremental Version

    Incremental versions are hierarchical in a way that they can have child versions and once a deployment is successful, the deployed versions, the environment variables, and the deployed images can never be modified. Because of this, you’re able to roll back the deployed incremental version and reinstate the last functional version.

    Step 1: After picking the incremental tag, click ‘Save’. You’ll be directed to the incremental version’s preview. Click ‘Add Version’.

    Step 2: Enter a name and a change log for the new version.

    Step 3: Click ‘Save’. You’ll be redirected to the project's version board.

    Step 4: To add images, click ‘Images’ and ‘Add Image’ on the next view.

    Step 5: Select the Registry you want to filter images from.

    Step 6: Type the image’s name to filter images. Select the image by clicking on the checkbox next to it.

    Step 7: Click ‘Add’.

    Step 8: Pick the ‘Tag’ icon next to the bin icon under the actions column to pick a version of the image you selected in the previous step.

    Now you can define environment configurations to the selected image. For further adjustments, click on the JSON tab where you can define other variables. Copy and paste it to another image when necessary. Learn more about Configuration management .

    Step 9: Click ‘Add Image’ to add another image. Repeat until you have all the desired images included in your product.

    Add new version to your incremental version

    Step 1: Open Projects and select the versioned project you’d like to increase.

    Step 2: Click ‘Increase’ button under the version of the project you’d like to add a new version to.

    Step 3: Enter the version's name and add changelog. Click ‘Save’.

    Step 4: Click 'Add image’ to search for images you’d like to include in the new version. If you’d like to remove an image from the previous version, click on the red trash icon.

    Step 5: Pick the ‘Tag’, which is a version of the image you selected in the previous step.

    MLflow

    MLflow is a platform to streamline machine learning development, including tracking experiments, packaging code into reproducible runs, and sharing and deploying models. The Docker image of MLflow is available with the 2.4.0 tag.

    After the node where you'd like to run MLflow is registered, you can set it up by following the steps of deployments as documented here.

    Once the deployment is successful, MLflow is ready to use at http://localhost:5001/ by default, as seen below.

    LinkAce

    LinkAce is a self-hosted archive to collect links of your favorite websites. You can quickly set it up on your infrastructure. Template consists of MariaDB (10.7) and LinkAce image with simple tag.

    After the Node where you'd like to run LinkAce is registered, you can set it up by following the steps of deployments as documented here.

    Requirements:

    1. APP_KEY environment variable must be 32 characters long.

    2. After deployment, exec in the linkace-app container and add chmod 777 privileges to the \app\.env file.

    Once the deployment is successful, LinkAce is ready to use at by default, as seen below.

    Templates

    Templates are presets of the most popular applications for quick setup.

    To setup Templates, users need a Node set up with either of the platform's agents. The deployment process is the same as documented. Some of the templates require a level of configuration before deployment. These are documented, as well.

    Give the platform a try by deploying one of the templates.

    Available templates:

    Reach out to us at , or on if you'd like to request a new template.

    Features in progress

    Continuous Delivery

    Manually triggered deployments at the end of a CD pipeline. Related features: scheduled releases. Configure your release and schedule a deployment time for the designated environment when the deployment won't be disruptive to users.

    Bundled configurations

    Misconfiguration induced failures are very common, especially when you don't have to regularly deal with configuration variables. Add human factor to the equation and the chances of outages induced by faulty configurations increase significantly.

    For this reason we're working on a feature that allows users to manage bundled configurations. This way you'll be able to treat your configurations in a templatized manner.

    Changelog generation

    Unawareness of how one version of your image is different from another is a risky practice. To avoid this, the platform helps you create changelogs based on your commit messages with Conventional Commits service. Make sure developers working on your application leave meaningful commit messages, so everyone working on your project understands the details of each version.

    Changelog generation can reduce knowledge gap between stakeholders, like developers who work every day on the project and outsiders who occasionally deal with the project, like decision-makers.

    Besides the changelogs, you can also leave a comment related to nodes and projects on the platform which your teammates can see on the platform's UI.

    Use cases

    • Auto send changelogs: once the changelog is generated, you can send it via e-mail or chat, whichever your team uses to communicate. For further information, check the ChatOps section.

    Secrets management

    You can use HashiCorp’s Vault Integration for secrets management to keep your passwords and encryption keys secure. This means the platform compliments your DevSecOps practices. Your secrets will be securely stored by HashiCorp, which you can access through the platform.

    HashiCorp Vault is the de facto tool of security, used by most organisations. We encourage our users to use it, as well.

    Use cases of HashiCorp’s Vault

    • General Secret Storage: store your secrets, including sensitive configurations, tokens, API keys. Query them by using vault read.

    • Employee Credential Storage: instead of using sticky notes around your screen, store and distribute credentials in one place. Vault has an audit log mechanism, which lets you know who had access to one of the stored secrets. This simplifies monitoring which keys have been rolled or not.

    • API Key Generation for Scripts: generate temporary access keys for the duration of a script. The keys only exist for that duration and are logged by HashiCorp.

    Role Based Access Control - RBAC

    Role based access control allows you to manage the privileges of other users. This is an extra measure of security to your infrastructure and data. Using RBAC helps you to avoid situations when someone has unauthorised access to your account to execute harmful actions.

    Use cases

    • Principle of Least Privilege: consider the tasks of each user having access to your infrastructure. Only give them privileges necessary to complete their tasks, including modifying and managing configurations.

    ChatOps

    The platform's functionality implemented into ChatOps commands.

    YAML export

    In case you decide to stop using the platform, you can generate YAML files to easily setup their services using another platform without using data.

    Portainer vs. dyrector.io

    Portainer is a popular Docker GUI for containerized applications. It supports Docker, Docker Swarm and Kubernetes orchestrated runtimes.

    The most important difference between Portainer and dyrector.io is the feature-rich release management capability the latter offers for containerized applications. You're able to configure and deploy your application's containerized stack with dyrector.io.

    While you can trigger multi-instance deployments with dyrector.io, Portainer offers single-node deployments.

    Which to choose?

    Portainer is very useful for teams who would like to interact with containerized applications and their infrastructure in a simple manner. Its Community Edition leaves room for many Docker specific use cases, but some premium features are only available in the Business Edition which offers limited usage for free users.

    dyrector.io offers more for teams who develop their own software and want to manage its versions as a containerized stack, and then deploy them to a single or multiple deployment targets with a single click. Self-managed dyrector.io is 100% open-source without usage limitations.

    Functionalities compared

    Portainer
    dyrector.io

    Create a versioned project

    Step 1: On the Product tab, click ‘Add’ on top right.

    Step 2: Enter the Product’s name.

    Tip: You can write a description so your teammates can understand what’s the purpose of this Complex Product.

    Step 3: Select Complex on the switch under description.

    Step 4: Click ‘Save’. You’ll be directed to the Product tab. Select the Product you just created.

    Step 5: Click ‘Add Version’.

    Step 6: Enter a name and a changelog for the new version. At this point, you can choose whether you’d like to create a Rolling or an Incremental product.

    Cal.com

    Cal.com is a meeting scheduler application. Users can set up its self-hosted stack.

    Why use dyrector.io to set up Cal.com

    Cal.com is awesome. We like it and use it everyday, people like it, too. Chances are, if you're here, you like it, as well. Even better that they provide self-hosted usage. But as some users pointed out on , self-hosting Cal.com is a challenging process. So, we turned it into a template for easy setup.

    Storage

    File injection to containers is possible with the Storage function. It's S3 API compatible, as of now only Azure Blob Storage isn't supported.

    Storage capabilities don't cover configuration backup storage. It's sole purpose is to offer a way for .

    We decided to go with S3 API compatible storages as it’s one of the most popular technologies that offer interoperability with a fair number of open-source projects. They represent a bunch of functions as flat structure file storages, including versioning, different types of access control, and so on.

    One example of S3 API use cases is to upload the object via a REST endpoint and the object will be available through a simple URL.

    FAQ

    Can I use dyrector.io without containerization?

    Unfortunately we don't support applications that don't run in a containerized environment.

    Is dyrector.io Kubernetes specified?

    Integrations in progress

    GitLab CI/CD & GitHub Action

    The platform isn’t a CI/CD tool but it covers certain steps of CD and its release management related aspects.

    Both GitLab’s CI/CD and GitHub’s Action tools can be integrated. Its main benefit is that the platform enables you to manage multi-instance deployments to different environments, and it enables you to manage several different configurations. You can bring multiple services and operational practices under the same hood.

    Add GitLab Registry

    You can add registries available from both self-managed or SaaS GitLab.

    Add SaaS GitLab Registry

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Data Encryption: aligning with the purpose of the platform, HashiCorp’s Vault enables developers to focus on developing. The Vault takes care of data encryption and decryption, instead of the developers and other technical staff on the team.

    No. It can be configured with any environment, cloud or on-premises, Docker or Kubernetes. Read how you can set up Nodes.

    Can I use the self-managed platform with NGINX?

    Yes. Find the NGINX example here.

    What is the difference between Image and Container configuration?

    Short: Generic configuration => Image, specific configuration => Container config, configuration is inherited from Image configuration.

    Parameters that are generic and context independent should be defined on the Image level. Other, context dependent information, like an environment variable PUBLIC_URL="https://example.com" should be defined on the Deployment's level. During deployment there is a one-way merge using these configurations with Container configuration having the higher priority.

    Can I use the platform without a profile and teams?

    Unfortunately no, but there are settings you can use to disable Kratos. More details here.

    Can I deploy my images to a cluster orchestrated by Kind?

    Yes.

    Can I schedule database backups with dyrector.io?

    Unfortunately there's no such capability within the platform now, but creating a similar functionality is in our plans.

    Is it a CI/CD tool?

    The platform provides CD capabilities, but it doesn't offer CI, as of now. Such capabilities are in our long-term plans.

    Does the platform manage routing?

    Unfortunately routing isn't managed by the platform itself. When you'd like to access your node or a deployed stack through a domain, you'll need to configure routing on your own.

    Is it only for businesses?

    dyrector.io is for anyone who works with containerized applications. That means organizations, or independent developers can gain advantage of the platform's functions.

    Will the tool remain completely free in the future?

    Self-managed use will stay 100% free and unrestricted. But most of our team works full-time on the platform. While we gain some revenue as a cloud consultancy, we accept donations to fund the project.

    What was the motivation behind making this tool?

    We needed a solution for self-service release management capabilities for an entirely different project. We couldn't find one that fit exactly our needs, so we made our own platform.

    I have a feature request. Can I send you a message about it?

    Don’t hesitate, reach out to us at [email protected]. Also drop us a mail to the same address if you find a bug or any other anomaly you experience. We’ll respond within 24 hours.

    My question isn’t answered here. Where can I reach you?

    Send us an e-mail at [email protected] or check in on Discord.

    Deployments: you can integrate the services and pipelines you already use to build your applications, and then deploy them to any desired environment.
  • Change log generation: increase the transparency of version management by generating change logs based on commit messages left by your developers.

  • Configuration management: simplified configuration management to keep your infrastructure under control while you focus on delivering value to your users.

  • Secrets management: HashiCorp’s Vault integration enables you to store your sensible keys, configuration variables, tokens and other things secure.

  • Monitoring: get notifications and alerts on multiple channels about what happens on your infrastructure.

  • Others

    Prometheus integration

    Integrate Prometheus to track and monitor your application’s and infrastructure’s performance.

    Grafana integration

    Make the data tracked by Prometheus visible and easy-to-interpret to non-technical stakeholders with Grafana.

    Graylog integration

    Create and manage logs of events occurring for analytics purposes with Graylog.

    Cal.com

  • WordPress

  • LinkAce

  • Gitea

  • Minecraft Server

  • MLflow

  • Strapi
    Google Microservices Demo
    Self-managed GitLab
    Vaultwarden
    [email protected]
    Discord
    localhost:6780
    Amazon's S3 solution isn’t open-source but a few S3 API compatible open-source implementations are listed below:
    • MinIO,

    • OpenIO,

    • Scality.

    You can set up the S3 implementations mentioned above as Docker containers. Find out how in the Tutorials section.

    file injection
    here

    ❌

    ✅

    Open-source

    Premium functions restricted

    100% open-source

    Supports Docker & K8s

    ✅

    ✅

    Continuous Deployments

    ✅

    ✅

    Chat notifications

    ❌

    ✅

    Multi-instance deployments

    Set up Cal.com

    After the Node where you'd like to run Cal.com is registered, you can set it up by following the steps of deployments as documented here.

    Configuration

    • cal-db (latest)

      • POSTGRES_PASSWORD has to be specified.

    • cal-com (2.5.10)

      • DATABASE_URL needs to contain POSTGRES_PASSWORD's value in postgresql://cal-user:${POSTGRES_PASSWORD}@cal-db:5432/cal-db for cal-db.

      • NEXTAUTH_SECRET and CALENDSO_ENCRYPTION_KEY needs to be specified. We recommend to generate these secrets.

      • If you have a node with Traefik enabled you can use http://cal.localhost (or any other domain setup in the ingress settings) by setting NEXT_PUBLIC_WEBAPP_URL to the public URL.

    Once the deployment is successful, self-hosted Cal.com is ready to use at localhost:7000 by default, as seen below.

    Hacker News
    Step 2: Enter your registry’s name and select an icon.

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select GitLab Registry type.

    Step 4: Select if you'd like to add a group or a project.

    Step 5: In the corresponding fields, enter:

    • Your GitLab username,

    • Your password or access token generated in GitLab with the steps documented here. Select the read_api and read_registry scopes.

    • And your organization’s or your project's GitHub name. You can find either under their name in their main pages.

    Step 6: Make sure the Self-managed GitLab toggle is off. If you select GitLab Registry type, SaaS should be set by default.

    Step 7: Click ‘Save’ button on the top right.

    Add Self-managed GitLab Registry

    Step 1: Open Registries on the left and click ‘Add’ on the top right.

    Step 2: Enter your registry’s Nname and select an icon.

    Tip: You can write a description, so others on your team can understand what’s the purpose of this registry.

    Step 3: Select GitLab Registry type.

    Step 4: In the corresponding fields, enter:

    • your GitLab username,

    • your password or access token generated in GitLab with the steps documented here. Select the read_api and read_registry scopes.

    • And your organization’s GitHub name.

    Step 5: Turn on self-managed GitLab toggle.

    Step 6: Enter GitLab Registry’s URL and the GitLab API URL without the https prefixes.

    Step 7: Click ‘Save’ button on the top right.

    Proxies

    Proxies provide secure connection when you set up the platform for self-managed use. But they can be useful for any other uses, when you need a firewall, or you'd like to hide your location, and so on.

    When you set up the platform, we highly recommend you to use a proxy, such as Traefik or NGINX, to secure your network.

    Traefik

    Traefik is used by default, as seen in the designed for production use.

    OpenSSL
    NGINX

    By default we recommend using Traefik but if you already use NGINX then here's an example.

    When you configure NGINX for the platform, keep in mind the following:

    Inbound traffic needs to be directed towards 3 containers: kratos, crux-ui, and crux. The 5 locations defined are below:

    • /crux-ui

    • /kratos (needs to be stripped)

    • Locations routed to crux-ui:

      • /api/auth

      • /api/status

    • Locations routed to crux:

      • /api

    Example NGINX config with default ports:

    docker-compose
    upstream crux-ui {
        server localhost:3000;
    }
    
    upstream crux {
        server localhost:1848;
    }
    
    upstream kratos {
        server localhost:4433;
    }
    
    server {
        listen 80;
        listen [::]:80;
    
        server_name example.com;
    
        client_max_body_size 128m;
    
        proxy_read_timeout 300;
        return 301 https://$host$request_uri;
    }
    
    server {
        listen 443 ssl http2;
        listen [::]:443 ssl http2;
    
        server_name example.com;
    
        ssl_certificate /etc/ssl/ssl.crt;
        ssl_certificate_key /etc/ssl/ssl.key;
    
        client_max_body_size 128m;
    
        proxy_set_header Host $http_host; # required for docker client's sake
        proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 900;
    
        location / {
            proxy_pass http://crux-ui;
        }
    
        location /kratos {
            rewrite ^/kratos(.*)$ /$1 break;
    
            proxy_pass http://kratos;
        }
    
        location /api/auth {
                proxy_pass http://crux-ui;
        }
        
        location /api/status {
                proxy_pass http://crux-ui;
        }
    
        location /api {
                    proxy_pass http://crux;
        }
    }

    Configuration management

    Configurations can be all over the place without a single source of truth when left unmanaged for long periods of time. The more configurations you need to deal with, the more likely you’ll lose track of them. The platform can be used as single source of truth for all of your configurations, while being able to add, remove or modify configurations directly or via the JSON editor.

    Every configuration you specify will remain stored after any modification or deletion to ensure you won’t have to spend time again defining already specified configurations.

    How is it better than using a Git repository?

    Git repositories containing the configurations of your microservice architecture can be all over the place because one repo won’t cover all the configurations for all the images & components in your architecture. The platform substitutes Git repos by bringing every variable that belong to a specific Product in one place.

    Best practices

    • Think ahead: designing is the first step towards efficient and secure configuration management. Go through your organization’s structure, consider privileges and access points. This step is crucial for more efficient configuration management.

    • Configuration roll back: if it turns out the new configuration is faulty, you can roll back the last functioning ones.

    • Bundled configurations: instead of specifying the same configurations one by one to each component, you can apply variables to multiple components with one click by bundling them up.

    Configuration customization

    You're able to define configurations for both images of a Project and Deployments. Variables that belong to images can be overwritten by deployment variables. You can also use sub filters to hide irrelevant variables to your configs. Below you can see all the variables for each filter – common, Kubernetes and Docker.

    • Common

    • Kubernetes

    • Docker

    JSON

    You're also able to customize your configuration in a JSON format, for easier copying.

    The result should look like this:

    Quality Assurance (QA)

    Our main goal is to provide you with fast and reliable open-source services. To achieve this, we collect performance data about the navigation and the application feature usage, and send anonymous usage statistics to our servers. This data helps us track how changes affect the performance and stability of our open-source service and identify potential issues.

    We are fully transparent about what data we collect, why we collect it, and how it's transmitted. The source code for the telemetry package is open-source and can be found here. If you do not want to share telemetry data and help improve our projects, you can opt out of this feature.

    Data Processing

    To provide a clear understanding of why we collect data, how it's collected, and what we do with it, as well as real-world examples of how this data has improved our projects, let's break down the data processing pipeline:

    1. Telemetry data is collected from the browser.

    2. This data is periodically sent to eu.posthog.com.

    3. The data is stored and analyzed using the PostHog platform.

    Our data processing pipeline has been designed with specific goals in mind:

    • To track the number of dyrector.io installs.

    • To understand which features are in use and how they are utilized.

    • To evaluate the frequency of specific feature usage.

    • To detect issues introduced by new features, such as buggy releases.

    Opting Out

    1. You have the option to disable quality assurance features, also known as telemetry, by using the environment variable QA_OPT_OUT=true. Disabling telemetry doesn't have any drawbacks, except that it prevents us from making improvements to the project.

    Data Privacy

    In order to safeguard your privacy, we take several measures to protect your data:

    1. We are unable to access or store the IP address of your host or users. Our PostHog project's "Discard client IP data" is active, thus we are not able to identify who sent the data. You can find a comprehensive list of transmitted URL paths in the Request Telemetry section.

    2. We do not transmit any environment information from the host except for:

      • Operating system (e.g., Windows, Linux, OSX)

    All this information is stored in an aggregated format without any personally identifiable data, ensuring your privacy is protected.

    Identification

    To facilitate the identification of installations each running instance is assigned a unique identifier generated using a Universally Unique Identifier (V4). This identification process is triggered when we are confident that the instance is not a test instance, such as a tutorial or a local installation.

    The system metrics we collect include:

    • $os: The operating system of the user's device.

    • $browser: The web browser used by the user.

    • $device_type: The type of device used, such as "Desktop" or "Mobile."

    These measures allow us to effectively manage and group installations while maintaining data security and privacy.

    Source code

    The full code-base is open source.

    Example

    CLI

    CLI is a tool for deploying a complete dyrector.io stack locally, for demonstration, testing, or development purposes.

    Dependencies

    Before using the CLI, make sure you have the following dependencies installed on your local machine:

    • Docker installed on your system but works, too.

    {
      // Container runtime user.
      "user": null,
      // Pseudo terminal allocation.
      "tty": false,
      // Maps an internal 80 to external 8080, external refers to the host's port.
      "ports": [    
        {
          "internal": 80,
          "external": 8080
        }
      ],
      "portRanges": [],
      "volumes": [],
      // In Docker terminology, this is the equivalent of entrypoint.
      //
      // commands and args following one another will be the entrypoint, the actual
      // starting parameter of the container.
      "commands": [],
      // Equals to CMD in Docker terminology.
      "args": [],
      // Possible variables can be none, expose, exposeWithTls.
      "expose": null,
      // When left undefined, the container's name by default. Domain suffix comes
      // after. The two together makes up a rootable domain for the host.
      "ingress": {
        "name": "traefik",
        "host": ""
      },
      // An OCI image containing assets or other artifacts, copied over pre-start.
      "configContainer": null,
      // Pull assets and artifacts from remote sources, such as object stores, remote
      // services, and so on.
      "importContainer": null,
      // standard initContainers
      "InitContainers": []InitContainer
      // Docker only, see Docker documentation
      // https://docs.docker.com/config/containers/logging/configure/
      "logConfig": null,
      // Standard variable. Can be always, none, unless_stopped, and so on.
      "restartPolicy": "unless_stopped",
      // Docker specific networkMode configuration.
      "networkMode": "none",
      // Existing networks to attach the container with.
      "networks": [],
      // Kubernetes only. See Kubernetes documentation.
      "deploymentStrategy": "unknown",
      // HTTP reverse proxy custom headers.
      "customHeaders": [],
      // Widely used headers in case of RESTful APIs.
      "proxyHeaders": false,
      // Kubernetes only. See Kubernetes documentation. Changes service
      // type to loadbalancer.
      "useLoadBalancer": false,
      // Kubernetes only. See Kubernetes documentation. Custom
      // loadbalancer annotations, eg. to define internal loadbalancer.
      "extraLBAnnotations": null,
      // Kubernetes only. See Kubernetes documentation.
      "healthCheckConfig": null,
      // Kubernetes only. See Kubernetes documentation.
      "resourceConfig": null,
      // Running application container name.
      "name": "mysql",
      // Environment variables used to configure application behavior.
      // Tribute to https://12factor.net
      "environment": {},
      // WIP (not available yet) configure container behavior based on annotations.
      "capabilities": {},
      // Standard Docker labels. See Docker documentation.
      "dockerLabels": {},
      // Custom labels for each basic k8s component.
      "labels": {
        // Key value pairs for k8s deployments.
        "deployment": null,
        // Key value pairs for k8s service.
        "service": null,
        // Key value pairs for k8s ingress.
        "ingress": null
      },
      // Custom annotations for each basic k8s component. See labels above,
      // or k8s documentation.
      "annotations": null
    }
    Target architecture (e.g., amd64, darwin, ...)
  • Display dimensions

  • Browser data (e.g., Firefox, Chrome, English, browser version)

  • $browser_version: The version of the web browser.

  • $browser_language: The language of the web browser.

  • $screen_height: The height of the user's screen in pixels.

  • $screen_width: The width of the user's screen in pixels.

  • $viewport_height: The height of the viewport in pixels.

  • $viewport_width: The width of the viewport in pixels.

  • $lib: This'll always be web.

  • $lib_version: The type of PostHog library.

  • $insert_id: An identifier associated with the insertion.

  • $time: A timestamp associated with the event.

  • distinct_id: A distinct identifier for the user or event.

  • $device_id: The identifier associated with the user's device.

  • $groups: A dictionary of group identifiers.

  • dyrector.io
    PostHog

    Go (1.20 or higher) to run the go install.

    When you use Podman, make sure you have the network_backend set to netavark, if you have an older installation (before 4.0 released) as the old CNI network backend doesn't support name resolutions we use.

    You also have to get the aardvark-dns plugin for the same reason.

    If you use rootless containers, set your DOCKER_HOST environmental variable correctly, because if it's missing, Docker will assume it's /var/run/docker.sock and you can get misleading errors from it.

    Option #1: Go install

    Step 1: Execute go install github.com/dyrector-io/dyrectorio/golang/cmd/dyo@main

    Step 2: Execute dyo up

    Step 3: After you navigated to localhost:8000 (this is the default traefik port) you will see a Login screen

    Step 4: Register an account with whatever e-mail address you see fit (doesn't have to be valid one)

    Step 5: Navigate to localhost:4436 where you will find your mail as all outgoing e-mails will land here

    Step 6: Open your e-mail message and using the link inside you can activate your account

    Step 7: Happy deploying! 🎬

    Option #2: Run CLI from source

    Step 1: By using command line – posix shells, Git Bash or PowerShell –, pull dyrector.io's GitHub repository by executing git pull, if you don't already have the repository on your local machine you have to clone the repository by executing git clone https://github.com/dyrector-io/dyrectorio.git.

    Step 2: Open the project folder, and execute make up – alias to go run ./golang/cmd/dyo up – and wait until you get back the command prompt. It should take a few minutes the first time running, as it will pull a few docker images.

    Step 3: Enter localhost:8000 in your browser's address bar. You're ready to use the platform.

    The command-line interface (CLI) lets you run a complete the platform's development environment locally with the following services: UI Service (crux-ui), Backend Service (crux), PostgreSQL databases, Authentication, Migrations, and SMTP mock mail server. The CLI also runs the migration services. The default container names are listed below:

    • dyo-stable_traefik

    • dyo-stable_crux-postgres

    • dyo-stable_kratos-postgres

    • dyo-stable_kratos

    • dyo-stable_kratos-migrate

    • dyo-stable_crux

    • dyo-stable_crux-migrate

    • dyo-stable_mailslurper

    • dyo-stable_crux-ui

    The dyo-stable prefix can be changed in the settings.yaml file of the application.

    When you contribute to the project on GitHub, you can turn off crux and crux-ui with the global options listed below or overriding the values in the settings file.

    CLI commands

    As you seen above you can start the application with the up subcommand, after you finished your work, you can stop and remove the containers with the down subcommand.

    Running the stack again without stopping it will result in containers stopped, removed then recreated.

    Configuration

    The CLI generates a settings.yaml file containing the default configurations if the program doesn't find a configuration on the given path, or a default path if there isn't. Default path is dependant on your OS, you can find these on:

    • Linux: $XDG_CONFIG_HOME/dyo-cli/settings.yaml where the $XDG_CONFIG_HOME usually resolving to $HOME/.config.

    • Mac OSX: $HOME/Library/Application Support/dyo-cli/settings.yaml.

    • Windows: %AppData%/dyo-cli/settings.yaml.

    The settings.yaml file contains the following:

    Please note, this file stores some state too, in this case passwords and secrets. These have to match to use the installation multiple times as with bad passwords you won't be able to update or use the databases.

    Get help​

    To get usage tips and learn more about available commands from within CLI, run the following as we described above:

    If you have additional questions or ideas for new features, you can start an issue or a new discussion on our CLI’s open-source repository. You can also chat with our team on Discord.

    We’d love to hear from you!

    Podman
    {
      "uuid": "018b8632-5d72-7461-95e1-985aaa8590e7",
      "event": "select-chip",
      "properties": {
        "$os": "Linux",
        "$browser": "Firefox",
        "$device_type": "Desktop",
        "$pathname": "/[teamSlug]/nodes",
        "$browser_version": 119,
        "$browser_language": "en-US",
        "$screen_height": 1080,
        "$screen_width": 1920,
        "$viewport_height": 921,
        "$viewport_width": 1093,
        "$lib": "web",
        "$lib_version": "1.85.2",
        "$insert_id": "38hidmng7xk5jtet",
        "$time": 1698763529.587,
        "distinct_id": "018b860e-5987-79b1-ac1e-eaf008c67fcd",
        "$device_id": "018b860e-5987-79b1-ac1e-eaf008c67fcd",
        "$groups": {
          "dyoInstance": "8c5c8b11-3c21-4d5a-b09b-fefb56647aaf"
        },
        "$console_log_recording_enabled_server_side": false,
        "$session_recording_recorder_version_server_side": "v2",
        "$autocapture_disabled_server_side": true,
        "$active_feature_flags": [],
        "$feature_flag_payloads": {},
        "$referrer": "$direct",
        "$referring_domain": "$direct",
        "elementType": "button",
        "label": "nodeType-docker",
        "token": "phc_wc4nEUy7HYW8Elf8G9jiccvl2ZYt8pVts8NVBRMPzHu",
        "$session_id": "018b860e-5988-748e-9880-ab38ffb8c284",
        "$window_id": "018b860e-5988-748e-9880-ab39b3e577af",
        "$set": {
          "$os": "Linux",
          "$browser": "Firefox",
          "$device_type": "Desktop",
          "$pathname": "/[teamSlug]/nodes",
          "$browser_version": 119,
          "$referrer": "$direct",
          "$referring_domain": "$direct"
        },
        "$set_once": {
          "$initial_os": "Linux",
          "$initial_browser": "Firefox",
          "$initial_device_type": "Desktop",
          "$initial_pathname": "/[teamSlug]/nodes",
          "$initial_browser_version": 119,
          "$initial_referrer": "$direct",
          "$initial_referring_domain": "$direct"
        },
        "$sent_at": "2023-10-31T14:45:29.624000+00:00",
        "$group_0": "8c5c8b11-3c21-4d5a-b09b-fefb56647aaf"
      },
      "timestamp": "2023-10-31T14:45:35.050Z",
      "team_id": 10816,
      "distinct_id": "018b860e-5987-79b1-ac1e-eaf008c67fcd",
      "elements_chain": "",
      "created_at": "2023-10-31T14:45:35.132Z"
    }
    USAGE:
       dyo [global options] command [command options] [arguments...]
    
    COMMANDS:
       up, u    Run the stack
       down, d  Stop the stack
       help, h  Shows a list of commands or help for one command
    
    GLOBAL OPTIONS:
       --disable-crux, --dc      disable crux(backend) service (default: false) [$DISABLE_CRUX]
       --disable-crux-ui, --dcu  disable crux-ui(frontend) service (default: false) [$DISABLE_CRUXUI]
       --local-agent, --la       will set crux env to make dagent connect to localhost instead of container network, it's useful when you use a non-containerized agent (default: false) [$LOCAL_AGENT]
       --write, -w               enables writing configuration, storing current state (default: false)
       --debug                   enables debug messages (default: false)
       --disable-forcepull       try to use images locally available (default: false) [$DISABLE_FORCEPULL]
       --disable-podman-checks   disabling podman checks, useful when you run the CLI in a container (default: false) [$DISABLE_PODMAN_CHECKS]
       --config value, -c value  persisted configuration path (default: /home/sziszi/.config/dyo-cli/settings.yaml) [$DYO_CONFIG]
       --imagetag value          image tag, it will override the config [$DYO_IMAGE_TAG]
       --prefix value, -p value  prefix that is preprended to container names (default: dyo-stable) [$PREFIX]
       --local-imagetag value    special local image tag, CLI will try to find it and use it, otherwise it will fall back to config [$DYO_LOCAL_IMAGE_TAG]
       --network value           custom network, overriding the configuration [$DYO_NETWORK]
       --expect-container-env    when both the stack and observer are running inside containers, like during e2e tests (default: false) [$DYO_FULLY_CONTAINERIZED]
       --silent, -s              hides the welcome message and minimizes chattiness (default: false)
       --help, -h                show help
       --version, -v             print the version
    settings.yaml
    # This option directly affects the docker images' tags. 
    # This applies to kratos, crux, and crux-ui. Currently we offer stable and latest tags.
    version: latest
    # The network's name where the containers will run. Agent will be installed here by
    # agent's install script.
    network-name: dyo-stable
    # The following settings are mostly self-describing, you can see the default values
    # here. If an option isn't available here, the CLI will use a predefined default, 
    # where the secrets will be a new 32 character long random string. The ports here 
    # will be exposed for your convenience, if theres any local address that is bound to a 
    # defined port here, feel free to change it, and restart the CLI.
    options:
        # Timezone of the application affects both crux and crux-ui.
        timezone: UTC
        crux-agentgrpc-port: 5000
        crux-http-port: 1848
        crux-ui-port: 3000
        crux-secret: c8S9683U4eXHWr5ikqijZKAaQ89Lb9KJ
        cruxPostgresPort: 5432
        cruxPostgresDB: crux
        cruxPostgresUser: crux
        cruxPostgresPassword: rHNxQdtNQCMywNLAT07HtYKBOJw659rL
        traefikWebPort: 8000
        traefikUIPort: 8080
        traefikDockerSocket: /var/run/docker.sock
        # Necessary for Windows installations
        traefikIsDockerSocketNamedPipe: false
        kratosAdminPort: 4434
        kratosPublicPort: 4433
        kratosPostgresPort: 5433
        kratosPostgresDB: kratos
        kratosPostgresUser: kratos
        kratosPostgresPassword: PHKZhJpdTcWO7KoKdkSVAJjvoiHum597
        kratosSecret: A7ovxCOyBt8hbPfslcD37ZDcKGLKi8of
        mailSlurperSMTPPort: 1025
        mailSlurperWebPort: 4436
        mailSlurperWebPort2: 4437
        mailFromName: dyrector.io Platform
        mailFromEmail: [email protected]
    dyo help

    Changelog

    0.10.0

    Introduced node connection improvements: node kick option is added, fixed an issue with updated agents getting kicked, and added an agent connection mechanism which will attempt connection with the stored token first, then the environment token if the first attempt fails. Delivered a fix to agents occasionally crashing when a container is deleted. Fixed deployment logs and container events logs overwriting each other. Added Rocket.Chat and Mattermost notification integrations. Added working directory as a container option. Integrated PostHog for quality assurance purposes (more details about it ) - tracking can be disabled. Private Docker Hub registries are now supported. Added healthchecks to CLI upon up command. Added show icon feature to relevant pages. Minor fixes and improvements.

    Shouts to chandhuDev for his contribution in this release.

    More details about this release on GitHub.

    0.9.0

    Container settings (docker inspect) are now available in the platform. Updated deployment process screen with a progress bar. Container config fields are node type based now. Various fixes and updates: ory/kratos identity listing, unnecessary websocket error toasts, audit event filtering, key-value input error messages. Other fixes and improvements. Thanks to our Hacktoberfest contributors:

    • PapePathe

    • pedaars

    • GuptaPratik02

    • harshsinghcs

    • akash47angadi

    More details about this release on GitHub.

    0.8.2

    Improved yup validation on the UI of the platform. Agent improvements: added updating status to agent, update button is disabled when there's no update available, fixed an agent update issue when the agent stuck at an older version. Deployments are listed on the node detail page. Fixed a deployment issue when secrets are copied to a different node's deployment. Other fixes and improvements. More details about this release on GitHub.

    0.8.1

    Reworked agent connection handling to offer a more secure and stable user experience for node management. Added category labels to the platform's containers for better usability. Stack's Go toolchain is upgraded, deploymentStrategy is now utilized, and port routing is explicit. Implemented a fix for port range exposion. Minor fixes and improvements. More details about this release here.

    0.8.0

    Implemented two new capabilities: configuration bundles and protected deployments. Configuration bundles are configuration templates you can apply to other stacks you manage with the platform. Protected deployments prevent overwriting certain stacks on an infrastructure. Self-managed dyrector.io stack now pulls the latest image when a new version is available. Made several improvements to the UI of the platform: added deployment creation card, table sorting, and images are listed now on the page of a registry. We turned image and instance configuration settings more distinct from each other. Improved sign up and team validation workflow. Added MLflow template. Minor fixes and improvements. More details about this release here.

    0.7.0

    Added team slug to API endpoints. Implemented node check before deletion. Self-managed dyrector.io improvements: added HEALTCHECK directives to self-managed dyrector.io images, upgraded ory/kratos to 1.0 in dyrector.io stack. dagent improvements: host rule removed when no domain is given, unix socket based healthcheck. Configuration screen improvements: renamed ingress to routing in container configuration to simplify domain specification in config editor, swapped internal and external port inputs, port validation fixes. Made improvements to teams. Other fixes and improvements. More details about this release here.

    0.6.1

    Implemented fixes to dagent related issues, deployment token migration. UI improvements. More details about this release here.

    0.6.0

    Local images can be added as unchecked registry. Fixed a bug that prevented users from generating a CD token. Minor fixes. More details about this release here.

    0.5.5

    Made continuous deployment token improvements: name can be added to tokens for better usability, CD events show up in audit log, CD token has never expire option. Social sign-in is now available: GitHub, GitLab, Google, Azure. Fixed node edit bug. Made improvements to agent, onboarding checklist. Minor fixes and updates. More details about this release here.

    0.5.4

    Added deployment tokens to trigger CD pipelines. Versionless projects can be converted to versioned. You can select what images you'd like to deploy. Improved registry workflow. Added reload when Kratos isn't available. Small UI improvements. Minor fixes and updates. More details about this release here.

    0.5.3

    Added crane to signer image and add additional cache restore. More details about this release here.

    0.5.2

    Implemented principle of least privilege RBAC when managing a Kubernetes cluster through the platform. Improvements to node setup flow, container management, dagent registry auth. Minor fixes and improvements. More details about this release here.

    0.5.1

    The release includes a fix for minor versioning in the CI process and a change in the release script to incorporate the version of Golang components. More details about this release here.

    0.5.0

    Added onboarding checklist to the dashboard to guide users through deployment process. Automated multiarch builds to dyrector.io agent, including ARM. Renamed products to projects and their types: simple to versionless, complex to versioned. Improved audit logs with agent connectivity data. Rolling projects are now copyable. Fixes and improvements. More details about this release here.

    0.4.2

    Fixes and improvements to secrets, private V2 registry addition to the platform, and container view UI improvements. More details about this release here.

    0.4.1

    Minor fixes. More details about this release here.

    0.4.0

    We made various improvements to the project codebase, including adding an offline bundle Makefile target for offline development. We also enhanced the documentation by refactoring the README.md file, including FAQs and a CLI docs link. Unused texts were removed, making the readme more concise. To improve usability, we enhanced the API descriptions and examples in the web documentation. We also introduced container config annotations for greater container configuration flexibility. Deployment management and tracking were improved with the implementation of deployment and event index functionalities.

    We resolved a team invite captcha error and introduced code formatting for better readability. For logging and monitoring, we implemented HTTP and WebSocket audit log functionalities. Documentation organization was enhanced by adding .md files, and we improved the pull request labeling process. Title validation for pull requests was implemented, and OpenAPI descriptions and UUID parameter handling were validated. A PR labeler was added to automate labeling, and a deployment events API was introduced. In the UI module, we made the signup page responsive and implemented reCAPTCHA for team invites to enhance security.

    More details about this release here.

    0.3.4

    This version includes various bug fixes, template refinements, and updates to container IDs and UI status. Additionally, technology labels were added to templates and a demo video was introduced in the release.

    More details about this release here.

    0.3.3

    This release includes a number of bug fixes and new features across various components of the software stack. Notably, the crane component was fixed to use the original containerPreName as a name for namespace, the web component now has a Gitea template and a PowerShell script, and the agent component now has an option to not have CPU limits. The ci component has also been updated with new e2e testing and image building capabilities, as well as improved image signing and push to DockerHub. Other improvements include new templates and health checks, as well as updates to dependencies and minor UI fixes.

    More details about this release here.

    0.3.2

    Agents - dagent and crane - support ARM powered nodes now. New templates are added: Gitea & Minecraft server. Minor fixes to deployments, JSON editor and mapper.

    More details about this release here.

    0.3.1

    Dashboard is available to get a quick glance of the latest deployments and statistics. Templates are now available for 5 applications: WordPress, Strapi, self-managed GitLab, Google Microservices Demo, LinkAce. Configuration management improvements and fixes: previous secrets are reused, listing glitches of variables are fixed in filters. Improvements to dagent and crane: distroless image, abs path support for mounts, container builder extra hosts.

    More details about this release here.

    0.3.0

    dagent updated: posix, mingw64 is supported now. dagent updates and deletes itself when new version of dagent is released. CLI improvements: verbose Docker & Podman error messages when CLI is setup. Config updates: common, Kubernetes & Docker variable filters & new variables (labels & annotations) added, unmatched secrets are invalidated, users can now mark secrets as required. Deployment updates: flow fixed, new capabilities (deletion & copy) available. Link navigation fixes in signup email. crane registry auth update.

    Thanks to our Hacktoberfest contributors:

    • SilverTux (add unit test for crane clients),

    • joremysh (add unit tests for agent/internal/crypt),

    • oriapp (replaced all try-catch's with catch (err)),

    • tg44 (zerolog introduced),

    • raghav-rama (add new docker container builder attribute: shell),

    • minhoryang (crane init for private-key generate on k8s, crane init at k8s deployment for shared secret, goair for new watch tool and makefile modified),

    • clebs (Add unit tests for golang/internal/mapper)

    659 files changed, 48182 insertions(+), 24050 deletions(-)

    More details about this release here.

    0.2.2

    Fixed Prisma segfault.

    More details about this release here.

    0.2.1

    CLI tool developed for quick local setup. Read here how to use CLI.

    Container configuration & secret management improved. Google Container Registries are supported. Notifications are implemented for Discord, Slack and Microsoft Teams to notify teammates of new Nodes, Products, deployment statuses and new teammates. Google Microservices Demo is available with DemoSeeder implementation. Agent related improvements. E2E tested with Playwright. Improved Audit log with pagination and server side filtering. Status page available to check the statuses of the services of the platform. User facing documentation is available. Minor glitches and bugs fixed.

    More details about this release here.

    0.1.1

    Vital fixes and cleanups. Extended & actualized unit tests in agent.

    More details about this release here.

    0.1.0

    Migration into a monorepo on GitHub to measure up to open-source requirements. Automations and multiple platform support – Apple Silicon, Windows – is now available to provide a convenient developer experience. Agent's install script is added with MacOS support. Guidelines of contribution – code of conduct and README.

    More details about this release here.

    here

    API

    Registries

    Registries are 3rd party registries where the images of versions are located. Learn more about registries here.

    Projects

    There are two kinds of projects in dyrector.io: versionless and versioned. Versionless projects make up one deployable unit without versioning, while versioned projects come with multiple rolling or incremental versions. More details .

    Versions

    Versions belong to versioned projects. Versionless projects act similar to a rolling version of a versioned project.

    The purpose of versions is to separate different variations of your project. They can be either rolling or incremental. One versionless project can have multiple versions of both types. More details about rolling and incremental versions .

    Version/Images

    Images make up a versioned project's version, or a versionless project.

    Teams

    Teams are the shared entity of multiple users. The purpose of teams is to separate users, nodes and projects based on their needs within an organization. Team owners can assign roles. More details about teams .

    Users/Me

    Users/Me cover endpoints related to your user profile.

    Deployments

    Deployments are the process that gets the installation of your versions or versionless projects done on the node of your choice. More details about deployments .

    Tokens

    Tokens are the access tokens that grant you access to a user profile and the teams the profile is a member of.

    Nodes

    Nodes are the deployment targets. Nodes are registered by installing at least one of the agents – crane for Kubernetes, dagent for Docker. These agents connect the platform to your node. One team can have as many nodes as they like.

    Node installation takes place with Shell or PowerShell scripts, which can be created or revoked. More details .

    Audit log

    Audit log is a log of team activity generated by the platform.

    Health

    Health refers to the status of the different services that make up the platform. It can be checked to see if the platform works properly.

    Notifications

    Notifications are chat notifications in Slack, Discord, and Teams. They send an automated message about deployments, new versions, new nodes, and new users. More details .

    Templates

    Templates are preset applications that can be turned into a project right away. They can be deployed with minimal configuration. More details about templates .

    Dashboard

    Dashboard summarizes the latest activities of a team.

    Storages

    Storages are S3 compatible memory storages. They can be used for file injection. More details .

    here
    here
    here
    here
    here
    here
    here
    here

    Fetch data of registries.

    get

    Lists every registries available in the active team. Request must include teamSlug in URL. Response is an array including the name, id, type, description, and icon of the registry.Registries are 3rd party registries where the container images are stored.

    Path parameters
    teamSlugstringRequired
    Responses
    200

    Data of all registries within a team listed.

    application/json
    403

    Unauthorized request for registries.

    get
    /api/{teamSlug}/registries

    Create a new registry.

    post

    To add a new registry, include teamSlug in URL, body must include name, type, description, details, and icon. Type, details, and name are required. Response is an array including the name, id, type, description, imageNamePrefix, inUse, icon, and audit log info of the registry.

    Path parameters
    teamSlugstringRequired
    Body
    typestring · enumRequiredPossible values:
    detailsone ofRequired
    or
    or
    or
    or
    or
    namestringRequired
    descriptionstring | nullableOptional
    iconstring | nullableOptional
    Responses
    201

    New registry created.

    application/json
    400

    Bad request for registry creation.

    403

    Unauthorized request for registry creation.

    409

    Registry name taken.

    post
    /api/{teamSlug}/registries

    Fetch data of a registry.

    get

    Lists the details of a registry. Request must include teamSlug and RegistryID in URL. registryId refers to the registry's ID. Response is an array including the name, id, type, description, imageNamePrefix, inUse, icon, and audit log info of the registry.

    Path parameters
    teamSlugstringRequired
    registryIdstringRequired
    Responses
    200

    Data of a registry listed.

    application/json
    400

    Bad request for a registry.

    403

    Unauthorized request for a registry.

    404

    Registry not found.

    get
    /api/{teamSlug}/registries/{registryId}

    Modify the details of a registry.

    put

    Modify the name, type, description, details, and icon. RegistryId refers to the registry's ID. teamSlug and RegistryID is required in URL, body must include type, details, and name.

    Path parameters
    teamSlugstringRequired
    registryIdstringRequired
    Body
    typestring · enumRequiredPossible values:
    detailsone ofRequired
    or
    or
    or
    or
    or
    namestringRequired
    descriptionstring | nullableOptional
    iconstring | nullableOptional
    Responses
    204

    Registry modified.

    400

    Bad request for registry modification.

    403

    Unauthorized request for registry modification.

    404

    Registry not found.

    409

    Registry name taken.

    put
    /api/{teamSlug}/registries/{registryId}

    Delete a registry from dyrector.io.

    delete

    Deletes a registry with the specified registryId. teamSlug and RegistryID are required in URL.

    Path parameters
    teamSlugstringRequired
    registryIdstringRequired
    Responses
    204

    Registry deleted.

    403

    Unauthorized request for registry delete.

    404

    Registry not found.

    delete
    /api/{teamSlug}/registries/{registryId}

    No content

    Fetch the projects list.

    get

    Returns a list of a team's projects and their details. teamSlug needs to be included in URL.

    Path parameters
    teamSlugstringRequired
    Responses
    200

    List of projects.

    application/json
    403

    Unauthorized request for projects.

    get
    /api/{teamSlug}/projects

    Create a new project for a team.

    post

    Create a new project for a team. teamSlug needs to be included in URL. Newly created team has a type and a name as required variables, and optionally a description and a changelog.

    Path parameters
    teamSlugstringRequired
    Body
    typestring · enumRequiredPossible values:
    namestringRequired
    descriptionstring | nullableOptional
    changelogstring | nullableOptional
    Responses
    201

    New project created.

    application/json
    400

    Bad request for project creation.

    403

    Unauthorized request for project creation.

    409

    Project name taken.

    post
    /api/{teamSlug}/projects

    Fetch details of a project.

    get

    Returns a project's details. teamSlug and ProjectID needs to be included in URL. The response should contain an array, consisting of the project's name, id, type, description, deletability, versions and version related data, including version name and id, changelog, increasibility.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    Responses
    200

    Details of a project.

    application/json
    400

    Bad request for project details.

    403

    Unauthorized request for project details.

    404

    Project not found.

    get
    /api/{teamSlug}/projects/{projectId}

    Update a project.

    put

    Updates a project. teamSlug is required in URL, as well as projectId to identify which project is modified, name, description and changelog can be adjusted with this call.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    Body
    namestringRequired
    descriptionstring | nullableOptional
    changelogstring | nullableOptional
    Responses
    204

    Project details are modified.

    400

    Bad request for project details modification.

    403

    Unauthorized request for project details modification.

    404

    Project not found.

    409

    Project name taken.

    put
    /api/{teamSlug}/projects/{projectId}

    No content

    Delete a project.

    delete

    Deletes a project with the specified projectId. teamSlug and ProjectID are required in URL.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    Responses
    204

    Project deleted.

    403

    Unauthorized request for a project.

    404

    Project not found.

    delete
    /api/{teamSlug}/projects/{projectId}

    No content

    Convert a project to versioned.

    post

    Converts a project to versioned with the specified projectId. teamSlug and ProjectID are required in URL.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    Responses
    204

    Project converted.

    400

    Bad request for project conversion.

    403

    Unauthorized request for project conversion.

    post
    /api/{teamSlug}/projects/{projectId}/convert

    No content

    Fetch the list of all the versions under a project.

    get

    Returns an array containing the every version that belong to a project. teamSlug and ProjectId must be included in URL. ProjectId refers to the project's ID. Details include the version's name, id, type, audit log details, changelog, and increasibility.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    Query parameters
    nameContainsstringOptional
    Responses
    200

    Returns an array with every versions of a project.

    application/json
    403

    Unauthorized request for project versions.

    get
    /api/{teamSlug}/projects/{projectId}/versions

    Create a new version.

    post

    Creates a new version in a project. projectId refers to the project's ID. teamSlug and ProjectId must be included in URL, request's body need to include name and type of the version, changelog is optionable. Response should include the name, id, changelog, increasibility, type, and audit log details of the version.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    Body
    typestring · enumRequiredPossible values:
    namestringRequired
    changelogstringOptional
    Responses
    201

    New version created.

    application/json
    400

    Bad request for version creation.

    403

    Unauthorized request for version creation.

    409

    Version name taken.

    post
    /api/{teamSlug}/projects/{projectId}/versions

    Retrieve the details of a version of a project.

    get

    Returns the details of a version in the project. teamSlug and ProjectId must be included in URL. projectId refers to the project's ID, versionId refers to the version's ID. Details include the version's name, id, type, audit log details, changelog, increasibility, mutability, deletability, and all image related data, including name, id, tag, order and configuration data of the images.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    Responses
    200

    Details of a version under a project is fetched.

    application/json
    400

    Bad request for version details.

    403

    Unauthorized request for version details.

    404

    Version not found.

    get
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}

    Modify version.

    put

    Updates a version's name and changelog. teamSlug, ProjectId and VersionId must be included in URL. projectId refers to the project's ID, versionId refers to the version's ID.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    Body
    namestringRequired
    changelogstringOptional
    Responses
    204

    Changelog of a version is updated.

    400

    Bad request for version modification.

    403

    Unauthorized request for version modification.

    404

    Version not found.

    409

    Version name taken.

    put
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}

    No content

    Delete a version.

    delete

    This call deletes a version. teamSlug, ProjectId and VersionId must be included in URL. projectId refers to the project's ID, versionId refers to the version's ID.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    Responses
    204

    Version deleted.

    403

    Unauthorized request for version delete.

    404

    Version not found.

    delete
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}

    No content

    Turn version into a default one of the versioned project other versions under it will inherit images and deployments from.

    put

    This call turns a version into the default one, resulting other versions within this project later inherit images, deployments and their configurations from it. teamSlug, ProjectId and VersionId must be included in URL. projectId refers to the project's ID, versionId refers to the version's ID.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    Responses
    204

    Version turned into default.

    400

    Bad request.

    403

    Unauthorized request for setting version as default.

    404

    Version not found.

    put
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}/default

    No content

    Increase a the version of a versioned project with a new version.

    post

    Increases the version of a project with a new child version. teamSlug, ProjectId and VersionId must be included in URL. projectId refers to the project's ID, versionId refers to the version's ID. name refers to the name of the new version, and is required in the body.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    Body
    namestringRequired
    changelogstringOptional
    Responses
    201

    New version created.

    application/json
    400

    Bad request for increasing version.

    403

    Unauthorized request for increasing version.

    post
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}/increase

    Fetch data of all images of a version.

    get

    Fetch details of images within a version. ProjectId refers to the project's ID, versionId refers to the version's ID. Both, and teamSlug are required in the URL.Details come in an array, including name, id, tag, order, and config details of the image.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    Responses
    200

    Data of images listed.

    application/json
    403

    Unauthorized request for images.

    get
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images

    Add images to a version.

    post

    Add new images to a version. projectId refers to the project's ID, versionId refers to the version's ID. These, and teamSlug are required in the URL. registryId refers to the registry's ID, images refers to the name(s) of the images you'd like to add. These are required variables in the body.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    Bodyobject[]
    registryIdstringRequired
    imagesstring[]Required
    Responses
    201

    New image added.

    application/json
    400

    Bad request for images.

    403

    Unauthorized request for images.

    post
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images

    Fetch data of an image of a version.

    get

    Fetch details of an image within a version. projectId refers to the project's ID, versionId refers to the version's ID, imageId refers to the image's ID. All, and teamSlug are required in the URL.Image details consists name, id, tag, order, and the config of the image.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    imageIdstringRequired
    Responses
    200

    Data of an image.

    application/json
    400

    Bad request for image details.

    403

    Unauthorized request for image details.

    404

    Image not found.

    get
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images/{imageId}

    Delete an image from a version.

    delete

    Delete an image. projectId refers to the project's ID, versionId refers to the version's ID, imageId refers to the image's ID. All, and teamSlug are required in the URL.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    imageIdstringRequired
    Responses
    204

    Delete an image from a version.

    403

    Unauthorized request for an image.

    404

    Image not found.

    delete
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images/{imageId}

    No content

    Configure an image of a version.

    patch

    Modify the configuration variables of an image. projectId refers to the project's ID, versionId refers to the version's ID, imageId refers to the image's ID. All, and teamSlug are required in the URL. Tag refers to the version of the image, config is an object of configuration variables.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    imageIdstringRequired
    Body
    tagstring | nullableOptional
    configall of | nullableOptional
    Responses
    204

    Image's configure variables updated.

    400

    Bad request for an image.

    403

    Unauthorized request for an image.

    404

    Image not found.

    patch
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images/{imageId}

    Edit image deployment order of a version.

    put

    Edit image deployment order of a version. projectId refers to the project's ID, versionId refers to the version's ID. Both, and teamSlug are required in the URL. Request body should include the IDs of the images in an array.

    Path parameters
    teamSlugstringRequired
    projectIdstringRequired
    versionIdstringRequired
    Bodystring[]
    string[]Optional
    Responses
    204

    Image order modified.

    400

    Bad request for ordering.

    403

    Unauthorized request for ordering.

    put
    /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images/order

    Fetch data of teams the user is a member of.

    get

    List of teams consist of name, id, and statistics, including number of users, projects, nodes, versions, and deployments.Teams are the shared entity of multiple users. The purpose of teams is to separate users, nodes and projects based on their needs within an organization. Team owners can assign roles. More details about teams here.

    Responses
    200

    List of teams and their statistics.

    application/json
    403

    Unauthorized request for teams.

    get
    /api/teams

    Create new team.

    post

    Request must include name, which is going to be the name of the newly made team. Response should include name, id, and statistics, including number of users, projects, nodes, versions, and deployments.

    Body
    slugstringRequired
    namestringRequired
    Responses
    201

    New team created.

    application/json
    400

    Bad request for team creation.

    403

    Unauthorized request for team creation.

    409

    Team name taken.

    post
    /api/teams

    Fetch data of a team the user is a member of.

    get

    Get the details of a team. Request must include teamId, which is the ID of the team they'd like to get the data of. Data of teams consist of name, id, and statistics, including number of users, projects, nodes, versions, and deployments. Response should include user details, as well, including name, id, role, status, email, and lastLogin.

    Path parameters
    teamIdstringRequired
    Responses
    200

    Details of the team.

    application/json
    400

    Bad request for team details.

    403

    Unauthorized request for team details.

    404

    Team not found.

    get
    /api/teams/{teamId}

    Modify a team's name.

    put

    Request must include teamId and name. Admin access required for a successful request.

    Path parameters
    teamIdstringRequired
    Body
    slugstringRequired
    namestringRequired
    Responses
    204

    Team name modified.

    400

    Bad request for team modification.

    403

    Unauthorized request for team modification.

    404

    Team not found.

    409

    Team name taken.

    put
    /api/teams/{teamId}

    No content

    Deletes a team.

    delete

    Request must include teamId. Owner access required for successful request.

    Path parameters
    teamIdstringRequired
    Responses
    204

    Team deleted.

    403

    Unauthorized request for team delete.

    404

    Team not found.

    delete
    /api/teams/{teamId}

    No content

    Invite a new user to the team.

    post

    Request must include teamId, email and firstName. Admin access required for a successful request.Response should include new user's name, id, role, status, email, and lastLogin. Admin access required for a successful request.

    Path parameters
    teamIdstringRequired
    Body
    emailstringRequired
    firstNamestringRequired
    lastNamestringOptional
    captchastringOptional
    Responses
    201

    User invited.

    application/json
    400

    Bad request for user invitation.

    403

    Unauthorized request for user invitation.

    409

    User is already invited to or already in the team.

    post
    /api/teams/{teamId}/users

    Edit user role.

    put

    Promotes or demotes the user. Request must include teamId, userId and role. Admin access required for a successful request.

    Path parameters
    teamIdstringRequired
    userIdstringRequired
    Body
    rolestring · enumRequiredPossible values:
    Responses
    204

    User's role modified.

    400

    Bad request for user role modification.

    403

    Unauthorized request for user role modification.

    404

    User not found.

    put
    /api/teams/{teamId}/users/{userId}/role

    No content

    Remove the current user from the team.

    delete

    Removes the current user from the team. Request must include teamId.

    Path parameters
    teamIdstringRequired
    Responses
    204

    User removed from a team.

    403

    Unauthorized request for user removal.

    404

    User not found.

    delete
    /api/teams/{teamId}/users/leave

    No content

    Remove a user from the team.

    delete

    Removes the user from the team. Request must include teamId, userId. Admin access required for a successful request.

    Path parameters
    teamIdstringRequired
    userIdstringRequired
    Responses
    204

    User removed from a team.

    403

    Unauthorized request for user removal.

    404

    User not found.

    delete
    /api/teams/{teamId}/users/{userId}

    No content

    Reinvite user with a pending invite status to a team.

    post

    This call sends a new invitation link to a user who hasn't accepted invitation to a team.Request must include teamId, userId. Admin access required for a successful request.

    Path parameters
    teamIdstringRequired
    userIdstringRequired
    Responses
    204

    New invite link sent.

    400

    Bad request for reinvitation.

    403

    Unauthorized request for reinvitation.

    post
    /api/teams/{teamId}/users/{userId}/reinvite

    No content

    Fetch the current user.

    post

    Response includes the user, teams, and invitations.

    Responses
    200

    Fetch the current user.

    application/json
    400

    Bad request for current user.

    403

    Unauthorized request for current user.

    post
    /api/users/me

    Accept invitation to a team.

    post

    Request must include teamId.

    Path parameters
    teamIdstringRequired
    Responses
    204

    Invitation accepted.

    400

    Bad request for team invitation.

    403

    Unauthorized request for team invitation.

    post
    /api/users/me/invitations/{teamId}

    No content

    Decline invitation to a team.

    delete

    Request must include teamId.

    Path parameters
    teamIdstringRequired
    Responses
    204

    Invitation declined.

    403

    Unauthorized request for invite declination.

    404

    Invitation not found.

    delete
    /api/users/me/invitations/{teamId}

    No content

    Sets the onboarding tips to visible for the user.

    put

    Enable onboarding tips.

    Responses
    204

    Enabled.

    403

    Unauthorized request for onboarding tips.

    put
    /api/users/me/preferences/onboarding

    No content

    Sets the onboarding tips to hidden for the user.

    delete

    Disable onboarding tips.

    Responses
    204

    Disabled.

    403

    Unauthorized request for onboarding tips.

    delete
    /api/users/me/preferences/onboarding

    No content

    Fetch the list of deployments.

    get

    Get the list of deployments. Request needs to include teamSlug in URL. A deployment should include id, prefix, status, note, audit log details, project name, id, type, version name, type, id, and node name, id, type.

    Path parameters
    teamSlugstringRequired
    Responses
    200

    List of deployments.

    application/json
    403

    Unauthorized request for deployments.

    get
    /api/{teamSlug}/deployments

    Create new deployment.

    post

    Request must include teamSlug in URL, versionId, nodeId, and prefix, which refers to the ID of a version, a node and the prefix of the deployment, must be included in body. Response should include deployment id, prefix, status, note, and audit log details, as well as project type, id, name, version type, id, name, and node type, id, name.

    Path parameters
    teamSlugstringRequired
    Body
    versionIdstringRequired
    nodeIdstringRequired
    prefixstringRequired
    notestring | nullableOptional
    Responses
    201

    New deployment created.

    application/json
    400

    Bad request for a deployment.

    403

    Unauthorized request for a deployment.

    409

    Prefix taken for the node.

    post
    /api/{teamSlug}/deployments

    Retrieve details of a deployment.

    get

    Get details of a certain deployment. Request must include teamSlug and deploymentId in URL. Deployment details should include id, prefix, environment, status, note, audit log details, project name, id, type, version name, type, id, and node name, id, type.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    Responses
    200

    Details of a deployment.

    application/json
    400

    Bad request for deployment details.

    403

    Unauthorized request for deployment details.

    404

    Deployment not found.

    get
    /api/{teamSlug}/deployments/{deploymentId}

    Delete deployment.

    delete

    Request must include teamSlug and deploymentId in the URL.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    Responses
    204

    Deployment deleted.

    403

    Unauthorized request for a deployment.

    404

    Deployment not found.

    delete
    /api/{teamSlug}/deployments/{deploymentId}

    No content

    Update deployment.

    patch

    Request must include deploymentId and teamSlug in URL.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    Body
    notestring | nullableOptional
    prefixstring | nullableOptional
    Responses
    204

    Deployment modified.

    400

    Bad request for a deployment.

    403

    Unauthorized request for a deployment.

    404

    Deployment not found.

    patch
    /api/{teamSlug}/deployments/{deploymentId}

    No content

    Get details of a soon-to-be container.

    get

    Request must include teamSlug, deploymentId and instanceId, which refer to the ID of a deployment and the instance, in the URL. Instances are the manifestation of an image in the deployment. Response should include state, id, updatedAt, and image details including id, name, tag, order and config variables.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    instanceIdstringRequired
    Responses
    200

    Details of an instance.

    application/json
    400

    Bad request for instance details.

    403

    Unauthorized request for an instance.

    404

    Instance not found.

    get
    /api/{teamSlug}/deployments/{deploymentId}/instances/{instanceId}

    Update instance configuration.

    patch

    Request must include teamSlug, deploymentId, instanceId in URL, and portion of the instance configuration as config in the body. Response should include config variables in an array.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    instanceIdstringRequired
    Body
    Responses
    204

    Instance configuration updated.

    400

    Bad request for an instance.

    403

    Unauthorized request for an instance.

    404

    Instance not found.

    patch
    /api/{teamSlug}/deployments/{deploymentId}/instances/{instanceId}

    Fetch secrets of a soon-to-be container.

    get

    Request must include teamSlug, deploymentId and instanceId, which refer to the ID of a deployment and the instance, needs to be included in URL. Response should include container prefix and name, and publicKey, keys.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    instanceIdstringRequired
    Responses
    200

    Secrets of an instance listed.

    application/json
    400

    Bad request for instance secrets.

    403

    Unauthorized request for instance secrets.

    404

    Instance secrets not found.

    get
    /api/{teamSlug}/deployments/{deploymentId}/instances/{instanceId}/secrets

    Start the deployment process.

    post

    Request must include teamSlug and deploymentId in the URL.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    Body
    instancesstring[]Optional
    Responses
    204

    Deployment initiated.

    400

    Bad request for a deployment.

    403

    Unauthorized request for a deployment.

    post
    /api/{teamSlug}/deployments/{deploymentId}/start

    No content

    Copy deployment.

    post

    Request must include teamSlug and deploymentId in the URL, which will be copied. The body must include the nodeId, prefix and optionally a note. Response should include deployment data: id, prefix, status, note, and miscellaneous details of audit log, project, version, and node.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    Body
    nodeIdstringRequired
    prefixstringRequired
    notestring | nullableOptional
    Responses
    201

    Deployment copied.

    application/json
    400

    Bad request for a deployment.

    403

    Unauthorized request for a deployment.

    409

    Prefix taken for the node.

    post
    /api/{teamSlug}/deployments/{deploymentId}/copy

    Fetch event log of a deployment.

    get

    Request must include teamSlug and deploymentId in the URL. Response should include an items array with objects of type, deploymentStatus, createdAt, log, and containerState which consists of state and instanceId.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    Query parameters
    skipnumberRequired
    takenumberRequired
    trynumberOptional
    Responses
    200

    Deployment event log.

    application/json
    400

    Bad request for a deployment log.

    403

    Unauthorized request for a deployment log.

    404

    Deployment log not found.

    get
    /api/{teamSlug}/deployments/{deploymentId}/log

    Create deployment token.

    put

    Request must include teamSlug and deploymentId in the URL. In the body a name and optionally the expiration date as expirationInDays.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    Body
    namestringRequired
    expirationInDaysnumberOptional
    Responses
    200

    Deployment token with jwt and the curl command.

    application/json
    201Success
    application/json
    400

    Bad request for a deployment token.

    403

    Unauthorized request for a deployment token.

    409

    Token name taken.

    put
    /api/{teamSlug}/deployments/{deploymentId}/token

    Delete deployment token.

    delete

    Request must include teamSlug and deploymentId in the URL.

    Path parameters
    teamSlugstringRequired
    deploymentIdstringRequired
    Responses
    204

    Deployment token deleted.

    403

    Unauthorized request for a deployment token.

    404

    Deployment token not found.

    delete
    /api/{teamSlug}/deployments/{deploymentId}/token

    No content

    List of tokens.

    get

    Access token's support is to provide secure access to the HTTP api without a cookie.

    Responses
    200

    Token list fetched.

    application/json
    403

    Unauthorized request for tokens.

    get
    /api/tokens

    Create access token.

    post

    Request must include name and expirationInDays.

    Body
    namestringRequired
    expirationInDaysnumberRequired
    Responses
    201Success
    application/json
    400

    Bad request for token creation.

    403

    Unauthorized request for token creation.

    409

    Token name taken.

    post
    /api/tokens

    Fetch token details.

    get

    Access token's details are name, id, and the time of creation and expiration. Request must include tokenId.

    Path parameters
    tokenIdstringRequired
    Responses
    200

    Token details listed.

    application/json
    400

    Bad request for token details.

    403

    Unauthorized request for token details.

    404

    Token not found.

    get
    /api/tokens/{tokenId}

    Delete an access token.

    delete

    Request must include tokenId.

    Path parameters
    tokenIdstringRequired
    Responses
    204

    Delete token.

    403

    Unauthorized request for token delete.

    404

    Token not found.

    delete
    /api/tokens/{tokenId}

    No content

    Get data of nodes that belong to your team.

    get

    Fetch data of deployment targets. Request must include teamSlug in URL. Response should include an array with the node's type, status, description, icon, address, connectedAt date, version, updating, id, and name.

    Path parameters
    teamSlugstringRequired
    Responses
    200

    Data of nodes listed.

    application/json
    403

    Unauthorized request for nodes.

    get
    /api/{teamSlug}/nodes

    Create new node.

    post

    Request must include the teamSlug in URL, and node's name in body. Response should include an array with the node's type, status, description, icon, address, connectedAt date, version, updating, id, and name.

    Path parameters
    teamSlugstringRequired
    Body
    namestringRequired
    descriptionstringOptional
    iconstringOptional
    Responses
    201

    New node created.

    application/json
    400

    Bad request for node creation.

    403

    Unauthorized request for node creation.

    409

    Node name taken.

    post
    /api/{teamSlug}/nodes

    Get data of nodes that belong to your team.

    get

    Fetch data of a specific node. Request must include teamSlug in URL, and nodeId in body. Response should include an array with the node's type, status, description, icon, address, connectedAt date, version, updating, id, name, hasToken, and agent installation details.

    Path parameters
    teamSlugstringRequired
    nodeIdstringRequired
    Responses
    200

    Data of the node.

    application/json
    400

    Bad request for node details.

    403

    Unauthorized request for node details.

    404

    Node not found.

    get
    /api/{teamSlug}/nodes/{nodeId}

    Update details of a node.

    put

    Request must include the teamSlug in URL, and node's name in body, body can include description and icon.

    Path parameters
    teamSlugstringRequired
    nodeIdstringRequired
    Body
    namestringRequired
    descriptionstringOptional
    iconstringOptional
    Responses
    204

    Node details modified.

    400

    Bad request for node details.

    403

    Unauthorized request for node details.

    404

    Node not found.

    409

    Node name taken.

    put
    /api/{teamSlug}/nodes/{nodeId}

    No content

    Delete node.

    delete

    Request must include the teamSlug in URL, and node's name in body.

    Path parameters
    teamSlugstringRequired
    nodeIdstringRequired
    Responses
    204

    Node deleted.

    403

    Unauthorized request for node delete.

    404

    Node not found.

    delete
    /api/{teamSlug}/nodes/{nodeId}

    No content

    Fetch install script.

    get

    Request must include the teamSlug in URL, and node's name in body. Response should include type, status, description, icon, address, connectedAt date, version, updating, id, name, hasToken, and install details.

    Path parameters
    teamSlugstringRequired
    nodeIdstringRequired
    Responses
    200Success
    text/plain
    Responsestring
    400

    Bad request for an install script.

    403

    Unauthorized request for an install script.

    404

    Install script not found.

    get
    /api/{teamSlug}/nodes/{nodeId}/script

    Create agent install script.

    post

    Request must include teamSlug in URL and nodeId, type, and scriptType.

    Path parameters
    teamSlugstringRequired
    nodeIdstringRequired
    Body
    typestring · enumRequiredPossible values:
    scriptTypestring · enumRequiredPossible values:
    rootPathstringOptional
    Responses
    200

    Install script generated.

    application/json
    201Success
    application/json
    400

    Bad request for an install script.

    403

    Unauthorized request for an install script.

    post
    /api/{teamSlug}/nodes/{nodeId}/script

    Delete node set up install script.

    delete

    Request must include the teamSlug in URL, and node's name in body.

    Path parameters
    teamSlugstringRequired
    nodeIdstringRequired
    Responses
    204

    Agent install script deleted.

    403

    Unauthorized request for script delete.

    404

    Install script not found.

    delete
    /api/{teamSlug}/nodes/{nodeId}/script

    No content

    Revoke the node's access token.

    delete

    Request must include the teamSlug in URL, and node's name in body.

    Path parameters
    teamSlugstringRequired
    nodeIdstringRequired
    Responses
    204

    Token revoked.

    403

    Unauthorized request for a token.

    404

    Token not found.

    delete
    /api/{teamSlug}/nodes/{nodeId}/token

    No content

    Update the agent.

    post

    Request must include the teamSlug in URL, and node's name in body.

    Path parameters
    nodeIdstringRequired
    Responses
    204

    Node details modified.

    400

    Bad request for node details.

    403

    Unauthorized request for node details.

    post
    /api/{teamSlug}/nodes/{nodeId}/update

    No content

    Fetch audit log.

    get

    Request must include teamSlug in URL, and its body must include skip, take, and dates of from and to. Response should include an array of items: createdAt date, event, and data.

    Path parameters
    teamSlugstringRequired
    nodeIdstringRequired
    Query parameters
    skipnumberRequired
    takenumberRequired
    fromstring · date-timeRequired
    tostring · date-timeRequired
    Responses
    200

    Paginated list of the audit log.

    application/json
    400

    Bad request for audit log.

    403

    Unauthorized request for audit log.

    404

    Audit log not found.

    get
    /api/{teamSlug}/nodes/{nodeId}/audit

    Start a container deployed with dyrector.io on a node.

    post

    Request must include nodeId, prefix, and name.

    Path parameters
    nodeIdstringRequired
    prefixstringRequired
    namestringRequired
    Responses
    204

    Container started.

    400

    Bad request for container starting.

    403

    Unauthorized request for container starting.

    post
    /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers/{name}/start

    No content

    Stop a container deployed with dyrector.io on a node.

    post

    Request must include nodeId, prefix, and name.

    Path parameters
    nodeIdstringRequired
    prefixstringRequired
    namestringRequired
    Responses
    204

    Container stopped.

    400

    Bad request for container stopping.

    403

    Unauthorized request for container stopping.

    post
    /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers/{name}/stop

    No content

    Restart a container deployed with dyrector.io on a node.

    post

    Request must include nodeId, prefix, and name.

    Path parameters
    nodeIdstringRequired
    prefixstringRequired
    namestringRequired
    Responses
    204

    Container restarted.

    400

    Bad request for container restarting.

    403

    Unauthorized request for container restarting.

    post
    /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers/{name}/restart

    No content

    Delete containers deployed with dyrector.io, with the specified prefix on a node.

    delete

    Request must include nodeId, and prefix.

    Path parameters
    nodeIdstringRequired
    prefixstringRequired
    Responses
    204

    Containers deleted.

    403

    Unauthorized request for container delete.

    404

    Container not found.

    delete
    /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers

    No content

    Delete a container deployed with dyrector.io, with the specified prefix and name on a node.

    delete

    Request must include nodeId, prefix, and name.

    Path parameters
    nodeIdstringRequired
    prefixstringRequired
    namestringRequired
    Responses
    204

    Container deleted.

    403

    Unauthorized request for container delete.

    404

    Container not found.

    delete
    /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers/{name}

    No content

    Fetch data of all containers on a node.

    get

    Request must include nodeId and prefix. Response should include id, command, createdAt, state, status, imageName, imageTag and ports of images.

    Path parameters
    nodeIdstringRequired
    Query parameters
    prefixstringRequired
    Responses
    200

    Fetch data of containers running on a node.

    application/json
    403

    Unauthorized request for containers.

    get
    /api/{teamSlug}/nodes/{nodeId}/containers

    Start the specific container on a node.

    post

    Request must include nodeId, and the name of the container.

    Path parameters
    nodeIdstringRequired
    namestringRequired
    Responses
    204

    Container started.

    400

    Bad request for container starting.

    403

    Unauthorized request for container starting.

    post
    /api/{teamSlug}/nodes/{nodeId}/containers/{name}/start

    No content

    Stop the specific container on a node.

    post

    Request must include nodeId, and the name of the container.

    Path parameters
    nodeIdstringRequired
    namestringRequired
    Responses
    204

    Container stopped.

    400

    Bad request for container stopping.

    403

    Unauthorized request for container stopping.

    post
    /api/{teamSlug}/nodes/{nodeId}/containers/{name}/stop

    No content

    Restart the specific container on a node.

    post

    Request must include nodeId, and the name of the container.

    Path parameters
    nodeIdstringRequired
    namestringRequired
    Responses
    204

    Container restarted.

    400

    Bad request for container restarting.

    403

    Unauthorized request for container restarting.

    post
    /api/{teamSlug}/nodes/{nodeId}/containers/{name}/restart

    No content

    Delete the specific container from a node.

    delete

    Request must include nodeId, and the name of the container.

    Path parameters
    nodeIdstringRequired
    namestringRequired
    Responses
    204

    Container deleted.

    403

    Unauthorized request for container delete.

    404

    Container not found.

    delete
    /api/{teamSlug}/nodes/{nodeId}/containers/{name}

    No content

    Fetch audit log.

    get

    Request must include skip, take, and dates of from and to. Response should include an array of items: createdAt date, userId, email, serviceCall, and data.

    Path parameters
    teamSlugstringRequired
    Query parameters
    skipnumberRequired
    takenumberRequired
    filterstringOptional
    fromstring · date-timeRequired
    tostring · date-timeRequired
    Responses
    200

    Paginated list of the audit log.

    application/json
    403

    Unauthorized request for audit logs.

    get
    /api/{teamSlug}/audit-log

    Return service status of the platform.

    get

    Response should include status, version of the platform and lastMigration of database.

    Responses
    200

    Service status.

    application/json
    get
    /api/health
    200

    Service status.

    Retrieve notifications that belong to a team.

    get

    Response should include teamSlug in the URL, type, id, name, url, active, and creatorName in the body.

    Path parameters
    teamSlugstringRequired
    Responses
    200

    Notifications listed.

    application/json
    403

    Unauthorized request for notifications.

    get
    /api/{teamSlug}/notifications

    Create a new notification.

    post

    Request must include teamSlug in the URL, type, enabledEvents, id, name, url, and active in the body. Response should list type, enabledEvents, id, name, url, active, and creatorName.

    Path parameters
    teamSlugstringRequired
    Body
    typestring · enumRequiredPossible values:
    namestringRequired
    urlstringRequired
    activebooleanRequired
    Responses
    201

    New notification created.

    application/json
    400

    Bad request for a notification.

    403

    Unauthorized request for a notification.

    409

    Notification name taken.

    post
    /api/{teamSlug}/notifications

    Fetch details of a notification.

    get

    Request must include teamSlug and notificationId parameters in URL. Response should include type, enabledEvents, id, name, url, active, and creatorName.

    Path parameters
    teamSlugstringRequired
    notificationIdstringRequired
    Responses
    200

    Details of notification listed.

    application/json
    400

    Bad request for notification details.

    403

    Unauthorized request for notification details.

    404

    Notification not found.

    get
    /api/{teamSlug}/notifications/{notificationId}

    Modify a notification.

    put

    Request must include teamSlug in the URL, type, enabledEvents, id, name, url, and active in the body. Response should include type, enabledEvents, id, name, url, active, and creatorName.

    Path parameters
    teamSlugstringRequired
    notificationIdstringRequired
    Body
    typestring · enumRequiredPossible values:
    namestringRequired
    urlstringRequired
    activebooleanRequired
    Responses
    200

    Notification modified.

    application/json
    204Success
    application/json
    400

    Bad request for a notification.

    403

    Unauthorized request for a notification.

    404

    Notification not found.

    409

    Notification name taken.

    put
    /api/{teamSlug}/notifications/{notificationId}

    Delete a notification.

    delete

    Request must include teamSlug and notificationId in URL.

    Path parameters
    teamSlugstringRequired
    notificationIdstringRequired
    Responses
    204

    Notification deleted.

    403

    Unauthorized request for notification delete.

    404

    Notification not found.

    delete
    /api/{teamSlug}/notifications/{notificationId}

    No content

    Send a test message.

    post

    Request must include teamSlug and notificationId in URL.

    Path parameters
    teamSlugstringRequired
    notificationIdstringRequired
    Responses
    204

    Test message sent.

    400

    Bad request for a test message.

    403

    Unauthorized request for a test message.

    post
    /api/{teamSlug}/notifications/{notificationId}/test

    No content

    Return list of templates on the platform.

    get

    Response should include id, name, description and technologies of templates.

    Responses
    200

    Templates listed.

    application/json
    403

    Unauthorized request for templates.

    get
    /api/templates

    Creates a new project from the selected template.

    post

    Request must include type, id, and name. Response should include id, name, description, type, and audit log details of templates.

    Body
    typestring · enumRequiredPossible values:
    idstringRequired
    teamSlugstringRequired
    namestringRequired
    descriptionstringOptional
    Responses
    201

    New project created.

    application/json
    400

    Bad request for project creation.

    403

    Unauthorized request for project creation.

    409

    Project name taken.

    post
    /api/templates

    Retrieves the picture of the template

    get

    Request must include templateId.

    Path parameters
    templateIdstringRequired
    Responses
    200

    Retrieve data of an image of a template.

    No content

    400

    Bad request for template images.

    403

    Unauthorized request for template images.

    404

    Template images not found.

    get
    /api/templates/{templateId}/image

    No content

    Fetch dashboard data of latest activities.

    get

    teamSlug is required in URL. Response should include users, number of auditLogEntries, projects, versions, deployments, failedDeployments, details of nodes, latestDeployments and auditLog entries.

    Path parameters
    teamSlugstringRequired
    Responses
    200

    Dashboard data listed.

    application/json
    403

    Unauthorized request for the dashboard.

    get
    /api/{teamSlug}/dashboard

    Fetch the list of storages.

    get

    Response should include description, icon, url, id, and name. teamSlug is required in URL.

    Path parameters
    teamSlugstringRequired
    Responses
    200

    List of storages.

    application/json
    403

    Unauthorized request for storages.

    get
    /api/{teamSlug}/storages

    Create a new storage.

    post

    Creates a new storage. Request must include teamSlug in URL, body is required to include name, and url. Request body may include description, icon, accesKey, and secretKey. Response should include description, icon, url, id, name, accessKey, secretKey, and inUse.

    Path parameters
    teamSlugstringRequired
    Body
    namestringRequired
    descriptionstringOptional
    iconstringOptional
    urlstringRequired
    accessKeystringOptional
    secretKeystringOptional
    Responses
    201

    New storage created.

    application/json
    400

    Bad request for storage creation.

    403

    Unauthorized request for storage creation.

    409

    Storage name taken.

    post
    /api/{teamSlug}/storages

    Fetch the name and ID of available storage options.

    get

    Response should include id, and name. teamSlug is required in URL.

    Path parameters
    teamSlugstringRequired
    Responses
    200

    Name and ID of storage options listed.

    application/json
    400

    Bad request for storage options.

    403

    Unauthorized request for storage options.

    404

    Storage options not found.

    get
    /api/{teamSlug}/storages/options

    Return details of a storage.

    get

    Get the details of a storage. Request must include teamSlug and storageId in URL. Response should include description, icon, url, id, name, accessKey, secretKey, and inUse.

    Path parameters
    teamSlugstringRequired
    storageIdstringRequired
    Responses
    200

    Storage details.

    application/json
    400

    Bad request for storage details.

    403

    Unauthorized request for storage details.

    404

    Storage not found.

    get
    /api/{teamSlug}/storages/{storageId}

    Modify a storage.

    put

    Updates a storage. Request must include teamSlugand storageId in URL. name, and url must be included in body. Request body may include description, icon, accesKey, and secretKey.

    Path parameters
    teamSlugstringRequired
    storageIdstringRequired
    Body
    namestringRequired
    descriptionstringOptional
    iconstringOptional
    urlstringRequired
    accessKeystringOptional
    secretKeystringOptional
    Responses
    204

    Storage updated.

    400

    Bad request for storage update.

    403

    Unauthorized request for storage update.

    404

    Storage not found.

    409

    Storage name taken.

    put
    /api/{teamSlug}/storages/{storageId}

    No content

    Delete a storage from dyrector.io.

    delete

    Deletes a storage. Request must include teamSlug and storageId in URL.

    Path parameters
    teamSlugstringRequired
    storageIdstringRequired
    Responses
    204

    Storage deleted.

    403

    Unauthorized request for storage delete.

    404

    Storage not found.

    delete
    /api/{teamSlug}/storages/{storageId}

    No content

    PUT /api/users/me/preferences/onboarding HTTP/1.1
    Host: 
    Accept: */*
    
    DELETE /api/users/me/preferences/onboarding HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/health HTTP/1.1
    Host: 
    Accept: */*
    

    No content

    New version created.

    No content

    No content

    New deployment created.

    No content

    {
      "type": "group",
      "details": {
        "imageNamePrefix": "text"
      },
      "id": "text",
      "name": "text",
      "description": "text",
      "icon": "text",
      "inUse": true,
      "createdAt": "2025-12-13T13:50:19.851Z",
      "updatedAt": "2025-12-13T13:50:19.851Z"
    }
    {
      "type": "incremental",
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "changelog": "text",
      "default": true,
      "increasable": true,
      "id": "text",
      "name": "text"
    }
    {
      "type": "incremental",
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "changelog": "text",
      "default": true,
      "increasable": true,
      "id": "text",
      "name": "text"
    }
    [
      {
        "id": "text",
        "name": "text",
        "tag": "text",
        "order": 1,
        "config": {
          "expose": "none",
          "restartPolicy": "always",
          "networkMode": "none",
          "deploymentStrategy": "recreate",
          "name": "text",
          "environment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "secrets": [
            {
              "required": true,
              "id": "text",
              "key": "text"
            }
          ],
          "routing": {
            "domain": "text",
            "path": "text",
            "stripPath": true,
            "uploadLimit": "text"
          },
          "user": 1,
          "tty": true,
          "configContainer": {
            "image": "text",
            "volume": "text",
            "path": "text",
            "keepFiles": true
          },
          "ports": [
            {
              "id": "text",
              "internal": 1,
              "external": 1
            }
          ],
          "portRanges": [
            {
              "id": "text",
              "internal": {
                "from": 1,
                "to": 1
              },
              "external": {
                "from": 1,
                "to": 1
              }
            }
          ],
          "volumes": [
            {
              "type": "ro",
              "id": "text",
              "name": "text",
              "path": "text",
              "size": "text",
              "class": "text"
            }
          ],
          "commands": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "args": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "initContainers": [
            {
              "id": "text",
              "name": "text",
              "image": "text",
              "command": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "args": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "environment": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "useParentConfig": true,
              "volumes": [
                {
                  "id": "text",
                  "name": "text",
                  "path": "text"
                }
              ]
            }
          ],
          "capabilities": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "storage": {
            "storageId": "text",
            "path": "text",
            "bucket": "text"
          },
          "logConfig": {
            "driver": "nodeDefault",
            "options": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          },
          "networks": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "dockerLabels": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "customHeaders": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "proxyHeaders": true,
          "useLoadBalancer": true,
          "extraLBAnnotations": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "healthCheckConfig": {
            "port": 1,
            "livenessProbe": "text",
            "readinessProbe": "text",
            "startupProbe": "text"
          },
          "resourceConfig": {
            "limits": {
              "cpu": "text",
              "memory": "text"
            },
            "requests": {
              "cpu": "text",
              "memory": "text"
            }
          },
          "annotations": {
            "service": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "deployment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "ingress": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          },
          "labels": {
            "service": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "deployment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "ingress": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          }
        },
        "createdAt": "2025-12-13T13:50:19.851Z",
        "registry": {
          "type": "v2",
          "id": "text",
          "name": "text"
        }
      }
    ]
    {
      "status": "preparing",
      "note": "text",
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "project": {
        "type": "versionless",
        "id": "text",
        "name": "text"
      },
      "version": {
        "type": "incremental",
        "id": "text",
        "name": "text"
      },
      "node": {
        "type": "docker",
        "id": "text",
        "name": "text"
      },
      "id": "text",
      "prefix": "text"
    }
    {
      "status": "preparing",
      "note": "text",
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "project": {
        "type": "versionless",
        "id": "text",
        "name": "text"
      },
      "version": {
        "type": "incremental",
        "id": "text",
        "name": "text"
      },
      "node": {
        "type": "docker",
        "id": "text",
        "name": "text"
      },
      "id": "text",
      "prefix": "text"
    }
    {
      "type": "discord",
      "enabledEvents": [
        "deployment-created"
      ],
      "id": "text",
      "name": "text",
      "url": "text",
      "active": true,
      "creatorName": "text"
    }
    GET /api/{teamSlug}/registries HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "type": "v2",
        "id": "text",
        "name": "text",
        "description": "text",
        "icon": "text",
        "url": "text"
      }
    ]
    POST /api/{teamSlug}/registries HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 102
    
    {
      "type": "group",
      "details": {
        "imageNamePrefix": "text"
      },
      "name": "text",
      "description": "text",
      "icon": "text"
    }
    GET /api/{teamSlug}/registries/{registryId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "type": "group",
      "details": {
        "imageNamePrefix": "text"
      },
      "id": "text",
      "name": "text",
      "description": "text",
      "icon": "text",
      "inUse": true,
      "createdAt": "2025-12-13T13:50:19.851Z",
      "updatedAt": "2025-12-13T13:50:19.851Z"
    }
    PUT /api/{teamSlug}/registries/{registryId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 102
    
    {
      "type": "group",
      "details": {
        "imageNamePrefix": "text"
      },
      "name": "text",
      "description": "text",
      "icon": "text"
    }
    DELETE /api/{teamSlug}/registries/{registryId} HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/projects HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "type": "versionless",
        "description": "text",
        "versionCount": 1,
        "audit": {
          "createdAt": "2025-12-13T13:50:19.851Z",
          "createdBy": "text",
          "updatedAt": "2025-12-13T13:50:19.851Z",
          "updatedBy": "text"
        },
        "id": "text",
        "name": "text"
      }
    ]
    POST /api/{teamSlug}/projects HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 76
    
    {
      "type": "versionless",
      "name": "text",
      "description": "text",
      "changelog": "text"
    }
    {
      "type": "versionless",
      "description": "text",
      "versionCount": 1,
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "id": "text",
      "name": "text"
    }
    GET /api/{teamSlug}/projects/{projectId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "type": "versionless",
      "description": "text",
      "deletable": true,
      "versions": [
        {
          "type": "incremental",
          "audit": {
            "createdAt": "2025-12-13T13:50:19.851Z",
            "createdBy": "text",
            "updatedAt": "2025-12-13T13:50:19.851Z",
            "updatedBy": "text"
          },
          "changelog": "text",
          "default": true,
          "increasable": true,
          "id": "text",
          "name": "text"
        }
      ],
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "id": "text",
      "name": "text"
    }
    PUT /api/{teamSlug}/projects/{projectId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 55
    
    {
      "name": "text",
      "description": "text",
      "changelog": "text"
    }
    DELETE /api/{teamSlug}/projects/{projectId} HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/{teamSlug}/projects/{projectId}/convert HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/projects/{projectId}/versions HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "type": "incremental",
        "audit": {
          "createdAt": "2025-12-13T13:50:19.851Z",
          "createdBy": "text",
          "updatedAt": "2025-12-13T13:50:19.851Z",
          "updatedBy": "text"
        },
        "changelog": "text",
        "default": true,
        "increasable": true,
        "id": "text",
        "name": "text"
      }
    ]
    POST /api/{teamSlug}/projects/{projectId}/versions HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 55
    
    {
      "type": "incremental",
      "name": "text",
      "changelog": "text"
    }
    GET /api/{teamSlug}/projects/{projectId}/versions/{versionId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "type": "incremental",
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "changelog": "text",
      "default": true,
      "increasable": true,
      "id": "text",
      "name": "text",
      "mutable": true,
      "deletable": true,
      "images": [
        {
          "id": "text",
          "name": "text",
          "tag": "text",
          "order": 1,
          "config": {
            "expose": "none",
            "restartPolicy": "always",
            "networkMode": "none",
            "deploymentStrategy": "recreate",
            "name": "text",
            "environment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "secrets": [
              {
                "required": true,
                "id": "text",
                "key": "text"
              }
            ],
            "routing": {
              "domain": "text",
              "path": "text",
              "stripPath": true,
              "uploadLimit": "text"
            },
            "user": 1,
            "tty": true,
            "configContainer": {
              "image": "text",
              "volume": "text",
              "path": "text",
              "keepFiles": true
            },
            "ports": [
              {
                "id": "text",
                "internal": 1,
                "external": 1
              }
            ],
            "portRanges": [
              {
                "id": "text",
                "internal": {
                  "from": 1,
                  "to": 1
                },
                "external": {
                  "from": 1,
                  "to": 1
                }
              }
            ],
            "volumes": [
              {
                "type": "ro",
                "id": "text",
                "name": "text",
                "path": "text",
                "size": "text",
                "class": "text"
              }
            ],
            "commands": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "args": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "initContainers": [
              {
                "id": "text",
                "name": "text",
                "image": "text",
                "command": [
                  {
                    "id": "text",
                    "key": "text"
                  }
                ],
                "args": [
                  {
                    "id": "text",
                    "key": "text"
                  }
                ],
                "environment": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ],
                "useParentConfig": true,
                "volumes": [
                  {
                    "id": "text",
                    "name": "text",
                    "path": "text"
                  }
                ]
              }
            ],
            "capabilities": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "storage": {
              "storageId": "text",
              "path": "text",
              "bucket": "text"
            },
            "logConfig": {
              "driver": "nodeDefault",
              "options": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ]
            },
            "networks": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "dockerLabels": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "customHeaders": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "proxyHeaders": true,
            "useLoadBalancer": true,
            "extraLBAnnotations": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "healthCheckConfig": {
              "port": 1,
              "livenessProbe": "text",
              "readinessProbe": "text",
              "startupProbe": "text"
            },
            "resourceConfig": {
              "limits": {
                "cpu": "text",
                "memory": "text"
              },
              "requests": {
                "cpu": "text",
                "memory": "text"
              }
            },
            "annotations": {
              "service": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "deployment": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "ingress": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ]
            },
            "labels": {
              "service": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "deployment": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "ingress": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ]
            }
          },
          "createdAt": "2025-12-13T13:50:19.851Z",
          "registry": {
            "type": "v2",
            "id": "text",
            "name": "text"
          }
        }
      ],
      "deployments": [
        {
          "status": "preparing",
          "note": "text",
          "updatedAt": "2025-12-13T13:50:19.851Z",
          "node": {
            "type": "docker",
            "status": "unreachable",
            "id": "text",
            "name": "text"
          },
          "id": "text",
          "prefix": "text"
        }
      ]
    }
    PUT /api/{teamSlug}/projects/{projectId}/versions/{versionId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 34
    
    {
      "name": "text",
      "changelog": "text"
    }
    DELETE /api/{teamSlug}/projects/{projectId}/versions/{versionId} HTTP/1.1
    Host: 
    Accept: */*
    
    PUT /api/{teamSlug}/projects/{projectId}/versions/{versionId}/default HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/{teamSlug}/projects/{projectId}/versions/{versionId}/increase HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 34
    
    {
      "name": "text",
      "changelog": "text"
    }
    GET /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "id": "text",
        "name": "text",
        "tag": "text",
        "order": 1,
        "config": {
          "expose": "none",
          "restartPolicy": "always",
          "networkMode": "none",
          "deploymentStrategy": "recreate",
          "name": "text",
          "environment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "secrets": [
            {
              "required": true,
              "id": "text",
              "key": "text"
            }
          ],
          "routing": {
            "domain": "text",
            "path": "text",
            "stripPath": true,
            "uploadLimit": "text"
          },
          "user": 1,
          "tty": true,
          "configContainer": {
            "image": "text",
            "volume": "text",
            "path": "text",
            "keepFiles": true
          },
          "ports": [
            {
              "id": "text",
              "internal": 1,
              "external": 1
            }
          ],
          "portRanges": [
            {
              "id": "text",
              "internal": {
                "from": 1,
                "to": 1
              },
              "external": {
                "from": 1,
                "to": 1
              }
            }
          ],
          "volumes": [
            {
              "type": "ro",
              "id": "text",
              "name": "text",
              "path": "text",
              "size": "text",
              "class": "text"
            }
          ],
          "commands": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "args": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "initContainers": [
            {
              "id": "text",
              "name": "text",
              "image": "text",
              "command": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "args": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "environment": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "useParentConfig": true,
              "volumes": [
                {
                  "id": "text",
                  "name": "text",
                  "path": "text"
                }
              ]
            }
          ],
          "capabilities": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "storage": {
            "storageId": "text",
            "path": "text",
            "bucket": "text"
          },
          "logConfig": {
            "driver": "nodeDefault",
            "options": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          },
          "networks": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "dockerLabels": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "customHeaders": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "proxyHeaders": true,
          "useLoadBalancer": true,
          "extraLBAnnotations": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "healthCheckConfig": {
            "port": 1,
            "livenessProbe": "text",
            "readinessProbe": "text",
            "startupProbe": "text"
          },
          "resourceConfig": {
            "limits": {
              "cpu": "text",
              "memory": "text"
            },
            "requests": {
              "cpu": "text",
              "memory": "text"
            }
          },
          "annotations": {
            "service": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "deployment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "ingress": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          },
          "labels": {
            "service": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "deployment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "ingress": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          }
        },
        "createdAt": "2025-12-13T13:50:19.851Z",
        "registry": {
          "type": "v2",
          "id": "text",
          "name": "text"
        }
      }
    ]
    POST /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 41
    
    [
      {
        "registryId": "text",
        "images": [
          "text"
        ]
      }
    ]
    GET /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images/{imageId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "id": "text",
      "name": "text",
      "tag": "text",
      "order": 1,
      "config": {
        "expose": "none",
        "restartPolicy": "always",
        "networkMode": "none",
        "deploymentStrategy": "recreate",
        "name": "text",
        "environment": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "secrets": [
          {
            "required": true,
            "id": "text",
            "key": "text"
          }
        ],
        "routing": {
          "domain": "text",
          "path": "text",
          "stripPath": true,
          "uploadLimit": "text"
        },
        "user": 1,
        "tty": true,
        "configContainer": {
          "image": "text",
          "volume": "text",
          "path": "text",
          "keepFiles": true
        },
        "ports": [
          {
            "id": "text",
            "internal": 1,
            "external": 1
          }
        ],
        "portRanges": [
          {
            "id": "text",
            "internal": {
              "from": 1,
              "to": 1
            },
            "external": {
              "from": 1,
              "to": 1
            }
          }
        ],
        "volumes": [
          {
            "type": "ro",
            "id": "text",
            "name": "text",
            "path": "text",
            "size": "text",
            "class": "text"
          }
        ],
        "commands": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "args": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "initContainers": [
          {
            "id": "text",
            "name": "text",
            "image": "text",
            "command": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "args": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "environment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "useParentConfig": true,
            "volumes": [
              {
                "id": "text",
                "name": "text",
                "path": "text"
              }
            ]
          }
        ],
        "capabilities": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "storage": {
          "storageId": "text",
          "path": "text",
          "bucket": "text"
        },
        "logConfig": {
          "driver": "nodeDefault",
          "options": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        },
        "networks": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "dockerLabels": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "customHeaders": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "proxyHeaders": true,
        "useLoadBalancer": true,
        "extraLBAnnotations": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "healthCheckConfig": {
          "port": 1,
          "livenessProbe": "text",
          "readinessProbe": "text",
          "startupProbe": "text"
        },
        "resourceConfig": {
          "limits": {
            "cpu": "text",
            "memory": "text"
          },
          "requests": {
            "cpu": "text",
            "memory": "text"
          }
        },
        "annotations": {
          "service": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "deployment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "ingress": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        },
        "labels": {
          "service": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "deployment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "ingress": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        }
      },
      "createdAt": "2025-12-13T13:50:19.851Z",
      "registry": {
        "type": "v2",
        "id": "text",
        "name": "text"
      }
    }
    DELETE /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images/{imageId} HTTP/1.1
    Host: 
    Accept: */*
    
    PATCH /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images/{imageId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 2029
    
    {
      "tag": "text",
      "config": {
        "expose": "none",
        "restartPolicy": "always",
        "networkMode": "none",
        "deploymentStrategy": "recreate",
        "name": "text",
        "environment": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "secrets": [
          {
            "required": true,
            "id": "text",
            "key": "text"
          }
        ],
        "routing": {
          "domain": "text",
          "path": "text",
          "stripPath": true,
          "uploadLimit": "text"
        },
        "user": 1,
        "tty": true,
        "configContainer": {
          "image": "text",
          "volume": "text",
          "path": "text",
          "keepFiles": true
        },
        "ports": [
          {
            "id": "text",
            "internal": 1,
            "external": 1
          }
        ],
        "portRanges": [
          {
            "id": "text",
            "internal": {
              "from": 1,
              "to": 1
            },
            "external": {
              "from": 1,
              "to": 1
            }
          }
        ],
        "volumes": [
          {
            "type": "ro",
            "id": "text",
            "name": "text",
            "path": "text",
            "size": "text",
            "class": "text"
          }
        ],
        "commands": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "args": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "initContainers": [
          {
            "id": "text",
            "name": "text",
            "image": "text",
            "command": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "args": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "environment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "useParentConfig": true,
            "volumes": [
              {
                "id": "text",
                "name": "text",
                "path": "text"
              }
            ]
          }
        ],
        "capabilities": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "storage": {
          "storageId": "text",
          "path": "text",
          "bucket": "text"
        },
        "logConfig": {
          "driver": "nodeDefault",
          "options": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        },
        "networks": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "dockerLabels": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "customHeaders": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "proxyHeaders": true,
        "useLoadBalancer": true,
        "extraLBAnnotations": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "healthCheckConfig": {
          "port": 1,
          "livenessProbe": "text",
          "readinessProbe": "text",
          "startupProbe": "text"
        },
        "resourceConfig": {
          "limits": {
            "cpu": "text",
            "memory": "text"
          },
          "requests": {
            "cpu": "text",
            "memory": "text"
          }
        },
        "annotations": {
          "service": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "deployment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "ingress": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        },
        "labels": {
          "service": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "deployment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "ingress": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        }
      }
    }
    PUT /api/{teamSlug}/projects/{projectId}/versions/{versionId}/images/order HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 8
    
    [
      "text"
    ]
    GET /api/teams HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "statistics": {
          "users": 1,
          "projects": 1,
          "nodes": 1,
          "versions": 1,
          "deployments": 1
        },
        "id": "text",
        "name": "text",
        "slug": "text"
      }
    ]
    POST /api/teams HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 29
    
    {
      "slug": "text",
      "name": "text"
    }
    {
      "statistics": {
        "users": 1,
        "projects": 1,
        "nodes": 1,
        "versions": 1,
        "deployments": 1
      },
      "id": "text",
      "name": "text",
      "slug": "text"
    }
    GET /api/teams/{teamId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "statistics": {
        "users": 1,
        "projects": 1,
        "nodes": 1,
        "versions": 1,
        "deployments": 1
      },
      "id": "text",
      "name": "text",
      "slug": "text",
      "users": [
        {
          "role": "owner",
          "status": "pending",
          "email": "text",
          "lastLogin": "2025-12-13T13:50:19.851Z",
          "id": "text",
          "name": "text"
        }
      ]
    }
    PUT /api/teams/{teamId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 29
    
    {
      "slug": "text",
      "name": "text"
    }
    DELETE /api/teams/{teamId} HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/teams/{teamId}/users HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 70
    
    {
      "email": "text",
      "firstName": "text",
      "lastName": "text",
      "captcha": "text"
    }
    {
      "role": "owner",
      "status": "pending",
      "email": "text",
      "lastLogin": "2025-12-13T13:50:19.851Z",
      "id": "text",
      "name": "text"
    }
    PUT /api/teams/{teamId}/users/{userId}/role HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 16
    
    {
      "role": "owner"
    }
    DELETE /api/teams/{teamId}/users/leave HTTP/1.1
    Host: 
    Accept: */*
    
    DELETE /api/teams/{teamId}/users/{userId} HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/teams/{teamId}/users/{userId}/reinvite HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/users/me HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "user": {
        "id": "text",
        "name": "text"
      },
      "teams": [
        {
          "role": "owner",
          "id": "text",
          "name": "text",
          "slug": "text"
        }
      ],
      "invitations": [
        {
          "id": "text",
          "name": "text",
          "slug": "text"
        }
      ]
    }
    POST /api/users/me/invitations/{teamId} HTTP/1.1
    Host: 
    Accept: */*
    
    DELETE /api/users/me/invitations/{teamId} HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/deployments HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "status": "preparing",
        "note": "text",
        "audit": {
          "createdAt": "2025-12-13T13:50:19.851Z",
          "createdBy": "text",
          "updatedAt": "2025-12-13T13:50:19.851Z",
          "updatedBy": "text"
        },
        "project": {
          "type": "versionless",
          "id": "text",
          "name": "text"
        },
        "version": {
          "type": "incremental",
          "id": "text",
          "name": "text"
        },
        "node": {
          "type": "docker",
          "id": "text",
          "name": "text"
        },
        "id": "text",
        "prefix": "text"
      }
    ]
    POST /api/{teamSlug}/deployments HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 66
    
    {
      "versionId": "text",
      "nodeId": "text",
      "prefix": "text",
      "note": "text"
    }
    GET /api/{teamSlug}/deployments/{deploymentId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "status": "preparing",
      "note": "text",
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "project": {
        "type": "versionless",
        "id": "text",
        "name": "text"
      },
      "version": {
        "type": "incremental",
        "id": "text",
        "name": "text"
      },
      "node": {
        "type": "docker",
        "id": "text",
        "name": "text"
      },
      "id": "text",
      "prefix": "text",
      "environment": [
        {
          "value": "text",
          "id": "text",
          "key": "text"
        }
      ],
      "publicKey": "text",
      "instances": [
        {
          "id": "text",
          "updatedAt": "2025-12-13T13:50:19.851Z",
          "image": {
            "id": "text",
            "name": "text",
            "tag": "text",
            "order": 1,
            "config": {
              "expose": "none",
              "restartPolicy": "always",
              "networkMode": "none",
              "deploymentStrategy": "recreate",
              "name": "text",
              "environment": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "secrets": [
                {
                  "required": true,
                  "id": "text",
                  "key": "text"
                }
              ],
              "routing": {
                "domain": "text",
                "path": "text",
                "stripPath": true,
                "uploadLimit": "text"
              },
              "user": 1,
              "tty": true,
              "configContainer": {
                "image": "text",
                "volume": "text",
                "path": "text",
                "keepFiles": true
              },
              "ports": [
                {
                  "id": "text",
                  "internal": 1,
                  "external": 1
                }
              ],
              "portRanges": [
                {
                  "id": "text",
                  "internal": {
                    "from": 1,
                    "to": 1
                  },
                  "external": {
                    "from": 1,
                    "to": 1
                  }
                }
              ],
              "volumes": [
                {
                  "type": "ro",
                  "id": "text",
                  "name": "text",
                  "path": "text",
                  "size": "text",
                  "class": "text"
                }
              ],
              "commands": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "args": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "initContainers": [
                {
                  "id": "text",
                  "name": "text",
                  "image": "text",
                  "command": [
                    {
                      "id": "text",
                      "key": "text"
                    }
                  ],
                  "args": [
                    {
                      "id": "text",
                      "key": "text"
                    }
                  ],
                  "environment": [
                    {
                      "value": "text",
                      "id": "text",
                      "key": "text"
                    }
                  ],
                  "useParentConfig": true,
                  "volumes": [
                    {
                      "id": "text",
                      "name": "text",
                      "path": "text"
                    }
                  ]
                }
              ],
              "capabilities": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "storage": {
                "storageId": "text",
                "path": "text",
                "bucket": "text"
              },
              "logConfig": {
                "driver": "nodeDefault",
                "options": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ]
              },
              "networks": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "dockerLabels": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "customHeaders": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "proxyHeaders": true,
              "useLoadBalancer": true,
              "extraLBAnnotations": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "healthCheckConfig": {
                "port": 1,
                "livenessProbe": "text",
                "readinessProbe": "text",
                "startupProbe": "text"
              },
              "resourceConfig": {
                "limits": {
                  "cpu": "text",
                  "memory": "text"
                },
                "requests": {
                  "cpu": "text",
                  "memory": "text"
                }
              },
              "annotations": {
                "service": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ],
                "deployment": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ],
                "ingress": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ]
              },
              "labels": {
                "service": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ],
                "deployment": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ],
                "ingress": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ]
              }
            },
            "createdAt": "2025-12-13T13:50:19.851Z",
            "registry": {
              "type": "v2",
              "id": "text",
              "name": "text"
            }
          },
          "config": {
            "expose": "none",
            "restartPolicy": "always",
            "networkMode": "none",
            "deploymentStrategy": "recreate",
            "secrets": [
              {
                "required": true,
                "id": "text",
                "key": "text",
                "value": "text",
                "encrypted": true,
                "publicKey": "text"
              }
            ],
            "name": "text",
            "environment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "routing": {
              "domain": "text",
              "path": "text",
              "stripPath": true,
              "uploadLimit": "text"
            },
            "user": 1,
            "tty": true,
            "configContainer": {
              "image": "text",
              "volume": "text",
              "path": "text",
              "keepFiles": true
            },
            "ports": [
              {
                "id": "text",
                "internal": 1,
                "external": 1
              }
            ],
            "portRanges": [
              {
                "id": "text",
                "internal": {
                  "from": 1,
                  "to": 1
                },
                "external": {
                  "from": 1,
                  "to": 1
                }
              }
            ],
            "volumes": [
              {
                "type": "ro",
                "id": "text",
                "name": "text",
                "path": "text",
                "size": "text",
                "class": "text"
              }
            ],
            "commands": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "args": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "initContainers": [
              {
                "id": "text",
                "name": "text",
                "image": "text",
                "command": [
                  {
                    "id": "text",
                    "key": "text"
                  }
                ],
                "args": [
                  {
                    "id": "text",
                    "key": "text"
                  }
                ],
                "environment": [
                  {
                    "value": "text",
                    "id": "text",
                    "key": "text"
                  }
                ],
                "useParentConfig": true,
                "volumes": [
                  {
                    "id": "text",
                    "name": "text",
                    "path": "text"
                  }
                ]
              }
            ],
            "capabilities": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "storage": {
              "storageId": "text",
              "path": "text",
              "bucket": "text"
            },
            "logConfig": {
              "driver": "nodeDefault",
              "options": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ]
            },
            "networks": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "dockerLabels": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "customHeaders": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "proxyHeaders": true,
            "useLoadBalancer": true,
            "extraLBAnnotations": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "healthCheckConfig": {
              "port": 1,
              "livenessProbe": "text",
              "readinessProbe": "text",
              "startupProbe": "text"
            },
            "resourceConfig": {
              "limits": {
                "cpu": "text",
                "memory": "text"
              },
              "requests": {
                "cpu": "text",
                "memory": "text"
              }
            },
            "annotations": {
              "service": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "deployment": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "ingress": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ]
            },
            "labels": {
              "service": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "deployment": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "ingress": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ]
            }
          }
        }
      ],
      "lastTry": 1,
      "token": {
        "id": "text",
        "name": "text",
        "createdAt": "2025-12-13T13:50:19.851Z",
        "expiresAt": "2025-12-13T13:50:19.851Z"
      }
    }
    DELETE /api/{teamSlug}/deployments/{deploymentId} HTTP/1.1
    Host: 
    Accept: */*
    
    PATCH /api/{teamSlug}/deployments/{deploymentId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 89
    
    {
      "note": "text",
      "prefix": "text",
      "environment": [
        {
          "value": "text",
          "id": "text",
          "key": "text"
        }
      ]
    }
    GET /api/{teamSlug}/deployments/{deploymentId}/instances/{instanceId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "id": "text",
      "updatedAt": "2025-12-13T13:50:19.851Z",
      "image": {
        "id": "text",
        "name": "text",
        "tag": "text",
        "order": 1,
        "config": {
          "expose": "none",
          "restartPolicy": "always",
          "networkMode": "none",
          "deploymentStrategy": "recreate",
          "name": "text",
          "environment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "secrets": [
            {
              "required": true,
              "id": "text",
              "key": "text"
            }
          ],
          "routing": {
            "domain": "text",
            "path": "text",
            "stripPath": true,
            "uploadLimit": "text"
          },
          "user": 1,
          "tty": true,
          "configContainer": {
            "image": "text",
            "volume": "text",
            "path": "text",
            "keepFiles": true
          },
          "ports": [
            {
              "id": "text",
              "internal": 1,
              "external": 1
            }
          ],
          "portRanges": [
            {
              "id": "text",
              "internal": {
                "from": 1,
                "to": 1
              },
              "external": {
                "from": 1,
                "to": 1
              }
            }
          ],
          "volumes": [
            {
              "type": "ro",
              "id": "text",
              "name": "text",
              "path": "text",
              "size": "text",
              "class": "text"
            }
          ],
          "commands": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "args": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "initContainers": [
            {
              "id": "text",
              "name": "text",
              "image": "text",
              "command": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "args": [
                {
                  "id": "text",
                  "key": "text"
                }
              ],
              "environment": [
                {
                  "value": "text",
                  "id": "text",
                  "key": "text"
                }
              ],
              "useParentConfig": true,
              "volumes": [
                {
                  "id": "text",
                  "name": "text",
                  "path": "text"
                }
              ]
            }
          ],
          "capabilities": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "storage": {
            "storageId": "text",
            "path": "text",
            "bucket": "text"
          },
          "logConfig": {
            "driver": "nodeDefault",
            "options": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          },
          "networks": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "dockerLabels": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "customHeaders": [
            {
              "id": "text",
              "key": "text"
            }
          ],
          "proxyHeaders": true,
          "useLoadBalancer": true,
          "extraLBAnnotations": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "healthCheckConfig": {
            "port": 1,
            "livenessProbe": "text",
            "readinessProbe": "text",
            "startupProbe": "text"
          },
          "resourceConfig": {
            "limits": {
              "cpu": "text",
              "memory": "text"
            },
            "requests": {
              "cpu": "text",
              "memory": "text"
            }
          },
          "annotations": {
            "service": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "deployment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "ingress": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          },
          "labels": {
            "service": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "deployment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "ingress": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ]
          }
        },
        "createdAt": "2025-12-13T13:50:19.851Z",
        "registry": {
          "type": "v2",
          "id": "text",
          "name": "text"
        }
      },
      "config": {
        "expose": "none",
        "restartPolicy": "always",
        "networkMode": "none",
        "deploymentStrategy": "recreate",
        "secrets": [
          {
            "required": true,
            "id": "text",
            "key": "text",
            "value": "text",
            "encrypted": true,
            "publicKey": "text"
          }
        ],
        "name": "text",
        "environment": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "routing": {
          "domain": "text",
          "path": "text",
          "stripPath": true,
          "uploadLimit": "text"
        },
        "user": 1,
        "tty": true,
        "configContainer": {
          "image": "text",
          "volume": "text",
          "path": "text",
          "keepFiles": true
        },
        "ports": [
          {
            "id": "text",
            "internal": 1,
            "external": 1
          }
        ],
        "portRanges": [
          {
            "id": "text",
            "internal": {
              "from": 1,
              "to": 1
            },
            "external": {
              "from": 1,
              "to": 1
            }
          }
        ],
        "volumes": [
          {
            "type": "ro",
            "id": "text",
            "name": "text",
            "path": "text",
            "size": "text",
            "class": "text"
          }
        ],
        "commands": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "args": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "initContainers": [
          {
            "id": "text",
            "name": "text",
            "image": "text",
            "command": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "args": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "environment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "useParentConfig": true,
            "volumes": [
              {
                "id": "text",
                "name": "text",
                "path": "text"
              }
            ]
          }
        ],
        "capabilities": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "storage": {
          "storageId": "text",
          "path": "text",
          "bucket": "text"
        },
        "logConfig": {
          "driver": "nodeDefault",
          "options": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        },
        "networks": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "dockerLabels": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "customHeaders": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "proxyHeaders": true,
        "useLoadBalancer": true,
        "extraLBAnnotations": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "healthCheckConfig": {
          "port": 1,
          "livenessProbe": "text",
          "readinessProbe": "text",
          "startupProbe": "text"
        },
        "resourceConfig": {
          "limits": {
            "cpu": "text",
            "memory": "text"
          },
          "requests": {
            "cpu": "text",
            "memory": "text"
          }
        },
        "annotations": {
          "service": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "deployment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "ingress": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        },
        "labels": {
          "service": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "deployment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "ingress": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        }
      }
    }
    PATCH /api/{teamSlug}/deployments/{deploymentId}/instances/{instanceId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 2067
    
    {
      "config": {
        "expose": "none",
        "restartPolicy": "always",
        "networkMode": "none",
        "deploymentStrategy": "recreate",
        "secrets": [
          {
            "required": true,
            "id": "text",
            "key": "text",
            "value": "text",
            "encrypted": true,
            "publicKey": "text"
          }
        ],
        "name": "text",
        "environment": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "routing": {
          "domain": "text",
          "path": "text",
          "stripPath": true,
          "uploadLimit": "text"
        },
        "user": 1,
        "tty": true,
        "configContainer": {
          "image": "text",
          "volume": "text",
          "path": "text",
          "keepFiles": true
        },
        "ports": [
          {
            "id": "text",
            "internal": 1,
            "external": 1
          }
        ],
        "portRanges": [
          {
            "id": "text",
            "internal": {
              "from": 1,
              "to": 1
            },
            "external": {
              "from": 1,
              "to": 1
            }
          }
        ],
        "volumes": [
          {
            "type": "ro",
            "id": "text",
            "name": "text",
            "path": "text",
            "size": "text",
            "class": "text"
          }
        ],
        "commands": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "args": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "initContainers": [
          {
            "id": "text",
            "name": "text",
            "image": "text",
            "command": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "args": [
              {
                "id": "text",
                "key": "text"
              }
            ],
            "environment": [
              {
                "value": "text",
                "id": "text",
                "key": "text"
              }
            ],
            "useParentConfig": true,
            "volumes": [
              {
                "id": "text",
                "name": "text",
                "path": "text"
              }
            ]
          }
        ],
        "capabilities": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "storage": {
          "storageId": "text",
          "path": "text",
          "bucket": "text"
        },
        "logConfig": {
          "driver": "nodeDefault",
          "options": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        },
        "networks": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "dockerLabels": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "customHeaders": [
          {
            "id": "text",
            "key": "text"
          }
        ],
        "proxyHeaders": true,
        "useLoadBalancer": true,
        "extraLBAnnotations": [
          {
            "value": "text",
            "id": "text",
            "key": "text"
          }
        ],
        "healthCheckConfig": {
          "port": 1,
          "livenessProbe": "text",
          "readinessProbe": "text",
          "startupProbe": "text"
        },
        "resourceConfig": {
          "limits": {
            "cpu": "text",
            "memory": "text"
          },
          "requests": {
            "cpu": "text",
            "memory": "text"
          }
        },
        "annotations": {
          "service": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "deployment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "ingress": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        },
        "labels": {
          "service": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "deployment": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ],
          "ingress": [
            {
              "value": "text",
              "id": "text",
              "key": "text"
            }
          ]
        }
      }
    }
    GET /api/{teamSlug}/deployments/{deploymentId}/instances/{instanceId}/secrets HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "container": {
        "prefix": "text",
        "name": "text"
      },
      "publicKey": "text",
      "keys": [
        "text"
      ]
    }
    POST /api/{teamSlug}/deployments/{deploymentId}/start HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 22
    
    {
      "instances": [
        "text"
      ]
    }
    POST /api/{teamSlug}/deployments/{deploymentId}/copy HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 47
    
    {
      "nodeId": "text",
      "prefix": "text",
      "note": "text"
    }
    GET /api/{teamSlug}/deployments/{deploymentId}/log?skip=1&take=1 HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "items": [
        {
          "type": "log",
          "deploymentStatus": "preparing",
          "createdAt": "2025-12-13T13:50:19.851Z",
          "log": [
            "text"
          ],
          "containerState": {
            "state": "running",
            "instanceId": "text"
          }
        }
      ],
      "total": 1
    }
    PUT /api/{teamSlug}/deployments/{deploymentId}/token HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 36
    
    {
      "name": "text",
      "expirationInDays": 1
    }
    {
      "id": "text",
      "name": "text",
      "createdAt": "2025-12-13T13:50:19.851Z",
      "expiresAt": "2025-12-13T13:50:19.851Z",
      "token": "text",
      "curl": "text"
    }
    DELETE /api/{teamSlug}/deployments/{deploymentId}/token HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/tokens HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "id": "text",
        "name": "text",
        "expiresAt": "2025-12-13T13:50:19.851Z",
        "createdAt": "2025-12-13T13:50:19.851Z"
      }
    ]
    POST /api/tokens HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 36
    
    {
      "name": "text",
      "expirationInDays": 1
    }
    {
      "id": "text",
      "name": "text",
      "expiresAt": "2025-12-13T13:50:19.851Z",
      "createdAt": "2025-12-13T13:50:19.851Z",
      "token": "text"
    }
    GET /api/tokens/{tokenId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "id": "text",
      "name": "text",
      "expiresAt": "2025-12-13T13:50:19.851Z",
      "createdAt": "2025-12-13T13:50:19.851Z"
    }
    DELETE /api/tokens/{tokenId} HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/nodes HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "type": "docker",
        "status": "unreachable",
        "description": "text",
        "icon": "text",
        "address": "text",
        "connectedAt": "2025-12-13T13:50:19.851Z",
        "version": "text",
        "updating": true,
        "id": "text",
        "name": "text"
      }
    ]
    POST /api/{teamSlug}/nodes HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 50
    
    {
      "name": "text",
      "description": "text",
      "icon": "text"
    }
    {
      "type": "docker",
      "status": "unreachable",
      "description": "text",
      "icon": "text",
      "address": "text",
      "connectedAt": "2025-12-13T13:50:19.851Z",
      "version": "text",
      "updating": true,
      "id": "text",
      "name": "text"
    }
    GET /api/{teamSlug}/nodes/{nodeId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "type": "docker",
      "status": "unreachable",
      "description": "text",
      "icon": "text",
      "address": "text",
      "connectedAt": "2025-12-13T13:50:19.851Z",
      "version": "text",
      "updating": true,
      "id": "text",
      "name": "text",
      "hasToken": true,
      "install": {
        "command": "text",
        "script": "text",
        "expireAt": "2025-12-13T13:50:19.851Z"
      },
      "inUse": true
    }
    PUT /api/{teamSlug}/nodes/{nodeId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 50
    
    {
      "name": "text",
      "description": "text",
      "icon": "text"
    }
    DELETE /api/{teamSlug}/nodes/{nodeId} HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/nodes/{nodeId}/script HTTP/1.1
    Host: 
    Accept: */*
    
    text
    POST /api/{teamSlug}/nodes/{nodeId}/script HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 93
    
    {
      "type": "docker",
      "scriptType": "shell",
      "rootPath": "text",
      "dagentTraefik": {
        "acmeEmail": "text"
      }
    }
    {
      "command": "text",
      "script": "text",
      "expireAt": "2025-12-13T13:50:19.851Z"
    }
    DELETE /api/{teamSlug}/nodes/{nodeId}/script HTTP/1.1
    Host: 
    Accept: */*
    
    DELETE /api/{teamSlug}/nodes/{nodeId}/token HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/{teamSlug}/nodes/{nodeId}/update HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/nodes/{nodeId}/audit?skip=1&take=1&from=2025-12-13T13%3A50%3A19.851Z&to=2025-12-13T13%3A50%3A19.851Z HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "items": [
        {
          "createdAt": "2025-12-13T13:50:19.851Z",
          "event": "text",
          "data": {}
        }
      ],
      "total": 1
    }
    POST /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers/{name}/start HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers/{name}/stop HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers/{name}/restart HTTP/1.1
    Host: 
    Accept: */*
    
    DELETE /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers HTTP/1.1
    Host: 
    Accept: */*
    
    DELETE /api/{teamSlug}/nodes/{nodeId}/{prefix}/containers/{name} HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/nodes/{nodeId}/containers?prefix=text HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "state": "running",
        "id": {
          "prefix": "text",
          "name": "text"
        },
        "command": "text",
        "createdAt": "2025-12-13T13:50:19.851Z",
        "reason": "text",
        "imageName": "text",
        "imageTag": "text",
        "ports": [
          {
            "internal": 1,
            "external": 1
          }
        ]
      }
    ]
    POST /api/{teamSlug}/nodes/{nodeId}/containers/{name}/start HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/{teamSlug}/nodes/{nodeId}/containers/{name}/stop HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/{teamSlug}/nodes/{nodeId}/containers/{name}/restart HTTP/1.1
    Host: 
    Accept: */*
    
    DELETE /api/{teamSlug}/nodes/{nodeId}/containers/{name} HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/audit-log?skip=1&take=1&from=2025-12-13T13%3A50%3A19.851Z&to=2025-12-13T13%3A50%3A19.851Z HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "items": [
        {
          "actorType": "get",
          "context": "http",
          "method": "get",
          "createdAt": "2025-12-13T13:50:19.851Z",
          "user": {
            "id": "text",
            "email": "text"
          },
          "name": "text",
          "event": "text",
          "data": {}
        }
      ],
      "total": 1
    }
    {
      "status": {},
      "version": "text",
      "lastMigration": "text"
    }
    GET /api/{teamSlug}/notifications HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "type": "discord",
        "id": "text",
        "name": "text",
        "url": "text",
        "active": true,
        "creatorName": "text"
      }
    ]
    POST /api/{teamSlug}/notifications HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 98
    
    {
      "type": "discord",
      "enabledEvents": [
        "deployment-created"
      ],
      "name": "text",
      "url": "text",
      "active": true
    }
    GET /api/{teamSlug}/notifications/{notificationId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "type": "discord",
      "enabledEvents": [
        "deployment-created"
      ],
      "id": "text",
      "name": "text",
      "url": "text",
      "active": true,
      "creatorName": "text"
    }
    PUT /api/{teamSlug}/notifications/{notificationId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 98
    
    {
      "type": "discord",
      "enabledEvents": [
        "deployment-created"
      ],
      "name": "text",
      "url": "text",
      "active": true
    }
    DELETE /api/{teamSlug}/notifications/{notificationId} HTTP/1.1
    Host: 
    Accept: */*
    
    POST /api/{teamSlug}/notifications/{notificationId}/test HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/templates HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "id": "text",
        "name": "text",
        "description": "text",
        "technologies": [
          "text"
        ]
      }
    ]
    POST /api/templates HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 87
    
    {
      "type": "versionless",
      "id": "text",
      "teamSlug": "text",
      "name": "text",
      "description": "text"
    }
    {
      "type": "versionless",
      "description": "text",
      "audit": {
        "createdAt": "2025-12-13T13:50:19.851Z",
        "createdBy": "text",
        "updatedAt": "2025-12-13T13:50:19.851Z",
        "updatedBy": "text"
      },
      "id": "text",
      "name": "text"
    }
    GET /api/templates/{templateId}/image HTTP/1.1
    Host: 
    Accept: */*
    
    GET /api/{teamSlug}/dashboard HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "users": 1,
      "auditLog": 1,
      "projects": 1,
      "versions": 1,
      "deployments": 1,
      "failedDeployments": 1,
      "onboarding": {
        "signUp": {
          "done": true,
          "resourceId": "text"
        },
        "createTeam": {
          "done": true,
          "resourceId": "text"
        },
        "createNode": {
          "done": true,
          "resourceId": "text"
        },
        "createProject": {
          "done": true,
          "resourceId": "text"
        },
        "createVersion": {
          "done": true,
          "resourceId": "text"
        },
        "addImages": {
          "done": true,
          "resourceId": "text"
        },
        "addDeployment": {
          "done": true,
          "resourceId": "text"
        },
        "deploy": {
          "done": true,
          "resourceId": "text"
        }
      }
    }
    GET /api/{teamSlug}/storages HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "description": "text",
        "icon": "text",
        "url": "text",
        "id": "text",
        "name": "text"
      }
    ]
    POST /api/{teamSlug}/storages HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 101
    
    {
      "name": "text",
      "description": "text",
      "icon": "text",
      "url": "text",
      "accessKey": "text",
      "secretKey": "text"
    }
    GET /api/{teamSlug}/storages/options HTTP/1.1
    Host: 
    Accept: */*
    
    [
      {
        "id": "text",
        "name": "text"
      }
    ]
    GET /api/{teamSlug}/storages/{storageId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "description": "text",
      "icon": "text",
      "url": "text",
      "id": "text",
      "name": "text",
      "accessKey": "text",
      "secretKey": "text",
      "inUse": true
    }
    PUT /api/{teamSlug}/storages/{storageId} HTTP/1.1
    Host: 
    Content-Type: application/json
    Accept: */*
    Content-Length: 101
    
    {
      "name": "text",
      "description": "text",
      "icon": "text",
      "url": "text",
      "accessKey": "text",
      "secretKey": "text"
    }
    DELETE /api/{teamSlug}/storages/{storageId} HTTP/1.1
    Host: 
    Accept: */*
    
    {
      "type": "discord",
      "enabledEvents": [
        "deployment-created"
      ],
      "id": "text",
      "name": "text",
      "url": "text",
      "active": true,
      "creatorName": "text"
    }
    {
      "description": "text",
      "icon": "text",
      "url": "text",
      "id": "text",
      "name": "text",
      "accessKey": "text",
      "secretKey": "text",
      "inUse": true
    }
    https://github.com/dyrector-io/dyrectorio/blob/main/.env.example
    https://github.com/dyrector-io/dyrectorio/blob/develop/golang/cmd/crane/.env.example
    https://github.com/dyrector-io/dyrectorio/blob/main/web/crux-ui/.env.example
    https://github.com/dyrector-io/dyrectorio/blob/develop/golang/cmd/dagent/.env.example
    # This composition of compose files reflects the old one
    COMPOSE_FILE=docker-compose.yaml:distribution/compose/docker-compose.traefik.yaml:distribution/compose/docker-compose.traefik-labels.yaml:distribution/compose/docker-compose.mail-test.yaml
    # # Docker settings
    
    # Traefik requires this file to be able to route the requests to the containers
    DOCKER_SOCKET=/var/run/docker.sock
    
    # # General
    
    # Tag for images. It's stable by default
    DYO_VERSION=stable
    # Required for Traefik's certification resolution
    # It should be your domain where dyrector.io will be available
    DOMAIN=example.com
    # Your server's timezone
    TIMEZONE=UTC
    # Required for Traefik's certification resolution
    # If there's an issue with the certificate, or when it expires,
    # letsencrypt will send a notification to this e-mail address
    [email protected]
    # NodeJS services can run in two modes: production and development
    # These are the two values this key can have
    NODE_ENV=production
    
    # # Crux service settings
    
    # You can specify how thorough logging will be
    # Options: verbose, debug, info, warning, error
    # The settings come in a hierarchic order, meaning that in the order above they contain each other
    # Example: 'warning' contains 'error'
    LOG_LEVEL=debug
    
    # Secret key for encrypting stored credentials
    # Can be generated using the CLI
    # Example: docker run --rm ghcr.io/dyrector-io/dyrectorio/cli/dyo:latest generate crux encryption-key
    ENCRYPTION_SECRET_KEY=Random_Generate_Key
    
    # # Database passwords
    
    # This value is the password to crux's database
    CRUX_POSTGRES_PASSWORD=Random_Generated_String
    # This value is the password to Kratos' database
    KRATOS_POSTGRES_PASSWORD=Random_Generated_String
    # This value is the password to root user
    POSTGRES_ROOT_PASSWORD=Random_Generated_String
    
    # # External URL of the site https://example.com(:port if not 443)
    
    # This setting is to define where your
    # self-managed dyrector.io will be available
    EXTERNAL_PROTO=https
    
    # # Cookie/JWT secrets
    
    # Secret to sign JWTs.
    CRUX_SECRET=Random_Generated_String
    # Secret to sign Kratos cookies
    # More details in Ory/Kratos documentation:
    # https://www.ory.sh/docs/kratos/reference/configuration
    KRATOS_SECRET=Random_Generated_String
    
    # # Mailserver settings
    
    # The connection string for the mail server
    # The protocol can be SMTP or SMTPS
    # Example: protocol://smtp_user:smtp_password@mailserver_ip_or_domain:port
    SMTP_URI=smtps://username:[email protected]:465
    # E-mail address for dyrector.io invitation links,
    # password resets and others
    [email protected]
    # E-mail sender name for dyrector.io invitation links,
    # password resets and others
    FROM_NAME=dyrector.io
    
    # # ReCAPTCHA secrets
    
    # In case you don't want to use ReCAPTCHA set DISABLE_RECAPTCHA to true
    # Highly recommended to keep the default value, which is `false`
    DISABLE_RECAPTCHA=false
    # Create ReCAPTCHA V2 credentials in the ReCAPTCHA admin console
    # It is recommended to use the inivisble type
    RECAPTCHA_SECRET_KEY=Recaptcha_Secret_Key
    RECAPTCHA_SITE_KEY=Recaptcha_Site_Key
    
    # To turn off Quality Assurance (default: false)
    # more info: https://docs.dyrector.io/learn-more/quality-assurance-qa
    # QA_OPT_OUT=true
    
    # For providing a group identifier codename for the collected usage data
    # QA_GROUP_NAME=
    
    # Generic config options
    # filled with defaults where it's applicable
    DEFAULT_LIMITS_CPU=100m
    DEFAULT_LIMITS_MEMORY=128Mi
    DEFAULT_REQUESTS_CPU=50m
    DEFAULT_REQUESTS_MEMORY=64Mi
    DEFAULT_VOLUME_SIZE=1G
    # GRPC_TOKEN=
    IMPORT_CONTAINER_IMAGE=rclone/rclone:1.57.0
    INGRESS_ROOT_DOMAIN=
    READ_HEADER_TIMEOUT=15s
    DEBUG=true
    DEBUG_UPDATE_ALWAYS=false
    DEBUG_UPDATE_USE_CONTAINERS=true
    DEFAULT_REGISTRY=index.docker.io
    
    # Crane specific options
    # Put 'true' to use in-cluster auth
    CRANE_IN_CLUSTER=false
    # The duration amount that for a kubernetes API request to complete
    DEFAULT_KUBE_TIMEOUT=2m
    # Field manager name
    FIELD_MANAGER_NAME=crane-dyrector-io
    # Use 'Force: true' while deploying
    FORCE_ON_CONFLICTS=true
    # The key/label name for audit purposes
    KEY_ISSUER=co.dyrector.io/issuer
    # The "kubectl" configuration location
    KUBECONFIG=
    # Timeouts used in tests, no effect on deployment
    TEST_TIMEOUT=15s
    # For injecting SecretPrivateKey
    SECRET_NAME=dyrectorio-secret
    SECRET_NAMESPACE=dyrectorio
    
    CRUX_UI_URL=http://localhost:8000
    
    KRATOS_URL=http://localhost:8000/kratos
    KRATOS_ADMIN_URL=http://localhost:4434
    
    # Sets the severity level of logging
    # Possible values: trace, debug, info, warn, error, and fatal
    # The settings come in a hierarchic order
    # Example: error contains fatal
    LOG_LEVEL=trace
    
    # # Google ReCAPTCHA config
    DISABLE_RECAPTCHA=true
    
    # Required only when ReCAPTCHA is enabled
    RECAPTCHA_SITE_KEY=<public_recaptcha_site_key>
    RECAPTCHA_SECRET_KEY=<recaptcha_secret_key>
    
    # # Playwright test config (for e2e tests)
    E2E_BASE_URL=http://localhost:8000
    
    # Docker HUB Proxy (optional)
    # HUB_PROXY_URL=http://<proxy_url>
    # HUB_PROXY_TOKEN=<proxy_token>
    
    # For overriding the node dns result order regardless of the NODE_ENV value
    # It may be necessary for running the e2e tests,
    # because node resolves localhost to IPv6 by default
    # DNS_DEFAULT_RESULT_ORDER=ipv4first
    
    https://github.com/dyrector-io/dyrectorio/blob/main/web/crux/.env.example
    NODE_ENV=development
    
    # # Development configurations
    
    # Kratos public API
    KRATOS_URL=http://localhost:8000/kratos
    # Kratos admin API
    # This should never be exposed
    KRATOS_ADMIN_URL=http://localhost:4434
    DATABASE_URL="postgresql://username:password@localhost:5432/crux?schema=public"
    CRUX_UI_URL=http://localhost:8000
    
    
    CRUX_POSTGRES_PASSWORD="Random_Generated_String"
    
    # # Port settings
    
    # Agent gRPC API port
    GRPC_AGENT_PORT=5000
    # RestAPI port
    HTTP_API_PORT=1848
    # Prometheus metrics port
    METRICS_API_PORT=1956
    
    # Podman has different alias host.containers.local:5000
    CRUX_AGENT_ADDRESS=localhost:5000
    
    # Signing secret for the generated JWTs
    JWT_SECRET=jwt-secret-token
    
    # Secret key for encrypting stored credentials
    # Can be generated using the CLI
    # Example: docker run --rm ghcr.io/dyrector-io/dyrectorio/cli/dyo:latest generate crux encryption-key
    ENCRYPTION_SECRET_KEY=
    
    # The old encryption key used to decrypt existing secrets while rotating keys
    # ENCRYPTION_DEPRECATED_KEY=
    
    # The Docker image tag in the node install script
    # Uncomment to use a different agent version
    # Defaults to the version of dyrector.io
    # CRUX_AGENT_IMAGE=latest
    
    # Uncomment to prevent the install script from
    # overwriting your locally built agent image
    # AGENT_INSTALL_SCRIPT_DISABLE_PULL=true
    
    # Possible values: trace, debug, info, warn, error, and fatal
    # The settings above come in a hierarchic order
    # Example: error contains fatal
    LOG_LEVEL=debug
    
    # # Email service config
    # SMTP URL for the mailslurper
    SMTP_URI=smtps://test:test@localhost:1025/?skip_ssl_verify=true&legacy_ssl=true
    # E-mail address for dyrector.io invitation links, password resets and others
    [email protected]
    # E-mail sender name for dyrector.io invitation links, password resets and others
    FROM_NAME=dyrector.io
    
    # Google ReCAPTCHA config
    DISABLE_RECAPTCHA=true
    # Required only when ReCAPTCHA is enabled
    RECAPTCHA_SECRET_KEY=<recaptcha_secret_key>
    
    # Registry label fetching config
    DISABLE_REGISTRY_LABEL_FETCHING=false
    
    # Determines the maximum quantity of lines returned from a container
    MAX_CONTAINER_LOG_TAKE=1000
    
    # Determines how much time an agent callback has to execute
    AGENT_CALLBACK_TIMEOUT=5000
    
    # Maximum accepted message size sent by the agent in bytes
    # defaults to 4 Megabytes
    # MAX_GRPC_RECEIVE_MESSAGE_LENGTH=4194304
    
    # GRPC Timeout values and their respective defaults
    # GRPC_KEEPALIVE_TIMEOUT_MS=5000
    # GRPC_KEEPALIVE_TIME_MS=30000
    # HTTP2_MINPINGINTERVAL_MS=30000
    # HTTP2_MINTIMEBETWEENPINGS_MS=10000
    
    # For overriding the node DNS result order
    # regardless of the NODE_ENV value
    # It may be necessary for running the e2e tests,
    # because node resolves localhost to IPv6 by default
    # DNS_DEFAULT_RESULT_ORDER=ipv4first
    
    # To turn off quality assurance telemetry
    # defaults to false
    # more info: https://docs.dyrector.io/learn-more/quality-assurance-qa
    # QA_OPT_OUT=true
    
    # For providing a group identifier codename for the collected usage data
    # QA_GROUP_NAME=
    
    # Generic config options
    # filled with defaults where it's applicable
    DEFAULT_LIMITS_CPU=100m
    DEFAULT_LIMITS_MEMORY=128Mi
    DEFAULT_REQUESTS_CPU=50m
    DEFAULT_REQUESTS_MEMORY=64Mi
    DEFAULT_VOLUME_SIZE=1G
    # GRPC_TOKEN=jwt
    IMPORT_CONTAINER_IMAGE=rclone/rclone:1.57.0
    INGRESS_ROOT_DOMAIN=
    READ_HEADER_TIMEOUT=15s
    DEBUG=true
    DEBUG_UPDATE_ALWAYS=false
    DEBUG_UPDATE_USE_CONTAINERS=true
    
    # DAgent specific options
    AGENT_CONTAINER_NAME=dagent
    DAGENT_IMAGE=ghcr.io/dyrector-io/dyrectorio/dagent
    DAGENT_NAME=dagent-go
    DAGENT_TAG=latest
    # This should match the mount path that is
    # the root of configurations and containers
    DATA_MOUNT_PATH=/srv/dagent
    DEFAULT_TAG=latest
    DEFAULT_TIMEOUT=5s
    GRPC_KEEPALIVE=60s
    # Path of 'docker.sock' or other local/remote
    # address where we can communicate with docker
    HOST_DOCKER_SOCK_PATH=/var/run/docker.sock
    # Containers mount path default
    INTERNAL_MOUNT_PATH=/srv/dagent
    # Loglines to skip if not defined on the request
    LOG_DEFAULT_SKIP=0
    # Loglines to take
    LOG_DEFAULT_TAKE=100
    MIN_DOCKER_VERSION=20.10
    # E-mail address to use for dynamic certificate requests
    TRAEFIK_ACME_MAIL=
    TRAEFIK_ENABLED=false
    # Loglevel for Traefik
    # Set to "DEBUG" to access Traefik dashboard
    TRAEFIK_LOG_LEVEL=
    # Whether to enable Traefik TLS or not
    TRAEFIK_TLS=false
    DEFAULT_REGISTRY=index.docker.io
    # Token used by the webhook to trigger the update
    WEBHOOK_TOKEN=