SERVICES_CUSTOM - nself-org/cli GitHub Wiki
Custom services are your own backend microservices that integrate seamlessly with the nself infrastructure. You can create up to 10 custom services using templates or your own code.
Define custom services in your .env file:
# Format: CS_N=service_name:template_type:port
CS_1=api:express-js:8001
CS_2=worker:bullmq-js:8002
CS_3=grpc:grpc:50051
CS_4=ml_api:fastapi:8004Run nself build to generate services from templates, then customize the code.
- express-js - Express.js REST API
- express-ts - Express with TypeScript
- fastify-js - High-performance REST API
- fastify-ts - Fastify with TypeScript
- nest-js - NestJS framework
- nest-ts - NestJS with TypeScript
- bullmq-js - BullMQ job worker
- bullmq-ts - BullMQ with TypeScript
- socketio-js - WebSocket server
- socketio-ts - Socket.IO with TypeScript
- temporal-js - Temporal workflow
- temporal-ts - Temporal with TypeScript
- trpc - tRPC API server
- hono-js - Ultrafast web framework
- hono-ts - Hono with TypeScript
- bun - Bun runtime service
- deno - Deno runtime service
- fastapi - FastAPI REST service
- flask - Flask web framework
- django-rest - Django REST Framework
- celery - Celery worker
- ray - Ray distributed computing
- agent-analytics - Analytics agent
- agent-llm - LLM agent service
- agent-vision - Computer vision agent
- agent-timeseries - Time series analysis
- agent-training - ML training agent
- gin - Gin web framework
- fiber - Fiber web framework
- echo - Echo web framework
- grpc - gRPC service
- rust/actix-web - Rust Actix framework
- ruby/rails - Ruby on Rails
- ruby/sinatra - Sinatra framework
- php/laravel - Laravel framework
- java/spring-boot - Spring Boot
- kotlin/ktor - Ktor framework
- csharp/aspnet - ASP.NET Core
- elixir/phoenix - Phoenix framework
- swift/vapor - Vapor framework
- zig/zap - Zap framework
- lua/lapis - Lapis framework
- cpp/oatpp - Oat++ framework
-
Define Service in
.env:CS_1=my_api:express-js:8001
-
Run Build to generate from template:
nself build
-
Service Created at
services/my_api/:services/my_api/ โโโ Dockerfile โโโ index.js โโโ package.json -
Customize your code - files won't be overwritten on rebuild
Templates use placeholders that are automatically replaced:
-
{{SERVICE_NAME}}- Your service name -
{{SERVICE_PORT}}- Service port number -
{{PROJECT_NAME}}- Project name -
{{BASE_DOMAIN}}- Base domain -
{{POSTGRES_HOST}}- Database host -
{{REDIS_HOST}}- Redis host
Each template provides:
- Dockerfile - Container configuration
- Source files - Language-specific code
- Dependencies - package.json, requirements.txt, go.mod, etc.
-
Health check -
/healthendpoint - Basic routes - Example endpoints
CS_1=api:express-js:8001Creates an Express.js API with:
- RESTful endpoints
- PostgreSQL connection
- JWT authentication ready
- Health checks
CS_2=worker:bullmq-js:8002Creates a BullMQ worker with:
- Job queue processing
- Redis connection
- Retry logic
- Dead letter queue
CS_3=grpc:grpc:50051Creates a Go gRPC service with:
- Protocol buffer definitions
- Service implementation
- Health checking
- Reflection enabled
CS_4=ml_api:fastapi:8004Creates a FastAPI service with:
- Async endpoints
- Pydantic models
- OpenAPI documentation
- ML model serving ready
All custom services receive these environment variables:
# Database
POSTGRES_HOST=postgres
POSTGRES_PORT=5432
POSTGRES_DB=${POSTGRES_DB}
POSTGRES_USER=${POSTGRES_USER}
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
REDIS_PASSWORD=${REDIS_PASSWORD}
# Hasura
HASURA_GRAPHQL_ENDPOINT=http://hasura:8080/v1/graphql
HASURA_ADMIN_SECRET=${HASURA_GRAPHQL_ADMIN_SECRET}
# Service Info
SERVICE_NAME=${service_name}
SERVICE_PORT=${port}
PROJECT_NAME=${PROJECT_NAME}
BASE_DOMAIN=${BASE_DOMAIN}
NODE_ENV=${ENV}Custom services are automatically:
- Added to Docker network
- Configured in nginx routing
- Given health check endpoints
- Exposed on specified ports
Default volumes for development:
volumes:
- ./services/${service_name}:/app
- /app/node_modules # Node.js
- /app/.venv # Python
- /app/vendor # PHP/RubyIf you don't use a template, create your service structure:
services/my_service/
โโโ Dockerfile
โโโ src/
โ โโโ main.js
โโโ package.json
โโโ .env
Dockerfile example:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
EXPOSE 8080
CMD ["node", "src/main.js"]Custom services are added to docker-compose.yml:
my_service:
build:
context: ./services/my_service
dockerfile: Dockerfile
container_name: ${PROJECT_NAME}_my_service
ports:
- "8080:8080"
environment:
- NODE_ENV=${ENV}
- DATABASE_URL=${DATABASE_URL}
depends_on:
- postgres
- redisServices can communicate internally using service names:
// From one service to another
const response = await fetch('http://other_service:8002/api/data');
// To Hasura
const graphql = await fetch('http://hasura:8080/v1/graphql', {
headers: {
'x-hasura-admin-secret': process.env.HASURA_ADMIN_SECRET
}
});
// To PostgreSQL
const pg = new Pool({
host: 'postgres',
port: 5432,
database: process.env.POSTGRES_DB
});Services are exposed via nginx:
-
https://api.<domain>โ Your API service -
https://worker.<domain>โ Worker dashboard -
https://grpc.<domain>โ gRPC service
Start with templates - they include best practices and proper configuration.
Always implement /health endpoint:
app.get('/health', (req, res) => {
res.json({ status: 'healthy', service: 'my_api' });
});Never hardcode configuration:
const port = process.env.SERVICE_PORT || 8080;
const dbUrl = process.env.DATABASE_URL;Use structured logging:
console.log(JSON.stringify({
level: 'info',
service: process.env.SERVICE_NAME,
message: 'Request processed',
requestId: req.id
}));Implement proper error handling:
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({
error: 'Internal Server Error',
requestId: req.id
});
});Expose Prometheus metrics at /metrics:
const prometheus = require('prom-client');
const register = prometheus.register;
app.get('/metrics', async (req, res) => {
res.set('Content-Type', register.contentType);
res.end(await register.metrics());
});Logs are automatically collected by Promtail and sent to Loki.
Use OpenTelemetry for distributed tracing:
const { trace } = require('@opentelemetry/api');
const tracer = trace.getTracer('my-service');# In docker-compose.yml
deploy:
replicas: 3deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M- Check logs:
nself logs my_service - Verify port isn't in use
- Check Dockerfile syntax
- Ensure dependencies installed
- Verify PostgreSQL is running
- Check connection string
- Ensure network connectivity
- Verify credentials
- Check template name spelling
- Verify template exists
- Use
nself templates list