Servers, databases and caches
This handbook covers MixEngine through the
mixcommand line. If you would rather work in a graphical interface, download the MixDB app at https://lab.mixnz.com/#mixdb. MixDB drives the same MixEngine, so everything in this handbook still applies.
Two words, kept apart the way MixEngine keeps them apart.
A package is a program MixEngine knows how to run — Caddy, MariaDB, Redis. Installing one puts a copy of it in MixEngine's own directory and does nothing else.
A service is a running instance of a package: a port, a data directory, a generated
configuration, a log, and a state. mariadb@main and mariadb@legacy are two services of one
package, with different ports, different data and possibly different versions.
What is on offer
| Service | Default line | Default port |
|---|---|---|
| Caddy | 2.x | 80 and 443 — the default front end |
| Nginx | 1.27 | 80 and 443 — the alternative, one front end at a time |
| php-fpm | one per installed PHP | a socket, or a local port on Windows |
| MariaDB | 11.4 LTS | 3306 |
| MySQL | 8.4 LTS | 3306 — a different product from MariaDB, not a version of it |
| PostgreSQL | 16 | 5432 |
| Redis | 7.x | 6379 |
| Memcached | 1.6 | 11211 |
Nothing arrives by itself. A fresh MixEngine has no web server until you install one, and "default" above means the one this project recommends when there is a choice, not the one that is already there.
Installing and creating
mix package available
mix package install mariadb 12.3.2
mix service create mariadb@main 12.3.2
The part of a service id before the @ is the package it is an instance of, which is why
mix service create needs no separate argument for it. The part after the @ is yours: it is what
tells two of them apart, and MixEngine attaches no meaning to the words. Caddy runs once for a whole
MixEngine home, so its service is simply caddy with no @ at all.
The id cannot be changed afterwards — it is also the generated configuration directory, the log directory, the socket and the address the password is stored at — so renaming one means creating the other and deleting this one, which keeps the data.
Useful flags on mix service create:
| Flag | What it does |
|---|---|
--port | The port it listens on. The recipe's own default when left out |
--bind | The address it binds. 127.0.0.1 when left out |
--data-dir | Where its data lives. A directory under the home when left out |
--autostart | Start it whenever the daemon starts |
Who gets 3306
MariaDB and MySQL want the same port, and so do two instances of either. The rule is one rule: first created, first served. The first to ask for 3306 gets it; the next gets the first free port above. MixEngine reports the port it chose, because a port you did not pick is one you have to be told about.
A port you name explicitly is taken at your word, with no allocation at all.
One data directory, one service
mix service create refuses a --data-dir another service already holds, and names who holds it.
Two servers over one set of files corrupt them, and that cost lands on your data rather than on a
start that fails.
Running them
mix service list
mix service status mariadb@main
mix service start mariadb@main
mix service stop mariadb@main
mix service logs mariadb@main --follow
mix service status requires an id where start and the rest take an optional one: a status with
no subject is a list typed wrongly, and answering it as a list would hide that.
Deleting a service takes the row and the configuration generated from it, and never the data — that is somebody's databases. The answer names the directory that was left, so nobody has to go looking:
mix service delete mariadb@legacy
Databases and accounts
Making a database is one command, and it starts the server if it is not running:
mix database create mariadb@main --name blog
mix database create mariadb@main --name shop --user shop_app
Nothing prints the password by default. It is generated and put into your operating system's own credential store — Credential Manager on Windows, the Keychain on macOS, the Secret Service on Linux — and what is printed is the address it was stored at, as the store's own name and key. That is what lets a client tell you "stored in your credential store as …" without anybody hardcoding MixEngine's naming.
When a project needs the password itself — most often for a .env file — mix database credentials prints it, and --password on create lets you choose it instead of letting MixEngine
generate one:
mix database credentials mariadb@main --user blog
mix database create mariadb@main --name shop --user shop-app --password
Without a value, --password prompts and reads one line from standard input, so it also works
piped: echo secret | mix database create … --password. Choosing a password for an account you
already made changes what is stored, and the server is realigned to it the same way it already is
when a password drifts — but an account already on the server that MixEngine holds no credential for
is still refused, even with the correct password: knowing a password is not what makes it yours.
To open the database in a desktop client:
mix database client mariadb@main # what is installed, and where this system looked
mix database open mariadb@main # open it
client reads only: it starts nothing and opens nothing, and "no client installed" is an answer
rather than a failure — it names where MixEngine looked and where to get one.
open starts the instance if it is stopped, reads the password from the credential store at that
moment, and hands it to the client in that process's own environment. It is never printed, never
put in an argument, and so never in your shell history.
What a service may take, and when it stops
mix service limits mariadb@main
mix service limits mariadb@main set --memory 512 --cpu 50
mix service idle mariadb@main --after 30m
limits with no subcommand reads; set replaces; clear removes. set replaces every field,
not only the ones you name — set --cpu 50 clears a memory ceiling that was there — so it prints
all three fields of the result, and a cleared limit is on your screen rather than a surprise. What
your operating system will actually enforce differs, and the answer says which of the two you have:
a hard ceiling is a wall — at it, the service is killed or its next allocation fails — while an
advisory one is a watched line the service may cross, after which MixEngine warns and, where the
recipe permits, restarts. A control drawn as a guarantee when it is advisory would be a lie about
your data.
idle says when a service is stopped for being unused, and what is currently holding it open.
Nothing idles by default: a stopped service stays stopped until you start it, so switching this
on is a choice you make per service.
The generated configuration
MixEngine writes the configuration for every service it runs, out of what it knows. Those files are disposable — they are regenerated, never read back — so there is nothing there for you to edit and nothing to keep in sync. If a setting you need has no flag, that is a gap in MixEngine rather than an invitation to edit the file.
This page as Markdown: https://mixnz.github.io/mixengine/en/services.md