Deploy a NixOS machine from a nix flake.
Pick a flake and a size. nixoku provisions the VM, boots NixOS, applies your flake's module and serves the machine over HTTPS at a name of its own.
./my-flake
your flake: a folder or github:you/repo
--size small
how much machine you need
You decide two things
nixoku names the machine for you, with a hyphenated name like
quiet-otter. Everything after that is nixoku's
job.
- A flake
-
Any flake reference nix understands, such as
github:you/repo, or a local folder the CLI uploads for you. It exportsnixosModules.default, and that is the whole contract. - A size
- How much machine you need. Your flake is built on the machine itself, so even the smallest size has room for nix to work.
Where it runs
One flake, any cloud. Google Cloud is live now; the others are on the way.
-
Google Cloud
Available now
-
AWS
Coming soon
-
DigitalOcean
Coming soon
-
Hetzner
Coming soon
What you get
- NixOS, ready for flakes
- A NixOS base image with flakes on.
- A name on the internet
-
Every machine gets a generated name such as
quiet-otter.nixoku.com, pointing at its address. - HTTPS by default
-
Every machine is served over HTTPS at its name, with a Let's Encrypt certificate.
Set
nixoku.web.portto the port your app listens on and nixoku proxies to it. - SSH as
nixoku -
nixoku ssh quiet-otterlogs you in with your own key as thenixokuuser, who has sudo. - Logs as they happen
- Provisioning, boot and the rebuild stream live to your terminal and to the web app, line by line.
- Redeploy and destroy
-
nixoku redeployapplies a new revision to the same machine.nixoku destroydeletes the VM and its DNS record. - Checkpoints built in
-
Every deploy and redeploy is a new NixOS generation, a complete checkpoint of the
system. If a change goes wrong,
nixoku rollback quiet-otterswitches back to the previous one. Generations are kept for two weeks.
Quick start
This is all you write
Your flake exports one module. It runs your app on a local port and tells nixoku which one to serve over HTTPS.
# flake.nix
outputs = { self, nixpkgs }: {
nixosModules.default = ./module.nix;
};
Python. The module from
examples/hello-app: Python serves a
page on port 8000.
# module.nix
{ pkgs, config, ... }:
{
nixoku.web.port = 8000;
systemd.services.hello-app = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.python3}/bin/python3 -m http.server 8000 --bind 127.0.0.1 --directory ${
pkgs.writeTextDir "index.html" "hello app via nixoku (${config.nixoku.fqdn})\n"
}";
DynamicUser = true;
Restart = "on-failure";
};
};
}
TypeScript.
server.ts sits next to the module.
Node 24 runs TypeScript as is, so there is no build step.
# module.nix
{ pkgs, ... }:
{
nixoku.web.port = 3000;
systemd.services.app = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
# Node 24 runs TypeScript directly (type stripping), no build step.
ExecStart = "${pkgs.nodejs_24}/bin/node ${./server.ts}";
DynamicUser = true;
Restart = "on-failure";
};
};
}
Go.
go.mod and
main.go sit next to the module; nix
builds the binary.
# module.nix
{ pkgs, ... }:
let
app = pkgs.buildGoModule {
pname = "app";
version = "0.1.0";
src = ./.; # go.mod (module app) and main.go
vendorHash = null; # no dependencies; set the hash once you add some
};
in
{
nixoku.web.port = 8080;
systemd.services.app = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${app}/bin/app";
DynamicUser = true;
Restart = "on-failure";
};
};
}
Rust.
Cargo.toml,
Cargo.lock and
src/ sit next to the module; nix
builds the binary.
# module.nix
{ pkgs, ... }:
let
app = pkgs.rustPlatform.buildRustPackage {
pname = "app";
version = "0.1.0";
src = ./.; # Cargo.toml (package "app"), Cargo.lock, src/
cargoLock.lockFile = ./Cargo.lock;
};
in
{
nixoku.web.port = 8080;
systemd.services.app = {
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${app}/bin/app";
DynamicUser = true;
Restart = "on-failure";
};
};
}
Then, from your terminal
nixoku login opens the browser so you can
approve the CLI once. No keys to paste.
nixoku deploy prints the machine's
generated name; use it for the rest.
nixoku login # approve in the browser
nixoku deploy ./my-flake --size small
nixoku logs quiet-otter -f # follow the build
nixoku ssh quiet-otter
nixoku rollback quiet-otter # previous generation
nixoku destroy quiet-otter
When the deploy finishes, the CLI prints your machine's HTTPS address. Prefer clicking? The same steps work in the web app.
Join the waiting list
nixoku is opening up in small batches. Leave your email and we'll write when there is room for you. Nothing else goes to that address.
You're on the list. We'll email you when there's room.