From d615322449a8cb94ced351f876b3573be3a694fb Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 20 Sep 2026 18:11:28 +0200 Subject: [PATCH 1/4] [wip] port readme contents over to an mdbook --- README.md | 9 +- book/.gitignore | 1 + book/book.toml | 4 + book/src/README.md | 7 + book/src/SUMMARY.md | 11 ++ book/src/configuration.md | 272 ++++++++++++++++++++++++++++++++++++++ book/src/frankenphp.md | 1 + book/src/proxy/README.md | 91 +++++++++++++ book/src/proxy/dns.md | 27 ++++ book/src/proxy/https.md | 78 +++++++++++ book/src/setup.md | 33 +++++ book/src/xdebug.md | 1 + flake.nix | 1 + 13 files changed, 533 insertions(+), 3 deletions(-) create mode 100644 book/.gitignore create mode 100644 book/book.toml create mode 100644 book/src/README.md create mode 100644 book/src/SUMMARY.md create mode 100644 book/src/configuration.md create mode 100644 book/src/frankenphp.md create mode 100644 book/src/proxy/README.md create mode 100644 book/src/proxy/dns.md create mode 100644 book/src/proxy/https.md create mode 100644 book/src/setup.md create mode 100644 book/src/xdebug.md diff --git a/README.md b/README.md index b05dfe4..23f3b8d 100644 --- a/README.md +++ b/README.md @@ -447,9 +447,11 @@ script can be overriden by running the script with ## Nushell scripts -By default, the script contents are executed as either `bash` script, or `nu` script based on the extension. +By default, the script contents are executed as either `bash` script, or `nu` +script based on the extension. -You can overwrite the interpreter used to execute the script by adding an extra `#!` line to the script, for example: +You can overwrite the interpreter used to execute the script by adding an extra +`#!` line to the script, for example: ```bash #! /usr/bin/env -S haze script @@ -459,7 +461,8 @@ You can overwrite the interpreter used to execute the script by adding an extra print("Hello"); ``` -Note that the interpreter used needs to already be available inside the haze container. +Note that the interpreter used needs to already be available inside the haze +container. ## Configuration diff --git a/book/.gitignore b/book/.gitignore new file mode 100644 index 0000000..e9c0728 --- /dev/null +++ b/book/.gitignore @@ -0,0 +1 @@ +book \ No newline at end of file diff --git a/book/book.toml b/book/book.toml new file mode 100644 index 0000000..c2ab188 --- /dev/null +++ b/book/book.toml @@ -0,0 +1,4 @@ +[book] +title = "Haze" +authors = ["Robin Appelman"] +language = "en" diff --git a/book/src/README.md b/book/src/README.md new file mode 100644 index 0000000..8d340b0 --- /dev/null +++ b/book/src/README.md @@ -0,0 +1,7 @@ +# Haze + +Hazy with a chance of clouds. + +`haze` is a tool that provides provides an easy way to set up Nextcloud test +instances with a choice of php version, database server, optional s3 or ldap +setup and much more. diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md new file mode 100644 index 0000000..565c8e4 --- /dev/null +++ b/book/src/SUMMARY.md @@ -0,0 +1,11 @@ +# Summary + +[Introduction](README.md) + +- [Setup](setup.md) +- [Configuration](configuration.md) +- [Proxy](proxy/README.md) + - [DNS](proxy/dns.md) + - [HTTPS](proxy/https.md) +- [Xdebug](xdebug.md) +- [FrankenPHP (experimental)](frankenphp.md) diff --git a/book/src/configuration.md b/book/src/configuration.md new file mode 100644 index 0000000..ab42b18 --- /dev/null +++ b/book/src/configuration.md @@ -0,0 +1,272 @@ +# Configuration + +Configuration is loaded from `~/.config/haze/haze.toml`. + +The minimum required configuration needed to get started is just the +`sources_root` options. + +The full list of supported options is: + +### sources_root + +The local path of the nextcloud sources. This options is **required**. + +Type: string + +### app_directories + +A list of additional app directory paths to look for apps into + +Default `[]` + +Type: list of strings + +### work_dir + +The location where haze keeps it's temporary files and caches + +Default: `/tmp/haze` + +Type: string + +### worktree_dir + +The location to to store git worktrees when using instances with detached +sources. + +Default: `/worktrees` + +Type: string + +## auto_setup + +Options for automatically setting up the newly created Nextcloud instance. + +Examples: + +```toml +[auto_setup] +username = "foo" +password = "bar" +enable_apps = ["files_external"] +disable_apps = ["contacts"] +post_setup = [ + "occ group:add test", +] +config = { "enforce_theme" = "dark" } +``` + +```toml +[auto_setup] +enabled = false +``` + +### auto_setup.enabled + +Whether to automatically setup Nextcloud inside a created instance. + +Default: `true` + +Type: boolean + +### auto_setup.username + +The username to use for the admin account during auto setup. + +Default: `admin` + +Type: string + +### auto_setup.password + +The password to use for the admin account during auto setup. + +Default: `admin` + +Type: string + +### auto_setup.enabled_apps + +Extra apps to enable after auto setup + +Default: `[]` + +Type: list of strings + +### auto_setup.disabled_apps + +Apps to disabled after auto setup + +Default: `[]` + +Type: list of strings + +### auto_setup.post_setup + +Commands to execute after auto setup + +Default: `[]` + +Type: list of strings + +### auto_setup.config + +System configuration options to set before auto setup + +Default: `{}` + +Type: Object + +## volume + +Additional files or directories to bind-mount into instances. + +Any number of volume options can be configured + +Examples: + +```toml +[[volume]] +source = "/tmp/haze-shared" +target = "/shared" +create = true +``` + +```toml +[[volume]] +source = "/home/me/Downloads" +target = "/Downloads" +read_only = true +``` + +### volume.source + +The source path on the host + +Type: string + +### volume.target + +The target path inside the container + +Type: string + +### volume.create + +Create the source directory on the host if it doesn't exist already. + +Default: `false` + +Type: boolean + +### volume.read_only + +Whether to mount the file or directory as read read_only + +Default: `false` + +Type: boolean + +### preset + +Configured presets that can be used when creating instances. + +Any number of presets can be configured. + +Example: + +```toml +[[preset]] +name = "groupfolders" +apps = ["groupfolders"] +commands = [ + "occ groupfolders:create gf", + "occ groupfolders:group 1 admin read write share delete" +] +``` + +### preset.name + +The name of the preset, this is used when creating instances to select the +preset. + +Type: string without whitespace + +### preset.apps + +A list of apps to enable when the preset is used. + +Default: `[]` + +Type: list of strings + +### preset.commands + +A list of commands to run post-setup when the preset is used. + +Default: `[]` + +Type: list of strings + +## proxy + +Configuration for the haze proxy. Only required when using the proxy. + +```toml +[proxy] +address = "haze.example.com" +listen = "/run/haze/haze.sock" +https = true +cert = "/path/to/haze.test.crt" +key = "/path/to/haze.test.key" +``` + +### proxy.listen + +The ip and port or unix socket for the proxy to listen on. + +**Required** when the proxy is enabled. + +Type: string + +Examples: + +```toml +listen = "/run/haze/haze.sock" +``` + +```toml +listen = "127.0.0.1:8080" +``` + +### proxy.address + +The base domain the proxy is accessible on. + +**Required** if the proxy is enabled. + +Type: string + +### proxy.https + +Whether to enable built-in https support for the proxy. + +Default: `false` + +Type: boolean + +### proxy.cert + +The path of the PEM encoded certificate chain to use for https. + +**Required** if https is enabled for the proxy. + +Type: string. + +### proxy.cert + +The path of the PEM encoded private key to use for https. + +**Required** if https is enabled for the proxy. + +Type: string. diff --git a/book/src/frankenphp.md b/book/src/frankenphp.md new file mode 100644 index 0000000..ad8871f --- /dev/null +++ b/book/src/frankenphp.md @@ -0,0 +1 @@ +# FrankenPHP (experimental) diff --git a/book/src/proxy/README.md b/book/src/proxy/README.md new file mode 100644 index 0000000..5be009b --- /dev/null +++ b/book/src/proxy/README.md @@ -0,0 +1,91 @@ +# Proxy + +By default, instances can be accessed by their IP. In order to get more +memorable URLs and allow supporting https. haze comes with a builtin reverse +proxy to allow using a wildcard domain. + +## Setup + +- [Setup a DNS record](./dns.html) for `*.haze.example.com` and + `haze.example.com` pointing to your development machine. +- Set the `proxy` configuration with your domain and desired listen endpoint. +- Set up a service to run `haze proxy` in the background as your own user. A + systemd user service is recommended (see + [haze.service](<[./haze.service](https://codeberg.org/icewind/haze/src/branch/main/haze.service)>) + for an example). +- If you're already running a reverse proxy, configure your reverse proxy of + choice to proxy `*.haze.example.com` and `haze.example.com` to the proxy's + listen endpoint. +- (Optionally) [setup https](./https.html) for the proxy. + +### Configuration + +Add the following configuration to the `haze.toml` config file: + +```toml +[proxy] +address = "haze.example.com" # the base domain for the proxy to use +listen = "127.0.0.1:8080" # the port+ip to listen on +# listen = "/var/run/haze/haze.sock" # or a unix socket path +``` + +### Without a reverse proxy + +If you have no other http(s) servers on your development machine, you can setup +things without a reverse proxy. + +Simply configure the proxy to listen on port `80` (or `443` when using http). + +Binding to port 80 or443 as a regular user requires either giving the haze +binary the `net_bind_service` capability with +`sudo setcap cap_net_bind_service=+ep $(which haze)` (this will have to be done +every time your upgrade haze) or configure your system to allow unpriviled users +to bind on the low port numbers. Using +`sysctl net.ipv4.ip_unprivileged_port_start=80` and writing + +``` +net.ipv4.ip_unprivileged_port_start=80 +``` + +to `/etc/sysctl.d/bind.conf` to make it persistent across reboot. + +### With a reverse proxy + +If you're already have other http(s) services listening on your machine, you'll +probably want to setup a reverse proxy to allow them to all be served on your +machine. + +The setup for this will depend on your reverse proxy of the choice, the +following example config is for `nginx`. + +```nginx +upstream haze-handler { + server unix:/var/run/haze/haze.sock; +} + +server { + listen 80; + server_name *.haze.example.com; + + location / { + proxy_pass http://haze-handler; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` + +## Usage + +When the proxy is configured, generated URLs for the instances will use a +subdomain of the configured domain, e.g. the `rolling-bees` instance will be +available at `rolling-bees.haze.example.com`. Additionally, `haze.example.com` +will automatically point to the last created instance. + +Additionally, the proxy allows access to the service containers trough either +`-.haze.example.com` for a specific instance, or +`.haze.example.com` for the last created instance. For example +`rolling-bees-mail.haze.example.com` will give access to the smtp4dev web +interface of the `rolling-bees` instance. diff --git a/book/src/proxy/dns.md b/book/src/proxy/dns.md new file mode 100644 index 0000000..c0dc85d --- /dev/null +++ b/book/src/proxy/dns.md @@ -0,0 +1,27 @@ +# DNS + +Since the domain name used for the instance is dynamic, a wildcard dns record is +required. + +## With your domain's DNS provider + +If you own a domain you would like to use, you can create a wildcard domain +withing the DNS settings of your DNS provider. For example creating a record an +`A` record for `*.haze.example.com` with a value of `127.0.0.1` and a similar +one for `haze.example.com`. + +## With a local dnsmasq + +If you do not own a "real" domain for using with haze, you can setup `dnsmasq` +locally to achieve the same goal instead. + +How to install and enable `dnsmasq` will depend on your distro of choice and +should be documented by it's documentation. + +Once setup, a configuration line like + +``` +address=/haze.local/172.0.0.1 +``` + +should be enough to point `haze.local` and `*.haze.local` to your local host. diff --git a/book/src/proxy/https.md b/book/src/proxy/https.md new file mode 100644 index 0000000..0acd6c1 --- /dev/null +++ b/book/src/proxy/https.md @@ -0,0 +1,78 @@ +# HTTPS + +The proxy can be setup to enable using https to access the running instances. +Besides the warm and fuzy feeling of knowing that nobody can snoop on the trafic +that is happening completely local inside your machine. Accessing the page over +https is required for some javascript features (such as service workers), as +they are only available in "secure contexts". + +## Getting a wildcard certificate + +Since the domain name used for the instance is dynamic, a wildcard certificate +is required. + +## Let's encrypt + +Let's encrypt allows getting trusted wildcard certificates for free if you can +use DNS validation. + +How to setup DNS validation will depend on the specifics of the DNS provider and +ACME client. +[This](https://community.letsencrypt.org/t/dns-providers-who-easily-integrate-with-lets-encrypt-dns-validation/86438) +lists some DNS providers and supported ACME clients. + +## Self signed + +You can also create a self-signed wildcard certificate using a tool like +`mkcert`. This certificate will not be trusted by your browser and tools like +curl, but you can add manually add it to the trusted certificates on your +system, or bypass the certficate warning in the browser/curl every time. + +```bash +# Generate local wildcard certificate +mkcert -cert-file haze.example.com.crt -key-file haze.example.com.key '*.haze.example.com' +``` + +## Using the certificate + +### Without reverse proxy + +The haze proxy can serve over https directly, to enable that add the following +to the `[proxy]` section of your `haze.toml`. + +```toml +https = true +cert = "/path/to/haze.example.com.crt" +key = "/path/to/haze.example.com.key" +``` + +You might also want to change the port it's listening on to `443`. + +### With a reverse proxy + +This depends on what reverse proxy you have setup. The following example is for +`nginx`. + +```nginx +upstream haze-handler { + server unix:/run/haze/haze.sock; +} + +server { + listen 80; + listen 443 ssl; + http2 on; + server_name *.haze.example.com; + + ssl_certificate /haze.example.com.crt; + ssl_certificate_key /haze.example.com.key; + + location / { + proxy_pass http://haze-handler; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} +``` diff --git a/book/src/setup.md b/book/src/setup.md new file mode 100644 index 0000000..f191167 --- /dev/null +++ b/book/src/setup.md @@ -0,0 +1,33 @@ +# Setup + +## Requirements + +- Docker + +## Installation + +- Grab a binary from the + [Codeberg releases](https://codeberg.org/icewind/haze/releases) and place it + in your `$PATH` + +## Config + +Create a file `~/.config/haze/haze.toml` with the following options: + +```toml +sources_root = "/path/to/nextcloud/sources" +``` + +See the [configuration section](./configuration.html) for more options. + +## Test the Setup + +### Quick examples + +- Start a basic Nextcloud instance: + + ```bash + haze start + ``` + +- Navigate to the address that is provided in the output. diff --git a/book/src/xdebug.md b/book/src/xdebug.md new file mode 100644 index 0000000..e0cf5e1 --- /dev/null +++ b/book/src/xdebug.md @@ -0,0 +1 @@ +# Xdebug diff --git a/flake.nix b/flake.nix index 99f9772..bde0f45 100644 --- a/flake.nix +++ b/flake.nix @@ -63,6 +63,7 @@ bacon skopeo dive + mdbook ]; homeModules = { From 070972a316c2b5aac9879120140e4d56be7453a2 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 20 Sep 2026 18:28:33 +0200 Subject: [PATCH 2/4] book ci --- .forgejo/workflows/book-pr.yaml | 58 +++++++++++++++++++++++++++++++++ .forgejo/workflows/book.yaml | 29 +++++++++++++++++ flake.nix | 1 + nix/book.nix | 20 ++++++++++++ nix/overlay.nix | 1 + 5 files changed, 109 insertions(+) create mode 100644 .forgejo/workflows/book-pr.yaml create mode 100644 .forgejo/workflows/book.yaml create mode 100644 nix/book.nix diff --git a/.forgejo/workflows/book-pr.yaml b/.forgejo/workflows/book-pr.yaml new file mode 100644 index 0000000..cde53e6 --- /dev/null +++ b/.forgejo/workflows/book-pr.yaml @@ -0,0 +1,58 @@ +name: "Book - PR" + +on: + pull_request: + types: + - opened + - reopened + - synchronize + +concurrency: + group: page-preview + cancel-in-progress: false + +jobs: + createPreview: + runs-on: nix + env: + SITE_ORIGIN: + "https://${{ forge.event.repository.owner.username + }}.preview.codeberg.page" + SITE_BASEPATH: + "/${{ forge.event.repository.name }}@${{ forge.event.number }}/" + steps: + - uses: actions/checkout@v4 + - uses: https://codeberg.org/icewind/attic-action@v1 + with: + name: link + instance: https://cache.icewind.link + authToken: "${{ secrets.ATTIC_TOKEN }}" + - name: Build + run: | + # git-pages/action doesn't like symlinks + cp -r $(nix build .#haze-book --print-out-paths --no-link) dist + - name: "Deploy Site" + uses: https://code.forgejo.org/actions/git-pages@v2 + with: + site: "${{ env.SITE_ORIGIN }}${{ env.SITE_BASEPATH }}" # + token: "${{ forge.token }}" # + source: "dist/" # + - name: "Find comment" + uses: "https://github.com/peter-evans/find-comment@v4" # + id: comment + with: + issue-number: ${{ forge.event.number }} # + body-includes: "" # + - name: "Create or update comment" + uses: "https://github.com/peter-evans/create-or-update-comment@v5" # + with: + issue-number: ${{ forge.event.number }} # + comment-id: "${{ steps.comment.outputs.comment-id }}" # + edit-mode: "replace" + body: |- + # Pull request preview ready! + + The Preview of commit ${{ forge.event.pull_request.head.sha }} has been created. + You can find it here: ${{ env.SITE_ORIGIN }}${{ env.SITE_BASEPATH }} + + diff --git a/.forgejo/workflows/book.yaml b/.forgejo/workflows/book.yaml new file mode 100644 index 0000000..05b4f11 --- /dev/null +++ b/.forgejo/workflows/book.yaml @@ -0,0 +1,29 @@ +name: "Book" + +on: + push: + branches: + - main + +jobs: + preview: + runs-on: nix + env: + SITE_ORIGIN: "${{forge.event.repository.owner.username}}.codeberg.page" + SITE_BASEPATH: "/${{forge.event.repository.name}}/" + steps: + - uses: actions/checkout@v4 + - uses: https://codeberg.org/icewind/attic-action@v1 + with: + name: link + instance: https://cache.icewind.link + authToken: "${{ secrets.ATTIC_TOKEN }}" + - name: Build + run: | + # git-pages/action doesn't like symlinks + cp -r $(nix build .#haze-book --print-out-paths --no-link) dist + - uses: https://codeberg.org/git-pages/action@v2 + with: + site: https://${{ env.SITE_ORIGIN }}${{ env.SITE_BASEPATH }} + token: ${{ forge.token }} + source: dist/ diff --git a/flake.nix b/flake.nix index bde0f45..b9efaaa 100644 --- a/flake.nix +++ b/flake.nix @@ -55,6 +55,7 @@ "haze-image-php-8.2" = pkgs: pkgs.haze-image-php-82; "haze-image-php-8.1" = pkgs: pkgs.haze-image-php-81; "haze-image-php-8.0" = pkgs: pkgs.haze-image-php-80; + haze-book = pkgs: pkgs.haze-book; }; tools = pkgs: diff --git a/nix/book.nix b/nix/book.nix new file mode 100644 index 0000000..a1b1442 --- /dev/null +++ b/nix/book.nix @@ -0,0 +1,20 @@ +{ + mdbook, + stdenv, + ... +}: +stdenv.mkDerivation { + name = "haze-book"; + src = ../book; + + nativeBuildInputs = [mdbook]; + + buildPhase = '' + mdbook build + ''; + + installPhase = '' + mkdir -p $out + cp -r book/* $out/ + ''; +} diff --git a/nix/overlay.nix b/nix/overlay.nix index 276b70e..030b559 100644 --- a/nix/overlay.nix +++ b/nix/overlay.nix @@ -6,4 +6,5 @@ final: prev: { haze-image-php-82 = final.callPackage ./image/haze.nix {php = final.php82;}; haze-image-php-81 = final.callPackage ./image/haze.nix {php = final.php81;}; haze-image-php-80 = final.callPackage ./image/haze.nix {php = final.php80;}; + haze-book = final.callPackage ./book.nix {}; } From d027f17ec65456dbcaaab2fa1988d93cd3a4f17a Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 20 Sep 2026 19:06:54 +0200 Subject: [PATCH 3/4] move the rest of the docs over --- README.md | 539 +---------------------------------------- book/src/README.md | 23 ++ book/src/SUMMARY.md | 4 + book/src/federation.md | 13 + book/src/frankenphp.md | 10 + book/src/scripts.md | 72 ++++++ book/src/services.md | 41 ++++ book/src/setup.md | 3 + book/src/usage.md | 230 ++++++++++++++++++ book/src/xdebug.md | 30 +++ 10 files changed, 429 insertions(+), 536 deletions(-) create mode 100644 book/src/federation.md create mode 100644 book/src/scripts.md create mode 100644 book/src/services.md create mode 100644 book/src/usage.md diff --git a/README.md b/README.md index 23f3b8d..7e516d0 100644 --- a/README.md +++ b/README.md @@ -9,540 +9,7 @@ Easy setup and management of Nextcloud test instances using docker `haze` provides an easy way to set up Nextcloud test instances with a choice of php version, database server, optional s3 or ldap setup and more. -## Setup +## Documentation -### Requirements - -- Docker - -### Installation - -- Grab a binary from the - [Codeberg releases](https://codeberg.org/icewind/haze/releases) and place it - in your `$PATH` - -### Config - -Create a file `~/.config/haze/haze.toml` with the following options: - -```toml -sources_root = "/path/to/nextcloud/sources" -``` - -See the [configuration section](#configuration) for more options. - -### Quick examples - -- Start a Nextcloud instance with `postgresql`, and `s3` primary storage: - - ```bash - haze start pgsql s3 - ``` - -- Start a Nextcloud instance with `sqlite`, `php 8.3` and an `smb` external - storage: - - ```bash - haze start 8.3 smb - ``` - -- Run specific units test against an `oracle` database - ```bash - haze test oracle apps/dav/tests/unit/Connector/Sabre - ``` - -## Managing instances - -#### Start an instance - -```bash -haze start [--name ] [--detach] [database] [php-version] [services] [vX.Y.Z] -``` - -Where `database` is one of `sqlite`, `mysql`, `mariadb`, `pgsql` or `oracle` -with an optional version (e.g. `pgsql:12`), defaults to `sqlite`. And -`php-version` is one of `8.0`, `8.1`, `8.2`, `8.3`, `8.4` or `8.5`, defaults to -the maximum version support by the current Nextcloud version. - -You can specify a version number (e.g. `v32.0.2`) to use the sources from a -release instead of using the local sources. - -Use `--name ` to give the instance a specific name instead of a randomly -generated one. For example: - -Use `--detach` to give the instance -[its own sources](#instances-with-their-own-sources) instead of sharing -`sources_root` with all other instances. - -Additionally, you can use the following options when starting an instance: - -- `s3`: set up an S3 server and configure to Nextcloud to use it as primary - storage. - - `s3s`: enable TLS for the S3 setup. - - `s3mb`: enable multi-bucket S3 setup. - - `s3m`: enable multi-instance S3 setup. -- `ldap`: set up an LDAP server. -- `saml`: set up authentik as a SAML IDP. -- `oidc`: set up authentik as an OIDC IDP. -- `scim`: set up authentik as a SCIM server. -- `office`: set up a Nextcloud Office server. -- `onlyoffice` setup an onlyoffice document server. -- `push` set up [client push](https://github.com/nextcloud/notify_push). -- `smb`: set up a samba server for external storage use. -- `dav`: set up a WebDAV server for external storage use. -- `sftp`: set up a SFTP server for external storage use. -- `sftp-key`: set up a SFTP server for external storage use with public key - authentication. -- `kaspersky`: set up a kaspersky scan engine server in http mode. ( Requires - [manually setting up the image](https://github.com/icewind1991/kaspersky-docker)) -- `kaspersky-icap`: setup a kaspersky scan engine server in ICAP mode. -- `clamav`: set up a local clam av scanner in executable mode. -- `clamav-socket`: set up a clam av scanner in socket mode. -- `clamav-icap`: set up a clam av scanner in ICAP mode. -- `clamav-icap-tls`: set up a clam av scanner in ICAP mode with TLS encryption. -- `oc`: start an ownCloud instance in the same network. -- `imaginary`: start an Imaginary service and configure it for preview - generation. -- `mail`: start a [smtp4dev](https://github.com/rnwood/smtp4dev) server and - configure it the mail server. -- `webhook` start a - [webhook tester](https://github.com/tarampampam/webhook-tester) -- `redis`: start a separate container for redis. -- `redis-tls`: connect to redis over TLS. -- ``: by specifying the path to an app package this package - will be extracted into the apps. directory of the new instance (overwriting - any existing app code). This can be used to quickly test a packaged app. -- The name of any configured preset. - -#### Run tests in a new instance - -```bash -haze test [database] [php-version] [phpunit version] [path] -``` - -Where `path` is a file or folder to run PHPUnit in, relative to the sources -root. - -### List running instances - -```bash -haze -``` - -or - -```bash -haze list -``` - -#### Remove all running instances - -```bash -haze clean -``` - -### Instances with their own sources - -By default every instance shares the sources configured as `sources_root`, so -all instances always run the same code. An instance started with `--detach` gets -its own `git worktree` of `sources_root` instead, created in `worktree_dir`, -which lets you run several instances on different branches at the same time. - -```bash -haze start --name my-fix --detach -``` - -The worktree is checked out with a detached head. Every app in one of the -`app_directories` that gets enabled during setup receives its own worktree as -well, other apps keep running from the shared app directory. - -The worktrees are removed together with the instance, by `haze stop` or -`haze clean`. - -## Controlling running instances - -The following commands run against the most recently started instance and allow -optionally providing a `match` to select a specific instance by its name. - -#### Open an instance - -```bash -haze [match] open -``` - -#### Open the database of an instance - -```bash -haze [match] db -``` - -#### Execute a command on an instance - -```bash -haze [match] [service] [cmd] -``` - -If no `cmd` is specified it will launch `bash` - -If a service name or `db` is provided, the command will be in the container of -the service or database. - -#### Create a new instance and run a command - -```bash -haze [match] shell [cmd] -``` - -If no `cmd` is specified it will launch `bash` - -#### Execute an occ command on an instance - -```bash -haze [match] occ [cmd] -``` - -#### Connect to the database on an instance - -```bash -haze [match] db -``` - -#### Show the logs of an instance - -```bash -haze [match] logs -``` - -#### Stop an instance - -```bash -haze [match] stop -``` - -#### Pin an instance - -```bash -haze [match] pin -``` - -Pinned instances will not be removed by `haze clean`. - -#### Unpin an instance - -```bash -haze [match] unpin -``` - -#### Run a command with instance environment variables set - -```bash -haze [match] env [args] -``` - -Runs the provided command with `NEXTCLOUD_URL`, `DATABASE_URL` and `REDIS_URL` -environment variables set for the matched instance. - -This is intended to run a local -[push daemon](https://github.com/nextcloud/notify_push) against an instance. - -#### Update the container images - -```bash -haze update -``` - -#### Edit a file in an instance with the local $EDITOR - -```bash -haze [match] edit -``` - -#### Reload the php config of an instance - -```bash -haze [match] reload -``` - -The php configuration can edit changed with `haze edit /config/php.ini` - -#### Checkout a branch for all local apps - -```bash -haze git checkout [branch] -``` - -Checks out the branch in all git repositories within the apps folder. - -Defaults to the branch matching the current checked out server versions (e.g. -`master` or `stable33`). - -`master` and `main` can be used interchangeably. - -#### Pull remote changes for all local apps - -```bash -haze git pull -``` - -Performs a pull in all git repositories within the apps folder. - -## Federation - -Multiple instances can reach each other by using their instance name as domain -name to allow for testing federation between instances. Alternatively, you can -set up the haze proxy and the proxied domains to get https support between -instances. - -## Proxy - -By default, instances can be accessed by their IP. In order to get more -memorable URLs and allow supporting https, haze comes with a builtin reverse -proxy to allow using a wildcard domain. - -### DNS Setup - -#### Requirements - -- A domain name you can set wildcard DNS records for -- A reverse proxy like Nginx or Apache -- (optionally) a wildcard ssl certificate (can be acquiring using letsencrypt - and dns verification) - -#### Steps - -- Set a DNS record for `*.haze.example.com` and `haze.example.com` pointing to - your development machine. -- Set the `proxy` configuration with your domain and desired listen endpoint. -- Set up a service to run `haze proxy` in the background as your own user. A - systemd user service is recommended (see [haze.service](./haze.service) for an - example). -- Configure your reverse proxy of choice to proxy `*.haze.example.com` and - `haze.example.com` to the proxy's listen endpoint -- (optional) acquire a wildcard ssl certificate for your domain and set your - reverse proxy to use it. This will be highly dependent on your DNS provider, - [this](https://community.letsencrypt.org/t/dns-providers-who-easily-integrate-with-lets-encrypt-dns-validation/86438) - lists some DNS providers and supported ACME clients. - -### Local Setup - -- Setup `dnsmasq` to resolve `*.haze.test` to your development machine. -- Generate a wildcard ssl certificate for `*.haze.test` using `mkcert`: - -```bash -# Generate local wildcard certificate -mkcert -cert-file haze.test.crt -key-file haze.test.key '*.haze.test' -``` - -- Set up a service to run `haze proxy` in the background as your own user. A - systemd user service is recommended (see [haze.service](./haze.service) for an - example). -- Either point haze at the certificate directly: - -```toml -[proxy] -address = "haze.test" -https = true -listen = "127.0.0.1:443" -cert = "/haze.test.crt" -key = "/haze.test.key" -``` - -Binding to port 443 as a regular user requires either -`sudo setcap cap_net_bind_service=+ep $(which haze)` or -`sysctl net.ipv4.ip_unprivileged_port_start=443`. - -- Or, if you already have another web server, setup it up to proxy `*.haze.test` - and `haze.test` to the `haze proxy`'s socket. Example for Nginx: - -```nginx -upstream haze-handler { - server unix:/run/haze/haze.sock; -} - -server { - listen 80; - listen 443 ssl; - http2 on; - server_name *.haze.test; - - ssl_certificate /haze.test.crt; - ssl_certificate_key /haze.test.key; - - location / { - proxy_pass http://haze-handler; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } -} -``` - -### Usage - -When the proxy is configured, generated URLs for the instances will use a -subdomain of the configured domain, e.g. the `rolling-bees` instance will be -available at `rolling-bees.haze.example.com`. Additionally, `haze.example.com` -will automatically point to the last created instance. - -Additionally, the proxy allows access to the server containers trough either -`-.haze.example.com` for a specific instance, or -`.haze.example.com` for the last created instance. For example -`rolling-bees-mail.haze.example.com` will give access to the smtp4dev web -interface of the `rolling-bees` instance. - -## Haze scripts - -Haze scripts combine a set of instance options and a script to run in the -instance. - -Haze scripts are intended to way to create automated ways of running more -complex tests are setting up more complex instances. - -A script contains of 3 paths - -1. An optional shebang line setting `haze` as the interpreter, e.g. - `#! /usr/bin/env -S haze script` -2. A shebang line setting the options for the instance creation as the - interpreter, e.g. `#! haze shell pgsql s3` -3. The rest that is ran as a script inside the created instance. - -The first sheband is set, the script can be ran directly. Else it needs to be -run with `haze script [path-to-script]`. - -For example, the following script will create an instance with `postgresql` and -`s3` primary storage. Then creates a new file, gets the file id, read the object -of the file from S3, validate that it contains the expected contents, and -cleanup the instance. - -```bash -#! #! /usr/bin/env -S haze script -#! haze shell pgsql s3 - -echo 'test' | occ file:put '-' /admin/files/test.txt -FILE_ID=$(occ info:file /admin/files/test.txt | grep fileid: | grep -oE '[0-9]+') -OBJECT_CONTENTS=$(occ file:object:get urn:oid:$FILE_ID -) -if [ "$OBJECT_CONTENTS" == 'test' ]; then - echo "object contains expected contents" -else - echo "object does not contains expected contents!" -fi -``` - -### Script modes - -Scripts can be either `shell` or `start` scripts. - -`shell` scripts will automatically remove the created instance once the script -is done, just like `haze shell` will. The intended use case for this is -performing some tests in the created instance without leaving state behind. - -`start` scripts on the other hand will keep the instance, like `haze start` -will. The intended use case for this is creating more complex instances without -having to configure a dedicated preset. - -The script mode is determined based on the shebang line. The mode set in a -script can be overriden by running the script with -`haze script [shell|start] path-to-script.sh`. - -## Nushell scripts - -By default, the script contents are executed as either `bash` script, or `nu` -script based on the extension. - -You can overwrite the interpreter used to execute the script by adding an extra -`#!` line to the script, for example: - -```bash -#! /usr/bin/env -S haze script -#! haze shell pgsql s3 -#! php -f -/worktrees" - -[auto_setup] # optional -enabled = false # whether or not to automatically install nextcloud on `haze start`. enabled by default -username = "foo" # username for admin user during auto setup. optional, defaults to "admin" -password = "bar" # password for admin user during auto setup. optional, defaults to "admin" -enable_apps = ["files_external"] # apps to enable after setup, defaults to [] -disable_apps = ["contacts"] # apps to disable after setup, defaults to [] -post_setup = [# commands to execute after setup, defaults to [] - "occ group:add test", -] -config = { "foo" = "bar" } # configuration options to set before install - -[[volume]] # optional -source = "/tmp/haze-shared" -target = "/shared" -create = true - -[[volume]] -source = "/home/me/Downloads" -target = "/Downloads" -read_only = true - -[proxy] # optional -address = "haze.example.com" # base domain -https = true # Whether the instances are reachable over https -listen = "/run/haze/haze.sock" # either a unix socket path -#listen = "127.0.0.1:8080" # or a socket address -cert = "/path/to/haze.test.crt" # optional - PEM encoded certificate chain -key = "/path/to/haze.test.key" # optional - PEM encoded private key - -# presets allow for easy usage of commonly used setups -[[preset]] -name = "groupfolders" # name of the preset -apps = ["groupfolders"] # app to enable -commands = ["occ groupfolders:create gf", "occ groupfolders:group 1 admin read write share delete"] # commands to run post-setup -``` - -## Xdebug - -Haze Xdebug is running in a docker container, you need to tell you IDE how to -properly map the path. The IDE debugger config usually looks like: - -```json - { - "label": "PHP: Debug server within docker", - "adapter": "Xdebug", - "request": "launch", - "port": 9003, - "pathMappings": { - "/var/www/html": "", - "/var/www/html/apps-extra": "", - }, - }, -``` - -This would have to be adapted for detached instances. - -To enable Xdebug for all requests: - -- Uncomment the lines in `haze edit /config/php.ini` -- Then run `haze reload ` - -## FrankenPHP (experimental) - -You can have Nextcloud run on FrankenPHP. - -Caddy's admin metrics are then accessible through -`http://-franken-php.haze.test`. With ember you can run: - -```bash -ember --addr http://-franken-php.haze.test -``` +Documentation for haze can be found in the +[book](https://icewind.codeberg.page/haze/) diff --git a/book/src/README.md b/book/src/README.md index 8d340b0..0ebd550 100644 --- a/book/src/README.md +++ b/book/src/README.md @@ -5,3 +5,26 @@ Hazy with a chance of clouds. `haze` is a tool that provides provides an easy way to set up Nextcloud test instances with a choice of php version, database server, optional s3 or ldap setup and much more. + +## Quickstart + +- Grab a binary from the + [Codeberg releases](https://codeberg.org/icewind/haze/releases) and place it + in your `$PATH` + +- Create a file `~/.config/haze/haze.toml` with the following content: + + ```toml + sources_root = "/path/to/nextcloud/sources" + ``` + +- Start a basic Nextcloud instance: + + ```bash + haze start + ``` + +- Navigate to the address that is provided in the output. + +See the [setup](./setup.html), [configuration](./configuration.html) and +[usage](./usage.html) for a more details. diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md index 565c8e4..f771191 100644 --- a/book/src/SUMMARY.md +++ b/book/src/SUMMARY.md @@ -3,9 +3,13 @@ [Introduction](README.md) - [Setup](setup.md) +- [Usage](usage.md) - [Configuration](configuration.md) - [Proxy](proxy/README.md) - [DNS](proxy/dns.md) - [HTTPS](proxy/https.md) +- [Services](services.md) +- [Federation](federation.md) +- [Haze scripts](scripts.md) - [Xdebug](xdebug.md) - [FrankenPHP (experimental)](frankenphp.md) diff --git a/book/src/federation.md b/book/src/federation.md new file mode 100644 index 0000000..20bacd7 --- /dev/null +++ b/book/src/federation.md @@ -0,0 +1,13 @@ +# Federation + +Multiple instances can reach each other by using their instance name as domain +name to allow for testing federation between instances. + +For example, if you have a `rover-beavers` and `splendid-couch` instance, you +can create a federated share from the `rover-beavers` instance to +`http://admin@splendid-couch`. + +If the proxy is setup with https, you can use https between the instances by +using the full proxy urls. + +For example sharing to `admin@splendid-couch.haze.example.com`. diff --git a/book/src/frankenphp.md b/book/src/frankenphp.md index ad8871f..92f675b 100644 --- a/book/src/frankenphp.md +++ b/book/src/frankenphp.md @@ -1 +1,11 @@ # FrankenPHP (experimental) + +You can have Nextcloud run on FrankenPHP by starting the instance with the +`franken-php` option. + +Caddy's admin metrics are then accessible through +`http://-franken-php.haze.test`. With ember you can run: + +```bash +ember --addr http://-franken-php.haze.test +``` diff --git a/book/src/scripts.md b/book/src/scripts.md new file mode 100644 index 0000000..00fa6f8 --- /dev/null +++ b/book/src/scripts.md @@ -0,0 +1,72 @@ +# Haze scripts + +Haze scripts combine a set of instance options and a script to run in the +instance. + +Haze scripts are intended to way to create automated ways of running more +complex tests are setting up more complex instances. + +A script contains of 3 paths + +1. An optional shebang line setting `haze` as the interpreter, e.g. + `#! /usr/bin/env -S haze script` +2. A shebang line setting the options for the instance creation as the + interpreter, e.g. `#! haze shell pgsql s3` +3. The rest that is ran as a script inside the created instance. + +The first sheband is set, the script can be ran directly. Else it needs to be +run with `haze script [path-to-script]`. + +For example, the following script will create an instance with `postgresql` and +`s3` primary storage. Then creates a new file, gets the file id, read the object +of the file from S3, validate that it contains the expected contents, and +cleanup the instance. + +```bash +#! #! /usr/bin/env -S haze script +#! haze shell pgsql s3 + +echo 'test' | occ file:put '-' /admin/files/test.txt +FILE_ID=$(occ info:file /admin/files/test.txt | grep fileid: | grep -oE '[0-9]+') +OBJECT_CONTENTS=$(occ file:object:get urn:oid:$FILE_ID -) +if [ "$OBJECT_CONTENTS" == 'test' ]; then + echo "object contains expected contents" +else + echo "object does not contains expected contents!" +fi +``` + +### Script modes + +Scripts can be either `shell` or `start` scripts. + +`shell` scripts will automatically remove the created instance once the script +is done, just like `haze shell` will. The intended use case for this is +performing some tests in the created instance without leaving state behind. + +`start` scripts on the other hand will keep the instance, like `haze start` +will. The intended use case for this is creating more complex instances without +having to configure a dedicated preset. + +The script mode is determined based on the shebang line. The mode set in a +script can be overriden by running the script with +`haze script [shell|start] path-to-script.sh`. + +## Using different interpreters + +By default, the script contents are executed as either `bash` script, or `nu` +script based on the extension. + +You can overwrite the interpreter used to execute the script by adding an extra +`#!` line to the script, for example: + +```bash +#! /usr/bin/env -S haze script +#! haze shell pgsql s3 +#! php -f +`: by specifying the path to an app package this package + will be extracted into the apps. directory of the new instance (overwriting + any existing app code). This can be used to quickly test a packaged app. +- The name of any configured preset. diff --git a/book/src/setup.md b/book/src/setup.md index f191167..8ce4385 100644 --- a/book/src/setup.md +++ b/book/src/setup.md @@ -4,6 +4,9 @@ - Docker +haze is built around docker containers and manages containers using the docker +socket. Using podman with docker compatibility might also work, but is untested. + ## Installation - Grab a binary from the diff --git a/book/src/usage.md b/book/src/usage.md new file mode 100644 index 0000000..f8a23f0 --- /dev/null +++ b/book/src/usage.md @@ -0,0 +1,230 @@ +# Usage + +## Quick examples + +- Start a Nextcloud instance with `postgresql`, and `s3` primary storage: + + ```bash + haze start pgsql s3 + ``` + +- Start a Nextcloud instance with `sqlite`, `php 8.3` and an `smb` external + storage: + + ```bash + haze start 8.3 smb + ``` + +- Run specific units test against an `oracle` database + ```bash + haze test oracle apps/dav/tests/unit/Connector/Sabre + ``` + +## Managing instances + +### Starting an instance + +```bash +haze start [--name ] [--detach] [database] [php-version] [services] [vX.Y.Z] +``` + +Where `database` is one of `sqlite`, `mysql`, `mariadb`, `pgsql` or `oracle` +with an optional version (e.g. `pgsql:12`), defaults to `sqlite`. And +`php-version` is one of `8.0`, `8.1`, `8.2`, `8.3`, `8.4` or `8.5`, defaults to +the maximum version support by the current Nextcloud version. + +You can specify a version number (e.g. `v32.0.2`) to use the sources from a +release instead of using the local sources. + +Use `--name ` to give the instance a specific name instead of a randomly +generated one. For example: + +Use `--detach` to give the instance +[its own sources](#instances-with-their-own-sources) instead of sharing +`sources_root` with all other instances. + +See the [services documentation](./services.html) for a list of available +services. + +### List running instances + +```bash +haze +``` + +or + +```bash +haze list +``` + +### Stop an instance + +```bash +haze [match] stop +``` + +### Remove all unpinned running instances + +```bash +haze clean +``` + +### Pin an instance + +```bash +haze [match] pin +``` + +Pinned instances will not be removed by `haze clean`. + +### Unpin an instance + +```bash +haze [match] unpin +``` + +## Run commands in a temporary instance + +```bash +haze shell [database] [php-version] [services] [cmd] +``` + +This will create an instance, run the provided command, and cleanup the +instance. + +If no `cmd` is specified it will launch `bash` + +## Run tests in a new instance + +```bash +haze test [database] [php-version] [services] [phpunit version] [path] +``` + +Where `path` is a file or folder to run PHPUnit in, relative to the sources +root. + +This will create a fresh instance, run the PHPUnit tests, and clean up the +created instance. + +## Interacting with running instances + +The following commands run against the most recently started instance by default +and allow optionally providing a `match` to select a specific instance by its +name. + +### Open an instance in the browser + +```bash +haze [match] open +``` + +### Execute a command on an instance + +```bash +haze [match] [service] [cmd] +``` + +If no `cmd` is specified it will launch `bash` + +If a service name or `db` is provided, the command will be in the container of +the service or database. + +If no `cmd` is specified it will launch `bash` + +### Execute an occ command on an instance + +```bash +haze [match] occ [cmd] +``` + +### Connect to the database on an instance + +```bash +haze [match] db +``` + +### Show the logs of an instance + +```bash +haze [match] logs +``` + +### Edit a file in an instance with the local $EDITOR + +```bash +haze [match] edit +``` + +Where `` is the path of a file inside the container, for example +`config/config.php`. + +### Reload the php config of an instance + +```bash +haze [match] reload +``` + +The php configuration can edit changed with `haze edit /config/php.ini` + +### Run a command with instance environment variables set + +```bash +haze [match] env [args] +``` + +Runs the provided command with `NEXTCLOUD_URL`, `DATABASE_URL` and `REDIS_URL` +environment variables set for the matched instance. + +This is intended to run a local +[push daemon](https://github.com/nextcloud/notify_push) against an instance. + +## Git tools + +Haze provides a couple of utilities to make working with many git repositories +for apps easier. + +### Checkout a branch for all local apps + +```bash +haze git checkout [branch] +``` + +Checks out the branch in all git repositories within the apps folder. + +Defaults to the branch matching the current checked out server versions (e.g. +`master` or `stable33`). + +`master` and `main` can be used interchangeably. + +### Pull remote changes for all local apps + +```bash +haze git pull +``` + +Performs a pull in all git repositories within the apps folder. + +## Update the container images + +```bash +haze update +``` + +## Instances with their own sources + +By default every instance shares the sources configured as `sources_root`, so +all instances always run the same code. An instance started with `--detach` gets +its own `git worktree` of `sources_root` instead, created in `worktree_dir`, +which lets you run several instances on different branches at the same time. + +```bash +haze start --name my-fix --detach +``` + +The worktree is checked out with a detached head. Every app in one of the +`app_directories` that gets enabled during setup receives its own worktree as +well, other apps keep running from the shared app directory. + +The worktrees are removed together with the instance, by `haze stop` or +`haze clean`. diff --git a/book/src/xdebug.md b/book/src/xdebug.md index e0cf5e1..0a36bbe 100644 --- a/book/src/xdebug.md +++ b/book/src/xdebug.md @@ -1 +1,31 @@ # Xdebug + +To use Xdebug running in a haze instance with your IDE for debugging, you need +to tell you IDE how to properly map the path from the container to the host. The +IDE debugger config usually looks like: + +```json + { + "label": "PHP: Debug server within docker", + "adapter": "Xdebug", + "request": "launch", + "port": 9003, + "pathMappings": { + "/var/www/html": "", + "/var/www/html/apps-extra": "", + }, + }, +``` + +This would have to be adapted for detached instances. + +### Debugging all requests + +By default, xdebug is configured to only run for requests that containing the +trigger (e.g. from using the xdebug browser extension, or adding +`?XDEBUG_SESSION_START=1` to the url). + +To enable Xdebug for all requests: + +- Uncomment the lines in `haze [cloud-id] edit /config/php.ini` +- Then run `haze reload [cloud-id]` From 307dba81ec1ac120a388369d014af401f132a4f9 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sun, 20 Sep 2026 19:10:02 +0200 Subject: [PATCH 4/4] put quickstart in readme --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 7e516d0..8cdadbe 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,25 @@ php version, database server, optional s3 or ldap setup and more. Documentation for haze can be found in the [book](https://icewind.codeberg.page/haze/) + +## Quickstart + +- Grab a binary from the + [Codeberg releases](https://codeberg.org/icewind/haze/releases) and place it + in your `$PATH` + +- Create a file `~/.config/haze/haze.toml` with the following content: + + ```toml + sources_root = "/path/to/nextcloud/sources" + ``` + +- Start a basic Nextcloud instance: + + ```bash + haze start + ``` + +- Navigate to the address that is provided in the output. + +See the [book](https://icewind.codeberg.page/haze/) for more details.