←Back to Insights
Insights•

On-Premises Content Moderation: Deploy with Docker

C
CautionLabs Team
Core Contributor
server rack
Photo by kewl · CC BY 2.0 · Source

On-premises content moderation means the model runs inside your own network. Your text goes in over HTTP and the result comes back as JSON, and nothing about that request leaves the perimeter you control. CautionLabs ships this as a Docker image you run yourself, licensed per model, with unlimited installs and requests once you own it.

This guide is for backend and platform engineers, and for CTOs, who cannot send user text to a third-party service — health, finance, government, defence, or any team with data-residency or air-gap constraints. It walks through the four documented steps in order, shows the local request and response, and covers GPU-cloud and air-gapped deployments. If you have not decided yet whether to self-host, the hosted path is described in the content moderation API quickstart, and the trade-off is summarised near the end of this article.

Why Teams Run Content Moderation On Their Own Infrastructure

There are two structural reasons to self-host rather than call a hosted endpoint: where the data is allowed to go, and what you pay per request.

When a hosted API is not an option

Data-residency rules, privacy commitments and air-gapped networks all point the same way. If your corpus is regulated, if contractual terms forbid sending user text to a third party, or if the network has no route to the public internet at all, a hosted endpoint is off the table regardless of how good it is. In those environments the moderation model has to be a component you deploy, version and operate like the rest of your stack.

No outbound requests, no telemetry

The model container makes no outbound requests and has no telemetry. That property is what makes an air-gapped install possible: the image can be pulled and run in a network with no egress, because there is nothing for it to call home to. It also means there is no per-request network hop, no third-party retention question, and no external dependency in your request path.

The commercial difference is equally concrete. The hosted API is usage-based, while an on-premises licence is a one-time payment per model with unlimited installs and requests. Once you own the model, request volume stops being a line item.

What You Get: Argus 1 and the Local On-Premises Content Moderation Endpoint

Argus 1 is the first on-premises text moderation model, with model id argus_1. It runs as a container that exposes an HTTP API on your own network. The default address is http://localhost:8000, and the endpoint you call is POST /moderate.

The same twelve boolean categories

The response returns a categories object containing a true/false flag for each of twelve categories — toxic, profanity, hate, harassment, self_harm, adult, violence, drugs, weapons, pii, spam and minor — plus an overall flagged boolean that is true when any category is flagged.

There are no scores, probabilities or confidence values returned, and there are no thresholds to tune. The decision is the flag. This is deliberate: you are not calibrating a cut-off, you are reading a verdict.

JSON in, JSON out

The request body is JSON with a single text field. The response is JSON. There is no batch endpoint and the API sends no webhooks, so the integration pattern is one request per text, with your own code deciding what to do with the result.

The response shape matches the hosted cloud API, so client code that already parses a cloud moderation response can be pointed at the local endpoint and reused. That matters if you run a hybrid setup or if you migrate in either direction later.

Prerequisites Before You Deploy

Three things are required before the container will run:

  1. A purchased on-premises model licence.
  2. A private key created in the dashboard.
  3. Docker on the host.

Do not guess at hardware or OS specifications. The documented requirements — including what the model needs to run — live in the on-premises guide. Read that page before you size anything, because hardware sizing is not covered here and should not be inferred from general GPU rules of thumb.

Step 1: Buy a Model

On-premises licensing is a one-time payment of $299 USD per model. The first model is Argus 1, our text moderation model (argus_1).

The licence includes:

  • Unlimited installs of that model.
  • Unlimited requests against that model.
  • Upgrades to that model.

Licensing is per model, not per host and not per request, which is why the same purchase works for a single developer laptop, a staging cluster and a production fleet. The pricing page has the current figures, and the on-premises software licence sets out the terms. Note the distribution restriction: the software and its API keys may not be distributed. Unlimited installs is not the same as redistribution.

Step 2: Create a Private Key in the Dashboard

The private key is created from the dashboard and is used as the registry password in the next step. The registry checks the licence on every download, which is how the key stays tied to the model you bought.

One important caveat about key types: a private (on-premises) key does not work with the cloud API. The hosted API accepts Cloud Keys. If you send a private key to the cloud endpoint it is the wrong key type, and the cloud API rejects it accordingly. Keep the two kinds of key separate in your secret stores and in your CI configuration; mixing them up is a common first-day error.

Step 3: Log In to the Registry and Run the Image

docker login registery.cautionlabs.com

Authenticate against the CautionLabs registry with your private key as the password:

Shell
docker login registery.cautionlabs.com
# when prompted, supply your private key as the password

The registry validates the licence on every download, so the login is not a one-off ceremony you can skip on a fresh machine. Bake it into your deployment pipeline, and store the private key the same way you store any other production credential.

Running the container

The exact docker run invocation — image reference, flags and port mapping — is documented in the on-premises guide. Follow it as written rather than reconstructing it, since the guide is the source of truth for the supported command. The endpoint listens on port 8000 by default, so once the container is up you should be able to reach http://localhost:8000 from the host.

If you are deploying to more than one machine, note that the same private key is used as the registry password on each host. That is expected: installs are unlimited under the licence.

Step 4: Call POST /moderate on Your Own Network

With the container running, send {"text": "..."} to POST /moderate at the default http://localhost:8000.

Request example

Shell
curl -X POST http://localhost:8000/moderate \
  -H "Content-Type: application/json" \
  -d '{"text": "I will find you and make you regret posting that."}'

Response example

JSON
{
  "categories": {
    "toxic": true,
    "profanity": false,
    "hate": false,
    "harassment": true,
    "self_harm": false,
    "adult": false,
    "violence": true,
    "drugs": false,
    "weapons": false,
    "pii": false,
    "spam": false,
    "minor": false
  },
  "flagged": true
}

Every field is a boolean. flagged is true when any category is true. There is nothing to threshold and nothing to post-process unless your own policy maps specific categories to specific actions — for example, blocking on minor or self_harm while routing profanity to a softer queue.

Because the response shape matches the cloud API, a client that already consumes the hosted POST /moderation response can be reused against the local endpoint. In JavaScript that is the same parsing code with a different base URL:

JavaScript
const res = await fetch("http://localhost:8000/moderate", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ text: userText }),
});

const result = await res.json();
if (result.flagged) {
  // apply your own policy using result.categories
}

Deploying on GPU Clouds and Air-Gapped Networks

RunPod and other GPU clouds

Running the model on a GPU cloud such as RunPod follows the same pattern as a local install. You pull from registery.cautionlabs.com using the private key as the registry password, then run the image. The only difference from a laptop install is the host.

The registry licence check still applies on every download, so the credential has to be available to the cloud instance at pull time. Treat it as a deployment secret, not an image layer.

Air-gapped installs

Air-gapped installs are supported because the container makes no outbound requests and has no telemetry. There is no phone-home step to break when there is no route to the internet, and no licence callback that has to succeed in the request path. The registry check happens at download time; once the image is on the host, the model runs locally.

For environments where even the pull must happen from a mirror, work through the documented procedure in the on-premises guide rather than improvising. Do not assume anything about internal behaviour beyond what is documented: the container makes no outbound requests and has no telemetry, and that is the relevant fact for an air-gapped design review.

Upgrading and Handling Errors

Upgrades to the model you own are included in the licence. When a new version of Argus 1 is available, you pull it through the same authenticated registry. The licence check applies to each download, so the same private key and login flow are used.

For error handling, use the documented errors section of the on-premises guide rather than assuming the local container mirrors the hosted error set. Do not build retry logic against codes you have not confirmed; read the section, then wire your handler to what is actually documented.

One thing worth designing for regardless: there is no batch endpoint and no webhooks, so callers are responsible for concurrency, retries and any queueing. Because requests run on your own hardware, that is a capacity decision you control rather than a rate limit imposed by someone else.

On-Premises vs the Cloud API: Choosing a Path

The two paths are priced differently because they solve different problems.

  • Cloud API: usage-based at $0.40 USD per 1,000 requests. A request covers up to 3,000 characters, and texts of up to 10,000 characters are checked in 3,000-character pieces, one request each.
  • On-premises: a one-time payment of $299 USD per model, with unlimited installs and requests and upgrades to that model included.

Both return the same boolean flags and the same response shape. Keys are not interchangeable: a private (on-premises) key does not work with the cloud API, which accepts Cloud Keys. If you are weighing the hosted route, the add text moderation to your app guide covers the integration end to end, and the cloud API terms describe how text is handled there.

The decision usually comes down to two questions. Is the text allowed to leave your network at all? If the answer is no, the choice is made. If it is yes, then volume and predictability decide it — usage-based billing scales with traffic, while a per-model licence has a fixed cost and unlimited requests.

Either way, plan for the same constraint: no batch endpoint and no webhooks. Both APIs are request-and-response, and both expect your application to drive the loop.

FAQ

What does unlimited installs and requests actually cover? It covers installs of the model you bought, requests against that model, and upgrades to that model. It does not change the distribution rule: the software and its API keys may not be distributed.

Can I use my on-premises private key against the cloud API? No. A private (on-premises) key does not work with the cloud API. The hosted API accepts Cloud Keys. Keep the two key types separate in your secret management.

Does the container phone home or send telemetry? No. The model container makes no outbound requests and has no telemetry. The licence check happens against the registry at download time, which is why air-gapped installs are supported.

How does per-model licensing and upgrading work? Licensing is per model — the first is Argus 1 (argus_1). Upgrades to that model are included in the one-time payment, and you pull new versions through the same authenticated registry, where the licence is checked on every download.

How does POST /moderate differ from the hosted POST /moderation endpoint? The local POST /moderate runs on your own network, default http://localhost:8000, and returns the same response shape as the hosted POST /moderation on https://api.cautionlabs.com. The difference is where the model runs and how it is paid for — and which key type is accepted.

Next Step

Read the on-premises guide to check requirements and run your first local moderation request, and compare licence terms on the pricing page. If you want the exact wording on what you can do with the software and its keys, the on-premises software licence is the document to read before you deploy.

Want more insights?

Stay updated with the latest in moderation and platform safety.

Back to Overview