In production, submilli-server runs on a dedicated machine, and your
application calls it over the network. On Linux, run it like any other
service. It runs under systemd as a dedicated user, with the binaries in
/usr/local/bin, the configuration in /etc/submilli, and the state in
/var/lib/submilli.
This guide shows you how to set that up on Linux. The config file is the one Run the server builds, and this page decides where everything lives. If your application runs in containers, use Deploy with Compose. On Kubernetes, use Deploy on Kubernetes.
Install for the system
Section titled “Install for the system”The install script puts the binaries under your home directory unless told otherwise. The published Linux binaries require x86-64. For a service, put them where all users find them:
curl -fsSL https://submilli.ai/install.sh | sudo sh -s -- --install-dir /usr/local/binCreate the user and the directories
Section titled “Create the user and the directories”The server needs no privileges, so give it a system user that can’t log in, with the state directory as its home, and a configuration directory it can read:
sudo useradd --system --home-dir /var/lib/submilli --create-home --shell /usr/sbin/nologin submillisudo install -d -o submilli -g submilli -m 0750 /etc/submilliPlace the config and token files
Section titled “Place the config and token files”Generate the admin token, the application’s token, and the secret
store’s key into /etc/submilli, readable only by the server’s user:
sudo sh -c 'openssl rand -hex 32 > /etc/submilli/admin.token'sudo sh -c 'openssl rand -hex 32 > /etc/submilli/app.token'sudo sh -c 'head -c 32 /dev/urandom | base64 > /etc/submilli/store.key'sudo chown submilli:submilli /etc/submilli/admin.token /etc/submilli/app.token /etc/submilli/store.keysudo chmod 0400 /etc/submilli/admin.token /etc/submilli/app.token /etc/submilli/store.keyThen write the config file, with your editor or with tee as below,
with the paths of those three files in it. Your application is on
another machine, so the server listens on all interfaces. An application
that connects over MCP needs the name it will use for this machine under
mcp_allowed_hosts. hostname -f gives the machine’s name, which is
that name unless you point a DNS alias at it. The state directories
aren’t in the file. They keep their defaults under the state directory,
which the server takes from the SUBMILLI_HOME environment variable
(~/.submilli when it is unset). The unit below sets it to
/var/lib/submilli:
sudo tee /etc/submilli/server.yaml >/dev/null <<EOFbind: 0.0.0.0api_tokens: - name: admin role: admin token_file: /etc/submilli/admin.token - name: app role: user token_file: /etc/submilli/app.tokensecret_store: key_file: /etc/submilli/store.keymcp_allowed_hosts: - $(hostname -f):8128EOFRun it under systemd
Section titled “Run it under systemd”Write the unit the same way:
sudo tee /etc/systemd/system/submilli.service >/dev/null <<'EOF'[Unit]Description=Submilli serverAfter=network-online.targetWants=network-online.target
[Service]User=submilliGroup=submilliEnvironment=SUBMILLI_HOME=/var/lib/submilliExecStart=/usr/local/bin/submilli-server --config /etc/submilli/server.yamlRestart=on-failureTimeoutStopSec=10
[Install]WantedBy=multi-user.targetEOFOn stop, systemd sends SIGTERM and the server waits up to five seconds
for running requests to finish. Requests still running after that grace
period are cancelled and their connections dropped. TimeoutStopSec
gives the server that grace period and a margin to exit before systemd
forces it to stop.
sudo systemctl daemon-reloadsudo systemctl enable --now submillisudo journalctl -u submilliThe journal holds the server’s log, starting with the two lines Run the server shows at start-up. Check it from your shell with the admin token:
sudo submilli server status --token-file /etc/submilli/admin.tokenYour application connects to http://<the machine's name>:8128 with
the value in /etc/submilli/app.token, given to it through whatever keeps
its other secrets. From your machine, Connect the
CLI reaches the server with the
admin token. Register Blueprints, store their secrets, and install their
Packages as Register a Blueprint
shows. A deploy job does the same with the admin token, and Manage
Blueprints in Git builds one.
Enable HTTPS
Section titled “Enable HTTPS”Your application reaches this machine over the network, so its API token crosses that network with every request. Over plain HTTP anyone on the way can read it. Turn HTTPS on unless you control the network between the two end to end.
Put the certificate chain and its private key, in PEM, at
/etc/submilli/server.crt and /etc/submilli/server.key. Use a
certificate from your certificate authority, issued for the host name
your application connects to. To try it first, generate a self-signed
one for this machine’s name:
sudo openssl req -x509 -newkey rsa:2048 -nodes -days 365 \ -keyout /etc/submilli/server.key -out /etc/submilli/server.crt \ -subj "/CN=$(hostname -f)" \ -addext "subjectAltName=DNS:$(hostname -f)" \ -addext 'basicConstraints=critical,CA:FALSE'Give the server read access:
sudo chown submilli:submilli /etc/submilli/server.crt /etc/submilli/server.keysudo chmod 0400 /etc/submilli/server.crt /etc/submilli/server.keyAdd the TLS block to /etc/submilli/server.yaml:
tls: cert_file: /etc/submilli/server.crt key_file: /etc/submilli/server.keyRestart and watch the journal:
sudo systemctl restart submillisudo journalctl -u submilli -fWait for a new submilli-server listening line with protocol=https,
then press Ctrl+C to stop following the journal. systemctl restart
can return before the server is ready to accept connections. Connect
using HTTPS on the same port:
sudo submilli server status --server "https://$(hostname -f):8128" --token-file /etc/submilli/admin.tokenUpdate your application’s URL to https://<hostname>:8128, and restart
the service after you replace the certificate. For a self-signed
certificate, the CLI asks you to check and trust its fingerprint, as
Connect the
CLI
shows. Your application trusts a self-signed certificate the way its language
does. Node adds the file to the authorities it already trusts with
NODE_EXTRA_CA_CERTS:
export NODE_EXTRA_CA_CERTS=$PWD/server.crtPython’s SSL_CERT_FILE replaces those authorities, so a
Python application that also calls its model provider over HTTPS needs a
bundle that holds both:
cat "$(python -m certifi)" server.crt > ca-bundle.pemexport SSL_CERT_FILE=$PWD/ca-bundle.pemReach an internal service
Section titled “Reach an internal service”The server blocks programs from calling private addresses, whatever a Blueprint allows, so a Package that calls a service on your private network fails until you allow that address in the config file:
network: allow_ip: - 10.0.12.7Allow the single address. allow_private opens your entire internal
network. The server settings
reference covers the block and its settings.
Upgrade and back up
Section titled “Upgrade and back up”To upgrade, run the installer again and restart the service:
curl -fsSL https://submilli.ai/install.sh | sudo sh -s -- --install-dir /usr/local/binsudo systemctl restart submilliBack up /var/lib/submilli with the rest of the machine. /etc/submilli
holds the store’s key and the tokens. Leave it out of that backup and
keep its contents in your secrets manager. The encryption is only worth
having while the key stays apart from the store.