Skip to main content
This page is the destination of a short arc. If you want the reasoning behind the design, read the background first:
  1. Filesystems From First Principles — a filesystem is a metadata index over a pile of data blocks.
  2. Network Filesystems: From NFS to GFS — why bolting a network onto a disk-owning server is brittle, and how GFS, HDFS, and MooseFS split an authoritative metadata service from a scalable pool of data storage.
CloudFS is where that arc lands: a POSIX filesystem you mount on any host or container, backed by Telnyx Cloud Storage.

How CloudFS Does It

CloudFS is built on JuiceFS, which — in its authors’ words — was “inspired by Google File System, HDFS and MooseFS.” JuiceFS takes the metadata/data split those systems proved at cluster scale and replaces each half with a managed cloud primitive, so you operate neither a metadata master nor a fleet of data servers:
  • The metadata index — the master’s job in GFS, the NameNode’s in HDFS — becomes a transactional database. The database provides strong consistency for the small, hot, correctness-critical half: an entry is committed or it is not, and every client reads the same tree. This is the direct answer to NFS’s stale-attribute cache and AFS’s callback bookkeeping — put the index in one consistent place that all clients share, rather than caching copies and trying to keep them in sync. It also inherits the database’s transactions: the crash-consistency machinery a local filesystem hand-builds as journaling — write-ahead log, commit, replay — is simply what the database already does, so a metadata change is one atomic transaction with no partial-update window and no fsck-style recovery scan.
  • The data blocks — the chunkservers’ job — become object storage (Telnyx Cloud Storage). JuiceFS splits every file into a chunk → slice → block hierarchy and writes the blocks as ordinary objects; object storage supplies the durability and throughput for the large half. The blocks are opaque — you cannot reassemble a file from the bucket alone, because the index that orders them lives in the metadata database. Object storage also rewards writing new immutable objects over rewriting in place, so JuiceFS follows a log-structured discipline: each write becomes a new slice, never an overwrite, and a background compaction later merges overlapping slices and reclaims the garbage — exactly the cleaner a log-structured filesystem runs.
  • There is no CloudFS server in the data path. JuiceFS is a “rich client”: like AFS’s client and MooseFS’s FUSE mount, all the filesystem logic — the directory tree, inode allocation, splitting files into blocks, caching — runs in the process that mounts the volume. But instead of caching whole files and chasing callbacks, it reads and writes the shared metadata database directly, so consistency comes from the database rather than from a promise a server has to remember. When you juicefs mount, the client opens one connection to the metadata database and one to object storage, and serves POSIX calls from those two.
CloudFS is Telnyx’s managed packaging of JuiceFS Community Edition (Apache-2.0): Telnyx runs and authenticates both the metadata database and the object storage and hands you a formatted, ready-to-mount filesystem. Because JuiceFS Community Edition is a client library with no server process, there is no JuiceFS component running on the Telnyx side at all. The server side is a generic managed metadata database and object storage; every line of filesystem logic runs in the open-source JuiceFS client you mount — which you can read, pin a version of, and run yourself. CloudFS is that community client plus managed backends and a control-plane API, not a proprietary server tier. For the storage format in depth, see JuiceFS’s own architecture documentation, including its how JuiceFS stores files section.

The Two Lanes

Concretely, a CloudFS mount talks to two backends over two independent lanes, each with its own credential. There is no CloudFS server in the request path — your client connects to both directly. CloudFS two-lane architecture: the JuiceFS client on your host talks to a managed metadata lane and a Telnyx Cloud Storage data lane; no JuiceFS component runs server-side.

The Metadata Lane

The client reaches metadata over the connection string CloudFS gives you as meta_url:
A few things are load-bearing here:
  • You connect to a managed metadata endpoint, not to the database directly. The public host us-east-1.telnyxcloudfs.com:5432 is a pooled front end to a per-filesystem metadata database (fs_<hex>). The database server itself is not directly reachable.
  • TLS is required. The connection uses sslmode=require; there is no plaintext metadata path.
  • The meta_token is the password. In the meta_url above, the cloudfs_tok_... embedded before the @ is the meta_token used as the connection password. It is a managed, rotatable credential (see The Metadata Token Lifecycle) — not the underlying database’s own credential, which you never handle.
Metadata is centralized in us-east-1 for every filesystem, no matter which data region you pick. A us-central-1 or us-west-1 filesystem still has its metadata host set to us-east-1.telnyxcloudfs.com. Always use the host embedded in meta_url.
Because metadata lives only in us-east-1, a client mounting from another region pays a network round-trip on every metadata operation, so metadata-heavy work (listing large trees, many small files) is slower the farther you mount from us-east-1. Data throughput is unaffected — that lane goes to your region’s storage endpoint.

The Data Lane

File contents go to a per-filesystem bucket named cloudfs-fs-<hex> on Telnyx Cloud Storage, reached through the S3 endpoint for the filesystem’s region (s3_endpoint, e.g. https://us-east-1.telnyxcloudstorage.com). JuiceFS splits every file into 4 MiB block objects and writes them under chunks/… in that bucket; a 10 MiB file plus a small git repo, for example, lands as dozens of block objects. The blocks are opaque to S3 — reconstructing a file requires the chunk/slice index from the metadata lane.
That bucket lives in your own Telnyx Cloud Storage account — it shows up in your bucket list and is reachable with your TELNYX_API_KEY, exactly like any other bucket you own. But its contents are CloudFS’s internal state, not your files: the chunks/… objects are opaque 4 MiB JuiceFS blocks, and a small juicefs_uuid object holds the volume format. Do not delete, rename, move, or edit objects in a cloudfs-fs-* bucket by hand. An out-of-band change corrupts the filesystem — a missing or altered block cannot be reconstructed, and there is no fsck to repair it. Read and write your files through the mount, and leave the bucket to JuiceFS.
Authentication to the data lane reuses your account credentials, following the Telnyx Cloud Storage model:
  • The S3 access-key is your TELNYX_API_KEY.
  • The S3 secret-key is ignored — Telnyx Storage does not verify the SigV4 signature (see Cloud Storage authentication). You must still supply some non-empty secret, because JuiceFS’s AWS SDK rejects empty static credentials.
CloudFS pre-formats the bucket at create time: provisioning writes a juicefs_uuid object and formats the volume (JuiceFS volume name cloudfs-fs-<hex>). Do not run juicefs format against a ready filesystem — it is already formatted, and re-formatting fails with cannot update volume name. Just mount. The one exception is a filesystem whose status is needs_format, which was provisioned without the final format step: format it once as described in Mounting, then mount.

Two Credentials, One API Key

Putting the lanes together, a mounting client holds exactly what it needs and nothing more: The point of splitting the credentials this way is that the client never holds a raw database credential. It talks to the metadata endpoint with a managed meta_token that Telnyx can rotate independently of the underlying metadata database, and it never connects to the database server directly. Your API key, meanwhile, only ever reaches object storage. Compromising a mount host exposes a rotatable metadata token and your (already-scoped) API key — not standing database credentials.
Create and rotate are the only responses that return the meta_token (and the token-bearing meta_url). GET detail returns meta_url without the token, and list returns neither. Store the token when you create the filesystem — there is no way to read it back.

Regions

You choose a data region at create time: us-central-1, us-east-1, or us-west-1. That region is required — there is no default — and it determines the S3 endpoint (s3_endpoint) and where the file blocks physically live. It is the only region choice you make. Metadata is always in us-east-1. Picking us-west-1 for data does not move the metadata database; that filesystem’s metadata host is still us-east-1.telnyxcloudfs.com. Mount as close to us-east-1 as your data region allows if metadata latency matters to your workload.

The Metadata Token Lifecycle

The meta_token is the one credential in the system designed to be rolled. Rotation is a control-plane action: POST /v2/storage/cloudfs/{id}/actions/rotate-meta-token (Idempotency-Key required) issues a new meta_token and returns a new token-bearing meta_url. Rotation touches only the token — the metadata database and the S3 bucket are unchanged, so no data moves and no files are re-encrypted or re-keyed. The cutover is connection-scoped, which makes rotation safe to run against a live filesystem:
  • The old token stops authenticating on the next metadata connection — any new juicefs mount (or reconnect) must use the new meta_url.
  • An already-mounted client is unaffected on its existing connection. It keeps working with the connection it opened before rotation; you only need the new token the next time it reconnects.
So the operational rule is: rotate, then update wherever the old meta_url is stored (secrets, deploy config) before your mounts next reconnect.

Filesystem Status

Each filesystem carries a status: The steady states are ready, needs_format, and failed; provisioning and deleting are transitional. There is no soft-delete or trash lifecycle — deleted is terminal and permanent.

Further Reading

Next Steps