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
| Requirement | Notes |
|---|---|
| Linux server (Ubuntu 20.04+ recommended) | Any linux distro works |
| MySQL / MariaDB / PostgreSQL / Clickhouse | For the definition_store — Minimal's internal metadata database |
| nginx | As a reverse proxy in front of Minimal |
| Port access | Minimal 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: productiondebug_mode: falselog_level: infocors_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
| Symptom | Cause | Fix |
|---|---|---|
| Service fails to start | Config file not found | Check path in ExecStart matches actual config location |
connection refused on port 3045 | Service not running | Run systemctl status minimal and check logs |
502 Bad Gateway from nginx | Minimal not running or wrong port | Confirm proxy_pass port matches service.port in config |
| CORS errors in browser | OPTIONS preflight not handled | Ensure the if ($request_method = 'OPTIONS') block is in nginx config |
| Definition store connection fails | Wrong DB credentials or DB not running | Test DB connection manually with mysql -u minimalist -p minimal |