Skip to main content

AppServer Deployment Guide

Complete guide for deploying the Easy AppServer v2 backend service.

Overview

The AppServer v2 is the core backend service that provides:

  • HTTP Server (port 8080): REST API, GraphQL endpoint, UI asset serving
  • gRPC Server (port 9091): App registration, hooks, activities, settings management
┌─────────────────────────────────────────────────────────────┐
│ AppServer v2 │
├─────────────────────────────────────────────────────────────┤
│ HTTP Server (8080) │ gRPC Server (9091) │
│ ├── REST API endpoints │ ├── MarketplaceService │
│ ├── GraphQL at /graphql │ ├── HooksService │
│ ├── UI Asset serving │ ├── ActivityService │
│ ├── Proxy routes │ └── SettingsService │
│ └── Health checks │ │
└─────────────────────────────────────────────────────────────┘
│ │
└──────────────┬───────────────┘

┌──────────────┼──────────────┐
▼ ▼ ▼
PostgreSQL Redis OpenFGA
(Required) (Required) (Required)

Default vs Production Configuration

Setting APPSERVER_ENV=production automatically changes these defaults:

SettingDevelopment (default)Production
gRPC TLSDisabledEnabled
gRPC ReflectionEnabledDisabled
GraphQL PlaygroundEnabledDisabled
Bootstrap RegistrationEnabledDisabled

Important: When APPSERVER_ENV=production is set, gRPC TLS is automatically enabled and requires valid certificates. Developer tools are automatically disabled.

Entry Point

Binary: cmd/appserver-v2/main.go

Build and run:

# Build
go build -o appserver ./cmd/appserver-v2

# Run
./appserver

Required Dependencies

The AppServer requires these services to be running and accessible:

ServicePurposeDefault URLRequired
PostgreSQLApplication datapostgres:5432Yes
RedisCache, rate limitingredis:6379Yes
KratosSession validationhttp://kratos:4433Yes
OpenFGAPermission checkshttp://openfga:8089Yes

Optional Dependencies

ServicePurposeWhen Needed
RabbitMQEvent busWhen APPSERVER_EVENTBUS_ENABLED=true
HydraOAuth2 flowsWhen OAuth is configured

Environment Variables

Critical (Must Set)

# Encryption key for app settings (REQUIRED - exactly 32 characters)
APPSERVER_SETTINGS_ENCRYPTION_KEY=your-32-character-encryption-key

# Database credentials
APPSERVER_DB_HOST=postgres
APPSERVER_DB_PORT=5432
APPSERVER_DB_NAME=partner
APPSERVER_DB_USER=partner
APPSERVER_DB_PASSWORD=your-secure-password

# Authorization (from setup script or manual API calls - see Troubleshooting)
APPSERVER_OPENFGA_API_URL=http://openfga:8089
APPSERVER_OPENFGA_STORE_ID=01HQXXXXXXXXXXXXXXXXXXXXXX
APPSERVER_OPENFGA_MODEL_ID=01HQXXXXXXXXXXXXXXXXXXXXXX

# Identity service
APPSERVER_KRATOS_PUBLIC_URL=http://kratos:4433

Server Configuration

# Ports
APPSERVER_HTTP_PORT=8080 # HTTP/GraphQL server
APPSERVER_GRPC_PORT=9091 # gRPC server

# Environment mode
APPSERVER_ENV=production # 'production' or 'prod' enables production defaults

Security Settings

# gRPC TLS (ENABLE IN PRODUCTION)
APPSERVER_GRPC_TLS_ENABLED=true
APPSERVER_GRPC_TLS_CERT_FILE=/etc/appserver/tls/server.crt
APPSERVER_GRPC_TLS_KEY_FILE=/etc/appserver/tls/server.key

# Optional: Mutual TLS (client certificates)
APPSERVER_GRPC_MTLS_ENABLED=false
APPSERVER_GRPC_MTLS_CA_FILE=/etc/appserver/tls/ca.crt

# Developer tools (DISABLE IN PRODUCTION)
APPSERVER_GRPC_REFLECTION_ENABLED=false
APPSERVER_GRAPHQL_PLAYGROUND_ENABLED=false
APPSERVER_AUTH_ALLOW_BOOTSTRAP_REGISTRATION=false

Cache & Event Bus

# Redis cache
APPSERVER_REDIS_URL=redis://redis:6379
APPSERVER_CACHE_TTL=300 # Local cache TTL in seconds

# Event bus (optional - defaults to in-memory if disabled)
APPSERVER_EVENTBUS_ENABLED=true
APPSERVER_RABBITMQ_URL=amqp://guest:guest@rabbitmq:5672/

Telemetry

APPSERVER_LOG_LEVEL=info         # debug, info, warn, error
APPSERVER_METRICS_ENABLED=true # Prometheus metrics at /metrics
APPSERVER_TRACING_ENABLED=true # OpenTelemetry traces

Initialization Sequence

The AppServer initializes in this order:

  1. Load environment variables (.env.local > .env)
  2. Load configuration
  3. Initialize telemetry/logger
  4. Initialize EventBus (RabbitMQ or In-Memory)
  5. Initialize database connection pool
  6. Initialize repositories (App, Asset, Dependency, Route, Hook, Activity, Settings, Deployment)
  7. Initialize domain services (StateMachine, Validators, ResolverServices)
  8. Initialize infrastructure services (Auth, AuthZ, Rate Limiting, Health Checks)
  9. Wire cache invalidation to EventBus
  10. Initialize application services (Marketplace, UI, Proxy, Hooks, Activity, Settings)
  11. Initialize orchestration services (if Docker enabled)
  12. Subscribe to orchestration events
  13. Start orchestration health monitor (background)
  14. Wire UI service event subscriptions
  15. Start activity heartbeat monitor (background)
  16. Restore routes from database
  17. Bootstrap installed apps
  18. Start HTTP server
  19. Start gRPC server

Health Checks

The AppServer exposes health endpoints:

# Liveness check
curl http://localhost:8080/health

# Readiness check
curl http://localhost:8080/ready

# gRPC health check (requires grpc-health-probe)
grpc_health_probe -addr=localhost:9091

HTTP Endpoints

EndpointMethodDescription
/graphqlPOSTGraphQL queries and mutations
/graphqlGETGraphQL Playground (if enabled)
/apps/{appName}/assets/{assetPath}GETServe app UI assets
/healthGETLiveness check
/readyGETReadiness check
/metricsGETPrometheus metrics (if enabled)

gRPC Services

MarketplaceService

  • Subscribe() - Bidirectional stream for app registration
  • Apps push assets and register routes via this stream

HooksService

  • Subscribe() - Register webhook handlers
  • Trigger() - Invoke webhooks

ActivityService

  • Subscribe() - Stream activity notifications to apps

SettingsService

  • Get() - Retrieve app settings
  • Set() - Store app settings (AES-256-GCM encrypted)

Authentication

HTTP Requests

  • Session cookie: ory_kratos_session (configurable)
  • Validated against Kratos

gRPC Requests

  • Certificate auth: Apps authenticate with certificates
  • Session auth: Users authenticate with Kratos session cookies

Docker Deployment

Building the Image

The AppServer Dockerfile is located at docker/appserver/Dockerfile. It uses a multi-stage build for minimal image size.

Build with SSH keys (for private Bitbucket repos):

docker build \
--build-arg ssh_prv_key="$(cat ~/.ssh/id_rsa)" \
--build-arg ssh_pub_key="$(cat ~/.ssh/id_rsa.pub)" \
-f docker/appserver/Dockerfile \
-t appserver:latest \
.

Build with SSH agent (alternative):

docker build --ssh default \
-f docker/appserver/Dockerfile \
-t appserver:latest \
.

Image Details

PropertyValue
Build Imagegolang:1.25-bookworm
Runtime Imagegcr.io/distroless/static-debian12
Image Size~15MB
Usernonroot
Ports8080 (HTTP), 9091 (gRPC)

Running the Container

docker run -d \
-p 8080:8080 \
-p 9091:9091 \
--env-file docker/.env \
--network appserver-network \
appserver:latest

Docker Compose

See docker/docker-compose.dev.yml for the full configuration.

Key environment variables:

  • APPSERVER_DB_NAME=partner - Database name (contains appserver schema)
  • APPSERVER_SETTINGS_ENCRYPTION_KEY - Exactly 32 characters
  • APPSERVER_OPENFGA_STORE_ID / APPSERVER_OPENFGA_MODEL_ID - From setup script

Note: The AppServer tables are stored in the appserver schema within the partner database.

TLS Certificate Generation

Generate certificates for gRPC TLS:

# Generate CA key and certificate
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 365 -key ca.key -out ca.crt \
-subj "/CN=AppServer CA"

# Generate server key and certificate
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr \
-subj "/CN=appserver"
openssl x509 -req -days 365 -in server.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out server.crt

Production Checklist

  • Set APPSERVER_ENV=production
  • Set strong APPSERVER_SETTINGS_ENCRYPTION_KEY (32 chars)
  • Set strong APPSERVER_DB_PASSWORD
  • Configure OpenFGA Store ID and Model ID
  • Enable gRPC TLS (APPSERVER_GRPC_TLS_ENABLED=true)
  • Disable developer tools:
    • APPSERVER_GRPC_REFLECTION_ENABLED=false
    • APPSERVER_GRAPHQL_PLAYGROUND_ENABLED=false
    • APPSERVER_AUTH_ALLOW_BOOTSTRAP_REGISTRATION=false
  • Configure database SSL (APPSERVER_DB_SSLMODE=verify-full)
  • Enable telemetry for monitoring

Troubleshooting

Database Connection Failed

Error: pq: connection refused
  • Verify PostgreSQL is running and accessible
  • Check APPSERVER_DB_HOST and APPSERVER_DB_PORT
  • Ensure APPSERVER_DB_NAME=partner (the appserver schema is in the partner database)

OpenFGA Connection Failed

Error: failed to connect to OpenFGA
  • Verify OpenFGA is running on configured URL
  • Check OPENFGA_STORE_ID and OPENFGA_MODEL_ID are correct

Obtaining Store/Model IDs:

For Docker deployments, run the setup script:

./docker/scripts/setup-openfga-roles.sh

For non-Docker deployments or if the script fails, see Manual Setup for step-by-step API calls to:

  1. Create the OpenFGA store
  2. Upload the authorization model
  3. Assign default roles and permissions

Settings Encryption Error

Error: invalid key size
  • APPSERVER_SETTINGS_ENCRYPTION_KEY must be exactly 32 characters

gRPC TLS Errors

Error: transport: authentication handshake failed
  • Verify certificate paths are correct
  • Check certificate is valid and not expired
  • Ensure client has CA certificate for verification