Skip to main content

Deployment Guide

This guide covers how to deploy Minimal on a Linux server — from binary setup to running it as a production service behind nginx.


Prerequisites

RequirementNotes
Linux server (Ubuntu 20.04+ recommended)Any linux distro works
MySQL / MariaDB / PostgreSQL / ClickhouseFor the definition_store — Minimal's internal metadata database
nginxAs a reverse proxy in front of Minimal
Port accessMinimal listens on the port defined in config.yml — default 3045

Step 1 — Download the Binary

# Create a directory for Minimal
mkdir -p /opt/minimal && cd /opt/minimal

# Download the latest binary (replace with actual release URL)
wget https://releases.littlebit.in/minimal/latest/minimal-linux-amd64 -O minimal

# Make it executable
chmod +x minimal

Step 2 — Create the Config File

# Create config directory
mkdir -p /etc/minimal

# Create config file
nano /etc/minimal/config.yml

Paste and fill in your values:

service:
name: minimal
port: "3045"
version: "0.0.1"
environment: "production"
server_key: "your-secret-server-key"
log_level: "info"
debug_mode: false
cors_enabled: false
middleware_enabled: false
trace_to_stdout: false
shutdown_timeout: 30
timeout:
enable: true
timeout: 10
initial_interval: 1
max_interval: 30
max_elapsed_time: 120

definition_store:
type: mysql
port: 3306
username: minimalist
password_source: file
password: 'you****'
host: localhost
schema: minimal
connect_timeout_secs: 30
idle_timeout_secs: 600
max_open_connections: 60
max_idle_connections: 25
default_query_timeout_secs: 10
mode: single
encrypt_database: true
encryption_key_source: file
encryption_key: 'your-encryption-key'

cache_settings:
ttl_seconds: 1800

auto_api:
roles: [admin, power, wheel]
avg_columns_per_table: 20
indexing_page_size: 100
max_rows_per_page: 100
Production settings

Always set these for production:

  • environment: production
  • debug_mode: false
  • log_level: info
  • cors_enabled: false — handle CORS in nginx instead

Step 3 — Set Up the Definition Store Database

Minimal needs its own internal database. Create a dedicated user and schema:

-- Run as MySQL root
CREATE DATABASE minimal;
CREATE USER 'minimalist'@'localhost' IDENTIFIED BY 'you****';
GRANT ALL PRIVILEGES ON minimal.* TO 'minimalist'@'localhost';
FLUSH PRIVILEGES;

Minimal creates its own tables on first startup — no migrations to run manually.


Step 4 — Test the Binary

Run Minimal directly first to confirm config is valid:

/opt/minimal/minimal --config /etc/minimal/config.yml

You should see:

minimal service starting...
connected to definition store
listening on :3045

If there are config errors they will appear here. Press Ctrl+C to stop once confirmed working.


Step 5 — Create a systemd Service

nano /etc/systemd/system/minimal.service
[Unit]
Description=Minimal API Server
After=network.target mysql.service
Wants=mysql.service

[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/minimal
ExecStart=/opt/minimal/minimal --config /etc/minimal/config.yml
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=minimal

# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/minimal /etc/minimal /var/log/minimal

[Install]
WantedBy=multi-user.target

Enable and start the service:

# Reload systemd
systemctl daemon-reload

# Enable on boot
systemctl enable minimal

# Start now
systemctl start minimal

# Check status
systemctl status minimal

Step 6 — Configure nginx

Minimal should never be exposed directly to the internet. nginx handles TLS, CORS, and proxying:

server {
listen 443 ssl;
server_name your-domain.com;

ssl_certificate /etc/ssl/certs/your-cert.pem;
ssl_certificate_key /etc/ssl/private/your-key.pem;

location /minimal/ {

# Handle CORS preflight
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'X-Org-Id, X-Project-Id, X-Space-Id, X-User-Id, X-User-Roles, Content-Type' always;
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Length' 0;
return 204;
}

# CORS headers on all responses
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'X-Org-Id, X-Project-Id, X-Space-Id, X-User-Id, X-User-Roles, Content-Type' always;

proxy_pass http://127.0.0.1:3045/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 30s;
proxy_connect_timeout 10s;
}
}

# Redirect HTTP to HTTPS
server {
listen 80;
server_name your-domain.com;
return 301 https://$host$request_uri;
}

Test and reload nginx:

nginx -t && nginx -s reload

Step 7 — Verify End to End

# Health check — should return 200
curl -I https://your-domain.com/minimal/api/rest/auto/v1/ms/demo_db/users?pg=0&ps=1 \
-H 'X-Org-Id: <your-org-id>' \
-H 'X-Project-Id: <your-project-id>' \
-H 'X-Space-Id: <your-space-id>' \
-H 'X-User-Id: <your-user-id>' \
-H 'X-User-Roles: admin'

Logs

# Live logs
journalctl -u minimal -f

# Last 100 lines
journalctl -u minimal -n 100

# Logs since last boot
journalctl -u minimal -b

Managing the Service

# Stop
systemctl stop minimal

# Restart
systemctl restart minimal

# Reload config without full restart
systemctl reload minimal

# Disable from starting on boot
systemctl disable minimal

Upgrading Minimal

# Stop the service
systemctl stop minimal

# Replace the binary
wget https://releases.littlebit.in/minimal/latest/minimal-linux-amd64 -O /opt/minimal/minimal
chmod +x /opt/minimal/minimal

# Start again
systemctl start minimal

# Confirm new version
/opt/minimal/minimal --version

Common Deployment Issues

SymptomCauseFix
Service fails to startConfig file not foundCheck path in ExecStart matches actual config location
connection refused on port 3045Service not runningRun systemctl status minimal and check logs
502 Bad Gateway from nginxMinimal not running or wrong portConfirm proxy_pass port matches service.port in config
CORS errors in browserOPTIONS preflight not handledEnsure the if ($request_method = 'OPTIONS') block is in nginx config
Definition store connection failsWrong DB credentials or DB not runningTest DB connection manually with mysql -u minimalist -p minimal