SimpleNS LogoDocs

Self-Hosting Guide

Deploy SimpleNS to production with flexible infrastructure hosting options.


Initial installation and setup

Refer the Getting Started Guide guide for initial installation and setup.


Overview

SimpleNS uses a split architecture that separates application services from infrastructure services, allowing flexible deployment across single or distributed systems.

Compose FilePurposeWhen to Use
docker-compose.yamlApplication services (API, processors, dashboard)Always required
docker-compose.infra.yamlInfrastructure (MongoDB, Kafka, Redis, Loki, Grafana)Only if self-hosting infrastructure

SimpleNS can also be hosted easily on cloud providers using prebuilt Terraform templates: SimpleNS Terraform Templates.


Customizing Infrastructure

The @simplens/onboard cli tool lets you to choose which infrastructure services to deploy with Docker. This gives you flexibility to use managed cloud services for some components while self-hosting others.

Selective Infrastructure Services

During onboarding, you can select which services to deploy:

ServiceDescriptionDefault
MongoDBPrimary databaseYes
KafkaMessage queue for notificationsYes
Kafka UIWeb dashboard for Kafka monitoringNo
RedisCaching and delay queueYes
LokiLog aggregationNo
GrafanaObservability dashboardNo
NginxReverse proxy server needed when BASE_PATH is configuredNo

Using Managed/External Services

For any service you choose not to deploy via Docker, you'll be prompted to provide connection URLs:

Environment VariableDescriptionExample
MONGO_URIMongoDB connection stringmongodb+srv://user:pass@cluster.mongodb.net/simplens
BROKERSKafka broker addresseskafka-broker.cloud-provider.com:9092
REDIS_URLRedis connection URLredis://user:pass@redis.cloud-provider.com:6379
LOKI_URLLoki endpoint (optional)http://loki.cloud-provider.com:3100

Use managed services like MongoDB Atlas, Confluent Cloud, or Redis Cloud for production deployments to reduce operational overhead.


Plugin Configuration

The simplens.config.yaml file controls which notification providers are available and how they behave.

You can easily add a plugin in the simplens.config.yaml using the @simplens/config-gen cli tool. Refer the Plugin Installation Guide

Adding Providers

Each provider connects to an external notification service:

simplens.config.yaml
providers:
  - package: "@simplens/nodemailer-gmail"
    id: email-primary
    credentials:
      EMAIL_USER: ${EMAIL_USER}
      EMAIL_PASS: ${EMAIL_PASS}
    options:
      priority: 2  # Higher = preferred
      rateLimit:
        maxTokens: 500
        refillRate: 500
        refillInterval: day

  - package: "@simplens/resend"
    id: email-backup
    credentials:
      RESEND_API_KEY: ${RESEND_API_KEY}
      FROM_EMAIL: ${FROM_EMAIL}
    options:
      priority: 1  # Lower priority, used as fallback
      rateLimit:
        maxTokens: 1000
        refillRate: 100
        refillInterval: hour

channels:
  email:
    default: email-primary

Provider Options

OptionDescription
priorityHigher value = preferred provider. Used for automatic failover.
rateLimit.maxTokensToken bucket capacity (max burst size)
rateLimit.refillRateNumber of tokens added per interval
rateLimit.refillIntervalRefill period: second, minute, hour, or day

Channel Configuration

Map channels to their default providers:

channels:
  email:
    default: email-primary
  sms:
    default: twilio-main
  push:
    default: firebase-prod

Scaling with Kafka Partitions

SimpleNS uses Kafka topic partitions to enable horizontal scaling of workers. The partition count is set at initial startup via environment variables.

Partition Environment Variables

VariableRelated ServiceDescription
NOTIFICATION_STATUS_PARTITIONworkerPartitions for status update processing
<CHANNEL>_PARTITIONnotification_processorPartitions per channel (e.g., EMAIL_PARTITION, SMS_PARTITION)
DELAYED_PARTITIONdelayed_processorPartitions for scheduled notifications

The recovery service doesn't depend on Kafka partitions and can be scaled independently.

Scaling Workers

To scale a worker, increase its corresponding partition count before first startup, then deploy multiple instances:

.env
# Scale notification processor for email channel
EMAIL_PARTITION=4

# Scale worker for status updates
NOTIFICATION_STATUS_PARTITION=3

# Scale delayed processor
DELAYED_PARTITION=2
# Deploy multiple instances
docker-compose up -d --scale notification_processor=4
docker-compose up -d --scale worker=3
docker-compose up -d --scale delayed_processor=2

Partition counts cannot be decreased after Kafka topics are created. Plan your scaling needs before initial deployment.

For detailed configuration of all environment variables, see the Configuration Reference.


Deployment Configurations

SimpleNS is designed to scale from a single Raspberry Pi to a multi-node Kubernetes cluster. How you deploy depends on your expected volume and whether you want to manage stateful databases yourself.

Hardware Requirements

EnvironmentMinimum ResourcesRecommended Resources
Development (Devcontainer)4 CPU Cores, 6GB RAM8 CPU Cores, 8GB RAM
Production (All-in-one)2 CPU Cores, 2GB RAM4 CPU Cores, 4GB RAM
Production (App Only)1 CPU Core, 1GB RAM2 CPU Cores, 2GB RAM + Managed DBs

Kafka and MongoDB are the most resource-intensive components when self-hosting the full stack.

Choose Your Setup

Best for: Side-projects, staging environments, and low-volume production (<100k events/day).

This setup runs both the Application and Infrastructure locally on a single machine.

.env
# Ensure MONGO, KAFKA, and REDIS point to your local docker networks
MONGO_URI=mongodb://host.docker.internal:27017/simplens?replicaSet=rs0
BROKERS=host.docker.internal:9092
REDIS_URL=redis://host.docker.internal:6379
LOKI_URL=http://host.docker.internal:3100
# Step 1: Start Infrastructure (DBs, Queues)
docker-compose -f docker-compose.infra.yaml up -d

# Step 2: Start Application Services
docker-compose up -d

Best for: Most production workloads. You run the stateless Node.js services, while handing off database maintenance to cloud providers.

.env
# MongoDB Atlas
MONGO_URI=mongodb+srv://user:pass@cluster.mongodb.net/simplens?retryWrites=true

# Confluent Cloud Kafka / AWS MSK
BROKERS=kafka-broker.cloud-provider.com:9092

# Redis Cloud / AWS ElastiCache
REDIS_URL=redis://user:pass@redis.cloud-provider.com:6379
# Only start application services
docker-compose up -d

With this setup, you completely ignore docker-compose.infra.yaml.

Best for: High availability and massive throughput.

You deploy infrastructure on dedicated nodes (or managed services), and spread Application workers across multiple machines behind a load balancer.

  1. API Nodes: Scale api container horizontally behind NGINX/ALB.
  2. Processor Nodes: Deploy notification_processor on separate servers tailored to target specific channels using PROCESSOR_CHANNEL=email.
  3. Background Nodes: Run worker and delayed_processor on background compute.

Ensure you adjust your *_PARTITION environment variables before creation to support the number of parallel processor instances you plan to run.


Application Services

The docker-compose.yaml uses pre-built images from GitHub Container Registry:

ServiceImageDescription
apighcr.io/simplenotificationsystem/simplens-core:latestREST API for notification ingestion
workerghcr.io/simplenotificationsystem/simplens-core:latestBackground worker for outbox processing
notification_processorghcr.io/simplenotificationsystem/simplens-core:latestPlugin-based notification delivery
delayed_processorghcr.io/simplenotificationsystem/simplens-core:latestScheduled notification handling
recoveryghcr.io/simplenotificationsystem/simplens-core:latestDetects and rescues stuck notifications
dashboardghcr.io/simplenotificationsystem/simplens-dashboard:latestAdmin dashboard (Next.js)

All application services share a plugin-data volume for plugins and mount simplens.config.yaml as read-only.


Infrastructure Services

The docker-compose.infra.yaml provides self-hosted infrastructure:

ServiceImageDescription
mongomongo:7.0MongoDB with replica set
kafkaapache/kafka-nativeKafka with KRaft mode (no Zookeeper)
kafka-uikafbat/kafka-ui:mainKafka monitoring UI (optional)
redisredis:7-alpineRedis for caching and queues
lokigrafana/loki:2.9.0Log aggregation
grafanagrafana/grafana:10.2.0Log visualization

Port Reference

ServicePortDescription
API3000REST API for notification ingestion
Dashboard3002Admin web interface
MongoDB27017Database
Kafka9092Message broker
Kafka UI8080Kafka monitoring (optional)
Redis6379Cache and queues
Loki3100Log aggregation
Grafana3001Log visualization

Config Generator CLI

The @simplens/config-gen CLI generates simplens.config.yaml from plugin manifests.

Commands

# Generate config for single plugin
npx @simplens/config-gen generate @simplens/mock

# Generate config for multiple plugins
npx @simplens/config-gen gen @simplens/nodemailer-gmail @simplens/mock

# Add plugin to existing config
npx @simplens/config-gen gen @simplens/nodemailer-gmail -c simplens.config.yaml

# Custom output path
npx @simplens/config-gen gen @simplens/mock -o custom.yaml

# Print to stdout
npx @simplens/config-gen gen @simplens/mock --stdout

# List official plugins
npx @simplens/config-gen list --official

# List community plugins
npx @simplens/config-gen list --community

Security Considerations

Before Deploying to Production

Complete these security checks before going live.

  1. ✅ Generate strong NS_API_KEY and AUTH_SECRET values
  2. ✅ Set a secure ADMIN_PASSWORD
  3. ✅ Configure firewall rules to restrict infrastructure ports
  4. ✅ Set up SSL/TLS for API and dashboard
  5. ✅ Configure MongoDB authentication
  6. ✅ Set up backup strategy for MongoDB
  7. ✅ Review and limit exposed ports

Troubleshooting

Services can't connect to infrastructure

  • INFRA_HOST: Ensure it matches the infrastructure machine's accessible IP
  • Firewall: Check ports 27017, 9092, 6379, 3100 are open
  • Network: Verify machines can ping each other

MongoDB replica set issues

# Reset and reinitialize
docker-compose -f docker-compose.infra.yaml down -v
docker-compose -f docker-compose.infra.yaml up -d
# Wait 60 seconds for auto-initialization

Plugin configuration not loading

# Verify config file exists
ls -la simplens.config.yaml

# Regenerate if needed
npx @simplens/config-gen generate @simplens/mock --stdout

# Set required environment variables in .env

On this page