logoSemaphor

Deployment

Deploy and manage Semaphor on your own infrastructure

Overview

Semaphor Self-Hosted Edition gives you complete control over your analytics infrastructure. Run the entire Semaphor stack on your own servers, maintain data sovereignty, and customize to your needs.

Why Self-Host?

  • Data Sovereignty: Keep all data within your infrastructure
  • Compliance: Meet regulatory requirements for data residency
  • Customization: Configure for your specific security and network needs
  • Performance: Optimize for your workload and geographic distribution
  • Cost Control: Predictable infrastructure costs at scale

Architecture

Semaphor's self-hosted edition consists of three core services:

  • API Service: Main application container running on port 3000, handles authentication, Semaphor Console UI, and API endpoints
  • Data Service: Responsible for connecting to your databases and executing queries
  • Data Service Sidecar: Runs custom code (Python) in a secure sandbox environment

Database Options:

  • Testing & Development: Use the embedded PostgreSQL and Redis that start automatically inside the API container - perfect for trying out Semaphor with zero database setup
  • Production Deployment: Connect to your existing dedicated PostgreSQL and Redis instances for better performance, scalability, and integration with your infrastructure

The embedded databases make it incredibly easy to test Semaphor, while the external database option ensures you can scale to production workloads using your existing database infrastructure.

Prerequisites

Before you begin, you'll need:

1. Docker

  • Docker 20.10+ and Docker Compose 2.0+
  • Verify installation: docker --version and docker-compose --version
  • Install Docker if needed

2. Semaphor License

  • Get your license key from support.semaphor.cloud
  • Format: SEMA-<payload>.<signature>
  • Note: You can request a free 60-day evaluation license to test Semaphor

3. Kinde Authentication

Semaphor requires Kinde for user authentication and access control.

Quick Setup:

Required Credentials:

  • Client ID
  • Client Secret
  • Issuer URL (format: https://your-subdomain.kinde.com)

→ See Kinde Authentication Setup for detailed instructions

Quick Start (Docker Compose)

1. Get Setup Files

First, create a new directory for your Semaphor deployment:

mkdir semaphor-deployment
cd semaphor-deployment

Create a docker-compose.yml file with the following content:

services:
  # API Service (with embedded PostgreSQL and Redis)
  api-service:
    image: semaphorstack/api-service:latest
    env_file:
      - ./semaphor.env # All configuration including LICENSE_KEY
    volumes:
      - ./semaphor.env:/app/.env
      - semaphor-data:/data # Persistent storage for embedded DB and cache
    ports:
      - '3000:3000'
    healthcheck:
      test:
        [
          'CMD-SHELL',
          'node -e "http=require(''http''); http.get(''http://localhost:3000/api/health'', r=>process.exit(r.statusCode===200?0:1)).on(''error'', ()=>process.exit(1))"',
        ]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s # Give embedded services time to start
 
  # Data Service (Main)
  data-service:
    image: semaphorstack/data-service:latest
    depends_on:
      api-service:
        condition: service_healthy
    environment:
      PORT: 80
      SIDECAR_URL: http://data-service-sidecar:8080
    ports:
      - '8080:80'
    healthcheck:
      test:
        [
          'CMD',
          'python',
          '-c',
          "import urllib.request,sys; r=urllib.request.urlopen('http://localhost:80/health', timeout=2); sys.exit(0 if r.getcode()==200 else 1)",
        ]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 20s
 
  # Data Service Sidecar
  data-service-sidecar:
    image: semaphorstack/data-service-sidecar:latest
    depends_on:
      data-service:
        condition: service_healthy
    environment:
      PORT: 8080
      # Add any sidecar-specific environment variables
    ports:
      - '8081:8080'
    healthcheck:
      test:
        [
          'CMD',
          'python',
          '-c',
          "import urllib.request,sys; r=urllib.request.urlopen('http://localhost:8080/health', timeout=2); sys.exit(0 if r.getcode()==200 else 1)",
        ]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 20s
 
volumes:
  semaphor-data: # Stores embedded PostgreSQL and Redis data
 
networks:
  default:
    name: semaphor-network
    driver: bridge

Then generate your configuration file:

docker run --rm semaphorstack/api-service:latest generate-env > semaphor.env

2. Configure

Edit semaphor.env and configure the required fields:

# ===== REQUIRED: License Token =====
# Provided by Semaphor (format: SEMA-<payload>.<sig>)
LICENSE_KEY=SEMA-<payload>.<sig>

# ===== REQUIRED: Authentication =====
KINDE_CLIENT_ID=<your_kinde_client_id>
KINDE_CLIENT_SECRET=<your_kinde_client_secret>
KINDE_ISSUER_URL=https://<your_kinde_subdomain>.kinde.com

Leave the rest of the configuration as-is. The default values are pre-configured for local testing.

3. Start

docker-compose up

Wait for all 3 services to start - api-service, data-service, and data-service-sidecar. You should see output similar to:

api-service-1           | Database connected
api-service-1           | Mode: DB=embedded, Redis=embedded
api-service-1           | App: starting on http://0.0.0.0:3000
api-service-1           |   ▲ Next.js 14.2.31
api-service-1           |   - Local:        http://localhost:3000
api-service-1           |  ✓ Ready in 47ms
data-service-1          | INFO:     Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
data-service-sidecar-1  | INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)

Once you see "Ready" from all services, Semaphor is running. You can now stop the services with Ctrl+C and restart them in the background:

docker-compose up -d

To shut down the services later:

docker-compose down

Your data remains safe in the semaphor-data volume even after shutdown.

4. Access

Open http://localhost:3000/project

Deploy as Independent Containers

To run Semaphor services as individual containers instead of using docker-compose:

1. API Service

docker run -it --rm \
  --name semaphor-api \
  --network semaphor-network \
  -p 3000:3000 \
  -v $(pwd)/semaphor.env:/app/.env:ro \
  -v semaphor-data:/data \
  semaphorstack/api-service:latest

2. Data Service

docker run -it --rm \
  --name semaphor-data \
  --network semaphor-network \
  -p 8080:80 \
  -e PORT=80 \
  -e SIDECAR_URL=http://semaphor-sidecar:8080 \
  semaphorstack/data-service:latest

3. Data Service Sidecar

docker run -it --rm \
  --name semaphor-sidecar \
  --network semaphor-network \
  -p 8081:8080 \
  -e PORT=8080 \
  semaphorstack/data-service-sidecar:latest

Monitoring

# Health check
curl http://localhost:3000/api/health
 
# View logs
docker logs -f semaphor
 
# Resource usage
docker stats semaphor
 
# License info (shown in logs on startup)
docker logs semaphor | grep -i license

Optional: Report Generation and Scheduling

Semaphor supports automated report generation and email delivery through an AWS-based scheduling service that you deploy in your own AWS account.

Architecture

The service consists of three Lambda functions:

  • Schedule Processor: Triggered by CloudWatch Events every 60 minutes (configurable), polls Semaphor APIs to check for active schedules
  • PDF Generator: Creates PDFs of dashboards and paginated reports
  • Email Sender: Handles email delivery through AWS SES

What It Enables

  • Manual PDF export of visuals and dashboards
  • Automated report generation on schedules
  • Email delivery of generated reports

Prerequisites

  • AWS account with appropriate permissions
  • AWS CLI and SAM CLI installed locally
  • AWS SES configured for sending emails

Deployment

  1. Deploy the report scheduler to your AWS account:

    Follow the instructions at: github.com/semaphor-analytics/report-scheduler

  2. Get your Lambda function URL after deployment completes

  3. Add the Lambda URL to your semaphor.env:

    # PDF generation Lambda URL (required for PDF export and report scheduling)
    PDF_FUNCTION_URL='https://your-lambda-url.lambda-url.region.on.aws/'
    

    Example:

    PDF_FUNCTION_URL='https://3hyxrgytvhjyobd3hi2tlpbepe0vhqkd.lambda-url.us-east-1.on.aws/'
    

    Note: This environment variable is required for users to export visuals as PDFs or generate reports.

  4. Restart Semaphor to apply the configuration:

    docker-compose restart

Once configured, users can create and manage scheduled reports directly from the Semaphor console.

Support