From cfa4ae787dd411a330b61d2191d90a6418ddb194 Mon Sep 17 00:00:00 2001 From: hackdefendr Date: Sat, 6 Jun 2026 19:53:56 -0500 Subject: [PATCH 1/4] macOS documentation updates (added local user steps). --- .goreleaser.yml | 2 +- docs/modules/ROOT/nav.adoc | 3 +- docs/modules/ROOT/pages/install/macos.adoc | 51 ++- .../ROOT/pages/install/macos_service.adoc | 240 +++++++++++ var/macos/app.olivetin.olivetin.plist | 47 +++ var/macos/config.yaml | 262 ++++++++++++ var/macos/install.md | 383 ++++++++++++++++++ 7 files changed, 982 insertions(+), 6 deletions(-) create mode 100644 docs/modules/ROOT/pages/install/macos_service.adoc create mode 100644 var/macos/app.olivetin.olivetin.plist create mode 100644 var/macos/config.yaml create mode 100644 var/macos/install.md diff --git a/.goreleaser.yml b/.goreleaser.yml index 2e2ffad..8b36755 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -77,7 +77,7 @@ archives: - src: Dockerfile.singlearch dst: Dockerfile - webui - - ./var/ + - var name_template: "{{ .ProjectName }}-{{ .Os }}-{{ .Arch }}{{ .Arm }}" wrap_in_directory: true format_overrides: diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 8438f60..f89c72b 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -17,7 +17,8 @@ *** xref:install/bsd.adoc[BSD] *** xref:install/windows.adoc[Windows] **** xref:install/windows_service.adoc[Windows Service] -*** xref:install/macos.adoc[MacOS] +*** xref:install/macos.adoc[macOS Desktop] +*** xref:install/macos_service.adoc[macOS Service] *** xref:install/choose_package.adoc[All download options] * Upgrade Guide ** xref:upgrade/2k3k.adoc[Understanding 2k vs 3k] diff --git a/docs/modules/ROOT/pages/install/macos.adoc b/docs/modules/ROOT/pages/install/macos.adoc index 1241181..6c35f66 100644 --- a/docs/modules/ROOT/pages/install/macos.adoc +++ b/docs/modules/ROOT/pages/install/macos.adoc @@ -1,8 +1,51 @@ -= MacOS += macOS Desktop -Sorry that these instructions are so primitive, the main developer of OliveTin's MacOS machine died :-( If you can help with instructions and screenshots that would be great. +OliveTin runs natively on macOS, on both Apple Silicon (M-series) and Intel Macs. It is a single, self-contained binary - there is no installer and no dependencies to set up. -. There is a .tar.gz that you can download, extract. Link: link:https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin-darwin-amd64.tar.gz[`OliveTin-darwin-amd64.tar.gz`] -. Start a terminal and CD into the OliveTin directory. +If you want OliveTin to run in the background and start automatically, follow the xref:install/macos_service.adoc[install OliveTin as a launchd service] instructions instead. + +== Download + +macOS builds are published on the link:https://github.com/OliveTin/OliveTin/releases/latest[releases page]. Choose the archive that matches your Mac's processor: + +[cols="1,1"] +|=== +| Your Mac | Archive + +| Apple Silicon (M1/M2/M3/M4) +| link:https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin-darwin-arm64.tar.gz[`OliveTin-darwin-arm64.tar.gz`] + +| Intel +| link:https://github.com/OliveTin/OliveTin/releases/latest/download/OliveTin-darwin-amd64.tar.gz[`OliveTin-darwin-amd64.tar.gz`] +|=== + +Not sure which you have? Run `uname -m` in Terminal - `arm64` means Apple Silicon, `x86_64` means Intel. + +[NOTE] +If you run the wrong architecture, macOS reports `Bad CPU type in executable`. Download the other archive if you see this. + +== Extract + +Start a terminal, then extract the archive and change into the directory (replace `arm64` with `amd64` on Intel): + +[source,shell] +---- +tar -xzf OliveTin-darwin-arm64.tar.gz +cd OliveTin-darwin-arm64 +---- + +== Remove the Gatekeeper quarantine + +The binary is downloaded from the internet and is not notarized by Apple, so on first run Gatekeeper blocks it with a message like _"OliveTin can't be opened because Apple cannot check it for malicious software."_ + +Clear the quarantine attribute so it will run: + +[source,shell] +---- +xattr -dr com.apple.quarantine ./OliveTin +---- + +[TIP] +Alternatively, the first time only, right-click the binary in Finder and choose *Open*, or approve it under *System Settings -> Privacy & Security*. include::partial$install/post_generic.adoc[] diff --git a/docs/modules/ROOT/pages/install/macos_service.adoc b/docs/modules/ROOT/pages/install/macos_service.adoc new file mode 100644 index 0000000..2731262 --- /dev/null +++ b/docs/modules/ROOT/pages/install/macos_service.adoc @@ -0,0 +1,240 @@ += macOS Service (launchd) + +This option installs OliveTin as a launchd service, so it runs in the background and starts automatically. This is the macOS equivalent of running OliveTin as a Linux systemd service or a xref:install/windows_service.adoc[Windows service]. If you just want to run OliveTin as a regular application, follow the xref:install/macos.adoc[macOS Desktop install] instructions instead. + +Before continuing, complete the xref:install/macos.adoc[macOS Desktop install] steps (download, extract, and clear the Gatekeeper quarantine) and confirm OliveTin starts correctly by running `./OliveTin`. + +== Choose LaunchAgent or LaunchDaemon + +launchd offers two ways to run a background service, and which one you pick decides whether you need root: + +* *LaunchAgent (local user)* - runs as your user and starts when you log in. *No `sudo` required*, and everything lives under your home folder. Best for a desktop Mac. Follow <>. +* *LaunchDaemon (system-wide)* - runs as `root` and starts at boot, before any user logs in. Requires `sudo`. Best for a headless, always-on Mac. Follow <>. + +You only need to follow *one* of the two sections below. + +[#local-user] +== Local user installation (no root) + +Everything - the binary, configuration, the `var` data folder, and the `webui` folder - is kept together under `~/Library/Application Support/OliveTin`, so you never need `sudo`. + +=== Install the files + +Run these from the extracted archive directory: + +[source,shell] +---- +# Create the application folder and a place for logs +mkdir -p ~/Library/Application\ Support/OliveTin/var +mkdir -p ~/Library/Logs/OliveTin + +# Copy in the binary, your config, and the bundled web UI +cp OliveTin ~/Library/Application\ Support/OliveTin/ +cp config.yaml ~/Library/Application\ Support/OliveTin/ +cp -R webui ~/Library/Application\ Support/OliveTin/ +---- + +This gives you the following layout, all owned by your user: + +[source] +---- +~/Library/Application Support/OliveTin/ +├── OliveTin # the binary +├── config.yaml # your configuration +├── webui/ # the web interface assets (shipped in the archive) +└── var/ # runtime data OliveTin writes (logs, etc.) + +~/Library/Logs/OliveTin/olivetin.log # service stdout/stderr +---- + +=== Create the service definition + +Create a file named `app.olivetin.olivetin.plist` with the contents below. + +[IMPORTANT] +launchd does *not* expand `~`, so the paths must be absolute. Replace `YOUR_USERNAME` with the output of `whoami` in every path. + +[source,xml] +---- + + + + + Label + app.olivetin.olivetin + + ProgramArguments + + /Users/YOUR_USERNAME/Library/Application Support/OliveTin/OliveTin + -configdir + /Users/YOUR_USERNAME/Library/Application Support/OliveTin + + + WorkingDirectory + /Users/YOUR_USERNAME/Library/Application Support/OliveTin + + KeepAlive + + + RunAtLoad + + + StandardOutPath + /Users/YOUR_USERNAME/Library/Logs/OliveTin/olivetin.log + StandardErrorPath + /Users/YOUR_USERNAME/Library/Logs/OliveTin/olivetin.log + + +---- + +`WorkingDirectory` makes the relative `webui` and `var` folders resolve inside the application folder, `KeepAlive` restarts OliveTin if it exits (like systemd's `Restart=always`), and `RunAtLoad` starts it as soon as the service is loaded. + +=== Register and start the service + +[source,shell] +---- +cp app.olivetin.olivetin.plist ~/Library/LaunchAgents/ +launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist +---- + +[NOTE] +`bootstrap`/`bootout` replace the deprecated `launchctl load`/`unload`. They take a _domain target_: `gui/$(id -u)` is your own per-user GUI domain (`id -u` is your numeric user ID). + +To stop and disable it: + +[source,shell] +---- +launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist +---- + +=== Restart after a change + +After editing `config.yaml` or replacing the binary, restart the service so the change takes effect. To restart in place: + +[source,shell] +---- +launchctl kickstart -k gui/$(id -u)/app.olivetin.olivetin +---- + +If you changed the *plist* itself, `kickstart` is not enough - boot the service out and back in so launchd re-reads it (`bootstrap` errors if the service is still loaded): + +[source,shell] +---- +launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist +launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist +---- + +=== Verify + +Open http://localhost:1337 in a browser. If the page does not load, check the service log: + +[source,shell] +---- +tail -f ~/Library/Logs/OliveTin/olivetin.log +---- + +[#system-wide] +== System-wide installation (requires root) + +Use this for a headless or shared Mac that should start OliveTin at boot, before anyone logs in. It installs the binary on the system `PATH` and runs as `root` via a LaunchDaemon, so the commands use `sudo`. + +=== Install the files + +[source,shell] +---- +sudo cp OliveTin /usr/local/bin/OliveTin + +sudo mkdir -p /usr/local/etc/OliveTin +sudo cp config.yaml /usr/local/etc/OliveTin/config.yaml +sudo cp -R webui /usr/local/etc/OliveTin/ +---- + +[NOTE] +OliveTin looks for `config.yaml` in the directory given by the `-configdir` flag, which defaults to the current directory. The service definition below passes `-configdir /usr/local/etc/OliveTin` explicitly, and sets `WorkingDirectory` so the `webui` and `var` folders resolve there. + +=== Create the service definition + +Create a file named `app.olivetin.olivetin.plist` with the following contents. Adjust the paths if you installed OliveTin elsewhere. + +[source,xml] +---- + + + + + Label + app.olivetin.olivetin + + ProgramArguments + + /usr/local/bin/OliveTin + -configdir + /usr/local/etc/OliveTin + + + WorkingDirectory + /usr/local/etc/OliveTin + + KeepAlive + + + RunAtLoad + + + StandardOutPath + /usr/local/var/log/olivetin.log + StandardErrorPath + /usr/local/var/log/olivetin.log + + +---- + +`KeepAlive` restarts OliveTin if it exits (like systemd's `Restart=always`), and `RunAtLoad` starts it as soon as the service is loaded. + +=== Register and start the service + +[source,shell] +---- +sudo mkdir -p /usr/local/var/log +sudo cp app.olivetin.olivetin.plist /Library/LaunchDaemons/ +sudo chown root:wheel /Library/LaunchDaemons/app.olivetin.olivetin.plist +sudo launchctl bootstrap system /Library/LaunchDaemons/app.olivetin.olivetin.plist +---- + +[NOTE] +`bootstrap`/`bootout` replace the deprecated `launchctl load`/`unload`. The domain target for a LaunchDaemon is `system`. + +To stop and disable it: + +[source,shell] +---- +sudo launchctl bootout system /Library/LaunchDaemons/app.olivetin.olivetin.plist +---- + +=== Restart after a change + +After editing `config.yaml` or replacing the binary, restart the service so the change takes effect. To restart in place: + +[source,shell] +---- +sudo launchctl kickstart -k system/app.olivetin.olivetin +---- + +If you changed the *plist* itself, `kickstart` is not enough - boot the service out and back in so launchd re-reads it (`bootstrap` errors if the service is still loaded): + +[source,shell] +---- +sudo launchctl bootout system /Library/LaunchDaemons/app.olivetin.olivetin.plist +sudo launchctl bootstrap system /Library/LaunchDaemons/app.olivetin.olivetin.plist +---- + +=== Verify + +Open http://localhost:1337 in a browser. If the page does not load, check the service log: + +[source,shell] +---- +tail -f /usr/local/var/log/olivetin.log +---- + +include::partial$install/post_generic.adoc[] diff --git a/var/macos/app.olivetin.olivetin.plist b/var/macos/app.olivetin.olivetin.plist new file mode 100644 index 0000000..da6b79d --- /dev/null +++ b/var/macos/app.olivetin.olivetin.plist @@ -0,0 +1,47 @@ + + + + + + Label + app.olivetin.olivetin + + + ProgramArguments + + /usr/local/bin/OliveTin + -configdir + /usr/local/etc/OliveTin + + + + KeepAlive + + + + RunAtLoad + + + + StandardOutPath + /usr/local/var/log/olivetin.log + StandardErrorPath + /usr/local/var/log/olivetin.log + + diff --git a/var/macos/config.yaml b/var/macos/config.yaml new file mode 100644 index 0000000..a4a6a08 --- /dev/null +++ b/var/macos/config.yaml @@ -0,0 +1,262 @@ +# ============================================================================= +# OliveTin example configuration — macOS (Apple Silicon & Intel) +# ============================================================================= +# +# This is a macOS-flavoured version of the stock `example.config.yaml`. Every +# action that differs from the Linux example carries a `# Linux equivalent:` +# comment so you can see exactly what was changed and why. +# +# All commands here are tested against macOS with /bin/zsh (the default login +# shell since macOS Catalina) and also work under /bin/bash. OliveTin runs the +# `shell:` string with `sh -c` by default, so these are written to be portable +# POSIX/zsh/bash one-liners. +# +# To use this file, copy it next to the OliveTin binary as `config.yaml`: +# cp config.macos.yaml config.yaml +# ./OliveTin +# +# Docs: https://docs.olivetin.app/ +# ============================================================================= + +# The built-in micro proxy hosts the WebUI and REST API on a single port. +# Listen on all addresses, port 1337. Open http://localhost:1337 after start. +listenAddressSingleHTTPFrontend: 0.0.0.0:1337 + +# Choose from INFO (default), WARN and DEBUG. +# Docs: https://docs.olivetin.app/advanced_configuration/logs.html +logLevel: "INFO" + +# Actions are commands that OliveTin executes, normally shown as buttons. +# Docs: https://docs.olivetin.app/action_execution/create_your_first.html +actions: + # The simplest possible action: run a command, flash the button for status. + # `ping` works identically on macOS and Linux. + - title: Ping the Internet + shell: ping -c 3 1.1.1.1 + icon: ping + popupOnStart: execution-dialog-stdout-only + execOnStartup: true + + # Show just the command output in a popup. + # + # Linux equivalent: shell: df -h /media + # macOS has no /media mountpoint. The root volume is `/`; external/USB disks + # mount under /Volumes. `df -h /` shows the boot disk; drop the path to list + # every mounted volume. + - title: Check disk space + icon: disk + shell: df -h / + popupOnStart: execution-dialog-stdout-only + + # Show a fuller dialog with details about the command that ran. + # + # Linux equivalent: shell: dmesg | tail + # macOS `dmesg` requires root and is rarely useful. The unified logging + # system is the macOS way to read kernel/system messages. This shows the + # last 2 minutes of high-level system log entries. + - title: Recent system log + shell: log show --last 2m --style compact | tail -n 40 + icon: logs + popupOnStart: execution-dialog + + # A mini button that links to the logs, with rate limiting and an hourly cron. + # `date` is identical across platforms. + - title: date + shell: date + id: date + timeout: 6 + icon: clock + popupOnStart: execution-button + maxRate: + - limit: 3 + duration: 1m + execOnCron: + - "@hourly" + + # --------------------------------------------------------------------------- + # macOS-native actions (no Linux equivalent — these showcase the platform) + # --------------------------------------------------------------------------- + + # Send a real macOS Notification Center banner via AppleScript. + - title: Send a notification + icon: '🔔' # bell + shell: osascript -e 'display notification "Triggered from OliveTin" with title "OliveTin" sound name "Glass"' + popupOnStart: execution-button + + # Stop the Mac from sleeping for 1 hour (handy during long jobs/downloads). + # `caffeinate` is a built-in macOS utility. `-t` is seconds. + - title: Keep awake for 1 hour + icon: '☕' # hot beverage + shell: caffeinate -d -i -t 3600 & + popupOnStart: execution-button + + # Put the displays to sleep immediately (the Mac stays running). + - title: Sleep the displays + icon: '💤' # zzz + shell: pmset displaysleepnow + popupOnStart: execution-button + + # Battery / power summary using the built-in `pmset`. + - title: Power & battery status + icon: '🔋' # battery + shell: pmset -g batt + popupOnStart: execution-dialog-stdout-only + + # --------------------------------------------------------------------------- + + # Prompt the user for input with `arguments`. `ping` again works as-is. + # Docs: https://docs.olivetin.app/action_examples/ping.html + - title: Ping host + id: ping_host + shell: ping {{ host }} -c {{ count }} + icon: ping + timeout: 100 + popupOnStart: execution-dialog-stdout-only + arguments: + - name: host + title: Host + type: ascii_identifier + default: example.com + description: The host that you want to ping + + - name: count + title: Count + type: int + default: 3 + description: How many times do you want to ping? + + # OliveTin can control Docker containers — `docker` is just a CLI app. + # On macOS this requires Docker Desktop (or colima/podman) to be installed + # and running. The command itself is identical to Linux. + # Docs: https://docs.olivetin.app/solutions/container-control-panel/index.html + - title: Restart Docker Container + icon: restart + shell: docker restart {{ container }} + arguments: + - name: container + title: Container name + choices: + - value: plex + - value: traefik + - value: grafana + + # The special `confirmation` argument guards against accidental clicks. + # Docs: https://docs.olivetin.app/args/input_confirmation.html + # + # Linux equivalent: shell: rm -rf /opt/oldBackups/ + # Using a path under the user's home is more natural on macOS. + - title: Delete old backups + icon: ashtonished + shell: rm -rf "$HOME/Backups/old/" + arguments: + - name: confirm + type: confirmation + title: Are you sure?! + + # Run your own scripts, not just OS commands. `maxConcurrent` prevents + # parallel runs; `timeout` kills a command that runs too long. + # + # Linux equivalent: shell: /opt/backupScript.sh + # macOS convention is to keep personal scripts under your home directory. + - title: Run backup script + shell: "$HOME/bin/backupScript.sh" + shellAfterCompleted: "osascript -e 'display notification \"Backup finished with code {{ exitCode }}\" with title \"OliveTin\"'" + maxConcurrent: 1 + timeout: 10 + icon: backup + popupOnStart: execution-dialog + + # Download themes using a script bundled with OliveTin. You still need to set + # `themeName` in this config to actually use the theme. + # Docs: https://docs.olivetin.app/reference/reference_themes_for_users.html + - title: Get OliveTin Theme + exec: + - "olivetin-get-theme" + - "{{ themeGitRepo }}" + - "{{ themeFolderName }}" + icon: theme + arguments: + - name: themeGitRepo + title: Theme's Git Repository + description: Find new themes at https://olivetin.app/themes + type: url + + - name: themeFolderName + title: Theme's Folder Name + type: ascii_identifier + + # Run actions on other servers over SSH. macOS ships with an OpenSSH client, + # so this works out of the box. The helper below is optional. + # Docs: https://docs.olivetin.app/action_examples/ssh-easy.html + - title: "Setup easy SSH" + icon: ssh + shell: olivetin-setup-easy-ssh + popupOnStart: execution-dialog + +# Entities let you generate actions dynamically from "things" (servers, +# containers, VMs) loaded from files on disk. +# Docs: https://docs.olivetin.app/entities/intro.html +# +# entities: +# - file: entities/servers.yaml +# name: server + +# Dashboards organise actions into folders and fieldsets. +# Docs: https://docs.olivetin.app/dashboards/intro.html +# +# dashboards: +# - title: My Mac +# contents: +# - title: Power & battery status +# - title: Sleep the displays + +# ============================================================================= +# Security - Authentication +# ============================================================================= + +# If "true", users must log in before doing anything. +authRequireGuestsToLogin: false + +# The simplest auth: define users/passwords in this config. OliveTin also +# supports header-based auth, OAuth2 and JWT (documented separately). +# Docs: https://docs.olivetin.app/security/local.html +# +# Generating an argon2id hash on macOS: +# brew install argon2 +# echo -n 'yourPassword' | argon2 "$(openssl rand -base64 16)" -id -e +# (Linux equivalent typically uses the distro's `argon2` package directly.) +authLocalUsers: + enabled: true +# users: +# - username: alice +# usergroup: admins +# password: "$argon2id$v=19$m=65536,t=4,p=2$puyxA0s555TSFx7hnFLCXA$PyhLGpZtvpMMvc2DgMWkM8OJMKO55euwV5gm//1iwx4" + +# ============================================================================= +# Security - Access Control +# ============================================================================= + +# Policies affect the whole app (eg: ability to view the log list). +# Docs: https://docs.olivetin.app/security/acl.html +defaultPolicy: + showDiagnostics: true + showLogList: true + +# Permissions affect individual actions. +defaultPermissions: + view: true + exec: true + logs: true + +# ACLs match policy/permissions to users. +accessControlLists: + - name: admin_acl + matchUsergroups: ["admins"] + policy: + showDiagnostics: true + permissions: + view: true + exec: true + logs: true + +# OliveTin has many more options not shown here. See docs.olivetin.app. diff --git a/var/macos/install.md b/var/macos/install.md new file mode 100644 index 0000000..290168d --- /dev/null +++ b/var/macos/install.md @@ -0,0 +1,383 @@ +# Installing OliveTin on macOS + +> **Draft** — local Markdown draft kept in sync with the AsciiDoc docs at +> and +> +> (`docs/modules/ROOT/pages/install/macos.adoc` and `macos_service.adoc`). + +OliveTin runs natively on macOS on both **Apple Silicon (M1/M2/M3/M4)** and +**Intel** Macs. It is a single self-contained binary written in Go — there is no +installer and no background dependencies to install. + +--- + +## 1. Choose the right download + +macOS builds are published on the +[GitHub releases page](https://github.com/OliveTin/OliveTin/releases). Pick the +archive that matches your Mac's processor: + +| Your Mac | Archive | +|---|---| +| Apple Silicon (M-series) | `OliveTin-darwin-arm64.tar.gz` | +| Intel | `OliveTin-darwin-amd64.tar.gz` | + +Not sure which you have? Run this in Terminal: + +```sh +uname -m +``` + +`arm64` → Apple Silicon, `x86_64` → Intel. + +> If you download the wrong architecture, macOS will refuse to run it with a +> "Bad CPU type in executable" error. + +--- + +## 2. Extract and place the binary + +```sh +# Move to your Downloads folder (adjust if needed) +cd ~/Downloads + +# Extract — replace arm64 with amd64 on Intel +tar -xzf OliveTin-darwin-arm64.tar.gz +cd OliveTin-darwin-arm64 +``` + +For a quick try-out you can run it straight from this folder. To install it +properly, see step 6 — you can install it **as your own user (no root)** or +**system-wide**. + +--- + +## 3. Clear the Gatekeeper quarantine + +Because the binary is downloaded from the internet and is **not notarized by +Apple**, macOS Gatekeeper will block the first run with a message like +*"OliveTin can't be opened because Apple cannot check it for malicious +software."* + +Remove the quarantine attribute so it will run: + +```sh +xattr -dr com.apple.quarantine ./OliveTin +``` + +Alternatively, the first time only, you can right-click the binary in Finder → +**Open**, or approve it under **System Settings → Privacy & Security**. + +--- + +## 4. Create a configuration file + +OliveTin looks for a file named `config.yaml` in its **config directory**, which +defaults to the current directory (`.`). You can point elsewhere with +`-configdir /path/to/dir`. + +A minimal `config.yaml` to confirm everything works: + +```yaml +listenAddressSingleHTTPFrontend: 0.0.0.0:1337 +logLevel: "INFO" + +actions: + - title: Hello macOS + icon: terminal + shell: echo "Hello from $(scutil --get ComputerName)!" + popupOnStart: execution-dialog-stdout-only +``` + +For a fuller, macOS-tuned starting point — with working examples for +notifications (`osascript`), `caffeinate`, `pmset`, disk usage, the unified +system log, and Docker — see the **`config.macos.yaml`** that ships alongside +this guide. Copy it in place with: + +```sh +cp config.macos.yaml config.yaml +``` + +--- + +## 5. Run OliveTin + +From the folder that contains both `OliveTin` and `config.yaml`: + +```sh +./OliveTin +``` + +Then open the web interface at: + +``` +http://localhost:1337 +``` + +(or `http://:1337` from another device on your network). + +Press **Ctrl-C** in the Terminal to stop it. + +--- + +## 6. Run OliveTin as a background service (launchd) + +On Linux, OliveTin is managed by **systemd**. The macOS equivalent is +**launchd**. launchd offers two ways to run a background service, and which one +you pick decides whether you need root: + +* **LaunchAgent (local user)** — runs as *your* user and starts when you log in. + **No `sudo` required**, and everything lives under your home folder. Best for a + desktop Mac. See [Local user installation](#local-user-installation-no-root). +* **LaunchDaemon (system-wide)** — runs as `root` and starts at boot, before any + user logs in. Requires `sudo`. Best for a headless, always-on Mac. See + [System-wide installation](#system-wide-installation-requires-root). + +You only need to follow **one** of the two sections below. + +### Local user installation (no root) + +Everything — the binary, configuration, the `var` data folder, and the `webui` +folder — is kept together under `~/Library/Application Support/OliveTin`, so you +never need `sudo`. + +**Install the files** (run from the extracted archive directory): + +```sh +# Create the application folder and a place for logs +mkdir -p ~/Library/Application\ Support/OliveTin/var +mkdir -p ~/Library/Logs/OliveTin + +# Copy in the binary, your config, and the bundled web UI +cp OliveTin ~/Library/Application\ Support/OliveTin/ +cp config.yaml ~/Library/Application\ Support/OliveTin/ +cp -R webui ~/Library/Application\ Support/OliveTin/ +``` + +This gives you the following layout, all owned by your user: + +``` +~/Library/Application Support/OliveTin/ +├── OliveTin # the binary +├── config.yaml # your configuration +├── webui/ # the web interface assets (shipped in the archive) +└── var/ # runtime data OliveTin writes (logs, etc.) + +~/Library/Logs/OliveTin/olivetin.log # service stdout/stderr +``` + +**Create the service definition.** Create a file named +`app.olivetin.olivetin.plist` with the contents below. + +> **Important:** launchd does *not* expand `~`, so the paths must be absolute. +> Replace `YOUR_USERNAME` with the output of `whoami` in every path. + +```xml + + + + + Label + app.olivetin.olivetin + + ProgramArguments + + /Users/YOUR_USERNAME/Library/Application Support/OliveTin/OliveTin + -configdir + /Users/YOUR_USERNAME/Library/Application Support/OliveTin + + + WorkingDirectory + /Users/YOUR_USERNAME/Library/Application Support/OliveTin + + KeepAlive + + + RunAtLoad + + + StandardOutPath + /Users/YOUR_USERNAME/Library/Logs/OliveTin/olivetin.log + StandardErrorPath + /Users/YOUR_USERNAME/Library/Logs/OliveTin/olivetin.log + + +``` + +`WorkingDirectory` makes the relative `webui` and `var` folders resolve inside +the application folder, `KeepAlive` restarts OliveTin if it exits (like systemd's +`Restart=always`), and `RunAtLoad` starts it as soon as the service is loaded. + +**Register and start the service:** + +```sh +cp app.olivetin.olivetin.plist ~/Library/LaunchAgents/ +launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist +``` + +> `bootstrap`/`bootout` replace the deprecated `launchctl load`/`unload`. They +> take a *domain target*: `gui/$(id -u)` is your own per-user GUI domain +> (`id -u` is your numeric user ID). + +To stop and disable it: + +```sh +launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist +``` + +**Restart after a change.** After editing `config.yaml` or replacing the +binary, restart the service so the change takes effect. To restart in place: + +```sh +launchctl kickstart -k gui/$(id -u)/app.olivetin.olivetin +``` + +If you changed the *plist* itself, `kickstart` is not enough — boot the service +out and back in so launchd re-reads it (`bootstrap` errors if the service is +still loaded): + +```sh +launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist +launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/app.olivetin.olivetin.plist +``` + +**Verify** — open . If the page does not load, check the +service log: + +```sh +tail -f ~/Library/Logs/OliveTin/olivetin.log +``` + +### System-wide installation (requires root) + +Use this for a headless or shared Mac that should start OliveTin at boot, before +anyone logs in. It installs the binary on the system `PATH` and runs as `root` +via a LaunchDaemon, so the commands use `sudo`. + +**Install the files:** + +```sh +sudo cp OliveTin /usr/local/bin/OliveTin + +sudo mkdir -p /usr/local/etc/OliveTin +sudo cp config.yaml /usr/local/etc/OliveTin/config.yaml +sudo cp -R webui /usr/local/etc/OliveTin/ +``` + +> OliveTin looks for `config.yaml` in the directory given by the `-configdir` +> flag, which defaults to the current directory. The service definition below +> passes `-configdir /usr/local/etc/OliveTin` explicitly, and sets +> `WorkingDirectory` so the `webui` and `var` folders resolve there. + +**Create the service definition.** Create a file named +`app.olivetin.olivetin.plist` with the following contents. Adjust the paths if +you installed OliveTin elsewhere. + +```xml + + + + + Label + app.olivetin.olivetin + + ProgramArguments + + /usr/local/bin/OliveTin + -configdir + /usr/local/etc/OliveTin + + + WorkingDirectory + /usr/local/etc/OliveTin + + KeepAlive + + + RunAtLoad + + + StandardOutPath + /usr/local/var/log/olivetin.log + StandardErrorPath + /usr/local/var/log/olivetin.log + + +``` + +`KeepAlive` restarts OliveTin if it exits (like systemd's `Restart=always`), and +`RunAtLoad` starts it as soon as the service is loaded. + +**Register and start the service:** + +```sh +sudo mkdir -p /usr/local/var/log +sudo cp app.olivetin.olivetin.plist /Library/LaunchDaemons/ +sudo chown root:wheel /Library/LaunchDaemons/app.olivetin.olivetin.plist +sudo launchctl bootstrap system /Library/LaunchDaemons/app.olivetin.olivetin.plist +``` + +> `bootstrap`/`bootout` replace the deprecated `launchctl load`/`unload`. The +> domain target for a LaunchDaemon is `system`. + +To stop and disable it: + +```sh +sudo launchctl bootout system /Library/LaunchDaemons/app.olivetin.olivetin.plist +``` + +**Restart after a change.** After editing `config.yaml` or replacing the +binary, restart the service so the change takes effect. To restart in place: + +```sh +sudo launchctl kickstart -k system/app.olivetin.olivetin +``` + +If you changed the *plist* itself, `kickstart` is not enough — boot the service +out and back in so launchd re-reads it (`bootstrap` errors if the service is +still loaded): + +```sh +sudo launchctl bootout system /Library/LaunchDaemons/app.olivetin.olivetin.plist +sudo launchctl bootstrap system /Library/LaunchDaemons/app.olivetin.olivetin.plist +``` + +**Verify** — open . If the page does not load, check the +service log: + +```sh +tail -f /usr/local/var/log/olivetin.log +``` + +--- + +## Troubleshooting + +**"Bad CPU type in executable"** — you downloaded the wrong architecture. Get +the `arm64` build for Apple Silicon, `amd64` for Intel (see step 1). + +**Gatekeeper still blocks it** — re-run the `xattr -dr com.apple.quarantine` +command in step 3, or approve the app under **System Settings → Privacy & +Security**. + +**It runs but the page won't load** — check that nothing else is using port +1337 (`lsof -i :1337`), and that you're browsing to `http://` (not `https://`). + +**Reading the logs** + +* Running in Terminal: the log is printed directly to the window. +* Running under launchd as a local user: `tail -f ~/Library/Logs/OliveTin/olivetin.log` +* Running under launchd system-wide: `tail -f /usr/local/var/log/olivetin.log` +* You can raise detail by setting `logLevel: "DEBUG"` in `config.yaml`. + +**Still stuck?** Ask in the +[OliveTin Discord](https://discord.gg/jhYWWpNJ3v) or open an issue on +[GitHub](https://github.com/OliveTin/OliveTin/issues). + +--- + +## Next steps + +* [Create your first action](https://docs.olivetin.app/action_execution/create_your_first.html) +* [Configuration reference](https://docs.olivetin.app/) +* [Security & authentication](https://docs.olivetin.app/security/local.html) From 51e5e526e41282c9011c1a6ffa01f4a1d0b9f4fe Mon Sep 17 00:00:00 2001 From: HackDefendr Date: Sun, 7 Jun 2026 10:05:18 -0500 Subject: [PATCH 2/4] Update app.olivetin.olivetin.plist --- var/macos/app.olivetin.olivetin.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/var/macos/app.olivetin.olivetin.plist b/var/macos/app.olivetin.olivetin.plist index da6b79d..edc4af7 100644 --- a/var/macos/app.olivetin.olivetin.plist +++ b/var/macos/app.olivetin.olivetin.plist @@ -6,8 +6,8 @@ As a per-user LaunchAgent (recommended, no root needed): cp app.olivetin.olivetin.plist ~/Library/LaunchAgents/ - launchctl load ~/Library/LaunchAgents/app.olivetin.olivetin.plist # start now + at login - launchctl unload ~/Library/LaunchAgents/app.olivetin.olivetin.plist # stop + disable + launchctl bootstrap ~/Library/LaunchAgents/app.olivetin.olivetin.plist # start now + at login + launchctl bootout ~/Library/LaunchAgents/app.olivetin.olivetin.plist # stop + disable As a system-wide LaunchDaemon (starts at boot, before login; needs root): sudo cp app.olivetin.olivetin.plist /Library/LaunchDaemons/ From 3f40fe2d0d7d6cda3035b33d5ebcf56d58ab70d4 Mon Sep 17 00:00:00 2001 From: HackDefendr Date: Sun, 7 Jun 2026 10:08:50 -0500 Subject: [PATCH 3/4] Update config.yaml --- var/macos/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/macos/config.yaml b/var/macos/config.yaml index a4a6a08..7e92e35 100644 --- a/var/macos/config.yaml +++ b/var/macos/config.yaml @@ -12,7 +12,7 @@ # POSIX/zsh/bash one-liners. # # To use this file, copy it next to the OliveTin binary as `config.yaml`: -# cp config.macos.yaml config.yaml +# cp ./var/macos/config.yaml config.yaml # ./OliveTin # # Docs: https://docs.olivetin.app/ From ca71e7fdab59f12243f3fb6d7caaad9a6b91cc26 Mon Sep 17 00:00:00 2001 From: HackDefendr Date: Sun, 7 Jun 2026 10:10:57 -0500 Subject: [PATCH 4/4] Update install.md --- var/macos/install.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/var/macos/install.md b/var/macos/install.md index 290168d..6c8ad6e 100644 --- a/var/macos/install.md +++ b/var/macos/install.md @@ -110,7 +110,7 @@ From the folder that contains both `OliveTin` and `config.yaml`: Then open the web interface at: -``` +```text http://localhost:1337 ```