An OpenBSD web server in one ssh command
Sign up with an invite, boot a VM that serves a page, stop it, start it, remove it.
One ssh command creates an OpenBSD VM, runs a script on its first boot and leaves httpd answering at https://web.chroot.run. From my connection in Brazil it took 0.9 s.
This post walks through the whole life of that VM on the 14-day trial: sign up, create it, look at the page, stop and start it, remove it. Every command after the sign-up was run against chroot.dev while writing this post; the outputs are from those runs, minus the login token and my other VMs.
SIGN UP WITH THE INVITE CODE
During the beta, accounts are created by invitation: ask at invite@chroot.dev and you get a one-time code by email.
Before the first connection, check the host key. chroot.dev and chroot.run share one:
$ ssh-keyscan -t ed25519 chroot.dev 2>/dev/null | ssh-keygen -lf - 256 SHA256:y0rdGMRXmIFbxKPP6Qhmcx6Npr/rH8PdfYEgv+zehoo chroot.dev (ED25519)
Then connect with the key you want on the account and type the code:
$ ssh -t -o IdentitiesOnly=yes -i ~/.ssh/id_ed25519 chroot.dev invite: code email: alice@example.org (from the invite) user: alice
The -o IdentitiesOnly=yes -i part matters if your agent holds more than one key. ssh offers them in order and the first one accepted wins, so name the key you mean. After this, plain ssh chroot.dev works.
The trial lasts 14 days and gives you 1 VM, 1 cpu, 512 MiB of memory, 5 GiB of disk and 10 GiB of traffic. ssh chroot.dev whoami shows the limits and what you use.
CREATE A VM THAT SERVES A PAGE ON ITS FIRST BOOT
Put the setup in a file. It runs once, as the user puffy, on the first boot, and puffy has doas(1) without a password:
$ cat setup.sh echo 'server "web" { listen on * port 80 }' | doas tee /etc/httpd.conf >/dev/null echo 'hi g33ks =]' | doas tee /var/www/htdocs/index.html >/dev/null doas rcctl enable httpd doas rcctl start httpd
The same file is at https://chroot.dev/blog/quickstart/setup.sh. Create the VM with it:
$ ssh chroot.dev new -n web -w -s /dev/stdin < setup.sh web 10.201.0.6 ssh in 758 ms
-n web names the VM; the name is also its hostname and its HTTPS name. -w waits until ssh on the VM answers and prints how long that took. -s /dev/stdin reads the first-boot script from the redirect.
Port 80 is where the HTTPS proxy sends requests by default, so there is nothing else to configure. httpd(8) could listen elsewhere, and ssh chroot.dev share port web 8080 would point the proxy there.
-w waits for ssh, not for the script. This one was done before my first request, but a script that runs pkg_add(1) takes longer, so poll the page instead of assuming it is up.
LOG IN
$ ssh vm+web@chroot.run uname -a OpenBSD web 8.0 MICROVM#10 amd64
vm+NAME@chroot.run is the whole addressing scheme. Your ssh talks to chroot.run, which reaches the VM over the internal network, so you never see or accept a per-VM host key. Leave the command out for a shell.
THE PAGE IS PRIVATE UNTIL YOU SHARE IT
https://web.chroot.run has a valid certificate from the start, but only you get through. A browser has no ssh key, so it logs in with a one-time link:
$ ssh chroot.dev browser https://chroot.dev/__fcm/auth?t=...
Open the link and press Log in: from then on the proxy knows that browser on every VM you can reach. curl has no session, so it gets the redirect to the login:
$ curl -s -o /dev/null -w '%{http_code}\n' https://web.chroot.run 303
To let everyone see the page:
$ ssh chroot.dev share set-public web $ curl https://web.chroot.run hi g33ks =]
share add web bob lets one other user in instead, and share set-private web goes back. website(7) has the rest, including the header that tells your application who is logged in.
STOP AND START: THE DISK STAYS
$ ssh chroot.dev stop web $ ssh chroot.dev ls NAME STATE IP CPUS MEM DISK IMAGE web stopped 10.201.0.6 1 128 0 base $ curl https://web.chroot.run <!doctype html> <meta charset=utf-8> <title>chroot.dev</title> <pre>web: VM stopped</pre>
stop is a clean shutdown and took 5 s. The proxy answers 503 with the reason while the VM is down.
$ ssh chroot.dev start web $ curl https://web.chroot.run hi g33ks =]
start returned in 0.2 s, and httpd answered under a second later; a request in between gets 502 with web: port 80 not responding. The disk kept the httpd.conf and rcctl enable brought httpd back. A stopped VM still counts against the trial's 1 VM and 5 GiB, so remove the ones you are done with.
REMOVE IT
$ ssh chroot.dev rm web $ curl https://web.chroot.run <!doctype html> <meta charset=utf-8> <title>chroot.dev</title> <pre>web: does not exist (ref 1f296e21)</pre>
The proxy answers 404 for a name that does not exist. rm destroys the VM and its disk. There is no undo and there are no backups yet, so keep a copy of anything you care about.
WHERE TO GO FROM HERE
- cp(1) copies a running VM, memory included: the copy comes up with httpd already running.
- api(7) runs the same commands over HTTPS with a token, for scripts and CI.
- billing(1) has the plans for after the trial, from US$ 5 a month.
- intro(1) is the start of the manual;
curl chroot.dev/man/introgives it as text.
Invites: invite@chroot.dev. Questions: contact@chroot.dev.
AUTHORS
Murilo Ijanc