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:
| Setting | Development (default) | Production |
|---|---|---|
| gRPC TLS | Disabled | Enabled |
| gRPC Reflection | Enabled | Disabled |
| GraphQL Playground | Enabled | Disabled |
| Bootstrap Registration | Enabled | Disabled |
Important: When
APPSERVER_ENV=productionis 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:
| Service | Purpose | Default URL | Required |
|---|---|---|---|
| PostgreSQL | Application data | postgres:5432 | Yes |
| Redis | Cache, rate limiting | redis:6379 | Yes |
| Kratos | Session validation | http://kratos:4433 | Yes |
| OpenFGA | Permission checks | http://openfga:8089 | Yes |
Optional Dependencies
| Service | Purpose | When Needed |
|---|---|---|
| RabbitMQ | Event bus | When APPSERVER_EVENTBUS_ENABLED=true |
| Hydra | OAuth2 flows | When 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:
- Load environment variables (
.env.local>.env) - Load configuration
- Initialize telemetry/logger
- Initialize EventBus (RabbitMQ or In-Memory)
- Initialize database connection pool
- Initialize repositories (App, Asset, Dependency, Route, Hook, Activity, Settings, Deployment)
- Initialize domain services (StateMachine, Validators, ResolverServices)
- Initialize infrastructure services (Auth, AuthZ, Rate Limiting, Health Checks)
- Wire cache invalidation to EventBus
- Initialize application services (Marketplace, UI, Proxy, Hooks, Activity, Settings)
- Initialize orchestration services (if Docker enabled)
- Subscribe to orchestration events
- Start orchestration health monitor (background)
- Wire UI service event subscriptions
- Start activity heartbeat monitor (background)
- Restore routes from database
- Bootstrap installed apps
- Start HTTP server
- 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
| Endpoint | Method | Description |
|---|---|---|
/graphql | POST | GraphQL queries and mutations |
/graphql | GET | GraphQL Playground (if enabled) |
/apps/{appName}/assets/{assetPath} | GET | Serve app UI assets |
/health | GET | Liveness check |
/ready | GET | Readiness check |
/metrics | GET | Prometheus 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 handlersTrigger()- Invoke webhooks
ActivityService
Subscribe()- Stream activity notifications to apps
SettingsService
Get()- Retrieve app settingsSet()- 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
| Property | Value |
|---|---|
| Build Image | golang:1.25-bookworm |
| Runtime Image | gcr.io/distroless/static-debian12 |
| Image Size | ~15MB |
| User | nonroot |
| Ports | 8080 (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 (containsappserverschema)APPSERVER_SETTINGS_ENCRYPTION_KEY- Exactly 32 charactersAPPSERVER_OPENFGA_STORE_ID/APPSERVER_OPENFGA_MODEL_ID- From setup script
Note: The AppServer tables are stored in the
appserverschema within thepartnerdatabase.
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_HOSTandAPPSERVER_DB_PORT - Ensure
APPSERVER_DB_NAME=partner(theappserverschema is in thepartnerdatabase)
OpenFGA Connection Failed
Error: failed to connect to OpenFGA
- Verify OpenFGA is running on configured URL
- Check
OPENFGA_STORE_IDandOPENFGA_MODEL_IDare 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:
- Create the OpenFGA store
- Upload the authorization model
- Assign default roles and permissions
Settings Encryption Error
Error: invalid key size
APPSERVER_SETTINGS_ENCRYPTION_KEYmust 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
Related Topics
- Orchestrator Guide - Container orchestration
- Shell Guide - Frontend deployment
- Docker Infrastructure - Full stack deployment
- Environment Reference - All environment variables