Getting started
From an installed binary to a running server: the service account, memory locking, the master key, a certificate, the configuration, the first tenant and its keys, and the server started under systemd or in the foreground.
This page takes a host with vcon-server installed to a running server that
answers a health check. Paste the commands in order, in one shell:
later steps use shell variables that earlier steps set. CI runs
the page from top to bottom on each change. It runs in a fresh Debian 13
container and a fresh Fedora 44 container, each with the server in the
foreground, and in a Debian 13 container under systemd.
Before you start
-
The binary.
vcon-server --versionprints its version. If it does not, follow install first. -
sudo,curl,opensslandjq. The steps below use all four. A minimal Debian or Ubuntu has none of them.procpsprovideskill, which stops a server that runs without systemd. As root, on Debian or Ubuntu:apt-get update -qq apt-get install -y -qq sudo curl openssl jq ca-certificates procps >/dev/nullOn Fedora, as root. There,
procps-ngprovidespidof, anddiffutilsprovidescmp, which compares a vCon read back with the one sent:dnf install -y -q sudo curl openssl jq procps-ng diffutils -
A name for the server. Clients reach the server by a DNS name that its certificate holds. This page uses
vcon.example.com. Write your own name wherever it appears.
Make the service account and its directories
The server runs as its own account, vcon. That account owns the data
directory and the files in /etc/vcon-server:
sudo useradd --system --user-group --no-create-home --home-dir /var/lib/vcon-server --shell /usr/sbin/nologin vcon
sudo install -d -m 0700 -o vcon -g vcon /var/lib/vcon-server
sudo install -d -m 0700 -o vcon -g vcon /etc/vcon-server
The server makes everything inside the data directory.
Allow it to lock its memory
At start the server locks all of its memory, so that no key or vCon body can
reach swap, and it turns core dumps off. It refuses to start if it cannot
lock its memory. Every other vcon-server command does the same, so the
account that runs them needs the same allowance. The
systemd unit below allows it for the server. For
the commands you run by hand, allow it for the vcon account:
echo 'vcon - memlock unlimited' | sudo tee /etc/security/limits.d/vcon-server.conf
vcon - memlock unlimited
sudo -u vcon then applies it, through pam_limits. Check it:
sudo -u vcon bash -c 'ulimit -l'
unlimited
Where the limit stays too small, every command stops with this error:
vcon-server: memory cannot be locked: Cannot allocate memory (os error 12); allow it, for example LimitMEMLOCK=infinity
In a container, the limits file cannot raise the limit past the container's
own. Start the container with --ulimit memlock=-1, as
running it in a container shows.
Run every command as vcon, with sudo -u vcon, never as root. A command
run as root leaves files in the data directory that vcon cannot open. The
server then refuses to start, with
the data directory cannot be locked: Permission denied (os error 13), or,
for a tenant made as root,
1 tenant catalog(s) cannot be opened: Permission denied (os error 13).
vcon-server check names the path. Give the files back to vcon:
sudo chown -R vcon:vcon /var/lib/vcon-server
Make the master key
The master key is a file of exactly 32 random bytes. It wraps every tenant key and opens the server's own catalog, so whoever holds it can read everything. Keep it on the server, readable only by the service account, and back it up apart from the data (see back up and restore).
head -c 32 /dev/urandom | sudo -u vcon tee /etc/vcon-server/master.key >/dev/null
sudo chmod 0400 /etc/vcon-server/master.key
sudo stat -c '%a %U %s' /etc/vcon-server/master.key
400 vcon 32
The server refuses to start with a file of any other length. It also refuses a key other than the one it made the data directory under.
The key's id is the first 16 hexadecimal digits of its SHA-256. It is the
master_key_id that vcon-server rekey master prints. Label each copy of
the key with it:
sudo sha256sum /etc/vcon-server/master.key | cut -c1-16
<master key id>
Get a certificate
The API is served over TLS only, with HTTP/2 and HTTP/1.1. The server needs
a PEM certificate chain and its PEM private key, readable by the service
account. With a certificate from your certificate authority or ACME client,
install the two files as cert.pem and key.pem:
sudo install -m 0400 -o vcon -g vcon fullchain.pem /etc/vcon-server/cert.pem
sudo install -m 0400 -o vcon -g vcon privkey.pem /etc/vcon-server/key.pem
The server reads them at start only. After a renewal, install the new files and restart it.
To try the server before you have a certificate, make a self-signed one for
the name that clients use, and install it the same way. By default
openssl req -x509 marks the certificate as a certificate authority
(CA:TRUE), and vcon-server mcp, which is built on rustls, refuses such a
certificate from a server. The -addext options below mark it CA:FALSE,
for signatures, and for a TLS server:
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -days 30 \
-subj /CN=vcon.example.com -addext subjectAltName=DNS:vcon.example.com \
-addext basicConstraints=critical,CA:FALSE -addext keyUsage=critical,digitalSignature -addext extendedKeyUsage=serverAuth \
-keyout privkey.pem -out fullchain.pem 2>/dev/null
sudo install -m 0400 -o vcon -g vcon fullchain.pem /etc/vcon-server/cert.pem
sudo install -m 0400 -o vcon -g vcon privkey.pem /etc/vcon-server/key.pem
sudo install -d -m 0755 /usr/local/share/vcon-server
sudo install -m 0644 fullchain.pem /usr/local/share/vcon-server/ca.pem
openssl x509 -in fullchain.pem -noout -subject -ext subjectAltName,basicConstraints
subject=CN=vcon.example.com
X509v3 Subject Alternative Name:
DNS:vcon.example.com
X509v3 Basic Constraints: critical
CA:FALSE
Clients then need the certificate to trust it. The server's copy,
/etc/vcon-server/cert.pem, is readable by vcon only, so the commands
above also install a copy for clients at /usr/local/share/vcon-server/ca.pem, readable by
every account. The curl commands on these pages pass it with
--cacert /usr/local/share/vcon-server/ca.pem, an absolute path, so they work from any
directory. With a certificate from a public certificate authority, leave
--cacert /usr/local/share/vcon-server/ca.pem out.
Write the configuration
The configuration is one TOML file. It must set these keys. Every other
key has a default (see configuration). Save this
as vcon-server.toml:
listen = "0.0.0.0:8443"
data_dir = "/var/lib/vcon-server"
master_key = "/etc/vcon-server/master.key"
[tls]
cert = "/etc/vcon-server/cert.pem"
key = "/etc/vcon-server/key.pem"
Install it where the server reads it:
sudo install -m 0400 -o vcon -g vcon vcon-server.toml /etc/vcon-server/vcon-server.toml
Make the first tenant and its keys
Every vCon belongs to a tenant, and every request carries a bearer key. Make
the first tenant before you start the server: tenant create runs only
while no server does. It prints the new tenant's id:
sudo -u vcon vcon-server tenant create acme --config /etc/vcon-server/vcon-server.toml
{"id":"<tenant id>"}
Keep the id in a variable for the next steps:
TENANT=$(sudo -u vcon vcon-server tenant list --config /etc/vcon-server/vcon-server.toml | jq -r 'select(.name == "acme") | .id')
echo "$TENANT"
<tenant id>
Then make three keys. Each key create prints one JSON line, such as
{"id":"5b0c3f9a1d2e4f60","token":"vcs_5b0c3f9a1d2e4f60_…"}. The commands
below keep each token in a variable. The server shows a token this once
and keeps only its hash, so store each one where its holder keeps secrets.
- An operator key (scope
admin) manages tenants and keys over the admin routes. It never reaches a vCon. - A write key,
recorder-1, for a producer that stores vCons. - A read key,
monitor, for the health check.
OPS=$(sudo -u vcon vcon-server key create --operator --label ops --config /etc/vcon-server/vcon-server.toml | jq -r .token)
RECORDER=$(sudo -u vcon vcon-server key create --tenant "$TENANT" --scope write --label recorder-1 \
--config /etc/vcon-server/vcon-server.toml | jq -r .token)
MONITOR=$(sudo -u vcon vcon-server key create --tenant "$TENANT" --scope read --label monitor \
--config /etc/vcon-server/vcon-server.toml | jq -r .token)
sudo -u vcon vcon-server key list --config /etc/vcon-server/vcon-server.toml | jq -c '{label, scopes}'
{"label":"ops","scopes":["admin"]}
{"label":"recorder-1","scopes":["write"]}
{"label":"monitor","scopes":["read"]}
key create also runs while the server runs. Once the server runs, more
tenants come from POST /admin/tenants, with the operator key. See the
admin routes. The
command line and
tenants and keys pages describe every command
and scope.
Start it with systemd
On a host with systemd, save this unit as
/etc/systemd/system/vcon-server.service. LimitMEMLOCK=infinity allows
the server to lock its memory:
[Unit]
Description=vcon-server
After=network-online.target
[Service]
User=vcon
Group=vcon
ExecStart=/usr/local/bin/vcon-server serve --config /etc/vcon-server/vcon-server.toml
LimitMEMLOCK=infinity
Restart=on-failure
[Install]
WantedBy=multi-user.target
Start it, now and at each boot:
sudo systemctl daemon-reload
sudo systemctl enable --now vcon-server
The server logs structured lines to standard error, which the journal keeps.
It logs serving once it listens, a line per request, and stopped after
SIGTERM or SIGINT. Wait for the serving line:
timeout 30 sh -c 'until sudo journalctl -u vcon-server -o cat | grep -q serving; do sleep 1; done'
sudo journalctl -u vcon-server -o cat | grep vcon_server
<time> INFO vcon_server::serve: serving listen=0.0.0.0:8443
<time> INFO vcon_server::serve: purge sweep purged=0 failed=0
systemctl status vcon-server shows whether it runs. When it does not,
journalctl -u vcon-server shows why.
Start it without systemd
On a host or in a container without systemd, run the server as vcon in
the foreground. The limits file allows it to
lock its memory:
sudo -u vcon vcon-server serve --config /etc/vcon-server/vcon-server.toml
<time> INFO vcon_server::serve: serving listen=0.0.0.0:8443
<time> INFO vcon_server::serve: purge sweep purged=0 failed=0
…
<time> INFO vcon_server::serve: stopped
It keeps the terminal and logs there. Leave it running, and open a second
terminal for the next steps. To keep it running after you log out, run it
under your init system or a supervisor, with the same command, as vcon,
and with a memory-lock limit of unlimited. A
container is one way.
When it does not start
It refuses to start, with the reason on standard error, when:
- the configuration is wrong. The error names the key.
- the master key is not the data directory's.
- memory cannot be locked, or core dumps cannot be turned off.
- another server already holds the data directory.
- a tenant's data is not all under its current key, because a key rotation
stopped part way. Run the rotation again;
vcon-server checknames the tenants.
Check that it answers
The certificate names vcon.example.com. Until DNS gives that name to this
host, add it to /etc/hosts on the host you test from:
echo '127.0.0.1 vcon.example.com' | sudo tee -a /etc/hosts
127.0.0.1 vcon.example.com
Ask for the server's health with the monitor key:
curl -sS --cacert /usr/local/share/vcon-server/ca.pem https://vcon.example.com:8443/health -H "Authorization: Bearer $MONITOR"
{"status":"ok"}
Without a key, the answer is 401, as an RFC 9457 problem document:
curl -sS --cacert /usr/local/share/vcon-server/ca.pem https://vcon.example.com:8443/health
{"status":401,"title":"A valid bearer key is needed","type":"https://vcon-server.com/problems/unauthorized"}
Stop it and start it again
SIGTERM or SIGINT stops the server. It logs stopped and exits. Under
systemd:
sudo systemctl stop vcon-server
sudo journalctl -u vcon-server -o cat | grep -c 'vcon_server::serve: stopped'
1
In the foreground, press Ctrl-C in its terminal. From another terminal, send it SIGTERM and wait until it has exited:
sudo kill -TERM "$(pidof vcon-server)"
while pidof vcon-server >/dev/null; do sleep 0.2; done
Every write is crash-safe, so a kill or a power cut loses at most the
requests not yet answered. Start it again, under systemd. systemctl start
returns before the server listens, so the second command waits until it
answers:
sudo systemctl start vcon-server
timeout 30 sh -c 'until curl -s -o /dev/null --cacert /usr/local/share/vcon-server/ca.pem https://vcon.example.com:8443/health; do sleep 1; done' && echo answering
answering
Or in the foreground:
sudo -u vcon vcon-server serve --config /etc/vcon-server/vcon-server.toml
<time> INFO vcon_server::serve: serving listen=0.0.0.0:8443
…
The tenant and the keys are still there:
curl -sS --cacert /usr/local/share/vcon-server/ca.pem https://vcon.example.com:8443/health -H "Authorization: Bearer $MONITOR"
{"status":"ok"}
Next
- Store your first vCon: store, read, list and delete a vCon, with a key for each scope.
- The how-to guides: keys and scopes, a second tenant, key rotation, backups, containers and upgrades.
- Operations: the data directory, logs, health checks, backups and key rotation.
- Configuration: every key, and its default.
Source of this page: website/content/docs/getting-started.md