Files
gokrazy/docs/searchindex.en.js
2026-06-25 19:32:06 +02:00

243 lines
134 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
var relearn_searchindex = [
{
"breadcrumb": "gokrazy Go appliances",
"content": "Prep: pick a supported device Currently, the Raspberry Pi 5 or Pi 4 B are the recommended platform for using gokrazy, but you can find other supported and upcoming platforms.\nPrep: Install Go If you dont already have Go installed, install the latest Go version.\nPrep: Install the gok CLI Now that you have a working Go installation, install the gok command line tool (CLI):\ngo install github.com/gokrazy/tools/cmd/gok@main Step 1: Insert an SD card Run watch -d1 ls -l '/dev/disk/by-id/*' (see the permanent data section for macOS instructions) and insert an SD card. Copy the highlighted device name:\nIn this example, well assume the SD card is accessible as /dev/sdx.\nStep 2: Create a gokrazy instance and overwrite an SD card with gokrazy Create a directory for this gokrazy instance:\ngok new # creates an instance named “hello” in --parent_dir default directory ~/gokrazy # alternatively, to use a different instance name: gok -i myname new The --parent_dir can also be changed permanently by setting the GOKRAZY_PARENT_DIR environment variable.\nIf youre curious, you can run gok edit to open the generated config.json in your editor.\nTo overwrite the entire SD card /dev/sdx with a build of this gokrazy installation, use:\ngok overwrite --full /dev/sdx The following packages are included in newly created instances by default:\ngithub.com/gokrazy/fbstatus github.com/gokrazy/hello github.com/gokrazy/serial-busybox The gokrazy packer builds each specified Go program (e.g. github.com/gokrazy/hello) in a separate build directory, each with its own go.mod file. See Working with Go modules for more details.\nThis is what the above gok commands look like in action:\nClick here to show the gok log output gokrazy gok ga84f00+ on GOARCH=amd64 GOOS=linux Build target: CGO_ENABLED=0 GOARCH=arm64 GOOS=linux Build timestamp: 2023-01-12T23:36:34+01:00 Loading system CA certificates from /etc/ssl/certs/ca-certificates.crt Building 4 Go packages: github.com/gokrazy/fbstatus github.com/gokrazy/hello github.com/gokrazy/serial-busybox github.com/gokrazy/breakglass will be started with command-line flags from /home/michael/gokrazy/hello/config.json last modified: 2023-01-12T23:36:23+01:00 (10s ago) [done] in 1.40s Including extra files for Go packages: github.com/gokrazy/breakglass will include extra files in the root file system from /home/michael/gokrazy/hello/breakglass.authorized_keys last modified: 2023-01-12T23:36:23+01:00 (12s ago) Including loadable kernel modules from: /home/michael/go/pkg/mod/github.com/gokrazy/kernel@v0.0.0-20230111172439-0cd82b0bec82/lib/modules Feature summary: use GPT: true use PARTUUID: true use GPT PARTUUID: true 2023/01/12 23:36:36 partitioning /dev/disk/by-id/usb-TS-RDF5_SD_Transcend_000000000037-0:0 (GPT + Hybrid MBR) 2023/01/12 23:36:36 device holds 15931539456 bytes 2023/01/12 23:36:36 Re-reading partition table failed: permission denied. Remember to unplug and re-plug the SD card before creating a file system for persistent data, if desired. Creating boot file system [creating boot file system] Kernel directory: /home/michael/go/pkg/mod/github.com/gokrazy/kernel@v0.0.0-20230111172439-0cd82b0bec82 EEPROM update summary: pieeprom.upd (sig d1e44edf33) recovery.bin vl805.bin (sig 6246230ecd) [done] in 0.18s, 71 MiB MBR summary: LBAs: vmlinuz=51795 cmdline.txt=144875 PARTUUID: 4f9f2cab Creating root file system [done] in 0.33s If your applications need to store persistent data, unplug and re-plug the SD card, then create a file system using e.g.: mkfs.ext4 /dev/disk/by-partuuid/60c24cc1-f3f9-427a-8199-4f9f2cab0004 To boot gokrazy, plug the SD card into a supported device (see https://gokrazy.org/platforms/) Build complete! To interact with the device, gokrazy provides a web interface reachable at: http://gokrazy:\u003cautomatically-generated-random-password\u003e@hello/ In addition, the following Linux consoles are set up: 1. foreground Linux framebuffer console on HDMI It is safe to unplug your SD card once gok returns.\nStep 3: Boot gokrazy After booting from this SD card, your device will:\ndisplay system status on the monitor connected via HDMI, if any obtain an IP address for hostname “gokrazy” via DHCP (IPv4) and SLAAC (IPv6) synchronize the clock using NTP expose a password-authenticated web interface on private IP addresses\n(each instance gets its own password in the Update → HTTPPassword key of its config.json, see gok edit) supervise all installed programs (only the hello world program in this example) To interact with your device, you can:\nOpen the gokrazy web interface in your browser (easiest option) Attach a serial console (see below) Use the breakglass package to start an interactive SSH session. gok new sets it up by default. Congratulations! 🎉 You now have a working gokrazy installation!\nNext, see the Configuration guide for details on how to use other programs.\nOptional: Using the serial console See also: Configuration → Instance Config Reference → SerialConsole\nIf you prefer the serial console, you can optionally connect a serial adapter to the Raspberry Pi and remove the \"SerialConsole\": \"disabled\" line from your gokrazy instances config.json to make the primary Linux console end up on the serial console.\nWhen pressing Enter on the serial console, gokrazy will interactively start either:\n/tmp/serial-busybox/ash (provided by the serial-busybox package) /perm/sh, if present (supplied by you, the user)",
"description": "Prep: pick a supported device Currently, the Raspberry Pi 5 or Pi 4 B are the recommended platform for using gokrazy, but you can find other supported and upcoming platforms.\nPrep: Install Go If you dont already have Go installed, install the latest Go version.",
"tags": [],
"title": "Quickstart",
"uri": "/quickstart/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Available packages",
"content": "Written for gokrazy The following third-party programs specifically target gokrazy.\nTo get your program listed here, just send us a pull request.\nscan2drive scan2drive is an appliance (with a web interface) that scans paper documents 📄 from a scanner 🖨️ as PDFs to Google Drive for full-text search.\nrouter7 router7 is a small home internet router completely written in Go.\nhmgo hmgo is a minimal HomeMatic house automation central control unit replacement (specific to stapelbergs home network).\nbeatbox beatbox is a Raspberry Pi 3-based toy that combines a Mir:ror and NFC figurines for playing music stored on the device or directly from Spotify.\nconsrv consrv is a Raspberry Pi 4-based appliance that provides a basic SSH to serial console bridge for accessing remote devices.\nkrazyotelcol krazyotelcol is an appliance running the OpenTelemetry Collector, a vendor-agnostic implementation on how to receive, process and export telemetry data.\nRestics rest-server Rest Server is a high performance HTTP server that implements restics REST backend API. Running it requires some setup and other configurations which are available in this blog post.\nwaiw waiw is a Go webserver to store movies/series/animes ratings and comments. Running it requires some setup but the README describes every step to make it work.\nThe relax switch The relax switch is a gokrazy appliance to enhance your bathroom experience. A friend of mine had a hilarious idea: having a dedicated switch in your bathroom that, when switched, would play a 90s relaxing song. The original prototype ran on top of Raspbian OS, but gokrazy is a much better fit for this project. You wire a smart relay to your switch. The switch talks MQTT. When the person turns on the switch, the service running on the Pi plays a 90s relaxing song. When they turn off the switch the music go off. Simple and relaxing.\nSuccessfully tested The following third-party programs have been successfully used with gokrazy but might require additional setup:\nPrometheus Prometheus is a monitoring and alerting system built on a time series database.\nThe Prometheus node exporter exposes various metrics of the system on which it is running for use with the prometheus monitoring and alerting system.\nThe Prometheus blackbox exporter allows blackbox probing of endpoints over HTTP, HTTPS, DNS, TCP and ICMP for use with the prometheus monitoring and alerting system.\nGrafana Grafana is an open platform for beautiful analytics and monitoring.\nMinIO MinIO is a high performance, S3-compatible, cloud native object storage service.\nSee also Available packages → MinIO.\nNo Go software for your idea? You can prototype your idea by temporarily using existing software to close the gap. See Prototyping.",
"description": "Written for gokrazy The following third-party programs specifically target gokrazy.\nTo get your program listed here, just send us a pull request.\nscan2drive scan2drive is an appliance (with a web interface) that scans paper documents 📄 from a scanner 🖨️ as PDFs to Google Drive for full-text search.",
"tags": [],
"title": "Showcase",
"uri": "/packages/showcase/index.html"
},
{
"breadcrumb": "gokrazy Go appliances",
"content": "Recommended: Raspberry Pi 4 or Pi 5 gokrazy development happens primarily on the Raspberry Pi 5, but the Pi 4 is also a great choice!\nAll currently supported platforms Raspberry Pi 5 Raspberry Pi 4B PC Engines APU Raspberry Pi Zero 2W Raspberry Pi 3 B and 3 B+ Continuous Integration (CI) Appliances which are marked in bold are tested in the CI setup on real hardware and gate new kernel and firmware versions, and hence can be considered supported.\nNon-bold appliances are supported in a best-effort way, meaning they might be temporarily broken at HEAD.\nThe leading github.com in front of package import paths has been omitted for space reasons.\nTarget Hardware GOARCH Kernel package Firmware package Appliances apu2c4 apu2c4 amd64 rtr7/kernel rtr7/kernel gokrazy/bakery/cmd/bake rtr7/router7 x86-64 qemu amd64 rtr7/kernel rtr7/kernel gokrazy/bakery/cmd/bake rpi5b raspi5b arm64 gokrazy/kernel.rpi gokrazy/firmware gokrazy/bakery/cmd/bake\nstapelberg/scan2drive rpi4b raspi4b arm64 gokrazy/kernel gokrazy/firmware gokrazy/bakery/cmd/bake\nstapelberg/hmgo rpi3b raspi3b arm64 gokrazy/kernel gokrazy/firmware gokrazy/bakery/cmd/bake rpi3b+ raspi3b+ arm64 gokrazy/kernel gokrazy/firmware gokrazy/bakery/cmd/bake rpizero2w raspizero2w arm64 gokrazy/kernel gokrazy/firmware gokrazy/bakery/cmd/bake Performance The turbojpeg encoding column is the result of running scan2drives turbojpeg micro-benchmark\nThe json column is the result of running the json benchmark from the x/benchmarks repo.\nHardware turbojpeg encoding json raspi5b 0.32s 24ms raspi4b 1.00s 38ms raspi3b 1.05s 216ms raspizero2w 1.04s 184ms Power Usage These power measurements were done using a myStrom WiFi Switch with measurement feature.\nThe Raspberry Pi 4 and Pi 5 were using their original Raspberry Pi power supply, the others were measured with a random USB power supply.\nAn Ethernet cable was connected in all tests, WiFi was not enabled.\nHardware Power Usage (with Ethernet) Power Usage (with HDMI and WiFi) apu2c4 4.0W n/a raspi5b 3.2W 3.5W raspi4b 2.8W 3.3W raspi3b+ 2.5W TODO raspi3b 1.5W TODO raspizero2w 0.8W TODO Hardware Support Hardware WiFi Bluetooth apu2c4 needs card, untested needs dongle, untested raspi3b open or WPA-PSK limited raspi3b+ open or WPA-PSK limited raspi4b open or WPA-PSK limited raspi5b open or WPA-PSK limited raspizero2w open or WPA-PSK limited gokrazy kernel repository map Officially supported kernels These kernels are tested in Continuous Integration.\nThey are built from one of two sources: Either from Raspberry Pis Linux kernel fork, or from the upstream Linux kernel from kernel.org.\nThe upstream Linux kernel gets security fixes the quickest, but the Raspberry Pi Linux kernel supports more Raspberry Pi models (notably the Pi 5, which upstream does not support) and peripherals.\nrepository source devices gokrazy/kernel.rpi Raspberry Pi Pi 3, Pi 4, Pi 5, Pi Zero 2 W gokrazy/kernel kernel.org Pi 3, Pi 4, Pi Zero 2 W gokrazy/kernel.amd64 kernel.org PC x86_64, VMs gokrazy/kernel.arm64 kernel.org PC arm64, VMs Community-supported kernels Independently from the officially supported gokrazy kernels listed above, people of our community provide alternative kernels and firmwares, in order to run gokrazy on unsupported platform or to provide new features. They may not be as thoroughly tested as the official platforms. Please report any issue to their respective repository.\nrepository source devices gokrazy-community/kernel-rpi-os-32 Raspberry Pi Pi 1, Pi 2, Pi 3, Pi 4, Pi 5, Pi Zero W, Pi Zero 2 W (32 bit) anupcshan/gokrazy-odroidxu4-kernel kernel.org Odroid XU4, HC1, HC2 anupcshan/gokrazy-rock64-kernel kernel.org Pine64 Rock64 Community-supported platforms This section provides more details for community-supported platforms.\nCommunity-supported Odroid XU4/HC1/HC2 Odroid XU4/HC1/HC2 is based on a Samsung Exynos 5422 SOC (4 ARM Cortex-A15 cores and 4 ARM Cortex-A7 cores) and has been on the market since ~2016. HC1 and HC2 variants support installing a 2.5/3.5 hard drive on board.\nKernel for these devices is available at github.com/anupcshan/gokrazy-odroidxu4-kernel. This package contains a recent kernel, U-boot and some binary blobs that are required to initiate the boot process. It has been tested against Odroid HC2 hardware with gigabit networking, USB and HDD functional.\nSee github.com/anupcshan/odroidbake for an example on how to create a new disk image.\n{ \"Hostname\": \"odroid\", \"DeviceType\": \"odroidhc1\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"KernelPackage\": \"github.com/anupcshan/gokrazy-odroidxu4-kernel\", \"FirmwarePackage\": \"\", \"EEPROMPackage\": \"\" } Community-supported Rock64 Pine64 Rock64 is based on a Rockchip RK3328 SOC (4 ARM Cortex-A53 cores) and has been on the market since ~2017.\nKernel for these devices is available at github.com/anupcshan/gokrazy-rock64-kernel. This package contains a recent kernel and mainline U-boot required to initiate the boot process. These have been tested against real hardware with gigabit networking and USB working under Gokrazy.\nUsage of eMMC module is not supported yet - github.com/gokrazy/gokrazy/issues/270.\n{ \"Hostname\": \"my-rock64\", \"DeviceType\": \"rock64\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"KernelPackage\": \"github.com/anupcshan/gokrazy-rock64-kernel\", \"FirmwarePackage\": \"\", \"EEPROMPackage\": \"\" }",
"description": "Recommended: Raspberry Pi 4 or Pi 5 gokrazy development happens primarily on the Raspberry Pi 5, but the Pi 4 is also a great choice!\nAll currently supported platforms Raspberry Pi 5 Raspberry Pi 4B PC Engines APU Raspberry Pi Zero 2W Raspberry Pi 3 B and 3 B+ Continuous Integration (CI) Appliances which are marked in bold are tested in the CI setup on real hardware and gate new kernel and firmware versions, and hence can be considered supported.",
"tags": [],
"title": "Supported platforms",
"uri": "/platforms/index.html"
},
{
"breadcrumb": "gokrazy Go appliances",
"content": "After following the Quickstart guide, you should have a working gokrazy instance to further customize.\nThese configuration guides walk you through various topics. If you feel a common use-case should be included here but isnt, please file an issue on GitHub.\nConfiguration guides Instance Config Reference Instance Config Migration Guide Automation Package config: flags, environment variables, extra files DHCP Client Remote Syslog: sending gokrazy logs over the network Connecting to WiFi networks Using TLS in untrusted networks Using Bluetooth Access permanent data NVMe disk (Pi 5) QEMU x86-64 virtual machine Permanent data backup with the gokrazy rsync",
"description": "After following the Quickstart guide, you should have a working gokrazy instance to further customize.\nThese configuration guides walk you through various topics. If you feel a common use-case should be included here but isnt, please file an issue on GitHub.\nConfiguration guides Instance Config Reference Instance Config Migration Guide Automation Package config: flags, environment variables, extra files DHCP Client Remote Syslog: sending gokrazy logs over the network Connecting to WiFi networks Using TLS in untrusted networks Using Bluetooth Access permanent data NVMe disk (Pi 5) QEMU x86-64 virtual machine Permanent data backup with the gokrazy rsync",
"tags": [],
"title": "Configuration",
"uri": "/userguide/index.html"
},
{
"breadcrumb": "gokrazy Go appliances",
"content": "The guides in this chapter show how to set up popular third-party software.\nIf you feel a common program should be included here but isnt, please file an issue on GitHub.\nInstalling existing Go software To add existing Go software to your gokrazy instance, run gok add with the import path of the program you want to add (the import path must refer to a package main in Go terminology).\nFor instance, to install github.com/stapelberg/scan2drive/cmd/scan2drive, use:\ngok add github.com/stapelberg/scan2drive/cmd/scan2drive Packages guides Showcase Tailscale VPN Caddy HTTP server MinIO object storage Docker containers Prometheus",
"description": "The guides in this chapter show how to set up popular third-party software.\nIf you feel a common program should be included here but isnt, please file an issue on GitHub.\nInstalling existing Go software To add existing Go software to your gokrazy instance, run gok add with the import path of the program you want to add (the import path must refer to a package main in Go terminology).",
"tags": [],
"title": "Available packages",
"uri": "/packages/index.html"
},
{
"breadcrumb": "gokrazy Go appliances",
"content": "A gokrazy package corresponds to a Go package (which in turn is part of a Go module). The gokr-packer program is a wrapper around go install.\nTo use the local version of a repository, use the replace directive of go.mod.\nDevelopment guides Process interface / requirements Controlling a GPIO input/output pin Working with Go modules The gokrazy Go build tag Non-Go Prototyping",
"description": "A gokrazy package corresponds to a Go package (which in turn is part of a Go module). The gokr-packer program is a wrapper around go install.\nTo use the local version of a repository, use the replace directive of go.mod.\nDevelopment guides Process interface / requirements Controlling a GPIO input/output pin Working with Go modules The gokrazy Go build tag Non-Go Prototyping",
"tags": [],
"title": "Package development",
"uri": "/development/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "Each gokrazy instance has a config.json file that contains the instance configuration.\nYou can open the instance config in your editor by running gok edit:\ngok edit will open the config of the default instance, which is named “hello”. gok -i scanner edit will open the config of instance “scanner”. If you prefer, you can also locate and edit the file directly on disk: ~/gokrazy/hello/config.json\nThis document is a reference, explaining all configuration fields. You dont need to read through it all before you first start using gokrazy — follow the other configuration guides in this section instead. In case anything should be unclear, you can look at the config.go source code (and send feedback, please!).\nOlder versions of gokrazy only used command-line flags and plain-text config files instead of a central instance configuration. See the design document gokrazy “instance-centric” config re-design for details on why the change was made, how old setups are kept working and how they can be migrated.\nHere is a minimal instance configuration example:\n{ \"Hostname\": \"hello\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } Most instance configuration files will be more complicated, for example:\n{ \"Hostname\": \"ts\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"tailscale.com/cmd/tailscaled\", \"tailscale.com/cmd/tailscale\", \"github.com/gokrazy/mkfs\", \"github.com/stapelberg/dr\" ], \"PackageConfig\": { \"tailscale.com/cmd/tailscale\": { \"CommandLineFlags\": [ \"up\" ] }, \"tailscale.com/cmd/tailscaled\": { \"CommandLineFlags\": [ \"--outbound-http-proxy-listen=localhost:9080\" ] }, \"github.com/stapelberg/dr\": { \"Environment\": [ \"HTTPS_PROXY=localhost:9080\", \"HTTP_PROXY=localhost:9080\" ] } } } Hostname (Corresponds to the former -hostname gokr-packer flag.)\nThe Hostname field sets the hostname of your gokrazy instance.\nThe gokrazy DHCP client sends this hostname when acquiring a lease, so if hostname resolution is working in your local network, you will be able to access the device in your browser by entering the hostname, e.g. http://hello/ (username gokrazy, password as configured in HTTPPassword or ~/.config/gokrazy/http-password.txt).\nExample:\n{ \"Hostname\": \"example\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } DeviceType (Corresponds to the former -device_type gokr-packer flag.)\nThe DeviceType field specifies which kind of target device this gokrazy instance should be built for.\nempty (\"\"): target the Raspberry Pi (default) or UEFI/BIOS PCs (router7 kernel), depending on the KernelPackage and FirmwarePackage you specify.\nodroidhc1: target the Odroid XU4/HC1/HC2 devices. This results in an MBR without a GPT (as the Odroid devices do not support GPT), and in extra bootloader files in the root partition.\nrock64: target Pine64 Rock64 devices.\nThe possible values are defined in github.com/gokrazy/internal/deviceconfig (→ config.go)\nExample:\n{ \"Hostname\": \"alternative\", \"DeviceType\": \"odroidhc1\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } Packages (Corresponds to the former gokr-packer command line arguments.)\nThe Packages field lists the Go packages that should be built and included in your gokrazy instance.\nEach listed package is a Go import path referencing an executable Go program (package main).\nTo add a package to a gokrazy instance, use the gok add command, which also works for packages that have not yet been published and are stored on your local disk.\nExample:\n{ \"Hostname\": \"hello\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/stapelberg/scan2drive/cmd/scan2drive\" ] } PackageConfig The PackageConfig field specifies how each package listed in Packages will be built into your instance, and how it will be started at runtime.\nPackageConfig is a map that is keyed by the package Go import path.\nSee also the Package Config page.\nPackageConfig → GoBuildEnvironment The GoBuildEnvironment field configures extra environment variables that the gok CLI passes to go build when building your Packages. See the cmd/go documentation for available environment variables.\nNote that no shell escaping or quoting (with single or double quotes) is required. The environment variables are passed when calling go build via the exec system call.\nExample:\n{ \"Hostname\": \"scanner\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/stapelberg/scan2drive/cmd/scan2drive\" ], \"PackageConfig\": { \"github.com/stapelberg/scan2drive/cmd/scan2drive\": { \"GoBuildEnvironment\": [ \"CC=aarch64-linux-gnu-gcc\", \"CGO_ENABLED=1\" ], \"GoBuildFlags\": [ \"-ldflags=-linkmode external -extldflags -static\" ], \"GoBuildTags\": [ \"turbojpeg\" ] } } } PackageConfig → GoBuildFlags (Corresponds to the former buildflags per-package directory text files.)\nThe GoBuildFlags field configures extra arguments that the gok CLI passes to go build when building your Packages. See the cmd/go documentation for available flags.\nTo pass build tags, do not use -tags=mycustomtag, as that will overwrite gokrazys own build tags. Instead, set the GoBuildTags field.\nNote that no shell escaping or quoting (with single or double quotes) is required. The build flags are passed when calling go build via the exec system call.\nExample:\n{ \"Hostname\": \"scanner\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/stapelberg/scan2drive/cmd/scan2drive\" ], \"PackageConfig\": { \"github.com/stapelberg/scan2drive/cmd/scan2drive\": { \"GoBuildEnvironment\": [ \"CC=aarch64-linux-gnu-gcc\", \"CGO_ENABLED=1\" ], \"GoBuildFlags\": [ \"-ldflags=-linkmode external -extldflags -static\" ], \"GoBuildTags\": [ \"turbojpeg\" ] } } } PackageConfig → GoBuildTags (Corresponds to the former buildtags per-package directory text files.)\nThe GoBuildTags field configures additional Go build tags (also known as build constraints) to use when building your program.\nNote: Some Go packages use build tags to optionally build code which uses cgo. Because gokrazy intentionally does not include a C runtime environment, configuring such build tags results either in compilation failures, or in programs that compile but wont start. But, for certain specific use-cases (scan2drives turbojpeg support, for example), you can enable just enough cgo to end up with a fully statically linked program, which does work on gokrazy.\nExample:\n{ \"Hostname\": \"scanner\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/stapelberg/scan2drive/cmd/scan2drive\" ], \"PackageConfig\": { \"github.com/stapelberg/scan2drive/cmd/scan2drive\": { \"GoBuildEnvironment\": [ \"CC=aarch64-linux-gnu-gcc\", \"CGO_ENABLED=1\" ], \"GoBuildFlags\": [ \"-ldflags=-linkmode external -extldflags -static\" ], \"GoBuildTags\": [ \"turbojpeg\" ] } } } PackageConfig → Environment (Corresponds to the former env per-package directory text files.)\nThe Environment field configures environment variables that will be set when starting your program.\nEach entry is a key=value pair, like in Gos os.Environ().\nExample:\n{ \"Hostname\": \"ts\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/stapelberg/dr\" ], \"PackageConfig\": { \"github.com/stapelberg/dr\": { \"Environment\": [ \"HTTPS_PROXY=localhost:9080\", \"HTTP_PROXY=localhost:9080\" ] } } } PackageConfig → CommandLineFlags (Corresponds to the former flags per-package directory text files.)\nThe CommandLineFlags field configures command line flags that will be set when starting your program.\nNote that no shell escaping or quoting (with single or double quotes) is required. The command line flags are passed when starting your program via the exec system call.\nExample:\n{ \"Hostname\": \"ts\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"tailscale.com/cmd/tailscaled\" ], \"PackageConfig\": { \"tailscale.com/cmd/tailscaled\": { \"CommandLineFlags\": [ \"--port=41641\", \"--outbound-http-proxy-listen=localhost:9080\" ] } } } PackageConfig → DontStart (Corresponds to the former dontstart per-package directory text files.)\nEnabling the DontStart field makes the gokrazy init system not start your program automatically.\nYou can still start the program manually via the web interface, or interactively via breakglass.\nThis is useful for programs that are interactive command line tools, instead of permanently running services.\nExample:\n{ \"Hostname\": \"ts\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"tailscale.com/cmd/tailscaled\", \"tailscale.com/cmd/tailscale\" ], \"PackageConfig\": { \"tailscale.com/cmd/tailscale\": { \"DontStart\": true } } } PackageConfig → WaitForClock (Corresponds to the former waitforclock per-package directory text files.)\nThe WaitForClock field makes the gokrazy init system wait for clock synchronization before starting the program. This is useful when modifying the program source to call gokrazy.WaitForClock() is inconvenient.\nExample:\n{ \"Hostname\": \"scanner\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/stapelberg/scan2drive/cmd/scan2drive\" ], \"PackageConfig\": { \"github.com/stapelberg/scan2drive/cmd/scan2drive\": { \"WaitForClock\": true } } } PackageConfig → ExtraFileContents (Corresponds to the former extrafiles per-package directory text files.)\nThe ExtraFileContents field allows adding extra files into the root file system of your gokrazy instance. Any file aside from the built Go program (e.g. scan2drive) is considered extra.\nExtraFileContents is a map from root file system destination path (e.g. /etc/caddy/Caddyfile) to the plain text contents of the extra file.\nThe extra file will be created as a regular file (not executable) with default permissions (UNIX mode 644, or -rw-r--r--). Note that gokrazys root file system is read-only.\nIt can be more convenient to manage extra files as standalone, separate files (not as part of config.json), which the ExtraFilePaths field allows you to do.\nExample:\n{ \"Hostname\": \"webserver\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/caddyserver/caddy/v2/cmd/caddy\" ], \"PackageConfig\": { \"github.com/caddyserver/caddy/v2/cmd/caddy\": { \"ExtraFileContents\": { \"/etc/caddy/Caddyfile\": \"http://:8080 { root * /tmp file_server browse } \" } } } } PackageConfig → ExtraFilePaths (Corresponds to the former extrafiles per-package directory text files.)\nThe ExtraFilePaths field allows adding extra files into the root file system of your gokrazy instance. Any file aside from the built Go program (e.g. scan2drive) is considered extra.\nExtraFilePaths is a map from root file system destination path (e.g. /etc/caddy/Caddyfile) to a relative or absolute path of the extra files to include. Relative paths are relative to the instance directory, e.g. ~/gokrazy/hello — the same directory in which config.json lives.\nThe extra file path can refer to one of:\na regular file. File modes are retained, including the executable bit. a directory. All files and directories within the directory are recursively included. a .tar archive: \u003cpath\u003e.tar. All files contained in the archive are included. an architecture-dependent .tar file: \u003cpath\u003e_\u003ctarget_goarch\u003e.tar, for example firmware_amd64.tar Go packages that target gokrazy can optionally include a _gokrazy directory, in which gokrazy will look for extrafiles. Conceptually, the directory is handled as if you had configured ExtraFilePaths: \"/home/michael/go/src/github.com/gokrazy/wifi/_gokrazy/extrafiles\".\nExample:\n{ \"Hostname\": \"webserver\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/caddyserver/caddy/v2/cmd/caddy\" ], \"PackageConfig\": { \"github.com/caddyserver/caddy/v2/cmd/caddy\": { \"ExtraFilePaths\": { \"/etc/caddy/Caddyfile\": \"Caddyfile\" } } } } cat \u003e ~/gokrazy/webserver/Caddyfile \u003c\u003c'EOT' http://:80 { root * /tmp file_server browse } EOT PackageConfig → Basename By default the basename of a package is the last part of the name of the Go package. For example, the basename for github.com/gokrazy/rsync/cmd/gokr-rsync will be gokr-rsync.\nTo install the program under a different basename (for example, in case of rsync, for compatibility), set the Basename field:\n{ \"PackageConfig\": { \"github.com/gokrazy/rsync/cmd/gokr-rsync\": { \"Basename\": \"rsync\" } }, … } Environment The Environment field sets the default environment variables that the gok commands use. When you create a new instance using gok new, the default environment will be set to GOOS=linux and GOARCH=arm64 (as gokrazy is a Linux system and the default target is the Raspberry Pi).\nThe following example builds a gokrazy instance for linux/amd64 PCs, perhaps run as a Virtual Machine on Proxmox.\nExample:\n{ \"Hostname\": \"vm\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"Environment\": [ \"GOOS=linux\", \"GOARCH=amd64\" ], \"KernelPackage\": \"github.com/gokrazy/kernel.amd64\", \"FirmwarePackage\": \"github.com/gokrazy/kernel.amd64\" } SerialConsole (Corresponds to the former -serial_console gokr-packer flag.)\nThe SerialConsole field controls whether the Linux kernel provides a serial console on the Raspberry Pis UART0 RX/TX ports (see pinout.xyz). To use this serial console, a popular option is to connect a USB-to-serial adapter.\nLinux supports multiple consoles, but only one can be the default console. Kernel messages during boot will be printed to the default console. When you turn off the serial console, the default console will be shown on the HDMI output, and accept input from the USB keyboard.\nThe advantage of using a serial console is that you can easily save the entire boot output to a file on a separate computer (whereas with an HDMI console, text scrolls by very fast), and you can get debug output from the Raspberry Pi bootloader as well for debugging.\nserial0,115200 (default if unset) enables UART0 as a serial console with 115200 baud. This value is used as console= Linux kernel parameter, so use values like ttyS0,115200 if you want to use a different serial port for your console, e.g. when running gokrazy on a PC. disabled will disable the serial console (the default console will be HDMI), which frees up the serial port for usage by your applications. off sets enable_uart=0 in config.txt for the Raspberry Pi firmware, which will save a little bit of power by running the Pi at lower clock speeds. If you want to write an application that uses the serial port, open /dev/serial0 (example), which is a symlink that points to the device handling the RX/TX pins (typically ttyAMA0 or ttyS0).\nExample:\n{ \"Hostname\": \"router7\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"SerialConsole\": \"ttyS0,115200\" } GokrazyPackages (Corresponds to the former -gokrazy_pkgs gokr-packer flag.)\nAside from the user-specified Packages, a gokrazy instance also includes a couple of packages that are considered part of the system, because they are needed to boot the system into a useful state. These are placed in the /gokrazy directory (other packages are placed in the /user directory).\nIf unset, the following packages will be included by default:\ngithub.com/gokrazy/gokrazy/cmd/dhcp sets the IP address after obtaining a DHCPv4 lease. github.com/gokrazy/gokrazy/cmd/ntp synchronizes the hardware clock via NTP. github.com/gokrazy/gokrazy/cmd/randomd stores/loads a kernel random seed across boots. Typically you dont need to configure this field, but it can be useful to overwrite the GokrazyPackages if some component clashes with how you want to use your device. For example, for router7, I need to remove the gokrazy dhcp package as router7 has its own DHCP client. Or, if you were building a local NTP server, you might want to remove the gokrazy ntp package.\nExample:\n{ \"Hostname\": \"router7\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"GokrazyPackages\": [ \"github.com/gokrazy/gokrazy/cmd/ntp\", \"github.com/gokrazy/gokrazy/cmd/randomd\" ] } KernelPackage (Corresponds to the former -kernel_package gokr-packer flag.)\nThe KernelPackage field specifies a Go import path that references a package which does not contain any Go code, but instead contains a Linux kernel image (vmlinuz).\nThe following files are taken from the kernel package directory and are included in the boot file system of your gokrazy instance:\nvmlinuz, a compiled Linux kernel image *.dtb, Linux device tree files boot.scr, U-Boot script Additionally, the lib/modules subdirectory (containing loadable Linux kernel modules) is included in the root file system. Note that these modules are only included, but not automatically loaded (there is no udev or equivalent on gokrazy). If you need to load modules for your hardware, see bluetooth.go for an example program that loads kernel modules.\nDefault if unset: github.com/gokrazy/kernel\nExample:\n{ \"Hostname\": \"router7\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"KernelPackage\": \"github.com/rtr7/kernel\" } FirmwarePackage (Corresponds to the former -firmware_package gokr-packer flag.)\nThe FirmwarePackage field specifies a Go import path that references a package which does not contain any Go code, but instead contains Raspberry Pi firmware files.\nThe following files are taken from the firmware package directory and are included in the boot file system of your gokrazy instance:\n*.bin, Raspberry Pi firmware files *.dat, Raspberry Pi firmware files *.elf, Raspberry Pi firmware files *.upd, Raspberry Pi EEPROM update files *.sig, Raspberry Pi EEPROM update signatures overlays/*.dtbo, Device Tree overlay files for the Raspberry Pi OS kernel Default if unset: github.com/gokrazy/firmware\nIf empty, no files will be included.\nExample:\n{ \"Hostname\": \"router7\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"FirmwarePackage\": \"\" } EEPROMPackage (Corresponds to the former -eeprom_package gokr-packer flag.)\nThe EEPROMPackage field specifies a Go import path that references a package which does not contain any Go code, but instead contains Raspberry Pi EEPROM update files.\nThe following files are taken from the firmware package directory and are included in the boot file system of your gokrazy instance:\npieeprom-*.bin, Raspberry Pi EEPROM update files recovery.bin, Raspberry Pi EEPROM update files vl805-*.bin, Raspberry Pi EEPROM update files Default if unset: github.com/gokrazy/rpi-eeprom\nIf empty, no files will be included.\nExample:\n{ \"Hostname\": \"router7\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"EEPROMPackage\": \"\" } Kernel command line configuration Certain hardware might require enabling workarounds in the Linux kernel via the kernels command-line. For example, you might need to specify acpi_enforce_resources=lax:\nExample:\n{ \"Hostname\": \"hello\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"KernelExtraArgs\": [ \"acpi_enforce_resources=lax\" ] } Bootloader configuration (config.txt) The Raspberry Pis “system configuration parameters” (interpreted by the bootloader, or “boot firmware”) can be configured via the config.txt file on the boot file system.\nThe BootloaderExtraLines array contains one string per extra line that should be added to config.txt when the gokrazy packer creates the boot file system.\nThis allows enabling the Raspberry Pi-provided Device Tree Overlays — the example below enables 1-Wire support. Note that not all Device Tree Overlays are guaranteed to work; compatibility depends on whether the upstream Linux driver matches the Raspberry Pi OS Linux driver.\nExample:\n{ \"Hostname\": \"hello\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"BootloaderExtraLines\": [ \"dtoverlay=w1-gpio\" ] } Bootloader configuration (EEPROM) The Raspberry Pis bootloader configuration uses the same syntax as the config.txt, but applies earlier in the boot process.\nThe BootloaderExtraEEPROM array contains one string per extra line that should be added to the bootconf.txt EEPROM section when the gokrazy packer creates the pieeprom.upd file on the boot file system.\nExample:\n{ \"Hostname\": \"hello\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"BootloaderExtraEEPROM\": [ \"BOOT_ORDER=0xf16\" ] } This BOOT_ORDER setting 0xf16 boots from NVMe disk first, then falls back to SD card.\nDevice mount configuration gokrazy allows specifying additional devices that will be mounted under /mnt when a gokrazy instance boots. The gok CLI will create the directory in the root file system, the gokrazy init system will (repeatedly, indefinitely) try to find the device specified by Source and mount it at Target.\nThis allows you to make use of e.g. an external SSD as fast and reliable storage.\nDevice mount configuration → Source Currently, the following formats are supported:\nPARTUUID=, where you identify a partition by its GPT partition UUID (print with blkid(8)) UUID=, where you identify an ext2, ext3 or ext4 file system by its UUID (print with blkid(8)) /dev/sda4, where you provide the (hopefully stable) path of a device node directly Example:\n{ \"Hostname\": \"hello\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"MountDevices\": [ { \"Source\": \"PARTUUID=c995c848-1d29-4f08-a34d-cd811e84a763\", \"Type\": \"ext4\", \"Target\": \"/mnt/usb-thumb-drive\", \"Options\": \"\" } ] } Device mount configuration → Type The Type field specifies the file system type to mount. Typically ext4, or any other file system your kernel supports. You can use cat /proc/filesystems in a breakglass shell to list them.\nDevice mount configuration → Target File system path under /mnt in which to mount the device, e.g. /mnt/usb-thumb-drive\nDevice mount configuration → Options gokrazy supports the usual filesystem-independent mount options like ro, noexec, etc.\nThe full list of supported options can be found in https://github.com/gokrazy/gokrazy/blob/main/mount.go#L26\nUpdate The Update field contains a struct that configures how gokrazy updates are done.\nYou typically dont need to configure the Update field.\nUpdate → Hostname Hostname (in UpdateStruct) overrides Struct.Hostname, but only for deploying the update via HTTP, not in the generated image.\nUpdate → UseTLS The UseTLS field accepts the following values:\nempty (\"\"): use TLS if certificates already exist on disk off: disable TLS even if certificates exist self-signed: create (self-signed) TLS certificates if needed See Using TLS in untrusted networks for more details.\nExample:\n{ \"Hostname\": \"webserver\", \"Update\": { \"HTTPPassword\": \"secret\", \"UseTLS\": \"self-signed\" }, \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } Update → HTTPPort (Corresponds to the former -http_port gokr-packer flag.)\nThe HTTPPort field sets the HTTP port (port 80 by default) on which the gokrazy web interface will be available. This field controls both: which port your gokrazy instance listens on (server), and which port the gok CLI will use for updating your instance (client).\nIt can be useful to configure a different port if you want to run a web server on port 80, for example.\nIf UseTLS is enabled, this field is ignored and HTTPSPort is used instead.\nExample:\n{ \"Hostname\": \"webserver\", \"Update\": { \"HTTPPassword\": \"secret\", \"HTTPPort\": \"1080\" }, \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } Update → HTTPSPort (Corresponds to the former -https_port gokr-packer flag.)\nSee HTTPPort, but when TLS is enabled (default 443).\nExample:\n{ \"Hostname\": \"webserver\", \"Update\": { \"HTTPPassword\": \"secret\", \"UseTLS\": \"self-signed\", \"HTTPSPort\": \"8443\" }, \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } Update → HTTPPassword (Corresponds to the former http-password.txt host-specific config file.)\nThe HTTPPassword field configures the secret password that allows accessing and updating your gokrazy instance.\nWhen creating a new gokrazy instance (gok new), the gok CLI will create a random password.\nExample:\n{ \"Hostname\": \"webserver\", \"Update\": { \"HTTPPassword\": \"secret\" }, \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } Update → CertPEM (Corresponds to the former cert.pem host-specific config file.)\nWhen enabling TLS, the CertPEM field allows you to use a custom certificate file. This can be useful if you already have a certificate setup for your environment (self-signed or otherwise).\nExample:\n{ \"Hostname\": \"webserver\", \"Update\": { \"HTTPPassword\": \"secret\", \"CertPEM\": \"/home/michael/.ca/webservercert.pem\", \"KeyPEM\": \"/home/michael/.ca/webserverkey.pem\" }, \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } Update → KeyPEM (Corresponds to the former key.pem host-specific config file.)\nLike CertPEM, but for the private key instead of the certificate.",
"description": "Each gokrazy instance has a config.json file that contains the instance configuration.\nYou can open the instance config in your editor by running gok edit:\ngok edit will open the config of the default instance, which is named “hello”. gok -i scanner edit will open the config of instance “scanner”. If you prefer, you can also locate and edit the file directly on disk: ~/gokrazy/hello/config.json\nThis document is a reference, explaining all configuration fields. You dont need to read through it all before you first start using gokrazy — follow the other configuration guides in this section instead. In case anything should be unclear, you can look at the config.go source code (and send feedback, please!).",
"tags": [],
"title": "Instance Config Reference",
"uri": "/userguide/instance-config/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Package development",
"content": "Process supervision Tip You can find the corresponding code in func gokrazy.supervise.\ngokrazys init process (pid 1) supervises all the binaries the user specified via gokr-packer flags.\nMore specifically, gokrazy:\nStarts your binary using Gos os/exec.Command API. The stdout and stderr file descriptors are hooked up to a ring buffer and can be viewed via gokrazys web interface. Extra command-line flags or environment variables can be specified using per-package configuration. When your binarys process exits, gokrazy restarts it! If the process exits with status code 0 (or 125), gokrazy will stop supervision. Exiting immediately with status code 0 when the GOKRAZY_FIRST_START=1 environment variable is set means “dont start the program on boot” Environment variables gokrazy sets the HOME environment variable to HOME=/perm/home/\u003ccmd\u003e, where \u003ccmd\u003e is the name of your binary. For example, tailscale.com/cmd/tailscaled is started with HOME=/perm/home/tailscaled.\nWhen your binary is first started, gokrazy sets the GOKRAZY_FIRST_START=1 environment variable.\nThe PATH environment variable is set to /user:/gokrazy so that all binaries on the system can be discovered.\nPrivilege dropping / security An easy way to implement privilege dropping in Go is to re-execute the process with syscall.SysProcAttr fields set. For example, this is how you would drop privileges to user nobody (uid/gid 65534):\n// mustDropPrivileges re-executes the program in a child process, // dropping root privileges to user nobody. func mustDropPrivileges() { if os.Getenv(\"NTP_PRIVILEGES_DROPPED\") == \"1\" { return } cmd := exec.Command(os.Args[0]) cmd.Env = append(os.Environ(), \"NTP_PRIVILEGES_DROPPED=1\") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.SysProcAttr = \u0026syscall.SysProcAttr{ Credential: \u0026syscall.Credential{ Uid: 65534, Gid: 65534, }, } log.Fatal(cmd.Run()) } Examples:\ngithub.com/gokrazy/gokrazy/cmd/ntp is a rather involved example which retains the CAP_SYS_TIME capability in the child process github.com/gokrazy/rsync uses Linux mount namespaces and constructs a file system with read-only bind mounts of the configured rsync modules",
"description": "Process supervision Tip You can find the corresponding code in func gokrazy.supervise.\ngokrazys init process (pid 1) supervises all the binaries the user specified via gokr-packer flags.\nMore specifically, gokrazy:\nStarts your binary using Gos os/exec.Command API. The stdout and stderr file descriptors are hooked up to a ring buffer and can be viewed via gokrazys web interface. Extra command-line flags or environment variables can be specified using per-package configuration. When your binarys process exits, gokrazy restarts it! If the process exits with status code 0 (or 125), gokrazy will stop supervision. Exiting immediately with status code 0 when the GOKRAZY_FIRST_START=1 environment variable is set means “dont start the program on boot” Environment variables gokrazy sets the HOME environment variable to HOME=/perm/home/\u003ccmd\u003e, where \u003ccmd\u003e is the name of your binary. For example, tailscale.com/cmd/tailscaled is started with HOME=/perm/home/tailscaled.",
"tags": [],
"title": "Process interface / requirements",
"uri": "/development/process-interface/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "Before 2023, the concept of gokrazy instance configuration was only a convention. Each gokrazy build was created using the gokr-packer CLI tool, and configured by the packers command-line flags, parameters, config files in ~/.config and per-package config files in the current directory (e.g. flags/github.com/gokrazy/breakglass/flags.txt).\nIn 2023, the concept of gokrazy instance configuration was introduced (see issue #147).\nNow, each gokrazy instance, which typically corresponds to one Raspberry Pi or other machine, has its own directory within the gokrazy parent directory (~/gokrazy by default), e.g. ~/gokrazy/scanner.\nThe new gok CLI tool works in the instance directory (e.g. ~/gokrazy/scanner) and reads the single config.json file, which contains all settings.\nMigration If youre using the old mechanism (gokr-packer commands), here is how to migrate to the new gok CLI. Assuming you use a command like the following:\ngokr-packer \\ -hostname=scanner \\ -update=yes \\ github.com/gokrazy/hello \\ github.com/gokrazy/breakglass \\ github.com/gokrazy/serial-busybox \\ github.com/stapelberg/scan2drive/cmd/scan2drive Run your gokr-packer command manually once, but add the -write_instance_config flag:\ngokr-packer \\ -write_instance_config=scanner \\ -hostname=scanner \\ -update=yes \\ github.com/gokrazy/hello \\ github.com/gokrazy/breakglass \\ github.com/gokrazy/serial-busybox \\ github.com/stapelberg/scan2drive/cmd/scan2drive This will make gokr-packer create ~/gokrazy/scanner.\nFrom now on, switch to using the gok CLI for updating your instance:\ngok -i scanner update To open your instances configuration in your editor, use gok -i scanner edit.",
"description": "Before 2023, the concept of gokrazy instance configuration was only a convention. Each gokrazy build was created using the gokr-packer CLI tool, and configured by the packers command-line flags, parameters, config files in ~/.config and per-package config files in the current directory (e.g. flags/github.com/gokrazy/breakglass/flags.txt).\nIn 2023, the concept of gokrazy instance configuration was introduced (see issue #147).\nNow, each gokrazy instance, which typically corresponds to one Raspberry Pi or other machine, has its own directory within the gokrazy parent directory (~/gokrazy by default), e.g. ~/gokrazy/scanner.",
"tags": [],
"title": "Instance Config Migration Guide",
"uri": "/userguide/migration-guide/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "This page demonstrates different ways of creating automation around gokrazy, in two different scenarios:\nAs a user of gokrazy, who wants to automate common workflows of one or more gokrazy instances.\nAs a provider of a package that can be used with gokrazy, who wants to ensure the program(s) can be built into a gokrazy instance in a continuous integration service like GitHub Actions.\nAutomating common workflows with a Makefile The make tool can be used to document and centralize common workflows.\nFor example, I use the following Makefile. I run make get \u0026\u0026 make update from cron every day. I sometimes manually run make overwrite with /dev/sdx being my USB SD card reader. And for debugging, make root produces a SquashFS image I can inspect with unsquashfs -ll.\nGOK := gok -i dr all: .PHONY: get update overwrite root get: ${GOK} get --update_all update: ${GOK} update overwrite: ${GOK} overwrite --full /dev/sdx root: ${GOK} overwrite --root /tmp/root.squashfs The first line is the so-called “gokline”. In this line, you can centrally put all the command-line flags, environment variables or config templating hooks.\nFor example, in router7, I set the GOARCH=amd64 environment variable to make Go compile for x86-64 (PC) instead of ARM (Raspberry Pi):\nGOK := GOARCH=amd64 gok -i router7 make: config templating You can start templating hooks, simple or complicated, by adding them into your gokline:\nGOK := sed 's,\"Hostname\": \"\",\"Hostname\": \"$(GOKRAZY_HOSTNAME)\",g' config.tmpl.json \u003e config.json \u0026\u0026 gok -i bakery I then run the following command from cron:\nmake update GOKRAZY_HOSTNAME=bakery Continuous Integration: GitHub Actions You can place the following gokrazy.yml into your .github/workflows directory to verify that your program builds as a gokrazy appliance:\nname: gokrazy appliance build on: push: pull_request: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: # Latest minor release of Go 1.19: go-version: ^1.19 - name: install gok CLI run: | go install github.com/gokrazy/tools/cmd/gok@main echo \"PATH=$PATH:$(go env GOPATH)/bin\" \u003e\u003e $GITHUB_ENV - name: create new gokrazy instance run: gok new - name: add this program to the gokrazy instance run: gok add . - name: generate gokrazy disk image run: gok overwrite --root root.squashfs",
"description": "This page demonstrates different ways of creating automation around gokrazy, in two different scenarios:\nAs a user of gokrazy, who wants to automate common workflows of one or more gokrazy instances.\nAs a provider of a package that can be used with gokrazy, who wants to ensure the program(s) can be built into a gokrazy instance in a continuous integration service like GitHub Actions.\nAutomating common workflows with a Makefile The make tool can be used to document and centralize common workflows.",
"tags": [],
"title": "Automation",
"uri": "/userguide/automation/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Available packages",
"content": "Tailscales website reads:\nA secure network that just works\nZero config VPN. Installs on any device in minutes, manages firewall rules for you, and works from anywhere.\ngokrazy-based devices are no exception! This guide shows you how to use Tailscale with gokrazy.\nTailscales networking will come in handy when accessing your gokrazy server remotely (no static DHCP leases, port-forwarding and DynDNS required!), or even to secure your communication when gokrazy is connected to an unencrypted WiFi network.\nRequirements Package tailscale.com v1.56.1 or later (latest version used automatically unless you have the package already in go.mod) Volume /perm/ needs to be initialized (instructions use github.com/gokrazy/mkfs to initialize) to persist authentication over reboots. Step 1. include the tailscale packages Add the Tailscale daemon tailscaled and CLI tailscale Go packages to your gokrazy instance:\ngok add tailscale.com/cmd/tailscaled gok add tailscale.com/cmd/tailscale # Automatically initialize a file system on the /perm partition on first boot: gok add github.com/gokrazy/mkfs Step 2. set command-line flags Then, open your instances config.json in your editor:\ngok edit And configure Package config: Command-line flags for Option A or Option B:\nOption A: interactive authentication\n{ \"Hostname\": \"ts\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"tailscale.com/cmd/tailscaled\", \"tailscale.com/cmd/tailscale\", \"github.com/gokrazy/mkfs\" ], \"PackageConfig\": { \"tailscale.com/cmd/tailscale\": { \"CommandLineFlags\": [ \"up\" ] } } } Option B: unattended authentication with auth key\nAlternatively, navigate to Tailscale console and open Settings / Keys. Generate auth key.\nInclude the key to tailscale flags:\n{ \"Hostname\": \"ts\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"tailscale.com/cmd/tailscaled\", \"tailscale.com/cmd/tailscale\", \"github.com/gokrazy/mkfs\" ], \"PackageConfig\": { \"tailscale.com/cmd/tailscale\": { \"CommandLineFlags\": [ \"up\", \"--auth-key=tskey-AAAAAAAAAAAA-AAAAAAAAAAAAAAAAAAAAAA\" ] } } } Then, deploy as usual:\ngok update Step 3. authenticate (interactive only) Skip this step if you are using option B with auth key.\nNavigate to your gokrazy web interface with browser using the URL displayed by the gok CLI. Open the service /user/tailscale and find the login URL. Open the link with browser and log in to Tailscale and authorize the client. Step 4. disable key expiry (optional) You are now connected to Tailscale and you can access your gokrazy instance over Tailscale.\nNote Tailscale requires re-authentication periodically. You can disable key expiry from Tailscale console for the gokrazy instance to not require login every 3 months.\nOptional: Using gokrazy as a Tailscale subnet router To allow hosts in your Tailnet to access devices in your network other than your gokrazy appliance, you can set up Tailscale as a subnet router.\n{ \"Hostname\": \"ts\", \"Packages\": [ \"github.com/gokrazy/serial-busybox\", \"tailscale.com/cmd/tailscaled\", \"tailscale.com/cmd/tailscale\" ], \"PackageConfig\": { \"tailscale.com/cmd/tailscale\": { \"CommandLineFlags\": [ \"up\", \"--advertise-routes=192.168.0.0/24\" ] } } } Starting Tailscale version v1.64, IP forwarding is automatically enabled on Gokrazy.\nOptional: Accessing gokrazy using Tailscale SSH To access the gokrazy appliance using SSH authenticating using Tailscale, you can enable Tailscale SSH.\n{ \"Hostname\": \"ts\", \"Packages\": [ \"github.com/gokrazy/serial-busybox\", \"tailscale.com/cmd/tailscaled\", \"tailscale.com/cmd/tailscale\" ], \"PackageConfig\": { \"tailscale.com/cmd/tailscale\": { \"CommandLineFlags\": [ \"up\", \"--ssh=true\" ] } } } Note that Tailscale SSH needs to be allowed by your Tailnet ACL. You can configure to allow, for example, each user to access their own devices using Tailscale SSH, or define which hosts users can access.\nOptional: Tailscale network for other programs Before Tailscale v1.56.1, Tailscale used Userspace networking mode on gokrazy, meaning you needed to use Tailscale as an HTTP proxy to establish outgoing connections into your tailnet.\nWith Tailscale v1.56.1 and newer, programs running on gokrazy can connect to other devices in your tailnet without extra steps! 🎉 DNS resolution and TCP connections work out of the box.\nOptional: Tailscale Go listener Before Tailscale v1.56.1, Tailscale used Userspace networking mode on gokrazy, meaning you needed to use the tsnet package if you wanted to restrict a listener to Tailscale.\nWith Tailscale v1.56.1 and newer, you can listen on Tailscale addresses and use LocalClient.WhoIs to obtain the remote identity:\npackage main import ( \"flag\" \"fmt\" \"log\" \"net/http\" \"tailscale.com/client/tailscale\" ) func main() { listen := flag.String(\"listen\", \"gokrazy.monkey-turtle.ts.net:8111\", \"[host]:port listen address\") allowedUser := flag.String(\"allowed_user\", \"\", \"the name of a tailscale user to allow\") flag.Parse() log.Printf(\"starting HTTP listener on %s\", *listen) var ts tailscale.LocalClient httpsrv := \u0026http.Server{ Addr: *listen, Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { who, err := ts.WhoIs(r.Context(), r.RemoteAddr) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } if who.UserProfile.LoginName != *allowedUser || *allowedUser == \"\" { err := fmt.Sprintf(\"you are logged in as %q (userprofile: %+v), but -allowed_user flag does not match!\", who.UserProfile.LoginName, who.UserProfile) log.Printf(\"forbidden: %v\", err) http.Error(w, err, http.StatusForbidden) return } fmt.Fprintf(w, \"hey there, %q! this message is served via tailscale from gokrazy!\", who.UserProfile.LoginName) }), } log.Fatal(httpsrv.ListenAndServe()) } Deploy this program to your gokrazy device Open the listening address in your browser, e.g. http://gokrazy.monkey-turtle.ts.net:8111 Specify the --allowed_user flag to verify that tailscale authentication works as expected",
"description": "Tailscales website reads:\nA secure network that just works\nZero config VPN. Installs on any device in minutes, manages firewall rules for you, and works from anywhere.\ngokrazy-based devices are no exception! This guide shows you how to use Tailscale with gokrazy.\nTailscales networking will come in handy when accessing your gokrazy server remotely (no static DHCP leases, port-forwarding and DynDNS required!), or even to secure your communication when gokrazy is connected to an unencrypted WiFi network.",
"tags": [],
"title": "Tailscale VPN",
"uri": "/packages/tailscale/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Package development",
"content": "In this guide, we are using periph.io, a library for peripheral I/O in Go, to set one of the Raspberry Pis General Purpose I/O (GPIO) pins to a logical high (3.3V) or low (0V) signal.\nperiph.io supports the Raspberry Pi 3, Raspberry Pi Zero 2W and Raspberry Pi 4, starting with version v3.6.4.\nConnect GPIO pins based on pinout To verify the code is doing what we expect, lets connect a multimeter as per pinout.xyzs pinout:\npin number 18 (signal BCM24, labeled 24 in the pinout above) pin number 20 (signal GND) We need to set the multimeter to “Voltage measurement, DC (direct current)”.\nSetting an output pin signal To set the pin high and low, alternatingly, with a 5 second frequency, we will be using the hello-gpio program, which is a slightly modified version of the example at periph.io/device/led:\npackage main import ( \"log\" \"time\" \"periph.io/x/conn/v3/gpio\" host \"periph.io/x/host/v3\" \"periph.io/x/host/v3/rpi\" ) func doGPIO() error { log.Printf(\"Loading periph.io drivers\") // Load periph.io drivers: if _, err := host.Init(); err != nil { return err } log.Printf(\"Toggling GPIO forever\") t := time.NewTicker(5 * time.Second) for l := gpio.Low; ; l = !l { log.Printf(\"setting GPIO pin number 18 (signal BCM24) to %v\", l) // Lookup a pin by its location on the board: if err := rpi.P1_18.Out(l); err != nil { return err } \u003c-t.C } } func main() { if err := doGPIO(); err != nil { log.Fatal(err) } } You have two options to run this program on your Raspberry Pi:\nUse gok run to temporarily run this program on a running gokrazy instance. Use gok add to permanently include this program in your gokrazy instance: # From the hello-gpio directory, run: gok add . # Then, deploy as usual: gok update At this point, we should be able to see the high/low signal on the multimeter, alternating between 3.3V (high) and 0V (low) every 5 seconds:\nSetting up an input pin To setup a Pin as an input and to act on change to High level, such as a button, we must poll the Pin periodically because periph.ios edge detection, which examples like the periph.io/device/button example rely on, is not available on gokrazy.\nThe below example configures a single Pin for Input and uses Go channels to signal level changes that can be acted on. Keep in mind that shortening the polling interval will increase CPU usage.\npackage main import ( \"log\" \"time\" \"periph.io/x/conn/v3/gpio\" \"periph.io/x/conn/v3/gpio/gpioreg\" host \"periph.io/x/host/v3\" ) type pinLevelMessage struct { State gpio.Level Reset gpio.Level } func setupGPIOInput(pinName string, levelChan chan pinLevelMessage) (gpio.PinIO, error) { log.Printf(\"Loading periph.io drivers\") if _, err := host.Init(); err != nil { return nil, err } // Find Pin by name p := gpioreg.ByName(pinName) // Configure Pin for input, configure pull as needed // Edge mode is currently not supported if err := p.In(gpio.PullNoChange, gpio.NoEdge); err != nil { return nil, err } // Setup Input signalling go func() { lastLevel := p.Read() // How often to poll levels, 100-150ms is fairly responsive unless // button presses are very fast. // Shortening the polling interval \u003c100ms significantly increases // CPU load. for range time.Tick(100 * time.Millisecond) { currentLevel := p.Read() log.Printf(\"level: %v\", currentLevel) if currentLevel != lastLevel { levelChan \u003c- pinLevelMessage{State: currentLevel, Reset: !currentLevel} lastLevel = currentLevel } } }() return p, nil } func main() { // Channel for communicating Pin levels levelChan := make(chan pinLevelMessage) p, err := setupGPIOInput(\"GPIO4\", levelChan) if err != nil { log.Fatal(err) } // Main loop, act on level changes for { select { case msg := \u003c-levelChan: if msg.State { log.Printf(\"Pin %s is High, processing high state tasks\", p.Name()) // Process high state tasks } else if msg.Reset { log.Printf(\"Pin %s is Low, resetting to wait for high state\", p.Name()) // Process resetting logic, if any } default: // Any other ongoing tasks } } }",
"description": "In this guide, we are using periph.io, a library for peripheral I/O in Go, to set one of the Raspberry Pis General Purpose I/O (GPIO) pins to a logical high (3.3V) or low (0V) signal.\nperiph.io supports the Raspberry Pi 3, Raspberry Pi Zero 2W and Raspberry Pi 4, starting with version v3.6.4.\nConnect GPIO pins based on pinout To verify the code is doing what we expect, lets connect a multimeter as per pinout.xyzs pinout:",
"tags": [],
"title": "Controlling a GPIO input/output pin",
"uri": "/development/gpio/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "gokrazy will arrange for each included package to be started at boot. For example, given the following instance config.json (open in your editor using gok edit):\n{ \"Hostname\": \"docs\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } …gokrazy will start the fbstatus, hello, serial-busybox and breakglass programs.\nPackage config This article shows how you can configure different aspects of individual packages.\nEach bit of configuration is nested under the PackageConfig map field in your instances config.json, see Instance Config Reference → PackageConfig. The map is keyed by package name (from the Packages field), and each map entry can have the following fields:\nCommandLineFlags for Command-line flags Environment for Environment variables GoBuildFlags for Go build flags ExtraFilePaths or ExtraFileContents for Extra files Command-line flags The breakglass package provides emergency/debugging access to a gokrazy installation.\nTo enable SSH port forwardings to localhost, set the -forward flag to loopback:\n{ \"PackageConfig\": { \"github.com/gokrazy/breakglass\": { \"CommandLineFlags\": [ \"-forward=loopback\" ] } }, … } Environment variables Environment variables such as the Go runtimes GODEBUG variable can be set as follows:\n{ \"PackageConfig\": { \"github.com/gokrazy/breakglass\": { \"Environment\": [ \"GODEBUG=gctrace=1\" ] } }, … } Go build flags If you want to influence the build of the package at image-creation time (as opposed to runtime), you can specify flags to be passed to the Go build invocation.\nThis example overwrites the value of the world variable using the -X linker flag, which is a common technique to embed version information:\n{ \"PackageConfig\": { \"github.com/gokrazy/hello\": { \"GoBuildFlags\": [ \"-ldflags=-X main.world=Welt\" ] } }, … } Extra files If your program needs extra files to be present in gokrazys root file system image at a specific location, you can add them with the extrafiles mechanism:\n{ \"PackageConfig\": { \"github.com/caddyserver/caddy/v2/cmd/caddy\": { \"ExtraFileContents\": { \"/etc/caddy/Caddyfile\": \"http://:80 { root * /tmp file_server browse } \" } } }, … } Or, if managing the file contents within the config.json becomes unwieldy, you can manage it in a separate file:\ncat \u003e ~/gokrazy/hello/Caddyfile \u003c\u003c'EOT' http://:80 { root * /tmp file_server browse } EOT { \"PackageConfig\": { \"github.com/caddyserver/caddy/v2/cmd/caddy\": { \"ExtraFilePaths\": { \"/etc/caddy/Caddyfile\": \"Caddyfile\" } } }, … }",
"description": "gokrazy will arrange for each included package to be started at boot. For example, given the following instance config.json (open in your editor using gok edit):\n{ \"Hostname\": \"docs\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } …gokrazy will start the fbstatus, hello, serial-busybox and breakglass programs.\nPackage config This article shows how you can configure different aspects of individual packages.",
"tags": [],
"title": "Package config: flags, environment variables, extra files",
"uri": "/userguide/package-config/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "Each gokrazy instance comes with a built-in DHCP client (see Instance Config → GokrazyPackages for more details on system packages) to set the IP address after obtaining a DHCPv4 lease from the local networks DHCP server.\nNetwork Interfaces The gokrazy DHCP client by default runs for eth0. If you want to use a different network interface, perhaps a USB ethernet adapter, you can set the -interface command-line flag:\n{ \"Hostname\": \"dynamic\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", ], \"PackageConfig\": { \"github.com/gokrazy/gokrazy/cmd/dhcp\": { \"CommandLineFlags\": [ \"-interface=enp0s58\" ] } } } If you configure gokrazy to connect to a WiFi network, the gokrazy/wifi package will run another instance of the gokrazy DHCP client with the -interface=wlan0 flag set.\nStatic Network Configuration If you want the DHCP client to not actually fetch a lease, but apply a statically supplied network configuration instead, you can set the -static_network_config flag to the name of a file which contains a JSON-encoded DHCP lease in rtr7/dhcp4.Lease format, for example:\n{ \"IP\": \"192.168.178.2\", \"Netmask\": \"\", \"Router\": \"192.168.178.1\", \"DNS\": [\"192.168.178.1\", \"8.8.8.8\"] } Specifically, the following fields are currently respected:\nIP+Netmask Router DNS You can configure the gokrazy DHCP client to pick up this configuration by setting Package config: Command-line flags and Package config: Extra files:\n{ \"Hostname\": \"dynamic\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ], \"PackageConfig\": { \"github.com/gokrazy/gokrazy/cmd/dhcp\": { \"CommandLineFlags\": [ \"-static_network_config=/etc/gokrazy/static-dhcp-lease.json\" ], \"ExtraFilePaths\": { \"/etc/gokrazy/static-dhcp-lease.json\": \"static-dhcp-lease.json\" } } } } Interface priority The gokrazy DHCP client automatically configures the route priority for default routes of ethernet interfaces (eth*) to 1, whereas on WiFi interfaces (wlan*), the priority is 5 (Linux prefers lower priorities).\nThis means you can configure your gokrazy instance to work with both, WiFi and wired network. Whenever a link is down, the gokrazy DHCP client changes its priority to 1024, meaning outgoing traffic will quickly switch away when an interface loses its link. In other words: When you un-plug the network cable, the device still works via WiFi.\nIf you need to influence the interfaces route priority, you can use the -extra_route_priority flag to add to the default priority. For example, to prefer sending traffic out via the WiFi interface if both WiFi and ethernet are connected, use:\n{ \"Hostname\": \"dynamic\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", ], \"PackageConfig\": { \"github.com/gokrazy/gokrazy/cmd/dhcp\": { \"CommandLineFlags\": [ \"-extra_route_priority=10\" ] } } }",
"description": "Each gokrazy instance comes with a built-in DHCP client (see Instance Config → GokrazyPackages for more details on system packages) to set the IP address after obtaining a DHCPv4 lease from the local networks DHCP server.\nNetwork Interfaces The gokrazy DHCP client by default runs for eth0. If you want to use a different network interface, perhaps a USB ethernet adapter, you can set the -interface command-line flag:",
"tags": [],
"title": "DHCP Client",
"uri": "/userguide/dhcp/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "If you update your gokrazy installations daily, as we recommend you do, logs will be cleared daily as a side effect of rebooting the device. You can use Remote Syslog to persist logs elsewhere for later analysis.\nClient side (gokrazy) To enable remote syslog, you need to configure a target. gokrazy checks the following sources in order, using the first value found:\nOption 1: Linux kernel command line Specify the target via the gokrazy.remote_syslog.target kernel command line parameter. This is primarily intended for integration tests where Linux is being booted from a qemu microvm.\nOption 2: permanent data partition (/perm) Create the file remote_syslog/target on the permanent data partition. This allows changing the target at runtime without rebuilding the image.\n# The following assumes you already created a file system # on the permanent data partition. Otherwise, please use: # sudo mkfs.ext4 /dev/disk/by-partuuid/2e18c40c-04 sudo mount /dev/disk/by-partuuid/2e18c40c-04 /mnt echo 10.0.0.76:514 | sudo tee /mnt/remote_syslog/target sudo umount /mnt Option 3: gokrazy config (/etc/gokrazy) Include the file remote_syslog/target in the /etc/gokrazy directory of your gokrazy image. This bakes the configuration into the image at build time.\nI recommend using a (static) IP address for increased reliability, so that remote syslog works even when DNS does not.\nServer side (syslog-ng) To run a syslog server on gokrazy, check out https://github.com/gokrazy/syslogd.\nIf you want to run your syslog server on a regular Linux distribution, this is how I instructed syslog-ng via its /etc/syslog-ng/syslog-ng.conf to write syslog messages it received from e.g. host gokrazy to /var/log/remote/gokrazy-log:\nsource net { network(ip(10.0.0.76) transport(\"udp\")); }; destination remote { file(\"/var/log/remote/${FULLHOST}-log\"); }; log { source(net); destination(remote); };",
"description": "If you update your gokrazy installations daily, as we recommend you do, logs will be cleared daily as a side effect of rebooting the device. You can use Remote Syslog to persist logs elsewhere for later analysis.\nClient side (gokrazy) To enable remote syslog, you need to configure a target. gokrazy checks the following sources in order, using the first value found:",
"tags": [],
"title": "Remote Syslog: sending gokrazy logs over the network",
"uri": "/userguide/remotesyslog/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Package development",
"content": "If you are not yet familiar with Go modules in general (outside of gokrazy), please read the Go wiki page on Modules first.\nSince September 2022, the gokrazy packer builds each package in its own build directory, with its own go.mod and go.sum files. This is done for isolation: if you update one program, that will not have any effect on the other programs you include in your gokrazy instance.\nExample setup Throughout this page, lets assume your gokrazy instance is named scanner, and will hence store its files in ~/gokrazy/scanner. A single additional program, scan2drive, is included:\ngok -i scanner new gok -i scanner add github.com/stapelberg/scan2drive/cmd/scan2drive When building this instance (using gok overwrite initially, or gok update afterwards), the gok CLI will create the following build directory structure:\n% cd ~/gokrazy/scanner % find . -name go.mod ./builddir/init/go.mod ./builddir/github.com/stapelberg/scan2drive/cmd/scan2drive/go.mod ./builddir/github.com/gokrazy/serial-busybox/go.mod ./builddir/github.com/gokrazy/hello/go.mod ./builddir/github.com/gokrazy/fbstatus/go.mod ./builddir/github.com/gokrazy/gokrazy/go.mod ./builddir/github.com/gokrazy/gokrazy/cmd/randomd/go.mod ./builddir/github.com/gokrazy/gokrazy/cmd/ntp/go.mod ./builddir/github.com/gokrazy/gokrazy/cmd/dhcp/go.mod ./builddir/github.com/gokrazy/rpi-eeprom/go.mod ./builddir/github.com/gokrazy/firmware/go.mod ./builddir/github.com/gokrazy/kernel/go.mod You can see that there is one subdirectory for each package listed in the Packages field of your instances config.json (see gok edit), which includes the explicitly added scan2drive, plus a couple extra ones that gokrazy always installs, e.g. github.com/gokrazy/gokrazy/cmd/dhcp.\nTop-level go.mod template If you want to influence the content of any newly created go.mod (no effect on existing go.mod files), you can create a go.mod template in your instance directory: ~/gokrazy/scanner/go.mod.\nBuilding local code: the replace directive Go modules are loaded from the internet by default and are stored read-only on disk.\nIf you want to make the gokrazy packer pick up a local working copy with not-yet-published code, or a working copy with local changes to existing code, use gok add with a directory name:\n# Create a local working copy in whichever directory you like. % cd ~/projects % git clone https://github.com/stapelberg/scan2drive % cd scan2drive # make some changes % gok -i scan2drive add ./cmd/scan2drive The gok CLI will set up the replace directive for you. For more details on replace, see the Go wiki.\nTo undo a local override, either manually delete the replace directive in the relevant builddir/.../go.mod file, or use go mod edit with -dropreplace=path/to/pkg. See this comment for a worked example.\nInfluencing the granularity Often, one Go package will be the only package you use from a certain Go module. But this isnt always the case: for example, the system packages github.com/gokrazy/gokrazy/cmd/dhcp and github.com/gokrazy/gokrazy/cmd/ntp both come from the github.com/gokrazy/gokrazy module.\nThe packer will by default create a separate builddir, including a separate go.mod and go.sum, for each package, even when they come from the same module.\nIf you want to add module-wide replace directives to your go.mod file, you can influence the granularity at which gokr-packer works as follows.\nMove the go.mod/go.sum files to the directory level within the builddir/ hierarchy at which you would like to work. gokr-packer will look for go.mod/go.sum files at the package level, going one level up until it finds the files.\nHence, you can use the following locations, ordered from finest to coarsest granularity:\nper-package builddir (default), e.g.: builddir/github.com/gokrazy/gokrazy/cmd/dhcp/go.mod\nper-module builddir (convenient when working with replace directives), e.g.: builddir/github.com/gokrazy/gokrazy/go.mod\nper-org builddir (convenient for wide-reaching replace directives), e.g.: builddir/github.com/gokrazy/go.mod\nsingle builddir, preserving the previous behavior, e.g.: builddir/go.mod",
"description": "If you are not yet familiar with Go modules in general (outside of gokrazy), please read the Go wiki page on Modules first.\nSince September 2022, the gokrazy packer builds each package in its own build directory, with its own go.mod and go.sum files. This is done for isolation: if you update one program, that will not have any effect on the other programs you include in your gokrazy instance.\nExample setup Throughout this page, lets assume your gokrazy instance is named scanner, and will hence store its files in ~/gokrazy/scanner. A single additional program, scan2drive, is included:",
"tags": [],
"title": "Working with Go modules",
"uri": "/development/modules/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Available packages",
"content": "Caddy is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go.\nTo install caddy, first add the caddy program to your gokrazy instance:\ngok add github.com/caddyserver/caddy/v2/cmd/caddy Then, open your instances config.json in your editor:\ngok edit And make the following changes:\nChange the HTTP port from 80 (default) to 1080 (for example) to move gokrazys web interface listening port out of the way and let caddy serve on TCP port 80. If you want to run caddy on a different port, you can skip this step. Configure Package config: Command-line flags and Package config: Extra files to make caddy run its webserver on startup (run) and to make caddy locate its config file (--config). { \"Hostname\": \"webserver\", \"Update\": { \"HTTPPort\": \"1080\" }, \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/caddyserver/caddy/v2/cmd/caddy\" ], \"PackageConfig\": { \"github.com/caddyserver/caddy/v2/cmd/caddy\": { \"CommandLineFlags\": [ \"run\", \"--config\", \"/etc/caddy/Caddyfile\" ], \"ExtraFilePaths\": { \"/etc/caddy/Caddyfile\": \"Caddyfile\" } } } } Then, create the referenced Caddyfile extra file and modify it to your liking. In this example, we explicitly configure an HTTP listener to disable Caddys automatic HTTPS setup, so that your server will work without a publically reachable address.\ncat \u003e ~/gokrazy/webserver/Caddyfile \u003c\u003c'EOT' http://:80 { root * /tmp file_server browse } EOT Then, deploy as usual:\ngok update Tip: When using breakglass, use the -gokrazy_url=:1080 flag to overwrite the port.",
"description": "Caddy is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go.\nTo install caddy, first add the caddy program to your gokrazy instance:\ngok add github.com/caddyserver/caddy/v2/cmd/caddy Then, open your instances config.json in your editor:\ngok edit And make the following changes:\nChange the HTTP port from 80 (default) to 1080 (for example) to move gokrazys web interface listening port out of the way and let caddy serve on TCP port 80. If you want to run caddy on a different port, you can skip this step. Configure Package config: Command-line flags and Package config: Extra files to make caddy run its webserver on startup (run) and to make caddy locate its config file (--config). { \"Hostname\": \"webserver\", \"Update\": { \"HTTPPort\": \"1080\" }, \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/caddyserver/caddy/v2/cmd/caddy\" ], \"PackageConfig\": { \"github.com/caddyserver/caddy/v2/cmd/caddy\": { \"CommandLineFlags\": [ \"run\", \"--config\", \"/etc/caddy/Caddyfile\" ], \"ExtraFilePaths\": { \"/etc/caddy/Caddyfile\": \"Caddyfile\" } } } } Then, create the referenced Caddyfile extra file and modify it to your liking. In this example, we explicitly configure an HTTP listener to disable Caddys automatic HTTPS setup, so that your server will work without a publically reachable address.",
"tags": [],
"title": "Caddy HTTP server",
"uri": "/packages/caddy-http-server/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "Since March 2022, gokrazy supports both encrypted and unencrypted WiFi networks! 🎉\nStep 1. Install the wifi package To make gokrazy connect to a WiFi network, first add the github.com/gokrazy/wifi package to your gokrazy instance:\ngok add github.com/gokrazy/wifi Step 2. Configure the wifi package Open your gokrazy instances config.json in your editor:\ngok edit Then, configure the wifi program by creating the file wifi.json as extra file.\n{ \"Hostname\": \"wifi\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/gokrazy/wifi\" ], \"PackageConfig\": { \"github.com/gokrazy/wifi\": { \"ExtraFilePaths\": { \"/etc/wifi.json\": \"wifi.json\" } } } } In the same directory, create wifi.json like so for an encrypted WiFi network:\n{ \"ssid\": \"Secure WiFi\", \"psk\": \"secret\" } If you need to connect to an unencrypted WiFi network, specify no psk, and use TLS:\n{ \"ssid\": \"My unencrypted WiFi\" } Alternatively, you can also create the wifi.json manually on the permanent data partition with path /perm/wifi.json.\nAfter starting gokrazy, the wifi program will connect to the configured WiFi network:\nFor debugging: known-working WiFi router setup In case you have trouble getting your Raspberry Pi to connect to your network, this is how I set up my TP-LINK TL-WDR4300 with OpenWrt 19.07:\nThe MAC address filter isnt a security measure, but prevents others from accidentally joining this open network.",
"description": "Since March 2022, gokrazy supports both encrypted and unencrypted WiFi networks! 🎉\nStep 1. Install the wifi package To make gokrazy connect to a WiFi network, first add the github.com/gokrazy/wifi package to your gokrazy instance:\ngok add github.com/gokrazy/wifi Step 2. Configure the wifi package Open your gokrazy instances config.json in your editor:",
"tags": [],
"title": "Connecting to WiFi networks",
"uri": "/userguide/wifi/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Package development",
"content": "If you want to add code to your project that is specific to gokrazy, you can conditionally compile it using the gokrazy Go build tag. Place this line at the top of your file, followed by a blank line:\n//go:build gokrazy // Program qrbill-api serves QR codes for the Swiss QR-bill standard via HTTP. package main By convention, the file name for such code should end in _gokrazy.go, similar to how the go tool picks up on GOOS and GOARCH from, for example, source_windows_amd64.go.\nExample: qrbill As an example, take a look at the qrbill programm, which changes its default listen address (in api_gokrazy.go) depending on where it runs.\nFor development, it listens on localhost:9933, but on gokrazy, it listens on :9933 (all IP addresses).",
"description": "If you want to add code to your project that is specific to gokrazy, you can conditionally compile it using the gokrazy Go build tag. Place this line at the top of your file, followed by a blank line:\n//go:build gokrazy // Program qrbill-api serves QR codes for the Swiss QR-bill standard via HTTP. package main By convention, the file name for such code should end in _gokrazy.go, similar to how the go tool picks up on GOOS and GOARCH from, for example, source_windows_amd64.go.",
"tags": [],
"title": "The gokrazy Go build tag",
"uri": "/development/buildtags/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Available packages",
"content": "Note: As of February 13, 2026, MinIO is archived and no longer maintained, so you are probably better off using a different option. This guide is left online as reference for now.\nMinIO was a high-performance object storage that was API compatible to Amazons Simple Storage Service (S3), but was open source and written in Go. It could be used as a building block for applications involving file storage and file transmission and while its native to the cloud, it turns out one can also use it on gokrazy. :)\nStep 1: Install MinIO to your gokrazy device Add the minio program to your gokrazy instance:\ngok add github.com/minio/minio # Automatically initialize a file system on the /perm partition on first boot: gok add github.com/gokrazy/mkfs Step 2: Configuring the environment variables and command-line flags Then, open your instances config.json in your editor:\ngok edit And configure Package config: Command-line flags and Package config: Environment variables:\n{ \"Hostname\": \"storage\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/minio/minio\", \"github.com/gokrazy/mkfs\" ], \"PackageConfig\": { \"github.com/minio/minio\": { \"CommandLineFlags\": [ \"server\", \"--address\", \":3001\", \"--console-address\", \":3002\", \"/perm/minio/\" ], \"Environment\": [ \"MINIO_ROOT_USER=minio\", \"MINIO_ROOT_PASSWORD=minio-on-gokrazy\" ] } } } Then, deploy as usual:\ngok update A few things can be noted here:\nThere are nice practical examples on the different options once you execute minio server --help if you have it installed locally or more advanced use cases in the official MinIO docs.\nThe ports for the storage server and console do not have to be explicitly set, but for me the default port collided with another service (Port 9000). If no port is set the console just chooses an arbitrary free one.\nFor some reason the HOME variable has to be set to the storage folder. See Issue #12641 on why that is the case. As default gokrazy sets HOME to HOME=/perm/\u003ccmd\u003e, so if you want to change your storage location to something different modify the Environment field accordingly.\nStep 3: Test whether the setup was successful If you have the mc command installed you can check out whether your installation of MinIO really works:\n$ mc alias set gokrazy http://gokrazy:3001 minio minio-on-gokrazy Added `gokrazy` successfully. $ mc ls gokrazy $ mc mb gokrazy/testbucket Bucket created successfully `gokrazy/testbucket`. $ mc ls gokrazy [2021-09-15 16:40:16 CEST] 0B testbucket/ Also check out the output in the logs on the gokrazy webinterface and login into the MinIO management console (http://gokrazy:3002 in this guide) to create service accounts view logs, bucket contents and more.",
"description": "Note: As of February 13, 2026, MinIO is archived and no longer maintained, so you are probably better off using a different option. This guide is left online as reference for now.\nMinIO was a high-performance object storage that was API compatible to Amazons Simple Storage Service (S3), but was open source and written in Go. It could be used as a building block for applications involving file storage and file transmission and while its native to the cloud, it turns out one can also use it on gokrazy. :)",
"tags": [],
"title": "MinIO object storage",
"uri": "/packages/minio/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "Lets assume that you have installed gokrazy on a Raspberry Pi and are currently successfully updating it over the network like so:\ngok update Enabling TLS To start using TLS, edit your gokrazy instances config.json:\ngok edit In the config.json, in the Update field, add a \"UseTLS\": \"self-signed\" line (dont forget adding a comma to the previous line):\n{ \"Hostname\": \"docs\", \"Update\": { \"HTTPPassword\": \"secret\", \"UseTLS\": \"self-signed\" }, \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\" ] } Save your changes and close the file, then run a first update with the --insecure flag:\ngok update --insecure The gok CLI will:\ngenerate a self-signed certificate include the certificate in the gokrazy installation verify the certificate fingerprint in future updates The gokrazy installation will start listening on TCP port 443 for HTTPS connections and redirect any HTTP traffic to HTTPS. When opening the gokrazy web interface in your browser, you will need to explicitly permit communication due to the self-signed certificate.\nFor all future updates, remove the --insecure flag:\ngok update You can now safely update your gokrazy installation over untrusted networks, such as unencrypted WiFi networks.\nDisabling TLS Change the UseTLS line to \"UseTLS\": \"off\" in your instances config.json.\nRun gok update --insecure, and afterwards gokrazy will no longer contain the certificates and will serve unencrypted HTTP again.",
"description": "Lets assume that you have installed gokrazy on a Raspberry Pi and are currently successfully updating it over the network like so:\ngok update Enabling TLS To start using TLS, edit your gokrazy instances config.json:\ngok edit In the config.json, in the Update field, add a \"UseTLS\": \"self-signed\" line (dont forget adding a comma to the previous line):",
"tags": [],
"title": "Using TLS in untrusted networks",
"uri": "/userguide/tls-for-untrusted-networks/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Available packages",
"content": "gokrazys goal is to make it easy to build Go appliances. In an ideal world, all building blocks you need would be available in Go. In reality, that is not entirely the case. Perhaps you need to run a C program next to your Go programs. Docker containers make incremental (or partial) adoption of gokrazy easy.\nWere going to use podman, a drop-in replacement for Docker, because there is a statically compiled version for amd64 and arm64 available that we could easily re-package into https://github.com/gokrazy/podman.\nStep 1: Install podman to your gokrazy device Include the following packages in your gokrazy installation:\ngok add github.com/gokrazy/nsenter gok add github.com/gokrazy/podman gok add github.com/spod/nftables Then, deploy as usual:\ngok update Note: Podman 5+ uses netavark for container networking instead of CNI. If you are migrating from podman \u003c 5, you can remove github.com/gokrazy/iptables and any CNI plugin packages, and replace them with github.com/spod/nftables.\nStep 2: Verify podman works Use breakglass to login to your gokrazy instance and run a container manually:\n/tmp/breakglass187145741 $ podman run --rm -ti docker.io/library/debian:sid root@gokrazy:/# cat /etc/debian_version 12.0 Step 3: Use podman programmatically Now that you have the required tools, there are a couple of decisions you have to make depending on what you want to run in your container(s):\nShould container data be stored ephemerally in tmpfs (lost with the next reboot), on the permanent partition of your SD card, or somewhere else entirely (e.g. network storage)? Do you want to pull new container versions automatically before each run, or manually on demand only? Should your container be started as a one-off job only (→ detached mode), or supervised continuously (restarted when it exits)? Should your container use a deterministic name (so that you can exec commands in it easily), or use a fresh name for each run (so that there never are conflicts)? Aside from these broad questions, you very likely need to set a bunch of detail options for your container, such as additional environment variables, volume mounts, networking flags, or command line arguments.\nThe following program is an example for how this could look like. I use this program to run irssi.\npackage main import ( \"fmt\" \"log\" \"os\" \"os/exec\" \"strings\" \"github.com/gokrazy/gokrazy\" ) func podman(args ...string) error { podman := exec.Command(\"/usr/local/bin/podman\", args...) podman.Env = expandPath(os.Environ()) podman.Env = append(podman.Env, \"TMPDIR=/tmp\") podman.Stdin = os.Stdin podman.Stdout = os.Stdout podman.Stderr = os.Stderr if err := podman.Run(); err != nil { return fmt.Errorf(\"%v: %v\", podman.Args, err) } return nil } func irssi() error { // Ensure we have an up-to-date clock, which in turn also means that // networking is up. This is relevant because podman takes whats in // /etc/resolv.conf (nothing at boot) and holds on to it, meaning your // container will never have working networking if it starts too early. gokrazy.WaitForClock() if err := podman(\"kill\", \"irssi\"); err != nil { log.Print(err) } if err := podman(\"rm\", \"irssi\"); err != nil { log.Print(err) } // You could podman pull here. if err := podman(\"run\", \"-td\", \"-v\", \"/perm/irssi:/home/michael/.irssi\", \"-v\", \"/perm/irclogs:/home/michael/irclogs\", \"-e\", \"TERM=rxvt-unicode\", \"-e\", \"LANG=C.UTF-8\", \"--network\", \"host\", \"--name\", \"irssi\", \"docker.io/stapelberg/irssi:latest\", \"screen\", \"-S\", \"irssi\", \"irssi\"); err != nil { return err } return nil } func main() { if err := irssi(); err != nil { log.Fatal(err) } } // expandPath returns env, but with PATH= modified or added // such that both /user and /usr/local/bin are included, which podman needs. func expandPath(env []string) []string { extra := \"/user:/usr/local/bin\" found := false for idx, val := range env { parts := strings.Split(val, \"=\") if len(parts) \u003c 2 { continue // malformed entry } key := parts[0] if key != \"PATH\" { continue } val := strings.Join(parts[1:], \"=\") env[idx] = fmt.Sprintf(\"%s=%s:%s\", key, extra, val) found = true } if !found { const busyboxDefaultPATH = \"/usr/local/sbin:/sbin:/usr/sbin:/usr/local/bin:/bin:/usr/bin\" env = append(env, fmt.Sprintf(\"PATH=%s:%s\", extra, busyboxDefaultPATH)) } return env }",
"description": "gokrazys goal is to make it easy to build Go appliances. In an ideal world, all building blocks you need would be available in Go. In reality, that is not entirely the case. Perhaps you need to run a C program next to your Go programs. Docker containers make incremental (or partial) adoption of gokrazy easy.\nWere going to use podman, a drop-in replacement for Docker, because there is a statically compiled version for amd64 and arm64 available that we could easily re-package into https://github.com/gokrazy/podman.",
"tags": [],
"title": "Docker containers",
"uri": "/packages/docker-containers/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "gokrazy has limited support for Bluetooth. The usual Bluetooth utilities (bluez) have a lot of dependencies that are not available on gokrazy and those are out of scope here. But the basic Bluetooth hardware are supported on low level. This is useful in particular for applications using Bluetooth LE natively in Go.\nTo enable Bluetooth in gokrazy, first add the github.com/gokrazy/bluetooth package to your gokrazy instance:\ngok add github.com/gokrazy/bluetooth The github.com/gokrazy/bluetooth package loads the appropriate kernel modules and firmware required.\nExample program As demo were using the bluewalker Bluetooth LE scanner utility to show that Bluetooth is working:\ngok add gitlab.com/jtaimisto/bluewalker Then, open your instances config.json in your editor:\ngok edit And configure Package config: Command-line flags:\n{ \"Hostname\": \"blue\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"gitlab.com/jtaimisto/bluewalker\" ], \"PackageConfig\": { \"gitlab.com/jtaimisto/bluewalker\": { \"CommandLineFlags\": [ \"-device=hci0\" ] } } } Then, deploy as usual:\ngok update Once deployed, you can see Bluetooth events being received in the bluewalker output.",
"description": "gokrazy has limited support for Bluetooth. The usual Bluetooth utilities (bluez) have a lot of dependencies that are not available on gokrazy and those are out of scope here. But the basic Bluetooth hardware are supported on low level. This is useful in particular for applications using Bluetooth LE natively in Go.\nTo enable Bluetooth in gokrazy, first add the github.com/gokrazy/bluetooth package to your gokrazy instance:\ngok add github.com/gokrazy/bluetooth The github.com/gokrazy/bluetooth package loads the appropriate kernel modules and firmware required.",
"tags": [],
"title": "Using Bluetooth",
"uri": "/userguide/bluetooth/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "Create the filesystem gokrazy provides a handy way to create the permanent data filesystem on the fourth partition of your gokrazy installation. The gokrazy/mkfs program will create the filesystem. To actually access the permanent data partition from your own program, gokrazy will mount the partition under /perm directory during the startup.\nYou can add the gokrazy/mkfs program to your gokrazy instance:\ngok add github.com/gokrazy/mkfs …or, if you want to run it only once without otherwise including it in your installation, you can use gok run:\ngit clone https://github.com/gokrazy/mkfs cd mkfs gok -i bakery run Permanent data in action The Go program demonstrates the functionality of the permanent data mount:\npackage main import ( \"encoding/json\" \"errors\" \"fmt\" \"io/fs\" \"io/ioutil\" \"os\" ) const config = \"/perm/my-example/config.json\" type Config struct { FilesToCreate int `json:\"files_to_create\"` } func main() { _, err := os.Stat(config) if err != nil { fsErr := \u0026fs.ErrNotExist if !errors.As(err, fsErr) { panic(err) } content, err := json.Marshal(\u0026Config{FilesToCreate: 4}) if err != nil { panic(err) } if err = ioutil.WriteFile(config, content, 0600); err != nil { panic(err) } } content, err := ioutil.ReadFile(config) if err != nil { panic(err) } var c Config if err := json.Unmarshal(content, \u0026c); err != nil { panic(err) } for i := 0; i \u003c c.FilesToCreate; i++ { if err := ioutil.WriteFile(fmt.Sprintf(\"/perm/my-example/%d.txt\", i), []byte(\"gokrazy rocks\"), 0600); err != nil { panic(err) } } } Manual inspection/modification You can inspect and modify the data on the permanent data filesystem manually. This can be handy if you need e.g. to pass a configuration file for your application. To access the filesystem put the SD card into your PC/notebook. Your OS will likely mount the filesystem automatically. Copy the file to the permanent data filesystem.\nmkdir /path/to-mounted/filesystem/my-example sudo cp config.json /path/to-mounted/filesystem/my-example If you want to access files on the permanent data filesystem you may need the sudo capability.\nNotes about macOS In macOS, to identify what device file maps to the mini sd card use:\n$ diskutil list If you want to create an ext4 filesystem from macOS, use the ext2/3/4 utilities. The easiest way to install them is via homebrew.\nWith the utilities installed you can run (replace X and Y based on the diskutil list output):\n$ sudo `brew --prefix e2fsprogs`/sbin/mkfs.ext4 /dev/diskXsY",
"description": "Create the filesystem gokrazy provides a handy way to create the permanent data filesystem on the fourth partition of your gokrazy installation. The gokrazy/mkfs program will create the filesystem. To actually access the permanent data partition from your own program, gokrazy will mount the partition under /perm directory during the startup.\nYou can add the gokrazy/mkfs program to your gokrazy instance:",
"tags": [],
"title": "Access permanent data",
"uri": "/userguide/permanent-data/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "This page shows you how to use an M.2 NVMe disk on your Raspberry Pi 5 with gokrazy.\nThe high-level plan is:\nInstall an M.2 HAT (with compatible NVMe SSD disk) on your Pi 5. Boot an SD card once on the Pi 5 to update the bootloader. Write gokrazy to the NVMe disk. Step 1. Install an M.2 HAT There are various products available to extend the Raspberry Pi 5 with an M.2 disk slot.\nUnfortunately, all of them require compromises:\nProduct fan? case? GPIO? M.2 form factor official Pi M.2 HAT+ ✅ yes ❌ no ❌ no 2230, 2242 official Pi M.2 HAT+ Compact ✅ yes ✅ yes ❌ no 2230 Pimoroni NVMe Base ✅ yes ❌ no ✅ yes 2230, 2242, 2260, 2280 (All of the above products have been successfully tested with gokrazy.)\nStep 2. Bootloader update On all three different Raspberry Pi 5 devices I tested, I needed to first update the bootloader firmware (stored in the EEPROM) before the NVMe port would start working.\nYou have multiple options for updating the firmware.\nOption A: gokrazy If you dont have a gokrazy instance yet, follow the Quickstart guide to create one.\nSet the EEPROMPackage instance config field as follows:\n{ … \"EEPROMPackage\": \"github.com/gokrazy/rpi5-eeprom\", … } Once you boot this gokrazy system, the EEPROM will be updated.\nIf you want, you can customize the boot order by setting the BootloaderExtraEEPROM instance config field, for example:\n{ … \"BootloaderExtraEEPROM\": [ \"BOOT_ORDER=0xf16\" ], … } This BOOT_ORDER setting 0xf16 boots from NVMe disk first, then falls back to SD card.\nOption B: Raspberry Pi Imager A gokrazy-managed bootloader (Option A) is the recommended way, but in case you need a different option, you can install and start the official Raspberry Pi Imager.\nClick “Operating System”, then chose Misc utility images → Bootloader (Pi 5 family) → NVMe/USB Boot.\nBoot the created SD card and observe the green LED. The LED is solid green for a few seconds, then starts blinking rapidly while the EEPROM is being written and ultimately blinks slowly. If you have an HDMI screen connected, the screen turns solid green once the EEPROM was written.\nStep 3. Using the NVMe disk If you want, you can mount the NVMe disk as an extra storage device, which requires no extra steps.\nThe rest of this section shows how to use the NVMe disk to store the entire gokrazy system.\nOption A: Writing to the NVMe disk directly The best way to write to the NVMe disk is to plug it into your computer, if you have a spare M.2 slot.\nIf you dont have an M.2 slot, you can use an USB M.2 NVMe SSD enclosure like the Icy Box IB-1817M-C31 (costs about 25 bucks).\nAfter plugging in the SSD, write gokrazy to it as usual:\ngok overwrite --full /dev/disk/by-id/… Option B: Copying a running system If you dont have a convenient way to write to an NVMe disk, you can boot gokrazy from SD card on the Raspberry Pi 5, then log in via SSH (using breakglass) and copy the running system.\nAfter using the breakglass command to log into your gokrazy instance, you should be able to list the /dev/mmcblk* and /dev/nvme* devices. With a fresh NVMe disk, you would expect to see no partitions after nvme0n1, and four partitions on mmcblk0:\n$ breakglass gokrazy 2025/11/16 16:46:54 checking breakglass status on gokrazy instance \"gokrazy\" 2025/11/16 16:46:54 polling SSH port to become available 2025/11/16 16:46:54 [ssh gokrazy.lan] Warning: Permanently added 'gokrazy.lan' (RSA) to the list of known hosts. __ .-----.-----| |--.----.---.-.-----.--.--. | _ | _ | \u003c| _| _ |-- __| | | |___ |_____|__|__|__| |___._|_____|___ | |_____| host: \"gokrazy\" |_____| model: Raspberry Pi 5 Model B Rev 1.0 build: 2025-11-16T15:55:04+01:00 /tmp/breakglass4067757295 # ls -l /dev/mmcblk* brw------- 1 0 0 179, 0 Nov 16 15:55 /dev/mmcblk0 brw------- 1 0 0 179, 1 Nov 16 15:55 /dev/mmcblk0p1 brw------- 1 0 0 179, 2 Nov 16 15:55 /dev/mmcblk0p2 brw------- 1 0 0 179, 3 Nov 16 15:55 /dev/mmcblk0p3 brw------- 1 0 0 179, 4 Nov 16 15:55 /dev/mmcblk0p4 /tmp/breakglass4067757295 # ls -l /dev/nvme* crw------- 1 0 0 239, 0 Nov 16 15:55 /dev/nvme0 brw------- 1 0 0 259, 0 Nov 16 15:55 /dev/nvme0n1 /tmp/breakglass4067757295 # Copy the first 1100 MB, which includes the gokrazy boot partition and gokrazy root A+B partitions, all of which are read-only and hence can be safely copied:\n/tmp # dd if=/dev/mmcblk0 of=/dev/nvme0n1 bs=1MB count=1100 1100+0 records in 1100+0 records out 1100000000 bytes (1.0GB) copied, 14.651804 seconds, 71.6MB/s /tmp # poweroff Connection to gokrazy.lan closed by remote host. Unplug the SD card and the Pi will now boot from the NVMe disk.\nAfterwards, create a permanent partition as usual and copy your files from the SD card to the partition, e.g. using scp (quick and built-in) or rsync for larger transfers.\nTODO: the partition table is not updated with this approach, meaning the permanent partition will be limited to the size of the SD card! See https://github.com/gokrazy/gokrazy/issues/267 for details.",
"description": "This page shows you how to use an M.2 NVMe disk on your Raspberry Pi 5 with gokrazy.\nThe high-level plan is:\nInstall an M.2 HAT (with compatible NVMe SSD disk) on your Pi 5. Boot an SD card once on the Pi 5 to update the bootloader. Write gokrazy to the NVMe disk. Step 1. Install an M.2 HAT There are various products available to extend the Raspberry Pi 5 with an M.2 disk slot.",
"tags": [],
"title": "NVMe disk (Pi 5)",
"uri": "/userguide/nvme-disk/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Available packages",
"content": "Prometheus is monitoring system and time series database.\nNote: In the following we will assume that your instance is called hello (default) as well as that the hostname is hello as well.\nInstalling the Prometheus Node Exporter If all you want to do is monitor your gokrazy installation, just add the Prometheus node exporter:\ngok add github.com/prometheus/node_exporter Installing the Prometheus Time Series Database To install the prometheus monitoring system, add the prometheus program to your gokrazy instance:\ngok add github.com/prometheus/prometheus/cmd/prometheus We need a valid prometheus config for prometheus to start successfully. Start with the default prometheus.yml from the prometheus repository. Save it to your gokrazy instance directory, e.g. ~/gokrazy/hello/prometheus.yml.\nOpen your instances config.json in your editor:\ngok edit To use the prometheus config file, we need to do two things in the gokrazy config:\nCopy over the prometheus.yml with Package config: Extra files Add Package config: Command-line flags We also add WaitForClock to get accurate timestamps for our timeseries data Your config should look something like this:\n{ \"Hostname\": \"hello\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/prometheus/prometheus\" ], \"PackageConfig\": { \"github.com/prometheus/prometheus\": { \"CommandLineFlags\": [ \"--config.file=/etc/prometheus/prometheus.yml\" ], \"WaitForClock\": true, \"ExtraFilePaths\": { \"/etc/prometheus/prometheus.yml\": \"prometheus.yml\" } } } } Then, deploy as usual:\ngok update In theory, this is enough to deploy prometheus, but unfortunately we are missing the web assets for the web UI which are not included in our build of prometheus.\nYou can use prometheus as is, if you never want to go to the web UI on hello:9090. If you visit the web UI anyway, you will get this (or a similar) error:\nError opening React index.html: open web/ui/static/react/index.html: no such file or directory To get the web UI to work, we first need the missing files. You have two options:\nOption A: Build Web Assets Follow Prometheus → Building from source, meaning:\ngit clone https://github.com/prometheus/prometheus cd prometheus make assets-compress Instruct gokrazy to use this build of Prometheus:\ngok -i hello add . Configure gokrazy to build Prometheus with the builtinassets Go build tag:\n{ \"Hostname\": \"hello\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/prometheus/prometheus\" ], \"PackageConfig\": { \"github.com/prometheus/prometheus\": { \"GoBuildTags\": [ \"builtinassets\" ], \"CommandLineFlags\": [ \"--config.file=/etc/prometheus/prometheus.yml\" ], \"WaitForClock\": true, \"ExtraFilePaths\": { \"/etc/prometheus/prometheus.yml\": \"prometheus.yml\" } } } } To update Prometheus, youll need to update your Prometheus dir instead of using gok get:\ngit pull \u0026\u0026 make assets-compress Option B: Download Web Assets The web assets are released with every prometheus release and you need to update them by hand with every new version.\nGo to https://github.com/prometheus/prometheus/releases Expand the section “Assets” for the lastest release Download prometheus-web-ui-VERSION.tar.gz with VERSION being something like 2.46.0 (example url for version 2.46.0: https://github.com/prometheus/prometheus/releases/download/v2.46.0/prometheus-web-ui-2.46.0.tar.gz) Extract the archive file: tar xf prometheus-web-ui-2.46.0.tar.gz Enable breakglass via gokrazy web Create the right folder on your device: ssh hello mkdir -p /perm/home/prometheus/web/ui Copy over the static/ directory you exctracted from the tar file: scp -r static/ hello:/perm/home/prometheus/web/ui Go to hello:9090 to check if the web UI is working",
"description": "Prometheus is monitoring system and time series database.\nNote: In the following we will assume that your instance is called hello (default) as well as that the hostname is hello as well.\nInstalling the Prometheus Node Exporter If all you want to do is monitor your gokrazy installation, just add the Prometheus node exporter:\ngok add github.com/prometheus/node_exporter Installing the Prometheus Time Series Database To install the prometheus monitoring system, add the prometheus program to your gokrazy instance:",
"tags": [],
"title": "Prometheus",
"uri": "/packages/prometheus/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "In addition to running gokrazy on a Raspberry Pi or another ARM board, you can also run it in a QEMU x86-64 virtual machine. The following guide covers whats necessary to build and run a gokrazy image on QEMU. Your hypervisor may require additional configuration.\nBuilding the image Create a new gokrazy instance gok -i virtual new The -i flag specifies the name of the instance. In this case, were using virtual, but you can use any name you like. The instance configuration will be created in your home directory under ~/gokrazy/virtual.\nEdit the instance configuration Run gok -i virtual edit to open the instance configuration file in your favorite editor. Youll need to make the following changes:\n{ \"Hostname\": \"virtual\", \"KernelPackage\": \"github.com/rtr7/kernel\", \"FirmwarePackage\": \"github.com/rtr7/kernel\", \"SerialConsole\": \"ttyS0,115200\", // ... } Build the image The following command will build a single image file that contains the kernel, firmware, and root filesystem. The --target_storage_bytes flag must be specified to set the size of the image. The example below creates a 4GB image.\nGOARCH=amd64 gok -i virtual overwrite --full virtual.img --target_storage_bytes 4294967296 The image will be written to the current directory as virtual.img.\nUse the image with QEMU You can now use the image with QEMU. The following command will boot the image in QEMU with a serial console:\nqemu-system-x86_64 \\ -machine accel=kvm \\ -smp 8 \\ -m 2048 \\ -drive file=virtual.img,format=raw \\ -nographic Use the image with Proxmox You can also use the image with other hypervisors, such as Proxmox PVE. Start by creating a new VM without a storage device. Then, upload the image to the Proxmox host and add it as a hard disk to the VM.\nqm importdisk \u003cvmid\u003e virtual.img \u003cstorage\u003e # for example, for vmid 105 and local-zfs storage: qm importdisk 105 virtual.img local-zfs Visit the Proxmox web UI and choose the unattached disk on the VM Hardware tab. Click “Edit” and select “SCSI” as the Bus/Device. Click “Add” to add the disk to the VM. Visit the “Options” tab and edit “Boot Order”. Make sure the SCIS disk is checked and move it to the top of the list. Click “OK” to save your changes.\nBonus: Deploy a QEMU guest agent If youre using Proxmox PVE, you can deploy a QEMU guest agent to the VM. This will allow you to discover the VMs IP address. The qemu-guest-kragent project provides a simple agent that can be used with gokrazy.\nTo add the agent to your gokrazy instance, run the following command:\ngok -i virtual add github.com/bradfitz/qemu-guest-kragent Visit the Proxmox web UI and choose the VM. Click “Options” and select “QEMU Guest Agent”. Make sure “Use QEMU Guest Agent” is checked. Click “OK” to save your changes.\nTips: Optimizing the VM The following tips can be used to optimize the VM and reduce CPU usage:\nDisable USB hotplug Disable USB tablet/pointer support Use the VirtIO graphics support. On Proxmox either “VirtIO-GPU” graphic card or vga: virtio in the config file. Next steps You can now use this gokrazy VM instance as you would any other gokrazy instance. For example, you can add packages, configure the instance, and update it.\nGOARCH=amd64 gok -i virtual update For more information, see the Instance config reference.",
"description": "In addition to running gokrazy on a Raspberry Pi or another ARM board, you can also run it in a QEMU x86-64 virtual machine. The following guide covers whats necessary to build and run a gokrazy image on QEMU. Your hypervisor may require additional configuration.\nBuilding the image Create a new gokrazy instance gok -i virtual new The -i flag specifies the name of the instance. In this case, were using virtual, but you can use any name you like. The instance configuration will be created in your home directory under ~/gokrazy/virtual.",
"tags": [],
"title": "QEMU x86-64 virtual machine",
"uri": "/userguide/qemu/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Configuration",
"content": "I like to periodically back up all scans from my scan2drive appliance to my PC. The PC is backed up as well, so that automatically distributes my scans to multiple machines in case one of them fails.\nA convenient way to set up an efficient partial or full backup of a gokrazy devices permanent data partition is to use the gokrazy rsync daemon. This article walks you through how I have set up my backup, but many variants are possible to cater to different requirements.\n(You dont typically need backups of your gokrazy devices root partition because it can be built reproducibly any time using Go.)\nStep 1. Install the gokrazy rsync daemon Add the gokrazy rsync implementation gokr-rsync to your gokrazy instance:\ngok add github.com/gokrazy/rsync/cmd/gokr-rsync Step 2. Configure the gokrazy rsync daemon Open your gokrazy instances config.json in your editor:\ngok edit Configure Package config: Command-line flags and Package config: Extra files:\n{ \"Hostname\": \"backedup\", \"Packages\": [ \"github.com/gokrazy/fbstatus\", \"github.com/gokrazy/hello\", \"github.com/gokrazy/serial-busybox\", \"github.com/gokrazy/breakglass\", \"github.com/gokrazy/rsync/cmd/gokr-rsync\" ], \"PackageConfig\": { \"github.com/gokrazy/rsync/cmd/gokr-rsync\": { \"Basename\": \"rsync\", \"CommandLineFlags\": [ \"--daemon\", \"--gokr.config=/etc/gokr-rsyncd.toml\" ], \"ExtraFilePaths\": { \"/etc/gokr-rsyncd.toml\": \"gokr-rsyncd.toml\", \"/etc/gokr-rsyncd.authorized_keys\": \"gokr-rsyncd.authorized_keys\" } } } } In the daemon config file, configure an authorized SSH listener and which rsync modules to serve:\ncat \u003e ~/gokrazy/hello/gokr-rsyncd.toml \u003c\u003c'EOT' dont_namespace = true [[listener]] [listener.authorized_ssh] address = \"scan2drive.lan:22873\" authorized_keys = \"/etc/gokr-rsyncd.authorized_keys\" [[module]] name = \"scans\" path = \"/perm/scans\" EOT Finally, create the authorized keys file that determines who can access the rsync daemon:\ncat \u003e ~/gokrazy/hello/gokr-rsyncd.authorized_keys \u003c\u003c'EOT' ssh-ed25519 […] michael@midna EOT Then, deploy as usual:\ngok update Step 3. Configure SSH from the backup machine On your PC (not the gokrazy instance), add an SSH configuration stanza to your ~/.ssh/config to configure the custom port (22873 for ssh+rsync) and which passwordless identity file to use (for the cron job in step 4):\nHost scan2drive-backup Hostname scan2drive.lan Port 22873 IdentityFile ~/.ssh/id_ed25519_scan2drivebackup Now you should be able to run rsync via SSH as usual:\nrsync -av -e ssh rsync://scan2drive-backup/scans/ ~/scan2drive-backup/ Step 4. Configure a daily cron job First, install the rsync-prom tool to monitor your periodic transfer with Prometheus:\ngo install github.com/stapelberg/rsyncprom/cmd/rsync-prom@latest Then wrap the above rsync command in an rsync-prom invocation in a shell script called scan2drive-backup-sync.sh:\n#!/bin/sh SSH_AUTH_SOCK= ~/go/bin/rsync-prom --instance=\"scan2drive@midna\" \\ rsync -av -e ssh rsync://scan2drive-backup/scans/ ~/scan2drive-backup/ Finally, run crontab -e and run the script at your convenience, like so:\n30 07 * * * /home/michael/scan2drive-backup-sync.sh",
"description": "I like to periodically back up all scans from my scan2drive appliance to my PC. The PC is backed up as well, so that automatically distributes my scans to multiple machines in case one of them fails.\nA convenient way to set up an efficient partial or full backup of a gokrazy devices permanent data partition is to use the gokrazy rsync daemon. This article walks you through how I have set up my backup, but many variants are possible to cater to different requirements.",
"tags": [],
"title": "Permanent data backup with the gokrazy rsync",
"uri": "/userguide/rsync-backups/index.html"
},
{
"breadcrumb": "gokrazy Go appliances \u003e Package development",
"content": "To realize the full benefits of gokrazy, you need to use only software written in Go. If there is no Go software for what you want to do, creating that piece of software can pose a seemingly unsurmountable hurdle. To make some quick progress and figure out if your idea can be implemented, it might make sense to temporarily use existing software before starting your own implementation.\nThis article shows a couple of techniques for getting non-Go software to work on gokrazy, in increasing order of complexity.\nNote that software which is manually installed like shown here will not be automatically updated by gokrazy and hence poses a security risk. Use these techniques only for prototyping.\nGo software not written for gokrazy: Grafana It would not suffice to add Grafana to your gokr-packer command, as the resulting Grafana binary requires assets, supports plugins, keeps state, etc.\nHence, you need to manually install Grafana into a directory underneath /perm. A convenient way to do that is to use breakglass to download the “Standalone Linux Binaries” release from https://grafana.com/grafana/download?platform=arm. Note that I am serving the file from my computer because my busybox version supports neither HTTPS nor DNS.\n/tmp/breakglass531810560 # wget http://10.0.0.76:4080/grafana-5.3.2.linux-arm64.tar.gz /tmp/breakglass531810560 # tar xf grafana-5.3.2.linux-arm64.tar.gz We cannot start Grafana yet, as its binary is dynamically linked. One way to fix this is to place the sources which correspond to the release you just unpacked (e.g. from https://github.com/grafana/grafana/tree/v5.3.2) in your $GOPATH and recompile the binaries:\nGOARCH=arm64 CGO_ENABLED=1 CC=aarch64-linux-gnu-gcc go install \\ -ldflags \"-linkmode external -extldflags -static\" \\ github.com/grafana/grafana/pkg/cmd/... Note that it is usually easier to set the environment variable CGO_ENABLED=0 to get a statically linked binary, but Grafana uses sqlite3, which is written in C, so we resort to the -ldflags variant.\nAt this point, we can start Grafana from breakglass:\n/tmp/breakglass531810560 # cd grafana-5.3.2 /tmp/breakglass531810560/grafana-5.3.2 # wget http://10.0.0.76:4080/grafana-server /tmp/breakglass531810560/grafana-5.3.2 # install -m 755 grafana-server bin/ \u0026\u0026 rm grafana-server /tmp/breakglass531810560/grafana-5.3.2 # ./bin/grafana-server INFO[10-30|19:27:51] Starting Grafana logger=server version=5.0.0 commit=NA compiled=2018-10-30T19:27:51+0100 … To have gokrazy start Grafana, we can use a Go package like this:\npackage main import ( \"log\" \"syscall\" ) func main() { const bin = \"/perm/grafana/bin/grafana-server\" if err := syscall.Exec(bin, []string{bin, \"-homepath=/perm/grafana\"}, nil); err != nil { log.Fatal(err) } } C software: WireGuard WireGuard is a modern VPN tunnel, which consists of a Linux kernel module and a configuration tool. See rtr7/kernel@c7afbc1f for how the kernel module was added to the router7 kernel.\nThe configuration tool can be statically cross-compiled. We can run Debian in a Docker container to not mess with our host system:\n% mkdir /tmp/wg % cd /tmp/wg % docker run -t -i debian root@d1728eaaa6e1:/# dpkg --add-architecture arm64 root@d1728eaaa6e1:/# apt update root@d1728eaaa6e1:/# apt install libmnl-dev:arm64 libelf-dev:arm64 linux-headers-amd64 crossbuild-essential-arm64 pkg-config wget root@d1728eaaa6e1:/# wget https://git.zx2c4.com/WireGuard/snapshot/WireGuard-0.0.20181018.tar.xz root@d1728eaaa6e1:/# tar xf WireGuard-0.0.20181018.tar.xz root@d1728eaaa6e1:/# cd WireGuard-0.0.20181018/src/tools root@d1728eaaa6e1:/# make CC=aarch64-linux-gnu-gcc LDFLAGS=-static root@d1728eaaa6e1:/# exit % docker cp -L d1728eaaa6e1:/WireGuard-0.0.20181018/src/tools/wg . Now we can copy and run the wg binary via breakglass:\n/tmp/breakglass531810560 # wget http://10.0.0.76:4080/wg /tmp/breakglass531810560 # chmod +x wg /tmp/breakglass531810560 # ./wg --help Usage: ./wg \u003ccmd\u003e [\u003cargs\u003e] … C software: tc Linuxs Traffic Control system (used e.g. for traffic shaping) is configured with the tc tool.\ntc is a special case in that it requires to be dynamically linked. The different queueing disciplines are implemented as plugins, and statically linking tc results in a binary which starts but wont be able to display or change queueing disciplines.\nBecause gokrazy doesnt include a C runtime environment, well need to copy not only the tc binary, but also the dynamic loader and all required shared libraries. We can run Debian in a Docker container to not mess with our host system, and use the freeze tool to automate the tedious parts of the process:\n% docker run -t -i debian:trixie root@6e530a973d45:/# dpkg --add-architecture arm64 root@6e530a973d45:/# apt update root@6e530a973d45:/# apt install iproute2:arm64 qemu-user-static golang-go ca-certificates root@6e530a973d45:/# go install github.com/gokrazy/freeze/cmd/...@latest root@6e530a973d45:/# ~/go/bin/freeze -wrap=qemu-aarch64-static $(which tc) 2022/03/20 11:45:46 /sbin/tc 2022/03/20 11:45:46 Copying tc together with its 12 ELF shared library dependencies 2022/03/20 11:45:46 [cp /sbin/tc /tmp/freeze2237965672/tc] 2022/03/20 11:45:46 [cp /usr/lib/aarch64-linux-gnu/libbpf.so.0.7.0 /tmp/freeze2237965672/libbpf.so.0] 2022/03/20 11:45:46 [cp /usr/lib/aarch64-linux-gnu/libelf-0.186.so /tmp/freeze2237965672/libelf.so.1] 2022/03/20 11:45:46 [cp /usr/lib/aarch64-linux-gnu/libmnl.so.0.2.0 /tmp/freeze2237965672/libmnl.so.0] 2022/03/20 11:45:46 [cp /usr/lib/aarch64-linux-gnu/libbsd.so.0.11.5 /tmp/freeze2237965672/libbsd.so.0] 2022/03/20 11:45:46 [cp /lib/aarch64-linux-gnu/libcap.so.2.44 /tmp/freeze2237965672/libcap.so.2] 2022/03/20 11:45:46 [cp /lib/aarch64-linux-gnu/libm-2.33.so /tmp/freeze2237965672/libm.so.6] 2022/03/20 11:45:46 [cp /lib/aarch64-linux-gnu/libdl-2.33.so /tmp/freeze2237965672/libdl.so.2] 2022/03/20 11:45:46 [cp /usr/lib/aarch64-linux-gnu/libxtables.so.12.4.0 /tmp/freeze2237965672/libxtables.so.12] 2022/03/20 11:45:46 [cp /lib/aarch64-linux-gnu/libc-2.33.so /tmp/freeze2237965672/libc.so.6] 2022/03/20 11:45:46 [cp /lib/aarch64-linux-gnu/ld-2.33.so /tmp/freeze2237965672/ld-linux-aarch64.so.1] 2022/03/20 11:45:46 [cp /lib/aarch64-linux-gnu/libz.so.1.2.11 /tmp/freeze2237965672/libz.so.1] 2022/03/20 11:45:46 [cp /usr/lib/aarch64-linux-gnu/libmd.so.0.0.5 /tmp/freeze2237965672/libmd.so.0] 2022/03/20 11:45:46 [tar cf /tmp/freeze2237965672.tar freeze2237965672] 2022/03/20 11:45:46 Download freeze2237965672.tar to your gokrazy device and run: LD_LIBRARY_PATH=$PWD ./ld-linux-aarch64.so.1 ./tc root@6e530a973d45:/# exit % mkdir /tmp/freeze % cd /tmp/freeze % docker cp 6e530a973d45:/tmp/freeze2237965672.tar . % caddy file-server -listen=:4080 Now we can copy the contents of the temporary directory to e.g. /perm/tc and run the tc command in breakglass:\n/tmp/breakglass531810560 # wget -O- http://10.0.0.76:4080/freeze2237965672.tar | tar xf - /tmp/breakglass531810560 # cd freeze2237965672 /tmp/breakglass531810560/freeze2237965672 # LD_LIBRARY_PATH=$PWD ./ld-linux-aarch64.so.1 ./tc Usage: tc [ OPTIONS ] OBJECT { COMMAND | help } …",
"description": "To realize the full benefits of gokrazy, you need to use only software written in Go. If there is no Go software for what you want to do, creating that piece of software can pose a seemingly unsurmountable hurdle. To make some quick progress and figure out if your idea can be implemented, it might make sense to temporarily use existing software before starting your own implementation.\nThis article shows a couple of techniques for getting non-Go software to work on gokrazy, in increasing order of complexity.",
"tags": [],
"title": "Non-Go Prototyping",
"uri": "/development/non-go/index.html"
},
{
"breadcrumb": "",
"content": "With gokrazy, you can deploy one or more Go programs as appliances to a Raspberry Pi, Virtual Machine, embedded or normal PC (see supported platforms).\ngokrazy uses its own minimal Go userland instead of a traditional Linux distribution base.\nThis minimalist approach offers several advantages in terms of security, maintainability and reliability:\nThe surface area for security vulnerabilities is drastically reduced. The root filesystem is entirely read-only (making persistent malware installation hard) and new versions of the system are installed by overwriting the root file system with the new version. No default shell access: There is neither xz nor OpenSSH on a gokrazy system. Interactive access for debugging is possible, but needs to be explicitly started. Backstory For a long time, we were unhappy about having to spend so much time on each of our various Raspberry Pis, taking care of security updates and other general Linux distribution maintenance.\nThen, we had a crazy idea: what if we massively reduced the overall system complexity by getting rid of all software we dont strictly need, and instead built up a minimal system from scratch entirely in Go, a memory safe programming language?\nTurns out this is feasible. gokrazy is the result. See it in action in this first installation demo video:\nYour app(s) + only 4 moving parts the Linux kernel new versions are typically available \u003c 24h after upstream release! the Raspberry Pi firmware files the Go compiler and standard library the gokrazy system (minimal init system, updater, DHCP, NTP, …) Uniformity Whats appealing about building an appliance entirely in Go? You get the same advantages you get when building Go software elsewhere:\nAll components mentioned above (except for the Go compiler) are managed as Go modules, using the same tooling youre already familiar with. Go has very quick compilation times; the gok run command allows for a fast edit-run loop. Gos tracing and profiling support can be used on the entire system With Gos replace directive, you can quickly modify any part of the system with the same workflow. Web status interface On a regular Linux distribution, wed largely use systemctls start, stop, restart and status verbs to manage our applications. gokrazy comes with a convenient web interface for seeing process status and stopping/restarting processes.\nDebugging Sometimes, an interactive busybox session or a quick tcpdump run are invaluable. breakglass allows you to temporarily enable SSH/SCP-based authenticated remote code execution: scp your statically compiled binary, then run it interactively via ssh.\nDue to no C runtime environment being present, your code must compile with the environment variable CGO_ENABLED=0. To cross-compile for the Raspberry Pi 3 or 4, use GOARCH=arm64. If your program still builds, youre good to go!\nNetwork updates After building a new gokrazy image on your computer, you can easily update an existing gokrazy installation in-place thanks to the A/B partitioning scheme we use. Just use the gok update command.\nMinimal state and configuration A tiny amount of configuration is built into the images (e.g. hostname, password, serial console behavior). In general, we prefer auto-configuration (e.g. DHCP) over config files. If you need more configurability, you may need to replace some of our programs.",
"description": "With gokrazy, you can deploy one or more Go programs as appliances to a Raspberry Pi, Virtual Machine, embedded or normal PC (see supported platforms).\ngokrazy uses its own minimal Go userland instead of a traditional Linux distribution base.\nThis minimalist approach offers several advantages in terms of security, maintainability and reliability:\nThe surface area for security vulnerabilities is drastically reduced. The root filesystem is entirely read-only (making persistent malware installation hard) and new versions of the system are installed by overwriting the root file system with the new version. No default shell access: There is neither xz nor OpenSSH on a gokrazy system. Interactive access for debugging is possible, but needs to be explicitly started. Backstory For a long time, we were unhappy about having to spend so much time on each of our various Raspberry Pis, taking care of security updates and other general Linux distribution maintenance.",
"tags": [],
"title": "gokrazy Go appliances",
"uri": "/index.html"
}
]