Cover what Dokploy v0.30 added
build / build (push) Successful in 3m56s
release / release (push) Successful in 15m2s

Six new resources, all backed by endpoints that did not exist before v0.30.0
and verified end-to-end against a live v0.30.2 instance:

  dokploy_network         Docker networks, now first-class. Services attach
                          through network_ids, which is what deprecates
                          Compose's isolated_deployment upstream.
  dokploy_dns_provider    Cloudflare or Route53, so adding a domain creates
                          its DNS record.
  dokploy_vault_provider  Env values resolved from HashiCorp Vault, Infisical,
                          AWS, Doppler, Azure or Scaleway at deploy time, so
                          the secret never lands in Dokploy or in state.
  dokploy_schedule        Cron jobs in a container, a stack, or on a server.
  dokploy_volume_backup   Scheduled backups of a named volume — the companion
                          to a mount that persists.
  dokploy_libsql          The sixth managed database engine.

libsql.create is the strictest endpoint in the API: eleven keys required to
be present, several only meaningfully null, no generated service name, and it
returns `true` rather than the row. CreateDefaults and ListIDs absorb all
three so the resource behaves like every other database.

Also filled the gaps a field-by-field diff against the live schema turned up:
domain gains `enabled` (the v0.30.0 park-a-domain toggle), compose gains
create_env_file, icon and service_networks, application gains icon and
preview_require_collaborator_permissions, and mounts accept libsql.

DNS and vault credentials are masked by Dokploy on read, so `config` is
tagged noread and keeps the configured value, as the basic-auth password
already does.
This commit is contained in:
max-voitcov
2026-08-26 00:40:27 +03:00
parent 3ddce62647
commit 2d1caf6e73
23 changed files with 1297 additions and 12 deletions
+77 -3
View File
@@ -51,6 +51,7 @@ resource "dokploy_domain" "api" {
- [Deployments are not managed](#deployments-are-not-managed)
- [Importing existing infrastructure](#importing-existing-infrastructure)
- [Using this from Pulumi](#using-this-from-pulumi)
- [Volumes that actually persist](#volumes-that-actually-persist)
- [Known API quirks](#known-api-quirks)
- [Development](#development)
@@ -70,7 +71,7 @@ endpoint that can serve the provider protocol `terraform init` speaks.
### From a release
```bash
VERSION=0.1.0
VERSION=0.2.0
OS_ARCH="$(go env GOOS)_$(go env GOARCH)"
BASE=https://gitea.coolify.vojtkov.dev/usr_unknown/terraform-provider-dokploy/releases/download
@@ -92,7 +93,7 @@ make install
```
That writes the binary to
`~/.local/share/terraform/plugins/registry.terraform.io/maxvojtkov/dokploy/0.1.0/<os>_<arch>/`
`~/.local/share/terraform/plugins/registry.terraform.io/maxvojtkov/dokploy/0.2.0/<os>_<arch>/`
and prints the CLI configuration to add to `~/.terraformrc`:
```hcl
@@ -114,7 +115,7 @@ terraform {
required_providers {
dokploy = {
source = "maxvojtkov/dokploy"
version = "0.1.0"
version = "0.2.0"
}
}
}
@@ -202,6 +203,7 @@ Full reference documentation lives in [`docs/`](./docs).
| [`dokploy_mariadb`](docs/resources/mariadb.md) | Managed MariaDB |
| [`dokploy_mongo`](docs/resources/mongo.md) | Managed MongoDB |
| [`dokploy_redis`](docs/resources/redis.md) | Managed Redis |
| [`dokploy_libsql`](docs/resources/libsql.md) | Managed libSQL (`sqld`) |
| [`dokploy_domain`](docs/resources/domain.md) | A hostname routed through Traefik |
| [`dokploy_mount`](docs/resources/mount.md) | Volume, bind mount or config file |
| [`dokploy_port`](docs/resources/port.md) | A port published straight onto the host |
@@ -211,6 +213,11 @@ Full reference documentation lives in [`docs/`](./docs).
| [`dokploy_ssh_key`](docs/resources/ssh_key.md) | SSH key pair for private Git and remote servers |
| [`dokploy_certificate`](docs/resources/certificate.md) | An uploaded TLS certificate |
| [`dokploy_destination`](docs/resources/destination.md) | S3-compatible backup destination |
| [`dokploy_network`](docs/resources/network.md) | A Docker network services attach to |
| [`dokploy_schedule`](docs/resources/schedule.md) | A cron job run in a container or on a server |
| [`dokploy_volume_backup`](docs/resources/volume_backup.md) | A scheduled backup of a Docker volume |
| [`dokploy_dns_provider`](docs/resources/dns_provider.md) | Cloudflare or Route53, for automatic DNS records |
| [`dokploy_vault_provider`](docs/resources/vault_provider.md) | An external secret manager for deploy-time env |
### Data sources
@@ -411,6 +418,56 @@ p := tfshim.NewProvider("0.1.0") // a plugin-framework provider.Provider
Keep `shim.NewProvider` stable — it is this repository's only public Go API.
## Volumes that actually persist
A `dokploy_mount` with `type = "volume"` **must** set `volume_name`:
```hcl
resource "dokploy_mount" "data" {
type = "volume"
volume_name = "shop-uploads" # required — see below
mount_path = "/app/uploads"
service_type = "application"
service_id = dokploy_application.api.id
}
```
Dokploy turns a mount into a Docker mount with
`{Source: volumeName || "", Target: mountPath}`. When `volumeName` is null the
source is the empty string, and Docker reads an empty source as an *anonymous*
volume — a new one on every single deploy, with the previous one left orphaned
on disk. Nothing errors: the service starts, the path is writable, and the data
is gone again after the next deployment while disk usage climbs.
Dokploy's API accepts that mount without complaint, so this provider rejects it
at plan time instead:
```
Error: Missing volume_name
with dokploy_mount.data,
on main.tf line 1, in resource "dokploy_mount" "data":
`volume_name` must be set to a non-empty value when `type` is `volume`.
Dokploy passes an unset `volume_name` to Docker as an empty source, which
creates a new anonymous volume on every deploy. The data written to the
previous volume is orphaned and never reused, so the mount silently does not
persist anything.
```
The same check covers `type = "bind"` without `host_path` and `type = "file"`
without `file_path`, and it rejects a field set against the wrong `type` —
`volume_name` on a bind mount, say — which Dokploy would otherwise ignore.
**If you already have such a mount**, adding `volume_name` and redeploying
gives you a persistent volume from that point on. The contents of the current
anonymous volume are not migrated; copy the data off the host first if you
need it.
Pair a named volume with [`dokploy_volume_backup`](docs/resources/volume_backup.md)
to get it off the host on a schedule.
## Known API quirks
These are properties of the Dokploy API that the provider works around; they
@@ -434,6 +491,23 @@ explain behaviour that would otherwise look surprising.
`environment.create`) reject it. The provider tracks this per field.
- **Basic auth passwords are never returned.** `dokploy_security.password`
keeps whatever you configured; drift in that one field cannot be detected.
DNS and vault provider credentials behave the same way: Dokploy masks
`config` on read, so `dokploy_dns_provider.config` and
`dokploy_vault_provider.config` keep the configured value and are not
checked for drift.
- **`libsql.create` is the strictest endpoint in the API.** It requires eleven
keys to be *present* — several only meaningfully `null` — declines to
generate a service name the way every other engine does, and then returns
`true` instead of the created row. The provider fills in the nulls, derives
an `app_name` from `name`, and finds the new ID by diffing the environment's
libSQL list, so `dokploy_libsql` behaves like the other databases.
- **A `volume` mount with no name is silently anonymous.** Covered in
[Volumes that actually persist](#volumes-that-actually-persist); the provider
rejects it at plan time.
- **Docker networks cannot be updated.** Dokploy exposes no `network.update`,
matching Docker itself, so every attribute of `dokploy_network` forces
replacement. Replacing a network detaches the services using it until they
are redeployed.
## Development