Skip to content

Storage

The Storage area manages two kinds of resource. A storage connection records access to object or file storage that runs elsewhere. Managed storage is S3-compatible object storage that Opfield provisions and runs on a Storage Node; new clusters use SeaweedFS. Both require Personal or higher. Storage resources serve as destinations for database backups, and managed storage can give workloads private, bucket-scoped access.

Question Storage connection Managed storage
Who runs the service The provider or your storage team Opfield, as SeaweedFS on one Storage Node with a bounded disk
Protocols S3 (AWS S3, Cloudflare R2, MinIO, other S3-compatible services), SFTP, FTP, FTPS S3
Object browser Yes Yes
Backup destination Yes Yes
Access keys and workload links No Yes
Public exposure Not applicable Private by default; a public S3 listener is opt-in
Delete Removes only Opfield’s saved connection Removes the service and erases its data

Select Add Storage and choose a provider:

Provider Connection details
AWS S3, Cloudflare R2, MinIO, Other (S3-compatible) Region, access key ID, and secret access key; an endpoint for everything except AWS; optional session token, default bucket, and path-style addressing (on by default for MinIO)
SFTP Host, port (22 by default), user name, password or private key with an optional passphrase, and the server’s SHA-256 SSH host key fingerprint, which is required and checked on every connection
FTP, FTPS Host, port (21, or 990 for implicit FTPS), user name, and password; FTPS supports explicit or Implicit TLS and always verifies the server certificate with the system trust store or a CA Certificate you provide

For FTP, FTPS, and SFTP, directories below the configured Base Path appear as buckets. SMB is not supported.

Opfield stores secrets, host-key fingerprints, and CA certificates encrypted and never returns secrets to the form: leaving a secret field blank keeps the stored value, but changing the endpoint, host, user name, protocol, or trust settings requires entering the secret again. Revealing saved credentials requires storage:credentials:reveal. storage:credentials:use lets database backups and copy jobs use the saved credentials without revealing them. A bucket that backup policies or backup history refer to cannot be deleted; for storage connections, see Delete storage that backups refer to.

The Objects tab browses buckets and objects, opens and edits files, uploads files, creates folders, and deletes files and folders. It is unavailable while the storage is offline. Creating a bucket appears when a connection has no buckets and requires storage:objects:admin. The API additionally deletes buckets and creates presigned download links; presigned links are not available for private managed storage, which must be downloaded through Opfield, or for FTP, FTPS, and SFTP. Asking for an object or bucket that does not exist returns STORAGE_NOT_FOUND. See Permissions.

MCP clients move large objects without base64 in tool calls: download_storage_object checks storage:objects:read and returns a one-time link, valid for 15 minutes, with a ready curl command that streams the object through Opfield, and upload_storage_object uploads in chunks that Opfield verifies. A download link is checked again against the owner’s current permissions when it is used and works once.

Choose Deploy managed storage to provision object storage on a Storage Node, optionally in a storage folder; the folder picker offers only folders where you may create storage. New clusters run SeaweedFS 4.47, pinned to an immutable image digest; there is no in-place version change. The Storage Node pulls the image from the Opfield mirror at ghcr.io/the-square-labs/gateway first and falls back to Docker Hub, verifying the same digest either way. If both sources fail, provisioning stops with MANAGED_STORAGE_IMAGE_PULL_FAILED.

A cluster runs on one Storage Node; distributed clusters are not available for SeaweedFS. Set CPU, memory (at least 512 MiB), and disk limits when you provision it; the Console caps the disk at the Node’s free space minus its reserve. The disk is a preallocated, bounded image on the Storage Node, like the storage of managed databases: each cluster holds one loop device there, and the Docker daemon starts the engine only after that image is mounted; see Operator details: storage and direct TLS. Opfield generates the root credentials, and revealing them requires storage:credentials:reveal.

After provisioning you can change the name, tags, CPU, memory, swap, disk size, and S3 publication. The disk can only grow, and a change is rejected while a previous one is still being applied. Growing the disk, and turning publication on or off or changing its port, recreate the storage container; data and keys are retained. Restart and retrying a failed provisioning are also available.

Managed storage names are unique on each Storage Node. Creating or renaming managed storage with a name that another managed storage on the same Node already uses fails with 409 MANAGED_STORAGE_NAME_IN_USE; when that other storage failed to provision, retry or delete it first. A name becomes free as soon as its storage starts being deleted. When Opfield was updated to 2.11, later clusters that shared a name on one Node were renamed with the first free -2, -3, … suffix, together with their storage connection; see Conflicts resolved by the 2.11 update.

Managed storage is private by default. Opfield reaches it through authenticated Relay routes. You can enable additional access paths explicitly:

  • Publish S3 endpoint exposes the S3 API on a host port, 9000 by default.
  • TLS encrypts the S3 endpoint with a certificate from the Opfield Storage CA. It is chosen when the cluster is created and cannot be turned on later. Clients must trust that CA: the credentials dialog shows its SHA-256 fingerprint and lets you download it as storage-ca.pem or copy it. Through the API, GET /api/managed-storage/{id}/ca-certificate returns the certificate and fingerprint to anyone who can view the cluster, or MANAGED_STORAGE_TLS_DISABLED (409) when TLS is off; the MCP tool manage_managed_storage offers the same as the ca_certificate action.

SeaweedFS clusters offer S3 only; they have no FTP or SFTP listeners.

Database backups and copy jobs reach managed storage through a local listener and verify its certificate as localhost or 127.0.0.1. Opfield adds those names automatically to certificates of clusters created with an earlier release. While the new certificate is being applied, backups wait in the queue with the reason shown and retry on their own; they fail with BACKUP_STORAGE_CERTIFICATE_OUTDATED only if the certificate is not served within 7 hours. Opfield does not change host firewalls. Open only the ports that an identified client needs.

Opfield renews the certificate of a TLS cluster automatically, checking hourly: when two thirds of its lifetime have passed, 30 days or fewer remain, a required name is missing, or the certificate comes from another CA. The Storage Node daemon writes the new certificate and the engine reloads it without a restart; Opfield switches to it only after the cluster serves it. The Storage CA does not change, so clients keep working.

  • The storage’s Connection Details show a quiet TLS Certificate row with the expiry date and either “renewed automatically” or “needs attention”. A notice appears on the page only when attention is needed—renewal failed, 7 days or fewer remain, the renewed certificate is not loaded yet, renewal waits for the Node daemon, or the CA limits the lifetime—with the reason, the expiry date, and Renew now for users who may edit the storage. The Dashboard also lists every managed storage and managed database whose certificate needs attention and that you may view. Through the API and MCP you can renew at any time.
  • A restart is used only when 7 days or fewer remain, when you allow it on a manual renewal, or when you renew manually on a Node whose daemon cannot reload certificates yet. Otherwise such a Node keeps the current certificate until its daemon is updated.
  • SeaweedFS clusters created before 2.11 reread their certificate files only every few hours, so a renewal can take that long to be served; allow a restart to apply it sooner.
  • While renewal keeps failing, Opfield raises the Managed Service Certificate Renewal Failed notification event, which clears after a successful renewal. Create an alert rule for it. Renewals are recorded in the audit log.
  • API: GET /api/managed-storage/{id}/certificate and POST /api/managed-storage/{id}/certificate/renew with optional allowRestart; MCP and assistant: manage_managed_storage actions certificate_status and renew_certificate. Renewing needs storage:edit and keeps working after a license grace period ends.

Each bucket is stored in at least one data volume of its own, and Opfield sizes the volumes from the disk, so plan for roughly one data volume per bucket and prefer a moderate number of buckets. When the disk is full, writes fail with HTTP 500 while existing objects stay readable; free space by deleting objects, or grow the disk in the settings, which recreates the container, and writes resume.

On the storage detail page, the IAM Keys tab issues S3 credentials with an optional name, read-only or read-write access, up to 64 buckets (none means all buckets), and an optional expiry. Each key is its own IAM principal in the engine, limited to its buckets: it can list only those buckets, read objects, and—with read-write access—write and delete objects, but it cannot create or delete buckets. The engine enforces the expiry itself, and revoking a key removes its principal immediately. The secret key is shown once when the key is created. Creating and revoking keys requires storage:iam.

The credentials dialog shows AWS CLI and rclone quick-start commands. For a TLS cluster they pass the downloaded CA as --ca-bundle storage-ca.pem (AWS CLI) or --ca-cert storage-ca.pem (rclone). With a bucket-scoped key, rclone needs no_check_bucket = true (included in the quick start); otherwise it tries to create the bucket and fails with 403.

A managed storage link gives a Container or Deployment private access to 1–32 buckets. Add it from the workload’s Environment tab; Compose services are not supported. Opfield issues a key limited to those buckets, attaches the workload to a small private network of its own for the link, served by the shared secure-link connector of its Docker Node, and stores the values as managed secrets in environment variables that default to S3_ENDPOINT, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET (the first bucket), and AWS_REGION. The key can reach only the listed buckets, so a compromised workload cannot read the rest of the storage. Buckets the link lists that do not exist yet are created when the link is created, because the link’s own key cannot create them. Creating a link requires storage:iam and permission to edit the workload’s environment and secrets; a link on a Deployment also needs docker:containers:manage on it, plus docker:containers:edit when it changes the Deployment’s environment.

A link carries up to 64 concurrent connections, which the slots of a Deployment share during a rollout; cap the S3 client’s connection pool at 32 or less per container. The workload’s overview shows the link’s runtime next to its database links. See Link capacity and connection pools.

From 2.11.1, storage links run on the shared connector, as database bindings and container links do, with no per-link connector container. A link created before 2.11.1 switches to it after the workload’s Docker daemon is updated, and Opfield recreates the linked workload once right after the switch: a Deployment rolls out blue/green without downtime, a Container restarts once. Links created on 2.11.1 need no recreate. Rolling the Docker daemon back to 2.11.0 switches the links back on its own, again with one recreate per workload.

The workload does not have to run: a link can target a Container or Deployment that is stopped, crash-looping, failed, or not deployed yet, and Opfield saves it without waiting for the workload. Until the workload runs with the link, the link shows as pending (observedState: "target_applied" in the API and MCP); it becomes active when the workload next starts or finishes its current rollout, and retrying a failed Git build deploys it. Through the API, MCP, or the assistant, a Git-source Container can also be linked by name before its first build, which then starts it with the link. A Deployment rollback or slot switch keeps the current links. The workload’s Docker Node must be online.

For advanced nginx configuration, a Route can also use an additional Secure Link binding to ready managed object storage, without a shared Docker network or a published S3 port; clients still need S3 credentials. Managed storage cannot be a Route’s main upstream. Creating the binding requires Route edit access and view access to the storage; see Secure upstreams.

Deleting managed storage erases its data and removes its workload links automatically. It is refused while Route Secure Link bindings or an active copy job refer to it, and backup references are handled as described below.

Opfield-managed storage networks (gateway-storage-*) are hidden from Docker network actions: users cannot connect or disconnect containers, remove these networks, or create containers on them.

A copy job copies objects server-side from one S3 storage to another, managed or external—for example from a legacy MinIO cluster to SeaweedFS, or from an external bucket into managed storage. In 2.11 copy jobs have no Console screen: start them from the built-in assistant, MCP, or the REST API.

  • Modes: copy adds and overwrites objects and never deletes. sync also deletes destination objects that the source does not have; use it only for a deliberate final pass. dryRun writes nothing and reports what differs.
  • Live destinations: a sync into managed storage that workload links or writable access keys still use, and whose writes are not frozen, is refused with STORAGE_COPY_DESTINATION_LIVE because it could delete objects those clients wrote. Freeze the destination’s writes, use copy, or pass allowLiveDestination: true when you accept that risk.
  • Buckets: "all" or a list of names. Each bucket keeps its name on the destination. Missing destination buckets are created when you hold storage:objects:admin on the destination; pass createBuckets: false to require existing buckets. Bucket versioning, lifecycle rules, and bucket policies are not copied.
  • Execution: the backup runner on a Storage Node streams the objects with rclone, preserving object metadata such as content type, and then compares both sides. Opfield picks an online Storage Node whose daemon supports copy jobs, or you choose one with executorNodeId. Private managed storage is reached through per-job Relay routes, so no port is published and no container is recreated. Credentials stay inside Opfield and the executor. Optional limits: timeoutSeconds (default one day, at most seven), cpuCores, memoryMb, and transfers.
  • Check report: a finished job reports, per bucket and in total, object counts and bytes on both sides, the number of missing, differing, and (for sync) extra objects with sample keys, and clean. Only a completed job with clean: true proves the copy; a completed job can still report differences, for example objects written by clients while it ran. Running the same job again transfers only what changed, and swapping source and destination copies back.
  • Limits: one active job may write to a storage, no job may read a storage that another job is writing, and an executor runs at most two copy jobs at a time.
Action REST API MCP and assistant
Start a job POST /api/storage/copy-jobs with sourceStorageId, destinationStorageId, buckets, mode, dryRun, and optional createBuckets, allowLiveDestination, executorNodeId, and limits manage_storage_connection copy_data_start
Follow a job and read its report GET /api/storage/copy-jobs/{id} copy_data_status
List jobs GET /api/storage/copy-jobs copy_data_list
Cancel a job POST /api/storage/copy-jobs/{id}/cancel copy_data_cancel

Copy jobs take storage connection IDs. For managed storage, use its storage connection ID (objectStorageConnectionId in the managed storage details returned by the API and MCP), not the managed storage ID.

A cancelled or timed-out job never leaves a runner container behind, and its final status is saved before it is reported, so it survives a daemon restart right afterwards.

Starting a job needs storage:objects:read and storage:credentials:use on the source, storage:objects:write and storage:credentials:use on the destination, and nodes:backups:execute on the executor Node. Opfield rechecks the job owner’s permissions when it dispatches the job. Starting a job needs a current Personal or higher plan; following, listing, and cancelling jobs keep working after a license grace period ends.

MinIO is no longer distributed by its vendor, so Opfield 2.11 creates new managed storage with SeaweedFS. Managed MinIO clusters created with earlier releases keep running as a legacy engine and are marked Legacy MinIO engine in the Console:

  • They keep serving S3, their access keys, workload links, Secure Link bindings, and any FTP or SFTP listeners, and day-to-day operations continue while the MinIO image is still on the Storage Node.
  • New MinIO clusters cannot be created.
  • An operation that needs to recreate the container and therefore pull the image—for example changing publication, growing the disk, or recovering a lost container—fails with MANAGED_STORAGE_ENGINE_IMAGE_UNAVAILABLE if the image is no longer on the Node, because it can no longer be downloaded. Opfield raises this before touching the container or its data.

There is no migration button. To move a cluster to SeaweedFS, ask the built-in assistant, for example: Migrate managed storage “files” from MinIO to SeaweedFS. The assistant follows Opfield’s migration guide step by step, reports the result of each step, and asks before the cutover and before it retires the MinIO cluster. It acts with your permissions, so you need the scopes listed in Migration actions. An MCP client such as Codex or Claude Code can run the same migration through the same tools.

  1. Preflight (read-only). The assistant checks that the cluster is ready, lists its buckets, used space, access keys, workload links, Secure Links, and backup policies and history, and checks that the target Node has at least 1.2 times the used space free and a current daemon. It stops if the cluster uses FTP or SFTP, which SeaweedFS does not offer.
  2. Build the target. It creates a SeaweedFS cluster, private by default. On request it reuses the MinIO root credentials so that clients using them keep working.
  3. Copy online. A copy job copies every bucket while applications keep writing to MinIO. The report can show differences while clients write, so the copy is repeated until only recent objects differ; each run transfers only what changed.
  4. Cut over. Writes pause for a short window; reads keep working.
    • Move backups first: backup policies that write to the MinIO cluster are moved to the new cluster, or paused if you prefer, and running backup and restore jobs that use it must finish or be cancelled.
    • Freeze writes: every access key and workload-link key that Opfield issued on the MinIO cluster becomes read-only, including keys issued during the freeze. Opfield also stops writing there: uploads, deletes, and bucket changes through the object browser, storage tools, and MCP fail with STORAGE_WRITES_FROZEN, and backups or restores that would write there are refused. The freeze is refused while a backup or restore that uses the cluster is running. The root credentials and copy jobs keep writing, so the copy continues. Keys that Opfield did not issue are listed so that you can stop those clients. The storage detail page shows that writes are paused.
    • Final pass: a sync copy job runs until its report is clean. Nothing is switched over before it is.
    • Import access keys: access keys are recreated on SeaweedFS with the same ID and secret, so their clients change only the endpoint. Expiring keys and IDs that SeaweedFS does not accept are listed for replacement.
    • Move workload links: each link moves to the new cluster with the same key, alias, and environment variables. The workload is not recreated; only its private route changes, and its connector is replaced when the clusters differ in TLS. Every bucket of the link must exist on the new cluster, otherwise the move is refused with MANAGED_STORAGE_BINDING_BUCKETS_MISSING. A failed move is rolled back and the link stays on MinIO; if it cannot be switched back, the link is left on the new cluster, marked failed, and reported.
    • Retarget Secure Links: Route Secure Link bindings switch to the new cluster and keep their ID and name, so Route configurations that use them keep working. If the new cluster does not answer or the Route configuration cannot be applied, the old target is restored.
    • Check backups: one backup of each moved policy is run, and paused policies are turned back on after they are moved.
  5. Verify and retire. After you confirm that applications are healthy, the assistant moves finished backup history to SeaweedFS. Only runs whose files are all found there with their recorded sizes move; the others stay on MinIO and are reported, and must be copied again or forgotten before MinIO can be deleted. The assistant then deletes the MinIO cluster, and a published S3 port can move to the new cluster.

Until MinIO is deleted, the assistant can roll back: freeze the new cluster, copy writes made after the cutover back to MinIO with sync until the report is clean, move links, Secure Links, and backup policies back, and unfreeze MinIO. MinIO access keys created before Opfield attached a policy to each key had the root user’s full access; after a freeze and unfreeze they keep only read and write access to their buckets.

During a migration, never restart, update, or retry the MinIO cluster or change its publication: each recreates its container, and the image may no longer be downloadable. Resource-scoped storage:* grants and folder placement are not copied to the new cluster; grant them again. Bucket versioning, lifecycle rules, and bucket policies are not copied either.

To migrate without the assistant, call the same actions through the REST API or MCP in the order above. Managed storage actions take managed storage IDs; copy jobs take storage connection IDs.

Step REST API MCP and assistant Permission
Copy data POST /api/storage/copy-jobs manage_storage_connection copy_data_start See Copy data between storage
Freeze writes POST /api/managed-storage/{id}/freeze-writes manage_managed_storage freeze_writes storage:iam
Unfreeze writes POST /api/managed-storage/{id}/unfreeze-writes unfreeze_writes storage:iam; also allowed after a license grace period ends
Import access keys POST /api/managed-storage/{targetId}/iam-keys/import with sourceStorageId and optional keyIds import_access_keys storage:iam on both clusters
Move a workload link POST /api/managed-storage/{id}/bindings/{bindingId}/move with targetStorageId move_binding storage:iam on both clusters and the workload permissions needed to create a link
Retarget a Secure Link POST /api/proxy-hosts/{routeId}/additional-secure-links/{bindingId}/retarget with upstreamKind: "managed_storage" and managedStorageId manage_additional_secure_link retarget proxy:edit on the Route and storage:view on the new cluster
Move backup history POST /api/managed-storage/{id}/backup-history/rehome with targetStorageId and optional dryRun rehome_backup_history storage:edit on both clusters

Freezing writes needs a current daemon on the MinIO cluster’s Storage Node; updating the daemon does not recreate the MinIO container. Move or pause backup policies that write to the cluster first: the freeze is refused while a backup or restore that uses the cluster is running, and its result reports policies that still use it. A partial freeze returns an error and leaves the cluster frozen; run it again to apply the remaining keys. Moving backup history is refused while backup runs are active and never changes policies. The actions need a current Personal or higher plan, except unfreezing, so that a freeze can always be lifted. Every action is recorded in the audit log.

Backup policies and active backup runs always block deleting a storage connection or managed storage; delete or move the policies and wait for the runs to finish. When only finished backup history refers to the storage, deletion is refused with STORAGE_BACKUP_HISTORY_EXISTS (409) until you confirm Forget history and delete. Forgetting removes that history from Opfield, so those backups can no longer be restored or deleted from Opfield, and the audit log records where their files are. The files of a storage connection stay in its buckets; the files in managed storage are erased with it.

Through the API, pass backupHistory=forget to DELETE /api/object-storage/{id} or DELETE /api/managed-storage/{id}. The AI Workspace and MCP storage tools accept the same confirmation as config.backupHistory. To delete individual backups together with their files first, use backup history.

Scope Allows
storage:view View storage connections, managed storage, access keys, and links
storage:create Create storage connections and managed storage
storage:edit Change settings, restart, and retry provisioning
storage:delete Delete storage connections and managed storage
storage:credentials:reveal Reveal saved credentials; includes storage:credentials:use
storage:credentials:use Let database backups and copy jobs use saved credentials without revealing them
storage:iam Create, revoke, and import access keys, freeze and unfreeze writes, and create and move workload links
storage:objects:read Browse and download objects and create presigned download links
storage:objects:write Upload, create prefixes, and delete objects
storage:objects:admin Create and delete buckets
storage:folders:manage Organize storage folders

Scopes can be limited to one storage resource or a folder. Database backups need only storage:credentials:use on their destination, not object access. See the scope reference.

  • Storage resources require Personal or higher; enrolling a Storage Node does not. See Plans and entitlements.
  • Storage Nodes run managed databases, managed storage, and backup jobs; generic application containers and builds run on Docker Nodes and Build Workers. See Node roles.
  • Managed storage lives on one host. Keep backups and other important copies outside its failure domain.
  • Keep destination-side encryption, retention, and access policies in the storage system that holds the data.