Skip to content

Deploy Shield360

Shield360 runs two ways:

A self-hosted deployment has three components:

  1. The Shield360 platform: the UI and APIs, collector ingest, the CLI downloads served to enrolling machines, and a bundled OpenTelemetry Collector
  2. PostgreSQL for users, organizations, projects and settings
  3. ClickHouse for telemetry and collector data

The repository’s docker-compose.yml runs the whole platform on one host:

ServiceImageHolds
postgrespostgres:17-alpineUsers, organizations, projects and settings
clickhouseclickhouse/clickhouse-server:24.4.1Telemetry and collector data
shield360Built from src/DockerfileThe UI and API, scheduled jobs, the OpAMP server and the bundled OpenTelemetry Collector

The compose file runs the open edition (SHIELD360_EDITION=oss). Shield360 manages its own users and roles, so it needs no external identity service. Telemetry about Shield360 itself is off (TELEMETRY_ENABLED=false).

  • Docker Engine 24 or later with the Compose v2 plugin (docker compose version)
  • 4 CPU cores and 8 GB of memory for the host. Building the platform image needs most of that memory.
  • 40 GB of free disk: about 20 GB for the image build and the rest for data. ClickHouse keeps telemetry for 30 days by default.
  • openssl to generate secrets
  • Free host port 3000 for the UI and API. ClickHouse (9000, 8123) and the collector’s raw OTLP ports (4317, 4318) are published on 127.0.0.1 only.
Get the Shield360 distribution

Once your access is set up (see the note above), get the distribution the way your access email describes, and open its folder:

Terminal window
cd shield360

For a licensed deployment without building anything, use the self-hosted image instead: it carries the same compose bundle.

Create the .env file

Copy the example, then replace every CHANGE_ME with its own random value:

Terminal window
cp .env.selfhost.example .env
chmod 600 .env
openssl rand -hex 32 # run once for each CHANGE_ME
VariablePurpose
POSTGRES_PASSWORDPostgreSQL password. Use a hex value: it is placed in a connection URL.
SHIELD360_DB_PASSWORDClickHouse password.
NEXTAUTH_SECRETSigns sessions. Changing it signs everyone out.
CRON_JOB_SECRETAuthenticates the platform’s scheduled jobs.
SHIELD360_VAULT_ENCRYPTION_KEYEncrypts stored credentials. If you lose it, the credentials cannot be decrypted.

docker compose refuses to start while any of these is missing. Keep .env out of version control, and back it up with your data.

Then name the first administrator, so the account exists before anyone else can reach the server:

VariablePurpose
SHIELD360_ADMIN_EMAILEmail address of the first administrator.
SHIELD360_ADMIN_PASSWORDTheir password: at least 12 characters, and not a well-known password.

Both are optional. If you leave them unset, the first account registered at /register becomes the administrator instead.

Build and start the stack
Terminal window
docker compose up -d --build

The first build takes 10 to 20 minutes. It compiles the platform, the collector and the shield360 CLI for every platform. To use a platform image you have already built or mirrored, set SHIELD360_IMAGE in .env and run docker compose up -d --no-build.

Wait for it to become healthy
Terminal window
docker compose ps
docker compose logs shield360 | grep -iE "migration|seeding"

On every start, the platform container applies PostgreSQL migrations and runs the seed. It then brings ClickHouse up to date and starts serving. If SHIELD360_ADMIN_PASSWORD is too short or well known, the seed stops the container and logs the reason; docker compose logs shield360 shows it. The shield360 service is healthy when http://127.0.0.1:3000/login answers.

The platform image carries the shield360 CLI for macOS, Linux and Windows. Machines enrolling against your deployment download it from /api/cli/download/*, with install scripts at /api/cli/install.sh and /api/cli/install.ps1. /api/cli/install-cli.sh and /api/cli/install-cli.ps1 install the CLI alone, without an install key or enrolment, and check it against the sha256 the server publishes at /api/cli/targets. See Deploy the collector.

SDKs and enrolled machines send telemetry to the platform’s authenticated OTLP routes on port 3000. The bundled collector’s raw receivers on 4317 and 4318 write to ClickHouse without authentication. They are bound to 127.0.0.1; set OTLP_BIND_ADDRESS only if you need them on a network you trust.

No account ships with Shield360. The first administrator owns the Default Organization and its Default Project, and comes from one of two places:

  • SHIELD360_ADMIN_EMAIL and SHIELD360_ADMIN_PASSWORD. On the first start, the seed creates this account when there are no users yet. Sign in at http://127.0.0.1:3000/login with those details.
  • The first registration. If those variables are unset, open http://127.0.0.1:3000/register and create an account. While there are no users, the page says so, and that account becomes the administrator.

Once an account exists, the seed never changes its password, even if SHIELD360_ADMIN_PASSWORD changes. Change it under Settings → Profile. You can also remove both variables from .env after the first start.

After that, registration is by invitation. Invite people from Settings → Team, choosing the role each one joins with (the organization’s default role unless you pick another; only an owner can invite an owner). Each person then registers at /register with the invited email address and joins with that role. You can change anyone’s role later on the same page. The server refuses a registration without an invitation, and so does Google or GitHub sign-in for an email it does not know.

SHIELD360_OPEN_REGISTRATION=true lets anyone who can reach the server create an account, as earlier versions did. This is not recommended.

To sign in through Google or GitHub, set the matching *_CLIENT_ID and *_CLIENT_SECRET in .env. Also set NEXTAUTH_URL to the public URL that the provider calls back to.

Update the distribution to the release you are moving to, then rebuild and restart:

Terminal window
docker compose build shield360
docker compose up -d

If you run a published or mirrored image, change SHIELD360_IMAGE in .env, then run docker compose pull shield360 && docker compose up -d --no-build. Migrations run automatically when the new container starts. Take a backup before every upgrade.

Earlier versions created a default account with a published password on every install. Upgrading keeps that account, but each start logs a warning while it still has that password. Sign in and change the password under Settings → Profile, or remove the account once another administrator exists.

Back up three things: PostgreSQL, ClickHouse and your .env file.

Back up PostgreSQL as a compressed custom-format dump:

Terminal window
docker compose exec -T postgres sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' \
> shield360-postgres-$(date +%F).dump

To restore it, stop the platform first:

Terminal window
docker compose stop shield360
docker compose exec -T postgres sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists' \
< shield360-postgres-YYYY-MM-DD.dump
docker compose start shield360

Back up ClickHouse with its native BACKUP command. First allow a backup directory once, then restart ClickHouse:

Terminal window
docker compose exec clickhouse sh -c 'mkdir -p /var/lib/clickhouse/backups && printf "%s\n" \
"<clickhouse><backups><allowed_disk>default</allowed_disk><allowed_path>/var/lib/clickhouse/backups/</allowed_path></backups></clickhouse>" \
> /etc/clickhouse-server/config.d/backups.xml'
docker compose restart clickhouse

Then take the backup and copy it off the host:

Terminal window
STAMP=$(date +%F)
docker compose exec clickhouse sh -c "clickhouse-client --user \"\$CLICKHOUSE_USER\" --password \"\$CLICKHOUSE_PASSWORD\" \
--query \"BACKUP DATABASE \$CLICKHOUSE_DATABASE TO File('/var/lib/clickhouse/backups/shield360-$STAMP.zip')\""
docker compose cp clickhouse:/var/lib/clickhouse/backups/shield360-$STAMP.zip .

The backups.xml file lives in the container, so write it again whenever the container is recreated. To restore, copy the file back into that directory and run RESTORE DATABASE shield360 FROM File('/var/lib/clickhouse/backups/<file>.zip').

docker compose down keeps all data. docker compose down -v deletes the postgres-data, clickhouse-data and shield360-data volumes. Run it only when you mean to start from nothing.

Shield360 needs no outbound network access at runtime:

  • The compose file turns off telemetry about Shield360 itself.
  • The image disables Next.js and Prisma telemetry and includes the Prisma engines.
  • The image serves the CLI binaries that enrolling machines download.

To install without internet access, build or pull the images on a connected machine, then carry them across:

Terminal window
# On a connected machine, from the Shield360 checkout
docker compose build shield360
docker pull postgres:17-alpine
docker pull clickhouse/clickhouse-server:24.4.1
docker save shield360:local postgres:17-alpine clickhouse/clickhouse-server:24.4.1 | gzip > shield360-images.tar.gz
# On the air-gapped host, with the same checkout and your .env
gunzip -c shield360-images.tar.gz | docker load
docker compose up -d --no-build

If you use an internal registry, push the three images to it and set SHIELD360_IMAGE to the platform image. Also point the postgres and clickhouse image: lines in the compose file at your mirror.

Features that call a model provider, such as LLM-as-a-judge evaluations and the chat assistant, need a provider the host can reach. That can be a model endpoint inside your network.

For production Kubernetes deployments, contact hello@shield360.ai for manifests and sizing guidance.

Should I use managed or self-hosted Shield360?

Managed is the quickest start. Self-host when collector data, prompts and telemetry must stay inside your own infrastructure; every feature in this documentation runs self-hosted.

Can I reuse my existing ClickHouse or OpenTelemetry Collector?

Yes. Shield360 can connect to infrastructure you already run instead of deploying its own ClickHouse or OTel Collector. See Connect Multiple Databases for setup.

Do enrolled machines need to reach the internet?

No. Machines download the CLI from, enrol with and report to your Shield360 deployment only.