Server diagnostics tab (Docker dashboard) with:
- Per-network IP usage: subnet capacity vs. containers in use, including
reserved networks like dokploy-network which are excluded from the
managed Networks tab. Surfaces read errors instead of silently showing
zeroes when the Docker API call fails.
- Broadened daemon-error detection and failure classification for Swarm
network failures: IP pool exhaustion on an existing network
("could not find an available IP", "task allocation failure") and
network attach timeouts ("attaching to network failed", "context
deadline exceeded") — both previously fell through as Unclassified.
Verified end-to-end against a real systemd-managed dockerd.
- Failed-deployment rows now carry the raw log tail used for
classification, shown on hover and linked to their service/project,
so a guess (or lack of one) can be verified against the actual error
and followed straight to the app.
- Daemon-error panel is a read-only code editor, always visible (not
hidden when empty), prefixed with the actual "Logs from X to Y"
window passed to journalctl so the --since window can be verified.
- "Download report" exports everything on screen (metrics + raw logs)
as Markdown, so a customer can send one file instead of a screen-share.
- Health check now IS_CLOUD-gated the same way network sync already is:
a cloud org can no longer omit serverId and have the check silently
run against the shared platform host instead of their own server.
Includes an inotify diagnostics card (current vs. max_user_instances/
watches/queued_events) and a failed-deployments log with automatic
cause classification based on daemon/log error patterns.
- Images tab: list, inspect and delete docker images, with a
force-delete fallback when an image is in use.
- Disk Usage tab: docker system df summary as stat cards plus a
Build Cache table (docker system df -v) with a prune action.
Adds a new Events tab to /dashboard/docker showing Docker daemon
events (equivalent to `docker events`), polled via docker.getEvents
with a time-range selector and refresh button.
Also fixes a stale isCloud redirect that forced the Networks tab
back to Containers even though it is now shown in cloud.
Lets you connect a DNS provider and manage its records (create,
update, delete) from Settings -> DNS Providers, instead of doing it
by hand in Cloudflare/AWS.
- dns_provider table, org-scoped, jsonb config as a discriminated
union per provider type
- Cloudflare adapter (REST, bearer token)
- Route53 adapter (AWS SDK, SigV4); records are identified by
type:name since Route53 has no native record id, so update
handles renames as delete-old + upsert-new
- listZones/listRecords/createRecord/updateRecord/deleteRecord/
testConnection wired through a shared DnsClient interface
- Settings UI: provider management, zone browser, record CRUD,
IP-fill dropdown for A records (panel IP + remote servers)
- Access control: dnsProvider resource wired into custom roles
- Unit tests for both adapters and the config mask/merge logic
- Updated the environment autocomplete component to include projectId and environmentId in vault secret fetching logic.
- Added authorization checks in the vault provider router to ensure users have access to the specified project and environment.
- Modified the vault provider schema to include projectId and optional environmentId for better validation.
- Improved error handling for unauthorized access and invalid vault provider assignments.
- Introduced support for project and environment assignments for vault providers, allowing for more granular access control.
- Updated the vault provider schema to include assignments and modified related components to handle these changes.
- Enhanced UI to display assignment status and allow users to manage project and environment associations effectively.
- Added validation to ensure assignments reference valid projects and environments within the organization.
- Updated tests to cover new functionality related to vault provider assignments and environment variable resolution.
- Added support for managing various vault providers (HashiCorp, AWS, Azure, Doppler, Infisical) in the dashboard.
- Implemented environment variable resolution using vault references, allowing seamless integration of secrets into application environments.
- Enhanced UI components to display and manage vault providers effectively.
- Introduced tests for vault reference resolution and environment variable preparation.
- Updated related components to utilize new vault management features.
- Updated ShowIconSettings component to handle both application and compose service types.
- Added new icon column to the compose table in the database.
- Implemented fetching and updating of icons for services in the environment and application pages.
- Introduced fetchTemplateLogo function to retrieve logos for templates, improving icon handling for compose services.
Dokploy stopped using Redis in v0.29.9 when the deployment queue moved
to an in-memory implementation, and install.sh no longer creates the
dokploy-redis service. Remove the remaining references so fresh installs
don't report Redis as unhealthy:
- checkRedisHealth from infrastructure health check
- cleanRedis/reloadRedis endpoints and their UI actions
- initializeRedis dev setup and redis-connection config
- unused bullmq dependency
- Added auditing functionality for network creation, recreation, and deletion actions in the network API.
- Updated the audit log schema to include "network" as a resource type.
- Enhanced the network router to log actions with relevant metadata, improving traceability and accountability for network management operations.
- Added functionality for assigning Docker networks to services, allowing users to manage network associations directly from the UI.
- Introduced new components for assigning networks to both individual services and compose files, improving user experience and flexibility.
- Updated existing components to integrate network assignment features, ensuring seamless interaction within the dashboard.
- Enhanced the database schema to support new network-related fields, including `networkIds` and `detachDokployNetwork`, for better service configuration.
- Improved the layout and responsiveness of various UI elements to accommodate new features and enhance usability.
- Added a new API endpoint for recreating Docker networks that have been removed, allowing users to restore networks directly from the Dokploy interface.
- Updated the ShowNetworks and SyncNetworks components to include options for recreating networks, improving user management capabilities.
- Enhanced the network synchronization process to better handle stale records, providing users with clear actions for network maintenance.
- Refactored network creation logic to streamline the process and ensure consistency across network management operations.
- Added server filtering capability to the dashboard, allowing users to manage networks specific to selected servers.
- Introduced SyncNetworks component for synchronizing Docker networks with Dokploy, enabling import of new networks and cleanup of stale records.
- Updated HandleNetwork and ShowNetworks components to support server-specific operations, improving user experience and functionality.
- Enhanced API to support network synchronization and importing, ensuring accurate data handling for network management.
- Introduced a new ShowNetworkConfig component for displaying detailed Docker network configuration.
- Integrated ShowNetworkConfig into the ShowNetworks component, allowing users to view network details directly.
- Updated the layout of network actions for improved user experience and accessibility.
- Enhanced the API to support network inspection functionality, providing necessary data for the new component.
- Simplified the network form schema by removing unnecessary fields and enforcing validation rules for IP settings.
- Updated the HandleNetwork component to eliminate the edit functionality, focusing on network creation only.
- Improved the ShowNetworks component by adding a delete action for network management, enhancing user experience.
- Introduced a new SQL migration for the network schema, establishing necessary constraints and types.
- Cleaned up the API by removing the update network functionality, reflecting the immutable nature of Docker networks.
- Updated the ShowNetworks component to improve the layout and user experience.
- Introduced a new Pencil icon for editing networks and added a Badge component for displaying network drivers.
- Refactored loading and empty state handling for better visual feedback.
- Modified the API query to include server details for each network, enhancing the data returned for better context.
Organization admins can define their own AI providers (name + API URL)
from the AI settings section. When at least one custom provider is
defined, it replaces the built-in provider list in the Add AI form,
the API URL is auto-filled and locked, and the backend rejects any
configuration whose URL is not in the allowed list.
The remote (execAsyncRemote) path built `echo ${password} | docker ${args.join(" ")}`
with the password, registryUrl and username interpolated unescaped, so a password
like `pw; whoami` ran arbitrary commands as root on the target server. Reuse
safeDockerLoginCommand (already used by create/update), which shell-escapes each
field and feeds the password via --password-stdin. The local argv+stdin path was
already safe.
server.remove deleted a server (and its deployment rows) by caller-supplied
serverId without checking it belongs to the active organization, unlike server.one
and server.update. An owner/admin of org A could delete org B's server registration.
Resolve and compare the server's organizationId before the active-services guard,
so cross-org callers are rejected without leaking existence.
Add VOLUME_NAME_REGEX (Docker volume-name format) and enforce it on volumeName in
create/update/runManually — a legit volume name never contains shell metacharacters,
so this blocks injection across every docker run/rm/rclone sink at once. Escape the
user-supplied backupFileName and the mount volumeName in database rebuild with quote().
Wrap S3 credential flags (getS3Credentials + destination.testConnection), the
listBackupFiles search path, and every restore backupPath/backupFile with
shell-quote's quote() so $(), backticks, quotes and spaces in destination
fields or backupFile can no longer break out of the rclone shell commands.
Host-level schedules (server / dokploy-server) run their script as root on the
host. The owner/admin gate only ran in the no-service branch, so a member could
attach an accessible applicationId to a dokploy-server schedule and skip it,
gaining root via schedule.runManually.
Extract assertHostScheduleAccess into the schedule service and call it before
the service-access branch in create/update/delete/runManually so the host-level
authorization always applies.
- cluster.removeWorker: input.nodeId (z.string(), no regex) was interpolated raw
into 'docker node update/rm ${nodeId}' — now shell-quoted.
- swarm image upload (getRegistryCommands): registryTag / imageName were
interpolated raw into 'docker tag'/'docker push' and an echo. registryTag is
built from username and imagePrefix, which have no schema regex, so it was
injectable — now shell-quoted. (The docker login already used
safeDockerLoginCommand, so credentials were already safe.)
- gpu-setup: nodeId (derived from 'docker info', not user input) escaped as
defense-in-depth.
Closes GHSA-4mfc-grxw-6858, GHSA-hfwh-69ch-gv47, GHSA-prwq-2mcm-mvhr
swarm.getNodes/getNodeInfo/getNodeApps/getAppInfos accepted a caller-supplied
serverId and ran remote Docker Swarm reads against it with no organization
check, exposing another tenant's swarm topology cross-org (getContainerStats
already had the check; the others did not). getNodeInfo additionally
interpolated nodeId unescaped into 'docker node inspect ${nodeId}'.
Adds an org-ownership assertion to the four unscoped handlers and passes nodeId
through shell-quote in getNodeInfo.
Closes GHSA-jj6h-388v-9rwm
findServerById eagerly loads the sshKey relation (needed for server-side SSH
operations) including the plaintext privateKey. server.one and server.remove
returned that record to the client, exposing the private key to any member
with server:read regardless of canAccessToSSHKeys.
Adds redactServerSshKey() in the server service and applies it to the server.one
and server.remove responses. No client feature consumes the private key (the SSH
key management UI uses the dedicated sshKey router), and server-side callers keep
using findServerById directly, so behaviour is unchanged.
Closes GHSA-w9cp-jqfw-4xj9
The getBranches inputs type the provider id as optional, so only fetch and
authorize when an id is actually present; the underlying getBranches already
returns [] when no id is supplied.
The .one / getRepositories / getBranches / testConnection handlers for
github, gitlab, gitea and bitbucket resolved a provider by bare id under
protectedProcedure and returned the full row (OAuth tokens, app private
keys, webhook secrets) with no organization or entitlement check, letting
any authenticated user read another org's git-provider credentials (IDOR).
Adds assertGitProviderAccess() in the git-provider service (rejects cross-org
with NOT_FOUND and non-entitled same-org with FORBIDDEN, reusing the existing
getAccessibleGitProviderIds entitlement logic) and calls it in every read
handler before returning secret-bearing data.
Closes GHSA-66r5-5m5f-57vg
Add a new settings page under Settings > Sessions that shows all active
and expired login sessions with user info, IP address, device, and an
option to revoke (force logout) any session.
Backend:
- listSessions: adminProcedure that returns sessions joined with user
data, ordered by creation date
- revokeSession: adminProcedure that deletes a session by ID (blocks
self-revocation)
Frontend:
- New /dashboard/settings/sessions page with ShowSessions component
- Sessions table with user, IP, device, timestamps, and revoke action
- Sidebar link under Users (gated by member.read permission)
Tests:
- Input validation tests for revokeSession schema
Add an `enabled` flag (default true) so a domain can be switched off
without deleting it, preserving its configuration.
- schema: new `enabled` column + migration; added to apiUpdateDomain
- traefik (applications): guard manageDomain so a disabled domain never
exposes a router from any caller (create/update/forward-auth/toggle);
applies instantly through the file provider
- compose: skip disabled domains when generating docker labels, so the
change applies on the next deployment
- tRPC: new domain.toggleEnable procedure (permission-checked + audited),
returns requiresRedeploy for compose domains
- UI: switch on the domain card (host row, variant E) and a Status column
in the table view; disabled cards are dimmed; reuses the compose
redeploy hint for the toast
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
API key names longer than 32 characters were rejected by better-auth
with a 400 that surfaced as an opaque INTERNAL_SERVER_ERROR (the generic
"Failed to generate API key" toast). Add a shared name schema (min 1,
max 32, matching better-auth's default maximumNameLength) used by both
the tRPC input and the client form, and surface the limit on the Name
field so users see it before submitting.
Fixes#4798