nano SIEM
Reference

Deployment Architecture

How nano deploys across tiers, from single-node Docker Compose to multi-pool Kubernetes with ClickHouse Cloud

Deployment Architecture

nano scales from a single VPS to a multi-pool Kubernetes cluster depending on your tier. This page covers what gets deployed at each level and how the services fit together.

Architecture Overview

Every nano deployment runs the same core services. What changes across tiers is how many replicas run, how storage is managed, and whether databases run in-cluster or as managed services.

Tiers

TierGB/DayEPSReplicasHACloud Providers
Hobby2301NoHetzner
Startup5751NoHetzner
Growth101551NoHetzner
Team253852YesCivo, Vultr, GCP, AWS
Business507702YesCivo, Vultr, GCP, AWS
Pro1001,5503YesGCP, AWS
EnterpriseCustomUnlimited4YesGCP, AWS

Hobby & Startup: Docker Compose

The smallest tiers run as a single-node Docker Compose deployment on a Hetzner VPS. All services share one machine, with no Kubernetes overhead.

HobbyStartup
Machine2 CPU / 8 GB4 CPU / 16 GB
Storage50 GB50 GB
ClickHouseSingle node, no replicationSingle node, no replication
PostgreSQLSingle instanceSingle instance
Replicas1 of everything1 of everything
Retention365+ days, FIFO365+ days, FIFO

Growth: Single-Pool Kubernetes

Growth moves to Kubernetes but keeps everything in one node pool. ClickHouse runs via the ClickHouse Operator, PostgreSQL via CloudNativePG.

AspectGrowth
Nodes1 x 4 CPU / 8 GB
ClickHouseOperator-managed, 1 shard x 2 replicas
PostgreSQLCNPG, 1 instance
Keeper3-node quorum (lightweight)
App replicas1 (API, Search, Web, Vector)
Storage100 GB hot
Retention365+ days, FIFO
ProvidersHetzner

Team & Business: HA Kubernetes

Team and Business add high availability: multiple replicas, database replication, and failover.

TeamBusiness
Nodes3 x 4 CPU / 8 GB3 x 4 CPU / 8 GB
App replicas22
ClickHouse1 shard x 2 replicas1 shard x 2 replicas
PostgreSQL2 instances (primary + replica)2 instances (primary + replica)
Storage120 GB hot300 GB hot
Object storageWasabi S3Wasabi S3
Retention365 days365 days
ProvidersCivo, Vultr, GCP, AWSCivo, Vultr, GCP, AWS

Pro: Multi-Pool Kubernetes

Pro separates workloads into dedicated node pools: stateless app services on spot instances, ClickHouse on dedicated on-demand nodes, and Vector on its own spot pool.

PoolNodesMachineSchedulingPurpose
App32 CPU / 8 GBSpotAPI, Search, Frontend, Prometheus
ClickHouse44 CPU / 16 GBOn-demandClickHouse (2 shards x 2 replicas)
Vector32 CPU / 8 GBSpotLog ingestion and parsing
AspectPro
App replicas3 (API, Search, Web)
ClickHouse2 shards x 2 replicas (4 pods)
PostgreSQL3 instances (primary + 2 replicas)
Storage1 TB hot (250 GB per CH pod)
Object storageWasabi S3
Retention365 days
ProvidersGCP, AWS

Enterprise: Managed Databases

Enterprise removes databases from the Kubernetes cluster entirely. ClickHouse runs on ClickHouse Cloud, PostgreSQL on Cloud SQL (GCP) or RDS (AWS). The K8s cluster only runs application services and Vector.

VolumeApp PoolVector Pool
Up to 100 GB/day3 x 4 CPU / 16 GB3 x 4 CPU / 16 GB
100 GB - 1 TB/day3 x 4 CPU / 16 GB4 x 8 CPU / 32 GB
1-10 TB/day3 x 8 CPU / 32 GB6 x 16 CPU / 64 GB
10-50+ TB/day6 x 8 CPU / 32 GB12+ x 16 CPU / 64 GB
  • ClickHouse Cloud handles storage, replication, and scaling, with no local disk management
  • PrivateLink connects the K8s cluster to ClickHouse Cloud for network isolation
  • 4 replicas of all application services (API, Search, Frontend)
  • Providers: GCP, AWS only

Services

API Service

All replicas serve HTTP requests simultaneously behind the load balancer. A PostgreSQL advisory lock elects one replica as the scheduler leader. Only the leader runs background tasks:

  • Detection rule execution (cron-based scheduled queries)
  • Signal processing (materialized view alerts)
  • Enrichment auto-sync (IPinfo, threat feeds)
  • Auto-tuning (baseline collection, threshold detection)

If the leader pod dies, another replica acquires the lock within ~15 seconds. HTTP serving is uninterrupted.

Search Service (Active/Active)

The Search service is stateless: all replicas serve queries simultaneously behind the load balancer. Query state, results, and search history are stored in ClickHouse and PostgreSQL, so any replica can handle any request.

On HA tiers (Team+), multiple Search replicas run with pod anti-affinity to spread across nodes. If a pod dies, the remaining replicas continue serving traffic with no interruption.

Search connects to a dedicated clickhouse-search service. On larger tiers a companion clickhouse-search-preferred service targets a specific ClickHouse replica, so read queries can be kept off the replica Vector writes to and heavy searches do not compete with ingestion on the same node. That preference is never a requirement: clickhouse-search itself always targets every replica, so if the preferred replica's availability zone is lost, search continues against the surviving replica rather than failing.

Vector (Log Ingestion)

Vector accepts logs on multiple protocols:

PortProtocolAuthUse Case
8080HTTPBearer tokenPrimary ingestion: applications, webhooks, log shippers
8088HECHEC tokenSplunk HTTP Event Collector compatible forwarders
6000Vector nativemTLS (client certs)On-prem Vector aggregators

Vector is stateless and spot-tolerant. On HA tiers, multiple replicas run with pod anti-affinity to spread across nodes.

ClickHouse

ClickHouse handles all log storage and query execution. Configuration varies by tier:

TierTopologyKeeperStorage
Hobby/StartupSingle nodeNoneLocal disk
Growth1 shard x 2 replicas3-node quorumLocal disk
Team/Business1 shard x 2 replicas3-node quorumLocal + Wasabi S3
Pro2 shards x 2 replicas3-node quorumLocal + Wasabi S3
EnterpriseClickHouse CloudManagedManaged

On Team+ tiers, older data is automatically moved to object storage (Wasabi S3 or your own S3/GCS bucket) while remaining fully searchable. There's no meaningful difference in query speed.

ClickHouse compresses data at roughly 8-10x, so 100 GB/day of raw logs uses approximately 10-12 GB/day of storage.

PostgreSQL

PostgreSQL stores metadata: rules, alerts, users, dashboards, credentials, and search history. Deployed via the CloudNativePG operator with streaming replication and automatic failover.

TierInstancesHA
Hobby/Startup1No
Growth1No
Team/Business2 (primary + replica)Yes
Pro3 (primary + 2 replicas)Yes
EnterpriseCloud SQL / RDSManaged

Deployment Modes

ModeDescription
Managednano provisions and manages the infrastructure on supported cloud providers
BYOC (Bring Your Own Cloud)nano deploys into your cloud account using your credentials

Both modes use the same architecture. Managed deployments handle provisioning, upgrades, and monitoring automatically. BYOC gives you full control over the cloud account and network configuration.

Data Durability and Retention

nano protects log data with replication and retention rather than point-in-time backup. This is the standard model for log platforms — Splunk, Microsoft Sentinel, Google SecOps, Sumo Logic and Datadog all work this way — and it follows from what log data is: append-only, high-volume, deliberately expired on a schedule, and still present at the sources that produced it. Metadata is small and transactional, so it is backed up conventionally.

The two are covered separately below, because their guarantees genuinely differ.

Log data (ClickHouse)

Every part is stored more than once on every tier that offers HA:

TierCopies of each partSpread across
Hobby, Startup1Single node — no replication
Growth, Team, Business2 (1 shard x 2 replicas)Separate nodes
Pro2 per shard (2 shards x 2 replicas)Separate nodes
Enterprise on AWS2 per shardSeparate availability zones
Enterprise on ClickHouse CloudManaged by ClickHouse CloudManaged

On Enterprise AWS the two replicas of a shard are placed in different AZs by a required topology constraint, and ClickHouse Keeper runs a 3-node quorum spread one per AZ, so losing an availability zone costs neither data nor quorum. On other providers and tiers replicas are spread one-per-node rather than one-per-AZ.

What replication protects against: losing a node, a disk, a volume, or — on Enterprise AWS — an entire availability zone. A replica that dies is rebuilt automatically from its peer, and queries continue against the surviving one throughout.

What replication does not protect against: anything that acts on the data logically. A DROP TABLE, an ALTER DELETE, or a bad schema migration is a replicated operation — it is applied to every copy, because applying operations to every copy is precisely what replication is. Both replicas are the same dataset, not two independent ones. There is no snapshot of a previous state to roll back to.

Retention is by tier — 365 days on Team and above, 365+ days FIFO on the single-node tiers — and is enforced by a DELETE TTL on the table. Expiry is the only mechanism that routinely removes data, and it applies regardless of which volume a part has moved to.

Recovery from logical destruction is re-ingestion from your own sources. This is the industry's real recovery path for log data and the one nano is designed around: the devices, cloud accounts, and applications that generated the events are the system of record, and most of them retain their own copy for some period. Where an event's only copy is the one in nano, treat the retention window as the exposure and keep an independent archive of anything you cannot afford to re-collect — the on-premise collection tier can fan out to a second destination for exactly this purpose.

nano does not offer point-in-time restore of log data, and no automated backup of the ClickHouse dataset is taken. Where a contract requires one, scheduled ClickHouse BACKUP to a dedicated bucket is available as a paid add-on scoped per engagement — talk to us before signing.

Cold-tier immutability

The object-storage tier is versioned. Overwritten and deleted objects remain recoverable for 30 days, and a lifecycle rule expires them after that so storage stays bounded.

This is a deliberate defence against a compromised deployment: the credential the ClickHouse pods hold can delete objects, but on a versioned bucket a delete writes a marker and leaves the data intact behind it. Permanently destroying a version requires s3:DeleteObjectVersion, and disabling versioning requires s3:PutBucketVersioning — neither of which is granted to anything running inside the deployment. An attacker who takes over the cluster can therefore hide aged data, reversibly, but not destroy it.

The hot tier has no equivalent protection; this covers data that has already aged out.

Metadata (PostgreSQL)

PostgreSQL holds rules, alerts, users, dashboards, credentials, and search history — not log events. It is backed up conventionally, because it is small enough for that to be cheap:

DeploymentBackupRetention
Kubernetes tiers (in-cluster PostgreSQL)Daily pg_dump, 04:00 UTC, uploaded to nano-managed object storage7 rolling daily copies
Enterprise (managed RDS)AWS automated backups, 04:00–05:00 window7 days
Hobby, Startup (single-VM Compose)None

Enterprise RDS instances are Multi-AZ. On nano-managed deployments, teardown takes a final snapshot rather than discarding the database, as a safety net against an accidental destroy. On BYOC the default is the opposite: destroying a deployment destroys its database outright, with no snapshot left in your account, so that one teardown leaves you with a genuinely clean account. Ask us to pass retainFinalSnapshot if you would rather keep the net — it is your account, and the snapshot is yours to keep and to pay storage on.

Restoring a PostgreSQL backup is an operator-assisted action; open a support request rather than expecting a self-serve button.

BYOC: your account, your backup policy

On a customer-hosted (BYOC) deployment the data never leaves your cloud account. The ClickHouse volumes, the cold-storage bucket, and the managed PostgreSQL instance are all resources you own, in a region you chose, under your own organisation's policies.

That means every durability control your organisation already runs applies to nano without nano's involvement:

  • EBS snapshots of the ClickHouse data volumes, on whatever schedule and retention your backup policy specifies — including AWS Backup plans and cross-region or cross-account snapshot copies.
  • Your own bucket policy on the cold tier, including S3 Object Lock if your compliance regime calls for WORM storage, replication to a second region, or a longer version-retention window than nano's default 30 days.
  • RDS snapshots on your own schedule, in addition to the automated 7-day retention.
  • Your key management, audit logging, and access reviews — every action nano takes appears in your CloudTrail under the session name nano-provisioning.

If your security questionnaire asks who can restore your data, on BYOC the answer is that you can, on your own terms, without depending on nano's roadmap. Recovering log data from a volume snapshot is crash-consistent rather than transactionally clean, so treat it as a bulk-recovery mechanism rather than a precise point-in-time restore — but it is a genuine one, and it is entirely under your control.

AWS IAM

For a BYOC deployment on AWS, nano needs permission to create and tear down the EKS cluster, VPC, load balancers, the managed PostgreSQL database, and the cold-tier storage bucket in your account. There are two ways to grant it.

OptionWhat nano storesRevoke by
IAM role (recommended)A role ARN — no credentialsDeleting the role
Access keysAn encrypted access key pairDeleting the IAM user

The role option is preferred: nano never holds long-lived credentials for your account, every action appears in your CloudTrail under the session name nano-provisioning, and deleting the role revokes access immediately without having to rotate anything.

How the role works

nano provisions from its own AWS account, so your role trusts that account and is gated on an External ID unique to your organisation. The External ID is what stops anyone else — including another nano customer who somehow learned your role ARN — from asking nano to use your role.

Both values are shown on the credential form in the nano console when you pick IAM role as the credential type: nano's AWS account ID, and your organisation's External ID.

Option 1: CloudFormation

Download the template and create the stack:

curl -O https://nano.rs/docs/nano-provisioning-role.yaml

aws cloudformation deploy \
  --template-file nano-provisioning-role.yaml \
  --stack-name nano-provisioning \
  --capabilities CAPABILITY_NAMED_IAM \
  --parameter-overrides \
      NanoAccountId=<NANO_ACCOUNT_ID> \
      ExternalId=<YOUR_EXTERNAL_ID>

Then read the role ARN back and paste it into the credential form:

aws cloudformation describe-stacks \
  --stack-name nano-provisioning \
  --query 'Stacks[0].Outputs[?OutputKey==`RoleArn`].OutputValue' \
  --output text

You can also create the stack through the CloudFormation console by uploading the same file.

Option 2: AWS CLI

If you don't use CloudFormation — or manage infrastructure in Terraform, or have service control policies restricting stack creation — the role is just three calls. Create the trust policy:

cat > nano-trust-policy.json <<'EOF'
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "AWS": "arn:aws:iam::<NANO_ACCOUNT_ID>:root" },
    "Action": "sts:AssumeRole",
    "Condition": {
      "StringEquals": { "sts:ExternalId": "<YOUR_EXTERNAL_ID>" }
    }
  }]
}
EOF

Create the role, then attach permissions:

aws iam create-role \
  --role-name NanoProvisioning \
  --assume-role-policy-document file://nano-trust-policy.json \
  --max-session-duration 43200

aws iam put-role-policy \
  --role-name NanoProvisioning \
  --policy-name nano-provisioning \
  --policy-document file://nano-provisioning-policy.json

Extract nano-provisioning-policy.json from the Policies block of the CloudFormation template above so the two paths grant identical permissions.

Session duration

Set MaxSessionDuration to 12 hours (43200 seconds). A large EKS cluster takes longer to build than AWS's one-hour default session, and a session that expires mid-provision leaves half-built infrastructure behind that still bills. If the role won't allow a 12-hour session nano falls back to one hour, which is enough for smaller tiers but not guaranteed for a full multi-pool cluster.

Permissions granted

ServiceWhy
eks:*Create and manage the cluster and its managed node groups
ec2:*VPC, subnets, NAT gateways, security groups, worker instances
elasticloadbalancing:*Load balancers fronting the deployment
acm (certificate lifecycle)The TLS certificate the load balancer's HTTPS listener serves, requested for your deployment's hostname and deleted on teardown
rds (scoped to nano-* databases)The managed PostgreSQL instance the deployment keeps its application data in, and the subnet group that places it in your private subnets
s3 (scoped to nano-* buckets)The cold-tier bucket: create it, turn on versioning and its lifecycle rule, and read/write the archived data in it
iam (scoped to nano-* roles)Cluster and node roles, the OIDC provider for IRSA, and the bucket-scoped role your ClickHouse pods assume
logsCluster logging
sts:GetCallerIdentityConfirms the role was assumed successfully

The IAM, RDS, and S3 permissions are scoped by resource name to the nano-* prefix, so the role can neither modify your other IAM principals, see your other buckets, nor touch your other databases.

Two read-only exceptions cannot be scoped: rds:DescribeDBInstances and rds:DescribeDBSubnetGroups act on a collection rather than a named resource, so IAM has no resource to pin them to. They return metadata — endpoint address, status, and the subnet ids the database sits in — and cannot read or change the contents of any database.

The ACM permissions cannot be scoped either: a certificate's ARN does not exist until acm:RequestCertificate returns it, so IAM has nothing to pin the request to. The certificate is validated through DNS in nano's own zone — nano needs no route53 permission in your account — and its private key never leaves AWS.

Cold storage needs no separate credentials

ClickHouse tiers data older than the hot retention window out to an S3 bucket in your account, and still queries it there. That bucket is covered by the same role — you do not create a bucket, an IAM user, or an access key for it.

At provision time nano creates a nano-prefixed bucket (encrypted with SSE-S3, all public access blocked, versioned — see Cold-tier immutability) and an IAM role scoped to just that bucket. That role is trust-bound to the Kubernetes ServiceAccount the ClickHouse pods run under, via the cluster's OIDC provider — the mechanism AWS calls IRSA. The pods authenticate with a short-lived web-identity token that EKS rotates, so no long-lived storage credential is ever created, stored, or transmitted.

Deleting the stack revokes this along with everything else. Tearing down the deployment removes the bucket and the bucket-scoped role.

Revoking access

Delete the CloudFormation stack, or the role if you created it by hand. nano loses access immediately — there are no credentials left behind to rotate. Do this only after destroying any deployment in the account, since teardown needs the same permissions as provisioning.

Monitoring

Prometheus scrapes all services at 10-15 second intervals:

EndpointMetrics
api:3000/metricsAPI latency, request counts, scheduler health
search:3002/metricsQuery performance, admission control
vector:9598/metricsIngestion throughput, buffer sizes, parse errors
postgres-exporter:9187Database health, replication lag

Next Steps

On this page

On this page