docs(guides): CLI install guides — forge/cloud/devops/edge/iot/embedded-linux (24 guides + index, self-hosted-first policy)
This commit is contained in:
parent
912cf45b51
commit
8e5ba6ba93
26 changed files with 2357 additions and 0 deletions
96
docs/guides/README.md
Normal file
96
docs/guides/README.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# CLI Guides
|
||||
|
||||
Install, authenticate, and configure the command-line tools used across the
|
||||
Portugal Futurista fleet. Every guide follows the same shape:
|
||||
**What it is → Install → Authenticate → Configure for this environment →
|
||||
Self-hosted equivalent → Aurélio integration → Verify → Troubleshooting**.
|
||||
|
||||
## Self-hosted first policy
|
||||
|
||||
Default to self-hosted endpoints in dev. Public clouds only when required.
|
||||
|
||||
Concretely:
|
||||
|
||||
- **Forge** — [Forgejo](https://code.portugalfuturista.org) (LAN `192.168.0.9:3001`)
|
||||
is the default. `github.com` is for public mirrors only; use `tea`, not `gh`.
|
||||
- **Object storage** — MinIO on `http://192.168.0.40:9000` (console `:9001`),
|
||||
S3-compatible. Point `aws s3`, Terraform/OpenTofu state, and backup jobs here first.
|
||||
- **AWS APIs** — LocalStack on `http://192.168.0.40:4566` emulates the common
|
||||
AWS services. Develop against it; switch profiles to real AWS only for
|
||||
cloud-specific behaviour.
|
||||
- **Azure Storage** — Azurite on `192.168.0.40` (blob `:10000`, queue `:10001`,
|
||||
table `:10002`) via connection strings.
|
||||
- **Secrets** — never in shell history or dotfiles. Store API tokens in
|
||||
Vaultwarden (https://vault.portugalfuturista.org, see
|
||||
[docs/vaultwarden-setup.md](../vaultwarden-setup.md)) and reference them from
|
||||
`~/.config` files with `chmod 600`.
|
||||
|
||||
## Self-hosted services
|
||||
|
||||
| Guide | What it covers |
|
||||
|-------|----------------|
|
||||
| [cloud-emulators](selfhosted/cloud-emulators.md) | MinIO + LocalStack v3 + Azurite on lattepanda (`192.168.0.40`) — deploy/manage, credentials, CLI wiring, Terraform state backend |
|
||||
|
||||
All guides target the laptop: **Linux x86_64, Debian/Ubuntu-based, bash**
|
||||
(arm64 variants noted where relevant).
|
||||
|
||||
## Guides
|
||||
|
||||
### Core (forge & collaboration)
|
||||
|
||||
| Guide | Tool | One-liner | Self-hosted equivalent |
|
||||
|-------|------|-----------|------------------------|
|
||||
| [gh](cli/gh.md) | GitHub CLI | PRs/issues/releases on github.com (public mirrors only) | Forgejo → use `tea` instead |
|
||||
| [tea](cli/tea.md) | Gitea/Forgejo CLI | **Primary forge tool** for code.portugalfuturista.org | It *is* the self-hosted tool |
|
||||
| [acli](cli/acli.md) | Atlassian CLI | Jira + Confluence from the terminal | None deployed (Plane/OpenProject deferred) |
|
||||
|
||||
### DevOps
|
||||
|
||||
| Guide | Tool | One-liner | Self-hosted equivalent |
|
||||
|-------|------|-----------|------------------------|
|
||||
| [aws](cli/aws.md) | AWS CLI v2 | AWS API access, profiles | LocalStack `:4566` + MinIO `:9000` |
|
||||
| [gcloud](cli/gcloud.md) | Google Cloud CLI | GCP projects, GKE, GCS | None real; Firebase emulators / fake-gcs-server |
|
||||
| [az](cli/az.md) | Azure CLI | Azure resources + storage | Azurite `:10000-10002` via connection strings |
|
||||
| [kubectl](cli/kubectl.md) | Kubernetes CLI | Cluster ops | k3s on Proxmox |
|
||||
| [helm](cli/helm.md) | Helm | Kubernetes package manager | Same — points at the k3s cluster |
|
||||
| [terraform-opentofu](cli/terraform-opentofu.md) | Terraform / OpenTofu | IaC; prefer OpenTofu (MPL-2.0) | State on MinIO via S3 backend |
|
||||
| [docker-compose](cli/docker-compose.md) | Docker Engine + Compose | Containers on the laptop | Docker itself is the self-hosted runtime |
|
||||
| [ansible](cli/ansible.md) | Ansible | Agentless config of Proxmox nodes | It *is* self-hosted (inventory = LAN nodes) |
|
||||
|
||||
### Edge / serverless
|
||||
|
||||
| Guide | Tool | One-liner | Self-hosted equivalent |
|
||||
|-------|------|-----------|------------------------|
|
||||
| [cloudflared-wrangler](cli/cloudflared-wrangler.md) | cloudflared + wrangler | Cloudflare tunnel `pf-tunnel-v2` + Workers | Tunnel already self-hosted on asus |
|
||||
| [vercel](cli/vercel.md) | Vercel CLI | Deploy previews / serverless frontends | None deployed (Coolify on Proxmox = future) |
|
||||
| [netlify](cli/netlify.md) | Netlify CLI | Static + functions deploys | None deployed; Caddy behind pf-tunnel-v2 |
|
||||
| [flyctl](cli/flyctl.md) | Fly.io CLI | Global container deploys | None; k3s/Kamal on Proxmox |
|
||||
| [doctl](cli/doctl.md) | DigitalOcean CLI | DO droplets/spaces | Proxmox cluster (`pct`/`qm`) is the self-hosted equivalent |
|
||||
|
||||
### IoT
|
||||
|
||||
| Guide | Tool | One-liner | Self-hosted equivalent |
|
||||
|-------|------|-----------|------------------------|
|
||||
| [mosquitto-clients](cli/mosquitto-clients.md) | mosquitto-clients | MQTT pub/sub from the shell | mosquitto broker LXC on Proxmox |
|
||||
|
||||
### Embedded Linux
|
||||
|
||||
| Guide | Tool | One-liner | Self-hosted equivalent |
|
||||
|-------|------|-----------|------------------------|
|
||||
| [esptool](cli/esptool.md) | esptool.py | ESP32 flash/serial | Local tool — no cloud dependency |
|
||||
| [arduino-cli](cli/arduino-cli.md) | Arduino CLI | Compile/upload Arduino sketches | Local tool — no cloud dependency |
|
||||
| [platformio](cli/platformio.md) | PlatformIO Core | Multi-platform embedded builds | Local tool; registry mirrorable |
|
||||
| [yocto](cli/yocto.md) | Yocto / poky + kas | Custom Linux images | Build in crops/poky container; Proxmox CT later |
|
||||
| [buildroot](cli/buildroot.md) | Buildroot | Minimal embedded Linux images | Fully local by design |
|
||||
| [uboot-tools](cli/uboot-tools.md) | u-boot-tools | `mkimage` for U-Boot images | Fully local by design |
|
||||
| [cross-toolchains](cli/cross-toolchains.md) | gcc-arm-none-eabi, aarch64-linux-gnu, west | Cross-compile for ARM targets | Fully local by design |
|
||||
|
||||
## Infra reference
|
||||
|
||||
| Host | IP | Role |
|
||||
|------|-----|------|
|
||||
| asus | 192.168.0.38 | Proxmox (CTs 202–220), cloudflared `pf-tunnel-v2` |
|
||||
| gigabyte | 192.168.0.104 | Proxmox (CTs 200–211), media stack, signal-cli |
|
||||
| lattepanda | 192.168.0.40 | Proxmox node; cloud emulators (MinIO, LocalStack, Azurite) |
|
||||
| Forgejo | 192.168.0.9:3001 / code.portugalfuturista.org | Default git forge |
|
||||
| Vaultwarden | vault.portugalfuturista.org | Secrets (see [setup](../vaultwarden-setup.md)) |
|
||||
82
docs/guides/cli/acli.md
Normal file
82
docs/guides/cli/acli.md
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
# acli (Atlassian CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Atlassian's official CLI (`acli`) for Jira and Confluence from the terminal:
|
||||
search issues, create/transition tickets, read and edit Confluence pages.
|
||||
|
||||
## Install
|
||||
|
||||
Linux x86_64 — official binary (always the latest stable; see the
|
||||
[Atlassian CLI docs](https://developer.atlassian.com/cloud/acli/guides/introduction/)
|
||||
for the canonical link):
|
||||
|
||||
```bash
|
||||
curl -LO "https://acli.atlassian.com/linux/latest/acli_linux_amd64/acli"
|
||||
chmod +x acli
|
||||
sudo mv acli /usr/local/bin/acli
|
||||
```
|
||||
|
||||
On arm64 use the `acli_linux_arm64` variant of the same URL. The CLI
|
||||
self-updates via `acli update` unless you disable it.
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
acli jira auth login
|
||||
```
|
||||
|
||||
Browser-based OAuth 2.0 (3LO) against your Atlassian cloud site; the token is
|
||||
cached under `~/.config/atlassian-cli/`. Keep a note of which Atlassian
|
||||
account/org you authorized in Vaultwarden so onboarding a second laptop is a
|
||||
one-minute job.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
acli jira workitem search --jql "project = PF AND status != Done" --limit 10
|
||||
acli confluence page view --id <page-id>
|
||||
```
|
||||
|
||||
Set a default site once so commands don't prompt:
|
||||
|
||||
```bash
|
||||
acli jira site list # pick your site
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
None deployed yet. Self-hosted Jira/Confluence replacements
|
||||
(**Plane**, **OpenProject**) were evaluated and deferred — when one lands on
|
||||
the Proxmox cluster it will be announced, and it won't be `acli`-compatible
|
||||
(Plane and OpenProject have their own REST APIs; closest dev stand-in today is
|
||||
the Plane community Docker compose stack).
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-atlassian** skill drives `acli` for Jira/Confluence queries and
|
||||
ticket updates. Connector registry id: `atlassian`
|
||||
(OAuth 2.0 3LO, `api.atlassian.com`).
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
acli --version
|
||||
# acli version x.y.z
|
||||
acli jira auth status
|
||||
# ✓ Authenticated as <name> (<site>.atlassian.net)
|
||||
acli jira workitem search --jql "assignee = currentUser()" --limit 3
|
||||
# KEY SUMMARY STATUS ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Browser flow fails on a headless shell** — run `acli jira auth login` from
|
||||
a desktop session, or copy the printed URL to a browser and paste the
|
||||
callback back.
|
||||
- **Wrong site** — you authorized multiple Atlassian sites; pass `--site` or
|
||||
re-login with the right tenant.
|
||||
- **403 on Jira API** — missing OAuth scope; re-run `auth login` and accept the
|
||||
full scope list.
|
||||
- **Corporate proxy breaking OAuth callback** — set `HTTPS_PROXY` before
|
||||
running `acli`, or use the API-token auth fallback for Jira REST scripts.
|
||||
89
docs/guides/cli/ansible.md
Normal file
89
docs/guides/cli/ansible.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# ansible (Ansible CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Agentless configuration management over SSH: `ansible` for ad-hoc commands,
|
||||
`ansible-playbook` for playbooks. Ideal for keeping the Proxmox nodes and CTs
|
||||
consistent.
|
||||
|
||||
## Install
|
||||
|
||||
Via pipx (current stable, isolated env — preferred over the lagging distro
|
||||
package):
|
||||
|
||||
```bash
|
||||
sudo apt install pipx
|
||||
pipx install --include-deps ansible-core
|
||||
pipx ensurepath # re-login so ~/.local/bin is on PATH
|
||||
```
|
||||
|
||||
Or the distro package if you don't need recent versions: `sudo apt install
|
||||
ansible`. Extra collections (e.g. `community.general`) via
|
||||
`ansible-galaxy collection install <name>`.
|
||||
|
||||
## Authenticate
|
||||
|
||||
Auth = SSH. Use your existing key:
|
||||
|
||||
```bash
|
||||
ssh-copy-id root@192.168.0.38 # asus
|
||||
ssh-copy-id root@192.168.0.104 # gigabyte
|
||||
ssh-copy-id root@192.168.0.40 # lattepanda
|
||||
```
|
||||
|
||||
Vault-stored secrets (sudo passwords, API tokens) go in Vaultwarden
|
||||
(https://vault.portugalfuturista.org); for playbook-level secrets use
|
||||
`ansible-vault encrypt_string`.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Inventory `~/.ansible/inventory/proxmox.ini`:
|
||||
|
||||
```ini
|
||||
[proxmox]
|
||||
asus ansible_host=192.168.0.38
|
||||
gigabyte ansible_host=192.168.0.104
|
||||
lattepanda ansible_host=192.168.0.40
|
||||
|
||||
[proxmox:vars]
|
||||
ansible_user=root
|
||||
ansible_python_interpreter=/usr/bin/python3
|
||||
```
|
||||
|
||||
Ad-hoc check:
|
||||
|
||||
```bash
|
||||
ansible -i ~/.ansible/inventory/proxmox.ini proxmox -m ping
|
||||
ansible -i ~/.ansible/inventory/proxmox.ini proxmox -a "pveversion"
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Ansible is inherently self-hosted — controller on the laptop, targets on the
|
||||
LAN. No cloud service involved; the closest "managed" analogue (AWX/Tower) is
|
||||
overkill for three nodes.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-devops** skill uses `ansible` for fleet maintenance tasks against
|
||||
the Proxmox nodes. Connector registry id: `ansible`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
ansible --version
|
||||
# ansible [core 2.x.y] ...
|
||||
ansible -i ~/.ansible/inventory/proxmox.ini asus -m ping
|
||||
# asus | SUCCESS => { "ping": "pong" }
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`UNREACHABLE`** — SSH key not installed on the node, or you're not on the
|
||||
LAN/VPN; test with plain `ssh root@<ip>`.
|
||||
- **`/usr/bin/python: not found`** — minimal Debian CTs ship only `python3`;
|
||||
set `ansible_python_interpreter=/usr/bin/python3` (as above).
|
||||
- **Privilege escalation prompts** — add `-b --ask-become-pass` or configure
|
||||
passwordless sudo on managed CTs.
|
||||
- **Slow runs** — enable SSH pipelining and `forks = 20` in
|
||||
`~/.ansible.cfg`.
|
||||
83
docs/guides/cli/arduino-cli.md
Normal file
83
docs/guides/cli/arduino-cli.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# arduino-cli (Arduino CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Arduino's headless build tool: manage cores (board support packages) and
|
||||
libraries, compile sketches, and upload over serial — no IDE required. Good
|
||||
fit for CI builds of Arduino-based firmware.
|
||||
|
||||
## Install
|
||||
|
||||
Official script (latest stable into `~/.local/bin`):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh \
|
||||
| BINDIR=~/.local/bin sh
|
||||
```
|
||||
|
||||
Static binaries (x86_64/arm64) also on the releases page if you want to pin a
|
||||
version. Add `~/.local/bin` to PATH if it isn't already.
|
||||
|
||||
## Authenticate
|
||||
|
||||
None for core functionality. Only the (optional) Arduino Cloud integration
|
||||
uses credentials — we don't use it; keep any such tokens in Vaultwarden if you
|
||||
ever enable it.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
First-run setup for AVR + ESP32:
|
||||
|
||||
```bash
|
||||
arduino-cli config init
|
||||
arduino-cli config add board_manager.additional_urls \
|
||||
https://espressif.github.io/arduino-esp32/package_esp32_index.json
|
||||
arduino-cli core update-index
|
||||
arduino-cli core install arduino:avr
|
||||
arduino-cli core install esp32:esp32
|
||||
arduino-cli lib install "PubSubClient"
|
||||
```
|
||||
|
||||
Serial access: `sudo usermod -aG dialout $USER` (re-login).
|
||||
|
||||
Typical cycle:
|
||||
|
||||
```bash
|
||||
arduino-cli board list # find the port + FQBN
|
||||
arduino-cli compile --fqbn esp32:esp32:esp32 sketch/
|
||||
arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:esp32 sketch/
|
||||
arduino-cli monitor -p /dev/ttyUSB0 -c baudrate=115200
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Fully local — cores/libraries download from public indexes, but builds and
|
||||
uploads happen on the laptop. No cloud dependency. (Build artifacts can be
|
||||
mirrored to MinIO `http://192.168.0.40:9000` with the rest of the firmware.)
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **embedded-linux** skill uses `arduino-cli` for Arduino-core firmware
|
||||
builds and uploads (ESP32/AVR). Flashed devices usually talk to the
|
||||
`mqtt-local` broker connector.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
arduino-cli version
|
||||
# arduino-cli Version: 1.x.y ...
|
||||
arduino-cli board list
|
||||
# Port Protocol Type Board Name FQBN Core
|
||||
# /dev/ttyUSB0 serial Serial Port (USB) Unknown esp32:esp32:... esp32:esp32
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`Board not found` on compile** — the core isn't installed;
|
||||
`arduino-cli core search <chip>` then `core install`.
|
||||
- **ESP32 package index ignored** — the `additional_urls` must be added via
|
||||
`config add` (as above), then `core update-index` again.
|
||||
- **Upload permission denied** — `dialout` group missing, or `arduino-cli
|
||||
monitor`/minicom still holding the port.
|
||||
- **Compile cache confusion after core upgrade** — `arduino-cli cache clean`
|
||||
then rebuild.
|
||||
106
docs/guides/cli/aws.md
Normal file
106
docs/guides/cli/aws.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# aws (AWS CLI v2)
|
||||
|
||||
## What it is
|
||||
|
||||
The official AWS command line (v2): S3, IAM, Lambda, IoT Core, CloudFormation —
|
||||
every AWS API from the shell, with named profiles for multi-account work.
|
||||
|
||||
## Install
|
||||
|
||||
Official Linux x86_64 installer (always current stable; use the `-aarch64` URL
|
||||
on arm64):
|
||||
|
||||
```bash
|
||||
curl -fsSL "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o /tmp/awscliv2.zip
|
||||
unzip -q /tmp/awscliv2.zip -d /tmp
|
||||
sudo /tmp/aws/install # add --update to upgrade in place
|
||||
```
|
||||
|
||||
Do **not** use the distro `awscli` package — it is usually the legacy v1.
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
aws configure --profile prod
|
||||
# AWS Access Key ID: <from Vaultwarden>
|
||||
# AWS Secret Access Key: <from Vaultwarden>
|
||||
# Default region name: eu-west-1
|
||||
# Default output format: json
|
||||
```
|
||||
|
||||
Credentials live in `~/.aws/credentials` (chmod 600). Keep the root copies of
|
||||
all access keys in Vaultwarden (https://vault.portugalfuturista.org); rotate
|
||||
rather than leak.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
`~/.aws/config` — real AWS plus the local emulators:
|
||||
|
||||
```ini
|
||||
[default]
|
||||
region = eu-west-1
|
||||
output = json
|
||||
|
||||
[profile prod]
|
||||
region = eu-west-1
|
||||
|
||||
[profile localstack]
|
||||
region = us-east-1
|
||||
output = json
|
||||
```
|
||||
|
||||
`~/.aws/credentials`:
|
||||
|
||||
```ini
|
||||
[localstack]
|
||||
aws_access_key_id = test
|
||||
aws_secret_access_key = test
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
**LocalStack** (AWS emulator, lattepanda `http://192.168.0.40:4566`) and
|
||||
**MinIO** (S3-compatible, `http://192.168.0.40:9000`, console `:9001`).
|
||||
|
||||
```bash
|
||||
# LocalStack: everything behind one endpoint
|
||||
aws --profile localstack --endpoint-url http://192.168.0.40:4566 s3 ls
|
||||
aws --profile localstack --endpoint-url http://192.168.0.40:4566 lambda list-functions
|
||||
|
||||
# MinIO: S3 only
|
||||
aws --profile localstack --endpoint-url http://192.168.0.40:9000 s3 mb s3://firmware
|
||||
aws --profile localstack --endpoint-url http://192.168.0.40:9000 s3 cp build.bin s3://firmware/
|
||||
```
|
||||
|
||||
For MinIO use its own access/secret keys (console at `:9001`), stored in
|
||||
Vaultwarden — not `test/test`.
|
||||
|
||||
Alternative: `pipx install awscli-local` gives `awslocal`, which wraps `aws`
|
||||
with the LocalStack endpoint pre-set (`awslocal s3 ls`).
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-aws** skill wraps `aws` (and `awslocal`) for infra and IoT Core
|
||||
tasks. Connector registry ids: `aws` (real), `aws-localstack` (emulator),
|
||||
`minio` (S3 storage).
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
aws --version
|
||||
# aws-cli/2.x.y Python/3.x Linux/x86_64 ...
|
||||
aws --profile localstack --endpoint-url http://192.168.0.40:4566 sts get-caller-identity
|
||||
# { "Account": "000000000000", "Arn": "arn:aws:iam::000000000000:root", ... }
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`aws: command not found` after install** — installer puts it in
|
||||
`/usr/local/bin`; check your `PATH`.
|
||||
- **Signature errors against MinIO** — wrong keys or clock skew; verify keys in
|
||||
the MinIO console and that the laptop clock is NTP-synced.
|
||||
- **`Connection refused` to LocalStack** — the emulator stack on lattepanda
|
||||
(192.168.0.40) isn't up; check its Docker stack before debugging `aws`.
|
||||
- **Real AWS used by accident** — always pass `--profile localstack
|
||||
--endpoint-url ...` in dev scripts; export `AWS_PROFILE=localstack` in your
|
||||
dev shell as a seatbelt.
|
||||
90
docs/guides/cli/az.md
Normal file
90
docs/guides/cli/az.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# az (Azure CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Microsoft's CLI for Azure resources (`az group`, `az vm`, `az storage`,
|
||||
`az iot`, ...). One login covers all Azure services.
|
||||
|
||||
## Install
|
||||
|
||||
Official Microsoft apt repo:
|
||||
|
||||
```bash
|
||||
curl -sLS https://packages.microsoft.com/keys/microsoft.asc \
|
||||
| sudo gpg --dearmor -o /etc/apt/keyrings/microsoft.gpg
|
||||
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/microsoft.gpg] \
|
||||
https://packages.microsoft.com/repos/azure-cli/ $(lsb_release -cs) main" \
|
||||
| sudo tee /etc/apt/sources.list.d/azure-cli.list
|
||||
sudo apt update && sudo apt install azure-cli
|
||||
```
|
||||
|
||||
(On arm64 use `arch=arm64`.) The one-liner `curl -sL
|
||||
https://aka.ms/InstallAzureCLIDeb | sudo bash` does the same but pins less —
|
||||
the explicit repo above is preferred.
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
az login # browser flow
|
||||
az account set --subscription <name-or-id>
|
||||
```
|
||||
|
||||
Token cache: `~/.azure/`. For automation, create a service principal and keep
|
||||
the client secret in Vaultwarden (https://vault.portugalfuturista.org):
|
||||
|
||||
```bash
|
||||
az login --service-principal -u <app-id> -p <secret-from-vaultwarden> --tenant <tenant-id>
|
||||
```
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
az config set defaults.group=<resource-group> defaults.location=westeurope
|
||||
az account list --output table
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
**Azurite** — the Azure Storage emulator on lattepanda
|
||||
(`192.168.0.40`: blob `:10000`, queue `:10001`, table `:10002`). Point `az
|
||||
storage` at it with a connection string:
|
||||
|
||||
```bash
|
||||
export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;\
|
||||
AccountName=devstoreaccount1;\
|
||||
AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;\
|
||||
BlobEndpoint=http://192.168.0.40:10000/devstoreaccount1;\
|
||||
QueueEndpoint=http://192.168.0.40:10001/devstoreaccount1;\
|
||||
TableEndpoint=http://192.168.0.40:10002/devstoreaccount1;"
|
||||
|
||||
az storage container create --name firmware
|
||||
az storage blob upload --container-name firmware --file build.bin --name build.bin
|
||||
```
|
||||
|
||||
(The account key above is Azurite's well-known dev key, not a secret.)
|
||||
There is no emulator for non-storage Azure services — use real Azure for those.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-azure** skill wraps `az` for resource and storage ops. Connector
|
||||
registry ids: `azure` (real), `azure-azurite` (storage emulator).
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
az version
|
||||
# "azure-cli": "2.x.y", ...
|
||||
az account show --output table
|
||||
# Name CloudName SubscriptionId State IsDefault
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`az login` opens no browser** — use `az login --use-device-code` and
|
||||
complete the flow at microsoft.com/devicelogin.
|
||||
- **Connection string ignored** — `az storage` flags (`--account-name`) win
|
||||
over the env var; unset conflicting flags or export
|
||||
`AZURE_STORAGE_ACCOUNT`/`AZURE_STORAGE_KEY` instead.
|
||||
- **Azurite SSL errors** — Azurite here is plain HTTP; make sure the
|
||||
connection string uses `DefaultEndpointsProtocol=http`.
|
||||
- **Wrong tenant** — `az account clear` then `az login --tenant <id>`.
|
||||
79
docs/guides/cli/buildroot.md
Normal file
79
docs/guides/cli/buildroot.md
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
# buildroot (Buildroot)
|
||||
|
||||
## What it is
|
||||
|
||||
Buildroot builds minimal embedded Linux systems (cross toolchain, rootfs,
|
||||
kernel, bootloader) with a Kconfig interface — much lighter than Yocto for
|
||||
simple appliances. One `make` produces a flashable image.
|
||||
|
||||
## Install
|
||||
|
||||
Host dependencies (Debian/Ubuntu):
|
||||
|
||||
```bash
|
||||
sudo apt install build-essential git libncurses-dev bison flex \
|
||||
libssl-dev bc rsync unzip wget cpio file python3
|
||||
```
|
||||
|
||||
Buildroot itself is just a git clone (pin a release branch or tag, e.g.
|
||||
`2024.02.x` LTS or newer — check buildroot.org for the current LTS):
|
||||
|
||||
```bash
|
||||
git clone -b 2024.02.x https://github.com/buildroot/buildroot.git ~/buildroot
|
||||
# or shallow: git clone --depth 1 -b <branch> ...
|
||||
```
|
||||
|
||||
## Authenticate
|
||||
|
||||
None. Everything is local; packages download from upstream mirrors over HTTPS.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
cd ~/buildroot
|
||||
make list-defconfigs | grep -i <board> # e.g. raspberrypi, beaglebone
|
||||
make <board>_defconfig
|
||||
make menuconfig # adjust packages/kernel/rootfs
|
||||
make -j"$(nproc)" # ~30-60 min first build
|
||||
ls output/images/ # sdcard.img, zImage, rootfs.tar...
|
||||
```
|
||||
|
||||
Keep project-specific configs as **external trees** (BR2_EXTERNAL) in the
|
||||
firmware repo on Forgejo — never fork Buildroot itself:
|
||||
|
||||
```
|
||||
BR2_EXTERNAL=../my-overlay make myboard_defconfig
|
||||
```
|
||||
|
||||
Archive release images to MinIO (`http://192.168.0.40:9000`) with the defconfig
|
||||
that produced them.
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Fully self-hosted by design — no cloud services anywhere in the loop. For
|
||||
reproducible offline builds, set `BR2_PRIMARY_SITE` to an internal mirror and
|
||||
commit the downloaded `dl/` cache to MinIO.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **embedded-linux** skill uses Buildroot for minimal appliance images.
|
||||
Resulting images are deployed with the [uboot-tools](uboot-tools.md) /
|
||||
`swupdate` flow and talk to the `mqtt-local` connector at runtime.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
cd ~/buildroot && make show-info | head -5 # prints configured packages as JSON
|
||||
make <board>_defconfig && make -j"$(nproc)" linux
|
||||
# ... after a full build: output/images/ contains the artifacts
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Missing host tool error at `make`** — install the package named in the
|
||||
error; `make` checks the host first (see deps above).
|
||||
- **Defconfig for your board missing** — look in `configs/` upstream or the
|
||||
board vendor's BR2_EXTERNAL layer; don't hand-write one from scratch.
|
||||
- **`make menuconfig` can't find ncurses** — `sudo apt install libncurses-dev`.
|
||||
- **Build breaks after `git pull`** — rebuild from clean: `make clean && make
|
||||
<board>_defconfig && make`; Buildroot doesn't support in-tree upgrades.
|
||||
97
docs/guides/cli/cloudflared-wrangler.md
Normal file
97
docs/guides/cli/cloudflared-wrangler.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# cloudflared & wrangler (Cloudflare tunnel + Workers CLIs)
|
||||
|
||||
## What it is
|
||||
|
||||
Two Cloudflare CLIs: **cloudflared** runs/manages tunnels (our
|
||||
`pf-tunnel-v2` exposes the `*.portugalfuturista.org` services), and
|
||||
**wrangler** builds and deploys Cloudflare Workers/Pages.
|
||||
|
||||
## Install
|
||||
|
||||
cloudflared (official apt repo):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \
|
||||
| sudo tee /usr/share/keyrings/cloudflare-main.gpg > /dev/null
|
||||
echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] \
|
||||
https://pkg.cloudflare.com/cloudflared $(lsb_release -cs) main" \
|
||||
| sudo tee /etc/apt/sources.list.d/cloudflared.list
|
||||
sudo apt update && sudo apt install cloudflared
|
||||
```
|
||||
|
||||
wrangler (via npm, current stable):
|
||||
|
||||
```bash
|
||||
npm install -g wrangler
|
||||
```
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
cloudflared tunnel login # browser → authorizes the zone, writes ~/.cloudflared/cert.pem
|
||||
wrangler login # browser OAuth for your Cloudflare account
|
||||
```
|
||||
|
||||
API tokens (for CI) go in Vaultwarden (https://vault.portugalfuturista.org)
|
||||
and are exported as `CLOUDFLARE_API_TOKEN`.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
`pf-tunnel-v2` **runs on asus** (192.168.0.38), config at
|
||||
`/etc/cloudflared/config-v2.yml` — tunnel administration happens there, not
|
||||
on the laptop. From the laptop you typically only:
|
||||
|
||||
```bash
|
||||
cloudflared tunnel list # see pf-tunnel-v2 and its connectors
|
||||
cloudflared tunnel info pf-tunnel-v2
|
||||
cloudflared tunnel route dns pf-tunnel-v2 new-service.portugalfuturista.org
|
||||
```
|
||||
|
||||
Adding a service = edit `config-v2.yml` on asus (ingress rule) + DNS route,
|
||||
then restart the cloudflared service on asus.
|
||||
|
||||
wrangler for Workers:
|
||||
|
||||
```bash
|
||||
wrangler init my-worker
|
||||
cd my-worker && wrangler dev # local dev server
|
||||
wrangler deploy
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
The tunnel **is** our self-hosted edge: `pf-tunnel-v2` on asus fronts all
|
||||
`*.portugalfuturista.org` services — no third-party ingress needed. Workers
|
||||
have no self-hosted runtime in production; for local dev `wrangler dev` (and
|
||||
Miniflare under the hood) emulates the Workers runtime on the laptop.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-edge** skill uses `cloudflared` for tunnel/DNS routes and `wrangler`
|
||||
for Workers deploys. Connector registry id: `cloudflare`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
cloudflared --version
|
||||
# cloudflared version 20xx.y.z ...
|
||||
wrangler --version
|
||||
# ⛅️ wrangler x.y.z
|
||||
cloudflared tunnel list
|
||||
# ID NAME CREATED CONNECTIONS
|
||||
# ... pf-tunnel-v2 ... 2xLISB
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`tunnel login` cert lands on the wrong machine** — the cert is per-user,
|
||||
per-machine; run `cloudflared tunnel login` on asus if you're managing the
|
||||
tunnel there, then copy `~/.cloudflared/<uuid>.json` credentials carefully.
|
||||
- **DNS route already exists** — `cloudflared tunnel route dns` refuses to
|
||||
overwrite; delete the CNAME in the dashboard or with `cloudflared tunnel
|
||||
route dns --overwrite-dns`.
|
||||
- **wrangler `Unauthorized`** — token scope too narrow; create a token with
|
||||
"Workers Scripts:Edit" and re-export `CLOUDFLARE_API_TOKEN`.
|
||||
- **Service 502 behind the tunnel** — check the ingress rule in
|
||||
`config-v2.yml` on asus points at a reachable LAN address, then
|
||||
`journalctl -u cloudflared` on asus.
|
||||
95
docs/guides/cli/cross-toolchains.md
Normal file
95
docs/guides/cli/cross-toolchains.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# cross-toolchains (ARM GCC + Zephyr west)
|
||||
|
||||
## What it is
|
||||
|
||||
Cross-compilers that run on the laptop (x86_64) and target embedded ARM:
|
||||
`gcc-arm-none-eabi` (bare-metal Cortex-M), `aarch64-linux-gnu` (64-bit ARM
|
||||
Linux userland/kernel), and Zephyr's `west` (meta-tool for Zephyr RTOS
|
||||
builds).
|
||||
|
||||
## Install
|
||||
|
||||
Debian/Ubuntu:
|
||||
|
||||
```bash
|
||||
# Bare-metal ARM (Cortex-M): distro package is fine for most work
|
||||
sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi
|
||||
|
||||
# aarch64 Linux cross toolchain
|
||||
sudo apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
|
||||
|
||||
# Zephyr west + build deps
|
||||
sudo apt install pipx python3-venv cmake ninja-build gperf ccache dfu-util \
|
||||
device-tree-compiler xz-utils file make gcc g++ multilib gcc-multilib
|
||||
pipx install west
|
||||
pipx ensurepath # re-login
|
||||
```
|
||||
|
||||
Note: distro `gcc-arm-none-eabi` can lag or be huge (newlib variants). The
|
||||
Arm GNU Toolchain tarball from developer.arm.com is the pin-able alternative —
|
||||
extract to `/opt` and add its `bin/` to PATH when a project requires a
|
||||
specific version.
|
||||
|
||||
## Authenticate
|
||||
|
||||
None. Zephyr modules fetch from public git (Forgejo mirrors where available:
|
||||
`code.portugalfuturista.org`).
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Zephyr workspace:
|
||||
|
||||
```bash
|
||||
west init -m https://github.com/zephyrproject-rtos/zephyr --mr main ~/zephyrproject
|
||||
cd ~/zephyrproject && west update
|
||||
west zephyr-export
|
||||
pipx runpip west install -r zephyr/scripts/requirements.txt # python deps
|
||||
```
|
||||
|
||||
(Alternatively install the Zephyr SDK tarball for its bundled toolchains, or
|
||||
set `ZEPHYR_TOOLCHAIN_VARIANT=cross-compile` +
|
||||
`CROSS_COMPILE=/usr/bin/arm-none-eabi-` to reuse the distro GCC.)
|
||||
|
||||
Kernel cross-compile example:
|
||||
|
||||
```bash
|
||||
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig
|
||||
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j"$(nproc)"
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Fully local — no cloud involved. Zephyr module fetches and toolchain tarballs
|
||||
can be mirrored to MinIO (`http://192.168.0.40:9000`) for CI reproducibility.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **embedded-linux** skill uses these toolchains for bare-metal and RTOS
|
||||
firmware (`west build`, kernel cross-compiles). Firmware targets the
|
||||
`mqtt-local` broker at runtime.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
arm-none-eabi-gcc --version | head -1
|
||||
# arm-none-eabi-gcc (...) x.y.z ...
|
||||
aarch64-linux-gnu-gcc --version | head -1
|
||||
# aarch64-linux-gnu-gcc (Debian ...) x.y.z ...
|
||||
west --version
|
||||
# West version: v1.x.y
|
||||
west boards | grep -i nrf52840 | head -3 # in a zephyr workspace
|
||||
# nrf52840dk/nrf52840 ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`arm-none-eabi-gcc: command not found` in make** — toolchain bin dir not
|
||||
on PATH in that shell (common when mixing tarball + distro installs).
|
||||
- **Newlib missing (`nano.specs` errors)** — install
|
||||
`libnewlib-arm-none-eabi` (and `libstdc++-arm-none-eabi-newlib` for C++).
|
||||
- **`west build` can't find the Zephyr SDK** — either install the SDK or
|
||||
point `ZEPHYR_TOOLCHAIN_VARIANT`/`CROSS_COMPILE` at the distro toolchain as
|
||||
above.
|
||||
- **Wrong architecture triplet** — `aarch64-linux-gnu-` for 64-bit ARM Linux,
|
||||
`arm-linux-gnueabihf-` for 32-bit hard-float, `arm-none-eabi-` for
|
||||
bare-metal; mixing them produces very confusing linker errors.
|
||||
95
docs/guides/cli/docker-compose.md
Normal file
95
docs/guides/cli/docker-compose.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# docker compose (Docker Engine + Compose plugin)
|
||||
|
||||
## What it is
|
||||
|
||||
Docker Engine runs containers on the laptop; the Compose plugin (`docker
|
||||
compose`, v2) brings up multi-container stacks from a `compose.yaml`. This is
|
||||
the local dev runtime for everything — including the MinIO/LocalStack/Azurite
|
||||
emulators.
|
||||
|
||||
## Install
|
||||
|
||||
Official Docker apt repo (Debian/Ubuntu; the `docker.io` distro package lags):
|
||||
|
||||
```bash
|
||||
sudo apt install ca-certificates curl
|
||||
sudo install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
|
||||
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
|
||||
https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" \
|
||||
| sudo tee /etc/apt/sources.list.d/docker.list
|
||||
sudo apt update
|
||||
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||
sudo usermod -aG docker $USER # re-login to pick up the group
|
||||
```
|
||||
|
||||
(On Debian use `download.docker.com/linux/debian`.) The repo always serves the
|
||||
current stable channel; pin with `apt install docker-ce=5:<version>` if needed.
|
||||
|
||||
## Authenticate
|
||||
|
||||
Only for registries:
|
||||
|
||||
```bash
|
||||
docker login # Docker Hub (PAT, not password)
|
||||
docker login code.portugalfuturista.org # if a Forgejo package registry is used
|
||||
```
|
||||
|
||||
Tokens are in `~/.docker/config.json` (base64 — treat it as secret; keep the
|
||||
PATs themselves in Vaultwarden, https://vault.portugalfuturista.org).
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Compose overrides for LAN services live in `compose.override.yaml` (gitignored).
|
||||
Typical dev stack pointing at the emulators on lattepanda:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
build: .
|
||||
environment:
|
||||
AWS_ENDPOINT_URL: http://192.168.0.40:4566
|
||||
S3_ENDPOINT: http://192.168.0.40:9000
|
||||
ports: ["8080:8080"]
|
||||
```
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
docker compose ps
|
||||
docker compose logs -f app
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Docker **is** the self-hosted runtime — no cloud dependency. The cloud
|
||||
counterpart would be managed container services (ECS/Cloud Run/ACI), which we
|
||||
only touch when a deployment target requires it.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-devops** skill shells out to `docker compose` for local stack
|
||||
management. No dedicated connector-registry entry — Docker is the local
|
||||
runtime the other connectors (minio, aws-localstack, azure-azurite) run on.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
docker --version
|
||||
# Docker version 2x.y.z, build ...
|
||||
docker compose version
|
||||
# Docker Compose version v2.x.y
|
||||
docker run --rm hello-world
|
||||
# Hello from Docker! ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Permission denied on `/var/run/docker.sock`** — you're not in the `docker`
|
||||
group (or haven't re-logged in since `usermod`).
|
||||
- **`docker-compose: command not found`** — that's v1 syntax; use the plugin:
|
||||
`docker compose ...`.
|
||||
- **Disk full** — `docker system df`, then `docker system prune -a` (drops
|
||||
unused images; emulator volumes survive unless you add `--volumes`).
|
||||
- **CT/VM can't reach images** — Docker Hub rate limits: `docker login` with a
|
||||
Hub account, or pull through a mirror.
|
||||
80
docs/guides/cli/doctl.md
Normal file
80
docs/guides/cli/doctl.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# doctl (DigitalOcean CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
DigitalOcean's CLI: droplets, Kubernetes (DOKS), Spaces (S3-compatible), App
|
||||
Platform, container registry — everything in the DO API from the shell.
|
||||
|
||||
## Install
|
||||
|
||||
GitHub release binary (x86_64; use the `arm64` archive on ARM):
|
||||
|
||||
```bash
|
||||
VERSION=$(curl -fsSL https://api.github.com/repos/digitalocean/doctl/releases/latest \
|
||||
| grep -oP '"tag_name":\s*"v\K[^"]+')
|
||||
curl -fsSL -o /tmp/doctl.tar.gz \
|
||||
"https://github.com/digitalocean/doctl/releases/download/v${VERSION}/doctl-${VERSION}-linux-amd64.tar.gz"
|
||||
tar -xzf /tmp/doctl.tar.gz -C /tmp
|
||||
sudo install /tmp/doctl /usr/local/bin/doctl
|
||||
```
|
||||
|
||||
(Also available as a snap, but the static binary pins cleanly and has no snap
|
||||
confinement surprises.)
|
||||
|
||||
## Authenticate
|
||||
|
||||
Create a personal access token in the DO dashboard (read+write), store it in
|
||||
Vaultwarden (https://vault.portugalfuturista.org), then:
|
||||
|
||||
```bash
|
||||
doctl auth init # paste the token
|
||||
doctl auth list
|
||||
```
|
||||
|
||||
Config: `~/.config/doctl/config.yaml`. Multiple tokens →
|
||||
`doctl auth init --context <name>` and `doctl auth switch`.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
doctl account get
|
||||
doctl compute droplet list
|
||||
doctl kubernetes cluster list
|
||||
doctl registry login # docker creds for registry.digitalocean.com
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Our **Proxmox cluster is the self-hosted DigitalOcean**: droplets → VMs/CTs
|
||||
managed with `qm`/`pct` (via SSH on asus/gigabyte/lattepanda), Spaces →
|
||||
**MinIO** at `http://192.168.0.40:9000` (S3-compatible, works with `aws s3
|
||||
--endpoint-url`), DOKS → planned **k3s** (see [kubectl.md](kubectl.md)).
|
||||
`doctl` is used only for resources that must live outside the lab.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-devops** skill can drive `doctl` for external VPS/registry ops. No
|
||||
dedicated connector-registry entry — external SaaS; the self-hosted
|
||||
counterparts are covered by `minio` and `kubernetes`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
doctl version
|
||||
# doctl version 1.x.y-release ...
|
||||
doctl account get
|
||||
# Email Droplet Limit Email Verified UUID Status
|
||||
# you@... 25 true ... active
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`401 Unable to authenticate you`** — token expired/revoked; regenerate in
|
||||
the dashboard, update Vaultwarden, `doctl auth init` again.
|
||||
- **Wrong context active** — `doctl auth list` then `doctl auth switch
|
||||
--context <name>`.
|
||||
- **Registry push denied** — run `doctl registry login` so Docker gets the
|
||||
short-lived registry credentials.
|
||||
- **Spaces endpoint confusion** — Spaces is S3-compatible; use `aws s3
|
||||
--endpoint-url https://<region>.digitaloceanspaces.com` rather than looking
|
||||
for a `doctl spaces` subcommand.
|
||||
75
docs/guides/cli/esptool.md
Normal file
75
docs/guides/cli/esptool.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# esptool (Espressif flashing tool)
|
||||
|
||||
## What it is
|
||||
|
||||
`esptool.py` — Espressif's official tool for ESP32/ESP8266: flash firmware,
|
||||
read flash, chip info, baud-tuned serial boot control. The standard last-mile
|
||||
tool for ESP32 firmware.
|
||||
|
||||
## Install
|
||||
|
||||
Via pipx (isolated, current stable):
|
||||
|
||||
```bash
|
||||
sudo apt install pipx python3-venv
|
||||
pipx install esptool
|
||||
pipx ensurepath # re-login so ~/.local/bin is on PATH
|
||||
```
|
||||
|
||||
(`pip install esptool` in a venv works too. Needs Python 3.8+.)
|
||||
|
||||
USB serial access:
|
||||
|
||||
```bash
|
||||
sudo usermod -aG dialout $USER # re-login to apply
|
||||
```
|
||||
|
||||
## Authenticate
|
||||
|
||||
None — talks to the chip over USB/UART. No tokens involved.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Devices appear as `/dev/ttyUSB0` (or `/dev/ttyACM0` for native-USB chips like
|
||||
ESP32-S3). Convenience alias for the common fast-flash settings:
|
||||
|
||||
```bash
|
||||
alias espflash='esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800'
|
||||
```
|
||||
|
||||
For firmware destined at AWS IoT Core, keep device certificates in Vaultwarden
|
||||
(https://vault.portugalfuturista.org) — never bake shared certs into images.
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Fully local by design — flashing happens over USB on the laptop. Firmware
|
||||
artifacts can be archived to MinIO (`http://192.168.0.40:9000`) for
|
||||
reproducibility. For OTA at scale the self-hosted route is an update server
|
||||
behind the LAN; cloud OTA (AWS IoT Jobs) only when devices are off-LAN.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **embedded-linux** skill uses `esptool` for ESP32 flash/verify cycles.
|
||||
Flashed firmware typically targets the `mqtt-local` broker or `aws-iot`
|
||||
connector endpoints.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
esptool.py version
|
||||
# esptool.py v4.x / v5.x ...
|
||||
esptool.py --port /dev/ttyUSB0 chip_id
|
||||
# Chip is ESP32-D0WDQ6 (revision ...)
|
||||
# MAC: xx:xx:xx:xx:xx:xx
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`Permission denied: /dev/ttyUSB0`** — not in `dialout` group, or a
|
||||
lingering serial monitor (minicom/IDE) holds the port.
|
||||
- **`Failed to connect`** — hold BOOT while plugging in (or press BOOT during
|
||||
connect) to force download mode; also try a lower `--baud`.
|
||||
- **Device not enumerated** — bad USB cable (charge-only) or missing driver
|
||||
for the CP210x/CH340 bridge; check `dmesg | tail`.
|
||||
- **Flash write errors at high baud** — drop to `--baud 115200`; some bridges
|
||||
and cables can't sustain 460800+.
|
||||
76
docs/guides/cli/flyctl.md
Normal file
76
docs/guides/cli/flyctl.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
# flyctl (Fly.io CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Fly.io's CLI (`fly`/`flyctl`): deploy containers globally as "Machines",
|
||||
manage volumes, WireGuard into your private Fly network, stream logs.
|
||||
|
||||
## Install
|
||||
|
||||
Official install script (current stable; also has arm64 builds):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://fly.io/install.sh | sh
|
||||
```
|
||||
|
||||
It installs to `~/.fly/bin` and prints the PATH snippet to add to `~/.bashrc`
|
||||
(`export FLYCTL_INSTALL="$HOME/.fly"; export PATH="$FLYCTL_INSTALL/bin:$PATH"`).
|
||||
Upgrade later with `fly version upgrade`.
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
fly auth login # browser OAuth
|
||||
```
|
||||
|
||||
Token cached in `~/.fly/config.yml`. For CI, `fly auth token` prints a
|
||||
deploy token — keep it in Vaultwarden (https://vault.portugalfuturista.org)
|
||||
and export as `FLY_API_TOKEN`.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
cd <app>
|
||||
fly launch # detects Dockerfile, creates fly.toml + app
|
||||
fly deploy
|
||||
fly logs
|
||||
fly ssh console # shell into the machine
|
||||
fly status # machines + regions
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
None deployed. The self-hosted counterpart for "run this container somewhere
|
||||
reachable" is: Docker on a Proxmox CT exposed via the `pf-tunnel-v2` tunnel
|
||||
(see [docker-compose.md](docker-compose.md) and
|
||||
[cloudflared-wrangler.md](cloudflared-wrangler.md)), or **k3s** once the
|
||||
cluster lands (see [kubectl.md](kubectl.md)). Fly stays in the toolbox for
|
||||
genuinely global/multi-region workloads only.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-edge** skill can use `flyctl` for global container deploys. No
|
||||
dedicated connector-registry entry (external SaaS; nearest listed edge
|
||||
connectors are `cloudflare` / `vercel`).
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
fly version
|
||||
# flyctl v0.x.y linux/amd64 ...
|
||||
fly auth whoami
|
||||
# Email: you@example.com
|
||||
fly apps list
|
||||
# NAME OWNER STATUS LATEST DEPLOY
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`fly` not found after install** — the PATH snippet wasn't added to
|
||||
`~/.bashrc`; open a new shell or export it manually.
|
||||
- **`Error: could not find app`** — run commands from the directory with
|
||||
`fly.toml`, or pass `-a <app-name>`.
|
||||
- **Deploy hangs on wireguard** — `fly wireguard reset` or toggle the agent
|
||||
with `fly agent restart`.
|
||||
- **Health checks failing** — the app must bind `0.0.0.0` and the port in
|
||||
`fly.toml` `internal_port`; check `fly logs` for the bind address.
|
||||
91
docs/guides/cli/gcloud.md
Normal file
91
docs/guides/cli/gcloud.md
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# gcloud (Google Cloud CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Google Cloud's CLI: `gcloud` (projects, compute, IAM, GKE), bundled with
|
||||
`gsutil` (Cloud Storage) and `bq` (BigQuery).
|
||||
|
||||
## Install
|
||||
|
||||
Official apt repo (Debian/Ubuntu):
|
||||
|
||||
```bash
|
||||
sudo apt install apt-transport-https ca-certificates gnupg curl
|
||||
curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg \
|
||||
| sudo gpg --dearmor -o /usr/share/keyrings/cloud.google.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" \
|
||||
| sudo tee /etc/apt/sources.list.d/google-cloud-sdk.list
|
||||
sudo apt update && sudo apt install google-cloud-cli
|
||||
```
|
||||
|
||||
Alternative: the versioned tarballs from the
|
||||
[install docs](https://cloud.google.com/sdk/docs/install) (`linux-x86_64` or
|
||||
`linux-arm`); extract and run `./google-cloud-sdk/install.sh`.
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
gcloud auth login # browser OAuth, user account
|
||||
gcloud config set project <project-id>
|
||||
gcloud auth application-default login # for SDKs/tools using ADC
|
||||
```
|
||||
|
||||
Credentials land in `~/.config/gcloud/`. For service accounts, store the JSON
|
||||
key in Vaultwarden (https://vault.portugalfuturista.org) and activate with:
|
||||
|
||||
```bash
|
||||
gcloud auth activate-service-account --key-file=<path> --project=<project-id>
|
||||
```
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Named configurations keep personal/lab projects apart:
|
||||
|
||||
```bash
|
||||
gcloud config configurations create lab
|
||||
gcloud config set project <lab-project-id>
|
||||
gcloud config configurations list
|
||||
gcloud config configurations activate lab
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
There is no real self-hosted GCP. Dev stand-ins we use instead:
|
||||
|
||||
- **Firebase Emulator Suite** (`firebase emulators:start`, via
|
||||
`npm i -g firebase-tools`) for Firestore/Auth/Functions.
|
||||
- **fake-gcs-server** for Cloud Storage:
|
||||
`docker run -p 4443:4443 fsouza/fake-gcs-server -scheme http`, then
|
||||
`STORAGE_EMULATOR_HOST=http://localhost:4443` for client libraries.
|
||||
- For plain object storage, prefer **MinIO** (`http://192.168.0.40:9000`) —
|
||||
S3-compatible and already on the LAN.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-gcloud** skill wraps `gcloud`/`gsutil` for project and storage ops.
|
||||
Connector registry id: `google-cloud`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
gcloud --version
|
||||
# Google Cloud SDK x.y.z
|
||||
gcloud auth list
|
||||
# Credentialed Accounts
|
||||
# ACTIVE ACCOUNT
|
||||
# * you@example.com
|
||||
gcloud config list project
|
||||
# [core]
|
||||
# project = <project-id>
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **Old SDK from distro packages** — only use the Google apt repo above;
|
||||
distro `google-cloud-sdk` packages are frequently broken/stale.
|
||||
- **`gcloud auth login` opens no browser** — run `gcloud auth login
|
||||
--no-browser` and paste the code back.
|
||||
- **ADC errors in scripts** — you authenticated `gcloud` but not
|
||||
application-default credentials; run `gcloud auth application-default login`.
|
||||
- **Wrong project billed** — check `gcloud config get-value project` before
|
||||
provisioning; use named configurations.
|
||||
96
docs/guides/cli/gh.md
Normal file
96
docs/guides/cli/gh.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# gh (GitHub CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
GitHub's official CLI for pull requests, issues, releases, Actions runs, and
|
||||
repo management against github.com and GitHub Enterprise hosts.
|
||||
|
||||
## Install
|
||||
|
||||
Debian/Ubuntu, official apt repo (recommended — tracks the stable channel):
|
||||
|
||||
```bash
|
||||
sudo mkdir -p -m 755 /etc/apt/keyrings
|
||||
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
|
||||
| sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg > /dev/null
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] \
|
||||
https://cli.github.com/packages stable main" \
|
||||
| sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
|
||||
sudo apt update && sudo apt install gh
|
||||
```
|
||||
|
||||
Alternative: download the `linux_amd64` tarball from the
|
||||
[releases page](https://github.com/cli/cli/releases) and drop `bin/gh` into
|
||||
`~/.local/bin`. Pin a version there if you need reproducibility across machines.
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
gh auth login
|
||||
```
|
||||
|
||||
Choose `GitHub.com` → `HTTPS` → browser flow. The token is stored in
|
||||
`~/.config/gh/hosts.yml` (mode 600). Keep a copy of a fine-grained PAT in
|
||||
Vaultwarden (https://vault.portugalfuturista.org) as the recovery secret;
|
||||
prefer `GH_TOKEN` env var in CI instead of the interactive login.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
github.com is **not** the default forge here — Forgejo is (see
|
||||
[tea.md](tea.md)). Use `gh` only for the public GitHub mirrors.
|
||||
|
||||
If you ever point `gh` at a GHE-style host:
|
||||
|
||||
```bash
|
||||
export GH_HOST=git.example.com # per-shell default host
|
||||
gh auth login --hostname git.example.com
|
||||
```
|
||||
|
||||
Note: `GH_HOST` assumes a GitHub Enterprise API layout. Forgejo speaks the
|
||||
Gitea API, so `gh` will not work against it — use `tea` instead.
|
||||
|
||||
```bash
|
||||
gh config set git_protocol https
|
||||
gh config set editor nvim
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
**Forgejo** at https://code.portugalfuturista.org (LAN `192.168.0.9:3001`) is
|
||||
our default forge. The equivalent CLI is [`tea`](tea.md):
|
||||
|
||||
```bash
|
||||
tea login add --url https://code.portugalfuturista.org
|
||||
```
|
||||
|
||||
Everything you'd do with `gh pr create` maps to `tea pr create` against the
|
||||
Forgejo remote.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-forge** skill drives `gh`/`tea` for PR and issue workflows. The
|
||||
connector registry (`.aurelio/connectors/registry.yaml`) covers github.com
|
||||
under id `github`; the Forgejo instance is id `forgejo`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
gh --version
|
||||
# gh version 2.x.x (YYYY-MM-DD)
|
||||
gh auth status
|
||||
# github.com
|
||||
# ✓ Logged in to github.com account <user> (...)
|
||||
gh repo list --limit 3
|
||||
# <owner>/<repo> <description> ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`gh` talks to the wrong host** — check `echo $GH_HOST`; unset it or pass
|
||||
`--hostname github.com` explicitly.
|
||||
- **Auth prompts in headless shells** — use `GH_TOKEN=<pat> gh ...` (token from
|
||||
Vaultwarden) instead of the browser flow.
|
||||
- **`error connecting to code.portugalfuturista.org`** — you used `gh` against
|
||||
Forgejo; switch to `tea`.
|
||||
- **Old version from distro repo** — Debian's `gh` package lags; use the
|
||||
official apt repo above.
|
||||
77
docs/guides/cli/helm.md
Normal file
77
docs/guides/cli/helm.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# helm (Helm CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Helm is the package manager for Kubernetes: charts bundle manifests, and
|
||||
`helm install/upgrade/rollback` manages releases against the cluster your
|
||||
kubeconfig points at.
|
||||
|
||||
## Install
|
||||
|
||||
Official install script (latest stable, detects arch):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
|
||||
```
|
||||
|
||||
Or the static binary: download `helm-<version>-linux-amd64.tar.gz` (or
|
||||
`-linux-arm64`) from the [releases page](https://github.com/helm/helm/releases)
|
||||
and move `linux-amd64/helm` to `/usr/local/bin`. Pin a version from the
|
||||
releases page when you need identical clients across machines.
|
||||
|
||||
## Authenticate
|
||||
|
||||
No separate auth — Helm reuses your kubeconfig (`~/.kube/config`, see
|
||||
[kubectl.md](kubectl.md)). Chart repos with private registries authenticate
|
||||
via:
|
||||
|
||||
```bash
|
||||
helm repo add <name> https://charts.example.com --username <u> --password <p>
|
||||
```
|
||||
|
||||
Store repo credentials in Vaultwarden (https://vault.portugalfuturista.org).
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
helm repo add bitnami https://charts.bitnami.com/bitnami
|
||||
helm repo update
|
||||
helm search repo bitnami | head
|
||||
```
|
||||
|
||||
Point it at the self-hosted k3s cluster by setting `KUBECONFIG` (see
|
||||
kubectl.md). Values overrides for LAN endpoints (MinIO etc.) go in a local
|
||||
`values-lab.yaml` kept out of git.
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Helm itself is infrastructure-neutral — the self-hosted part is the cluster it
|
||||
targets (**k3s** on Proxmox, see kubectl.md) and, if you outgrow public chart
|
||||
repos, a self-hosted **ChartMuseum** (which can store charts on MinIO at
|
||||
`http://192.168.0.40:9000`). OCI registries (e.g. `helm push ... oci://...`)
|
||||
are another option once a registry is deployed.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-devops** skill drives `helm` for release management alongside
|
||||
`kubectl`. Connector registry id: `kubernetes` (same cluster connector).
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
helm version
|
||||
# version.BuildInfo{Version:"v3.x.y", ...}
|
||||
helm list --all-namespaces # against a configured cluster
|
||||
# NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`Error: Kubernetes cluster unreachable`** — kubeconfig/context problem;
|
||||
fix with `kubectl` first, Helm inherits it.
|
||||
- **Chart not found after `helm repo add`** — run `helm repo update`.
|
||||
- **Upgrade fails with "another operation in progress"** — a release is stuck
|
||||
`pending-*`; `helm history <rel>` then `helm rollback <rel>`.
|
||||
- **CRDs missing** — some charts (e.g. cert-manager) need CRDs installed first
|
||||
(`helm install --set crds.enabled=true` or a separate CRD step); read the
|
||||
chart's README.
|
||||
86
docs/guides/cli/kubectl.md
Normal file
86
docs/guides/cli/kubectl.md
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# kubectl (Kubernetes CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
`kubectl` is the Kubernetes control client: apply manifests, inspect workloads,
|
||||
stream logs, exec into pods. It talks to any cluster via a kubeconfig.
|
||||
|
||||
## Install
|
||||
|
||||
Static binary, current stable (x86_64; swap `amd64`→`arm64` for ARM):
|
||||
|
||||
```bash
|
||||
curl -fsSLO "https://dl.k8s.io/release/$(curl -fsSL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
|
||||
sudo install -m 0755 kubectl /usr/local/bin/kubectl && rm kubectl
|
||||
```
|
||||
|
||||
Or the Google apt repo (`sudo apt install kubectl` after adding
|
||||
`pkgs.k8s.io`). Keep the client within one minor version of the server.
|
||||
|
||||
## Authenticate
|
||||
|
||||
Auth is the kubeconfig, not a login command:
|
||||
|
||||
```bash
|
||||
export KUBECONFIG=~/.kube/config # default
|
||||
kubectl config get-contexts
|
||||
kubectl config use-context <context>
|
||||
```
|
||||
|
||||
Kubeconfigs are bearer secrets — keep them mode 600, and archive copies in
|
||||
Vaultwarden (https://vault.portugalfuturista.org).
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
No production cluster yet on the Proxmox fleet; the plan is k3s (below). For
|
||||
cloud clusters, fetch credentials with the vendor CLI:
|
||||
|
||||
```bash
|
||||
gcloud container clusters get-credentials <name> --zone <zone>
|
||||
aws eks update-kubeconfig --name <name>
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
**k3s** — lightweight Kubernetes, ideal on a Proxmox CT/VM (asus or gigabyte):
|
||||
|
||||
```bash
|
||||
# on the node (Debian/Ubuntu CT, privileged or with nesting enabled)
|
||||
curl -sfL https://get.k3s.io | sh -
|
||||
sudo cat /etc/rancher/k3s/k3s.yaml # copy to laptop ~/.kube/config
|
||||
```
|
||||
|
||||
On the laptop, edit the `server:` line to `https://<node-ip>:6443` and:
|
||||
|
||||
```bash
|
||||
kubectl get nodes
|
||||
# NAME STATUS ROLES AGE VERSION
|
||||
# k3s1 Ready control-plane,master 1m v1.x.y+k3s1
|
||||
```
|
||||
|
||||
For a pure-laptop dev cluster, `k3d` (k3s in Docker) is the fastest option.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-devops** skill uses `kubectl`/`helm` for cluster operations.
|
||||
Connector registry id: `kubernetes`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
kubectl version --client
|
||||
# Client Version: v1.x.y ...
|
||||
kubectl get --raw /readyz # against a configured cluster
|
||||
# ok
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`connection refused` to 127.0.0.1:8080** — no context set; run
|
||||
`kubectl config get-contexts` and `use-context`.
|
||||
- **k3s kubeconfig 403 on the laptop** — you copied `k3s.yaml` but left
|
||||
`server: https://127.0.0.1:6443`; point it at the node IP.
|
||||
- **Version skew warnings** — keep kubectl within ±1 minor of the server;
|
||||
reinstall from `dl.k8s.io/release/stable.txt`.
|
||||
- **Proxmox CT can't run k3s** — enable nesting/keyctl or use an
|
||||
unprivileged-with-features CT; plain VMs are the least-friction path.
|
||||
94
docs/guides/cli/mosquitto-clients.md
Normal file
94
docs/guides/cli/mosquitto-clients.md
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
# mosquitto-clients (MQTT pub/sub CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
`mosquitto_pub` / `mosquitto_sub` — the reference MQTT command-line clients
|
||||
from the Eclipse Mosquitto project. The quickest way to poke a broker from a
|
||||
shell or script.
|
||||
|
||||
## Install
|
||||
|
||||
Debian/Ubuntu:
|
||||
|
||||
```bash
|
||||
sudo apt install mosquitto-clients
|
||||
```
|
||||
|
||||
(The `mosquitto` package is the broker — only install that on a broker host.)
|
||||
|
||||
## Authenticate
|
||||
|
||||
Broker-dependent. Typical username/password:
|
||||
|
||||
```bash
|
||||
mosquitto_sub -h <broker> -t 'lab/#' -u <user> -P <password>
|
||||
```
|
||||
|
||||
Keep broker credentials in Vaultwarden (https://vault.portugalfuturista.org).
|
||||
For TLS brokers: `-p 8883 --cafile <ca.crt>` (+ `--cert/--key` for mutual TLS).
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Convenience env for the lab broker:
|
||||
|
||||
```bash
|
||||
export MQTT_HOST=192.168.0.40 # or wherever the broker CT lands
|
||||
export MQTT_PORT=1883
|
||||
|
||||
mosquitto_sub -h $MQTT_HOST -t 'lab/#' -v & # watch everything
|
||||
mosquitto_pub -h $MQTT_HOST -t lab/test -m "hello"
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
The broker itself: **mosquitto in a Proxmox LXC** (Debian template):
|
||||
|
||||
```bash
|
||||
# on the Proxmox host, in the CT console:
|
||||
apt update && apt install mosquitto mosquitto-clients
|
||||
systemctl enable --now mosquitto
|
||||
```
|
||||
|
||||
Minimal hardening (`/etc/mosquitto/conf.d/lab.conf`):
|
||||
|
||||
```conf
|
||||
listener 1883 0.0.0.0
|
||||
allow_anonymous false
|
||||
password_file /etc/mosquitto/passwd
|
||||
```
|
||||
|
||||
```bash
|
||||
mosquitto_passwd -c /etc/mosquitto/passwd labuser
|
||||
systemctl restart mosquitto
|
||||
```
|
||||
|
||||
(LAN-only, so no TLS required; add it if the broker ever leaves the LAN.)
|
||||
Cloud MQTT (AWS IoT Core etc.) is only for production device fleets.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-iot** skill uses `mosquitto_pub/sub` to probe device topics during
|
||||
IoT bring-up. Connector registry ids: `mqtt-local` (LAN broker), `aws-iot`
|
||||
(cloud counterpart).
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
mosquitto_sub --help | head -3
|
||||
# mosquitto_sub is a simple mqtt client ...
|
||||
mosquitto_pub -h $MQTT_HOST -t lab/test -m ping
|
||||
mosquitto_sub -h $MQTT_HOST -t lab/test -C 1 -W 5
|
||||
# ping
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`Connection refused`** — broker not running, or listening on
|
||||
`127.0.0.1` only (default on many distros); add `listener 1883 0.0.0.0`.
|
||||
- **`Not authorized`** — anonymous access disabled; pass `-u/-P`, and check
|
||||
the password file matches the config path.
|
||||
- **Nothing received but publish succeeds** — topic mismatch; remember MQTT
|
||||
wildcards: `+` single level, `#` multi-level (and `#` must be quoted in
|
||||
bash).
|
||||
- **TLS handshake failure** — wrong CA file or hostname mismatch; use
|
||||
`--insecure` only as a temporary diagnostic, never in scripts.
|
||||
75
docs/guides/cli/netlify.md
Normal file
75
docs/guides/cli/netlify.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# netlify (Netlify CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Netlify's CLI: deploy static sites and serverless functions, run the local dev
|
||||
server (`netlify dev`) that emulates Netlify's edge/functions environment, and
|
||||
manage sites/env from the terminal.
|
||||
|
||||
## Install
|
||||
|
||||
Via npm (current stable; Node LTS required):
|
||||
|
||||
```bash
|
||||
npm install -g netlify-cli
|
||||
```
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
netlify login # browser OAuth
|
||||
netlify status # shows account + site link
|
||||
```
|
||||
|
||||
Token stored under `~/.config/netlify/`. For CI use a personal access token
|
||||
from the dashboard, kept in Vaultwarden (https://vault.portugalfuturista.org),
|
||||
exported as `NETLIFY_AUTH_TOKEN` (plus `NETLIFY_SITE_ID`).
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
cd <site>
|
||||
netlify init # or: netlify link
|
||||
netlify dev # local server w/ functions emulation
|
||||
netlify deploy # draft deploy, prints a preview URL
|
||||
netlify deploy --prod # production
|
||||
netlify env:list
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
None deployed. Closest self-hosted path for static + functions today:
|
||||
**Caddy** serving a build output directory on a Proxmox CT, exposed through
|
||||
the `pf-tunnel-v2` Cloudflare tunnel (route added via cloudflared — see
|
||||
[cloudflared-wrangler.md](cloudflared-wrangler.md)). Netlify-style edge
|
||||
functions have no drop-in self-hosted runtime; Cloudflare Workers + `wrangler
|
||||
dev` is the nearest alternative.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-edge** skill can drive `netlify` for legacy site deploys. No
|
||||
dedicated connector-registry entry — treated as an external SaaS; closest
|
||||
listed edge connector is `vercel`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
netlify --version
|
||||
# netlify-cli/1x.y.z linux-x64 node-v2x.y.z
|
||||
netlify status
|
||||
# ──────────────────────┐
|
||||
# Current Netlify User │
|
||||
# ... │
|
||||
netlify sites:list | head
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`netlify login` hangs** — no browser on a headless shell; use
|
||||
`NETLIFY_AUTH_TOKEN` from Vaultwarden instead.
|
||||
- **Functions work locally, 404 in prod** — check `netlify.toml`
|
||||
`[functions] directory` and that the deploy actually bundled them
|
||||
(`netlify deploy --prod --build` logs show "Functions bundling").
|
||||
- **Redirects not applied** — `_redirects` must end up in the publish dir;
|
||||
verify with `netlify deploy --prod` output listing published files.
|
||||
- **Wrong site linked** — `netlify unlink` then `netlify link` again.
|
||||
89
docs/guides/cli/platformio.md
Normal file
89
docs/guides/cli/platformio.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# platformio (PlatformIO Core)
|
||||
|
||||
## What it is
|
||||
|
||||
PlatformIO Core (`pio`) — cross-platform embedded build system: one
|
||||
`platformio.ini` pins the platform, board, framework (Arduino/ESP-IDF/Zephyr),
|
||||
and library deps. The default for multi-board firmware projects.
|
||||
|
||||
## Install
|
||||
|
||||
Via pipx (isolated, current stable):
|
||||
|
||||
```bash
|
||||
sudo apt install pipx python3-venv
|
||||
pipx install platformio
|
||||
pipx ensurepath # re-login so ~/.local/bin is on PATH
|
||||
```
|
||||
|
||||
Serial access + udev rules for common boards:
|
||||
|
||||
```bash
|
||||
sudo usermod -aG dialout $USER
|
||||
curl -fsSL https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/system/99-platformio-udev.rules \
|
||||
| sudo tee /etc/udev/rules.d/99-platformio-udev.rules
|
||||
sudo udevadm control --reload-rules && sudo udevadm trigger
|
||||
```
|
||||
|
||||
## Authenticate
|
||||
|
||||
Core features need no login. `pio account` (registry publishing, remote
|
||||
builds) is optional — skip it; if ever used, token goes in Vaultwarden.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Example `platformio.ini` for an ESP32 lab node:
|
||||
|
||||
```ini
|
||||
[env:esp32dev]
|
||||
platform = espressif32
|
||||
board = esp32dev
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
upload_port = /dev/ttyUSB0
|
||||
lib_deps =
|
||||
knolleary/PubSubClient @ ^2.8
|
||||
```
|
||||
|
||||
```bash
|
||||
pio run # build all envs
|
||||
pio run -t upload # flash
|
||||
pio device monitor # serial
|
||||
pio run -t clean
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Builds are fully local. The PlatformIO Registry is a cloud service, but deps
|
||||
are cached in `~/.platformio/` and can be vendored into the repo
|
||||
(`lib_deps = symlink://lib/...` or committed libraries) for offline
|
||||
reproducibility; firmware artifacts archive to MinIO
|
||||
(`http://192.168.0.40:9000`).
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **embedded-linux** skill drives `pio` for firmware build/upload/monitor
|
||||
cycles. Devices built here typically target the `mqtt-local` broker or
|
||||
`aws-iot` connectors.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
pio --version
|
||||
# PlatformIO Core, version 6.x.y
|
||||
pio device list
|
||||
# /dev/ttyUSB0 ... USB Serial
|
||||
pio run
|
||||
# ... SUCCESS ... RAM: [...] Flash: [...]
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **First build downloads a lot** — platforms/toolchains install into
|
||||
`~/.platformio/` on demand; keep that dir cached between CI runs.
|
||||
- **Upload fails, port busy** — close `pio device monitor` (or the IDE
|
||||
serial monitor) before flashing.
|
||||
- **Board not auto-detected** — set `upload_port` explicitly in
|
||||
`platformio.ini` (as above) after checking `pio device list`.
|
||||
- **`dialout` permission errors** — group membership needs a re-login; udev
|
||||
rules above fix most FTDI/CP210x/CH340 cases.
|
||||
93
docs/guides/cli/tea.md
Normal file
93
docs/guides/cli/tea.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
# tea (Gitea/Forgejo CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
`tea` is the official CLI for Gitea and Forgejo instances — repos, pull
|
||||
requests, issues, releases, notifications. Since Forgejo is our default forge,
|
||||
`tea` is the **primary forge CLI** on this fleet.
|
||||
|
||||
## Install
|
||||
|
||||
Debian/Ubuntu:
|
||||
|
||||
```bash
|
||||
sudo apt install tea # may lag upstream; fine for basics
|
||||
```
|
||||
|
||||
Latest stable binary (x86_64; use `linux-arm64` on arm64):
|
||||
|
||||
```bash
|
||||
curl -fsSL -o ~/.local/bin/tea \
|
||||
https://dl.gitea.com/tea/$(curl -fsSL https://dl.gitea.com/tea/version.json | grep -oP '"Version":\s*"\K[^"]+')/tea-linux-amd64
|
||||
chmod +x ~/.local/bin/tea
|
||||
```
|
||||
|
||||
Or build/pin via the Gitea releases page if you need a specific version.
|
||||
|
||||
## Authenticate
|
||||
|
||||
Create an access token first: in Forgejo → *Settings → Applications → Generate
|
||||
New Token* (scopes: `repo`, `issue`, `read:org`). Store it in Vaultwarden
|
||||
(https://vault.portugalfuturista.org).
|
||||
|
||||
```bash
|
||||
tea login add \
|
||||
--name portugalfuturista \
|
||||
--url https://code.portugalfuturista.org \
|
||||
--token <token-from-vaultwarden>
|
||||
tea login default portugalfuturista
|
||||
```
|
||||
|
||||
Logins live in `~/.config/tea/config.yml` (keep it mode 600 — it holds tokens).
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
# inside a clone
|
||||
git remote -v
|
||||
# origin https://code.portugalfuturista.org/portugalfuturista/<repo>.git
|
||||
```
|
||||
|
||||
`tea` auto-detects the login from the git remote. On the LAN the same instance
|
||||
is reachable at `http://192.168.0.9:3001` — prefer the TLS name so certs and
|
||||
tokens stay consistent.
|
||||
|
||||
```bash
|
||||
tea repos ls --limit 5
|
||||
tea issues ls
|
||||
tea pr create --title "..." --description "..."
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
`tea` *is* the self-hosted equivalent — Forgejo at
|
||||
https://code.portugalfuturista.org is the self-hosted GitHub. For public
|
||||
github.com mirrors only, see [gh.md](gh.md).
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-forge** skill uses `tea` for PR/issue automation against Forgejo.
|
||||
Connector registry id: `forgejo` (github.com mirrors: `github`).
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
tea --version
|
||||
# Version: 0.x.x ...
|
||||
tea logins ls
|
||||
# NAME URL DEFAULT
|
||||
# portugalfuturista https://code.portugalfuturista.org true
|
||||
tea whoami
|
||||
# <your-forgejo-username>
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`401 Unauthorized`** — token missing the needed scope; regenerate in
|
||||
Forgejo with `repo`/`issue` and re-run `tea login add` (or edit
|
||||
`~/.config/tea/config.yml`).
|
||||
- **Wrong login picked up** — `tea` matches by remote URL; set the default
|
||||
with `tea login default <name>` or pass `--login`.
|
||||
- **TLS error on the LAN IP** — the cert is for `code.portugalfuturista.org`;
|
||||
use the name, not `192.168.0.9:3001`, with HTTPS.
|
||||
- **`unknown command`** — distro package is old; install the latest binary.
|
||||
118
docs/guides/cli/terraform-opentofu.md
Normal file
118
docs/guides/cli/terraform-opentofu.md
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
# terraform / tofu (Terraform + OpenTofu)
|
||||
|
||||
## What it is
|
||||
|
||||
Infrastructure-as-code CLIs. **OpenTofu** (`tofu`) is the open-source
|
||||
(MPL-2.0) fork of Terraform and is our default; `terraform` is kept for modules
|
||||
or providers that lag Tofu compatibility. CLIs are drop-in compatible for
|
||||
current Terraform 1.5-era workflows.
|
||||
|
||||
## Install
|
||||
|
||||
OpenTofu (preferred — official apt repo):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://get.opentofu.org/install-opentofu.sh -o /tmp/install-opentofu.sh
|
||||
chmod +x /tmp/install-opentofu.sh
|
||||
sudo /tmp/install-opentofu.sh --install-method deb
|
||||
```
|
||||
|
||||
Terraform (HashiCorp apt repo):
|
||||
|
||||
```bash
|
||||
curl -fsSL https://apt.releases.hashicorp.com/gpg \
|
||||
| sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
|
||||
https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
|
||||
| sudo tee /etc/apt/sources.list.d/hashicorp.list
|
||||
sudo apt update && sudo apt install terraform
|
||||
```
|
||||
|
||||
Both publish static binaries too — pin versions via `required_version` in your
|
||||
root module rather than relying on whatever is installed.
|
||||
|
||||
## Authenticate
|
||||
|
||||
Per provider, via environment variables — keep the real secrets in Vaultwarden
|
||||
(https://vault.portugalfuturista.org) and load them into the shell:
|
||||
|
||||
```bash
|
||||
export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... # aws provider
|
||||
export ARM_CLIENT_ID=... ARM_CLIENT_SECRET=... # azurerm
|
||||
```
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Dev targets are the self-hosted emulators on lattepanda (`192.168.0.40`), so
|
||||
provider blocks point at them:
|
||||
|
||||
```hcl
|
||||
provider "aws" {
|
||||
region = "us-east-1"
|
||||
access_key = "test"
|
||||
secret_key = "test"
|
||||
skip_credentials_validation = true
|
||||
skip_metadata_api_check = true
|
||||
skip_requesting_account_id = true
|
||||
endpoints {
|
||||
s3 = "http://192.168.0.40:4566" # LocalStack
|
||||
lambda = "http://192.168.0.40:4566"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
**State on MinIO** via the S3 backend (`backend.tf`):
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "tf-state"
|
||||
key = "lab/terraform.tfstate"
|
||||
region = "us-east-1"
|
||||
endpoint = "http://192.168.0.40:9000"
|
||||
access_key = "<minio-access-key>"
|
||||
secret_key = "<minio-secret-key>"
|
||||
skip_credentials_validation = true
|
||||
skip_metadata_api_check = true
|
||||
skip_region_validation = true
|
||||
force_path_style = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Create the bucket first (`aws --endpoint-url http://192.168.0.40:9000 s3 mb
|
||||
s3://tf-state`), then `tofu init`. Better still, pass the MinIO keys via
|
||||
`AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` at init time so secrets never sit
|
||||
in `.tf` files.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-devops** skill runs `tofu plan/apply` against lab stacks. Connector
|
||||
registry ids: `terraform` (tool), `minio` (state backend), `aws-localstack`
|
||||
(provider target).
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
tofu version
|
||||
# OpenTofu v1.x.y
|
||||
terraform version
|
||||
# Terraform v1.x.y
|
||||
tofu init && tofu validate
|
||||
# Success! The configuration is valid.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`Error acquiring the state lock`** — with the MinIO backend there's no
|
||||
DynamoDB lock table; don't run two applies concurrently (MinIO conditional
|
||||
writes give basic protection only).
|
||||
- **Provider downloads blocked offline** — `tofu init` needs registry access
|
||||
once; use a filesystem mirror or vendor providers into
|
||||
`~/.terraform.d/plugins`.
|
||||
- **LocalStack endpoint ignored** — every `endpoints {}` service you use must
|
||||
be listed; unknown services fall through to real AWS.
|
||||
- **`InvalidSignatureException` on MinIO state** — clock skew or wrong keys;
|
||||
sync NTP and re-check Vaultwarden entry.
|
||||
83
docs/guides/cli/uboot-tools.md
Normal file
83
docs/guides/cli/uboot-tools.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# u-boot-tools (mkimage & friends)
|
||||
|
||||
## What it is
|
||||
|
||||
The `u-boot-tools` package provides host-side utilities for U-Boot images:
|
||||
`mkimage` (wrap kernels/ramdisks/scripts into U-Boot's legacy/FIT formats),
|
||||
`mkenvimage` (binary environment images), `dumpimage`, and `fw_printenv` /
|
||||
`fw_setenv` (read/write the U-Boot environment from Linux).
|
||||
|
||||
## Install
|
||||
|
||||
Debian/Ubuntu:
|
||||
|
||||
```bash
|
||||
sudo apt install u-boot-tools
|
||||
```
|
||||
|
||||
(For device-tree work also grab `device-tree-compiler`.)
|
||||
|
||||
## Authenticate
|
||||
|
||||
None — local file manipulation tools.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
Common lab uses:
|
||||
|
||||
```bash
|
||||
# legacy uImage for a kernel
|
||||
mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e 0x80008000 \
|
||||
-n "lab-kernel" -d zImage uImage
|
||||
|
||||
# FIT image (kernel + dtb + ramdisk) — preferred on modern boards
|
||||
mkimage -f image.its fitImage.itb
|
||||
|
||||
# boot script
|
||||
mkimage -A arm -T script -C none -n "boot script" -d boot.cmd boot.scr
|
||||
|
||||
# environment image
|
||||
mkenvimage -s 0x20000 -o uboot.env env.txt
|
||||
```
|
||||
|
||||
FIT source files (`.its`) and board-specific addresses live with the board
|
||||
bring-up docs in the firmware repo on Forgejo — don't guess addresses, copy
|
||||
them from the vendor BSP.
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Fully local tooling; no cloud equivalent exists or is needed. For **OTA /
|
||||
A-B updates** on deployed boards, the self-hosted stack is **SWUpdate**
|
||||
(`swupdate` on the target, update artifacts served from any LAN HTTP server or
|
||||
MinIO at `http://192.168.0.40:9000`) — that is our cloud-free alternative to
|
||||
managed update services like Mender cloud.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **embedded-linux** skill uses `mkimage` when packaging kernels/ramdisks
|
||||
for U-Boot boards, and mentions `swupdate` for field update flows. No
|
||||
connector-registry entry — local build tooling.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
mkimage -V
|
||||
# mkimage version 20xx.xx ...
|
||||
mkimage -l uImage # on a real image
|
||||
# Image Name: lab-kernel
|
||||
# Image Type: ARM Linux Kernel Image (uncompressed)
|
||||
# ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`mkimage: Can't open ...`** — input path wrong; remember `-d <datafile>`
|
||||
is the payload, output is the last positional argument.
|
||||
- **Board rejects the image (`Bad Magic Number`)** — wrong architecture `-A`
|
||||
or load/entry addresses; take them from the vendor BSP, not another board.
|
||||
- **FIT fails to boot with "hash mismatch"** — the `.its` referenced files
|
||||
changed after `mkimage` ran, or signing keys differ; rebuild the FIT and
|
||||
check `sign-images` config in U-Boot.
|
||||
- **`fw_printenv` CRC error** — environment not yet saved on the board
|
||||
(`saveenv` once from U-Boot), or `/etc/fw_env.config` offsets don't match
|
||||
the partition layout.
|
||||
77
docs/guides/cli/vercel.md
Normal file
77
docs/guides/cli/vercel.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# vercel (Vercel CLI)
|
||||
|
||||
## What it is
|
||||
|
||||
Vercel's CLI: link a project, get instant preview deploys from a branch,
|
||||
promote to production, manage env vars and domains.
|
||||
|
||||
## Install
|
||||
|
||||
Via npm (current stable; requires Node LTS):
|
||||
|
||||
```bash
|
||||
npm install -g vercel
|
||||
```
|
||||
|
||||
Standalone binaries also exist on the releases page if you don't want a global
|
||||
npm package.
|
||||
|
||||
## Authenticate
|
||||
|
||||
```bash
|
||||
vercel login # email link confirmation
|
||||
```
|
||||
|
||||
Token cached in `~/.vercel/` (actually platform config dir). For CI, create a
|
||||
token in the dashboard, store it in Vaultwarden
|
||||
(https://vault.portugalfuturista.org), and use:
|
||||
|
||||
```bash
|
||||
vercel --token "$VERCEL_TOKEN" deploy --prod
|
||||
```
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
```bash
|
||||
cd <project>
|
||||
vercel link # pick scope + project
|
||||
vercel env pull .env.local # fetch env vars for local dev
|
||||
vercel dev # local dev server with Vercel routing
|
||||
vercel # preview deploy
|
||||
vercel --prod # production
|
||||
```
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
None deployed. The planned self-hosted alternative is **Coolify** (or Dokku)
|
||||
on a Proxmox CT — git-push deploys with preview-like behaviour. Until then,
|
||||
static frontends are served via Caddy on the LAN behind the `pf-tunnel-v2`
|
||||
Cloudflare tunnel; Vercel is used only when its edge network or Next.js
|
||||
integration is genuinely required.
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **cli-edge** skill wraps `vercel` for preview/prod deploys of edge
|
||||
frontends. Connector registry id: `vercel`.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
vercel --version
|
||||
# 3x.y.z
|
||||
vercel whoami
|
||||
# > Success! <email> ...
|
||||
vercel ls
|
||||
# ... project deployments table ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`vercel login` email never arrives** — check spam; or use
|
||||
`vercel login <email>` and the token flow from the dashboard instead.
|
||||
- **Wrong scope/team** — `vercel switch` to change the active team, or
|
||||
re-run `vercel link`.
|
||||
- **Build works locally, fails on Vercel** — Node version mismatch; pin
|
||||
`"engines"` in `package.json` or the project settings.
|
||||
- **Env var missing in preview** — Vercel envs are per-environment
|
||||
(Production/Preview/Development); set the var for the right target.
|
||||
101
docs/guides/cli/yocto.md
Normal file
101
docs/guides/cli/yocto.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# yocto (Yocto Project / poky + kas)
|
||||
|
||||
## What it is
|
||||
|
||||
The Yocto Project builds custom Linux distributions from recipes. `poky` is
|
||||
the reference distribution; `kas` is the config-driven wrapper that pins
|
||||
layers/revisions in one YAML file. This is how we build appliance images for
|
||||
embedded targets.
|
||||
|
||||
## Requirements (read before building)
|
||||
|
||||
- **Disk: ~100 GB+ free** (sstate cache + downloads grow fast; 200 GB is
|
||||
comfortable).
|
||||
- **RAM: 16 GB** (8 GB works with a big swapfile and patience).
|
||||
- Long builds: first `core-image-minimal` can take hours on a laptop.
|
||||
|
||||
## Install (host tools)
|
||||
|
||||
```bash
|
||||
sudo apt install gawk wget git diffstat unzip texinfo gcc build-essential \
|
||||
chrpath socat cpio python3 python3-pip python3-pexpect xz-utils debianutils \
|
||||
iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \
|
||||
pylint xterm python3-subunit mesa-common-dev zstd liblz4-tool file locales
|
||||
pipx install kas
|
||||
```
|
||||
|
||||
## Recommended: build inside the crops/poky container
|
||||
|
||||
The laptop should not be a Yocto host. Use the official container (Ubuntu
|
||||
base, all deps preinstalled):
|
||||
|
||||
```bash
|
||||
docker run --rm -it \
|
||||
-v ~/yocto:/work -w /work \
|
||||
crops/poky:ubuntu-22.04
|
||||
# inside the container:
|
||||
git clone -b scarthgap https://git.yoctoproject.org/poky
|
||||
source poky/oe-init-build-env build
|
||||
bitbake core-image-minimal
|
||||
```
|
||||
|
||||
With kas instead of manual sourcing:
|
||||
|
||||
```bash
|
||||
kas build project.yml # runs bitbake per the pinned layer config
|
||||
kas shell project.yml # interactive shell inside the build env
|
||||
```
|
||||
|
||||
A dedicated **Proxmox CT/VM for Yocto builds** (100+ GB disk, 16 GB RAM,
|
||||
Docker or bare Debian) may come later — designs should already assume builds
|
||||
run there, not on the laptop.
|
||||
|
||||
## Authenticate
|
||||
|
||||
None. Layer repos clone over HTTPS/SSH (use Forgejo mirrors where they exist:
|
||||
`code.portugalfuturista.org`). Private-layer SSH keys stay in `~/.ssh`; never
|
||||
in recipes.
|
||||
|
||||
## Configure for this environment
|
||||
|
||||
- Set `DL_DIR` and `SSTATE_DIR` outside the build tree so multiple builds
|
||||
share downloads/cache (`local.conf`):
|
||||
```
|
||||
DL_DIR ?= "/work/downloads"
|
||||
SSTATE_DIR ?= "/work/sstate-cache"
|
||||
```
|
||||
- Pin every layer branch in the kas YAML — reproducibility over freshness.
|
||||
- Archive release images to MinIO (`http://192.168.0.40:9000`).
|
||||
|
||||
## Self-hosted equivalent
|
||||
|
||||
Yocto is inherently self-hosted — the entire toolchain and mirrorable source
|
||||
cache live on your infrastructure. For air-gapped reproducibility run an
|
||||
`sstate` mirror on MinIO (`SSTATE_MIRRORS` in `local.conf`).
|
||||
|
||||
## Aurélio integration
|
||||
|
||||
The **embedded-linux** skill drives `kas`/`bitbake` for image builds. Images
|
||||
produced are flashed with tools from [esptool.md](esptool.md) /
|
||||
[uboot-tools.md](uboot-tools.md) and target the `mqtt-local` connector at
|
||||
runtime.
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
kas --version
|
||||
# kas 4.x
|
||||
docker run --rm crops/poky:ubuntu-22.04 bitbake --version
|
||||
# BitBake Build Tool Core version 2.x ...
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **`do_fetch` stalls** — upstream git flaky; set a premirror or retry; check
|
||||
you cloned the matching release branch (e.g. `scarthgap`) for all layers.
|
||||
- **Disk full mid-build** — Yocto needs ~100 GB; clean with
|
||||
`bitbake -c cleanall <recipe>` or prune `tmp/` (keep `DL_DIR`/`SSTATE_DIR`).
|
||||
- **Host distro too new/old for a release** — that's exactly why we build in
|
||||
`crops/poky`; pick the container Ubuntu version matching the Yocto release.
|
||||
- **`kas` can't find layers** — paths in the kas YAML are relative to the
|
||||
repo root; run `kas build` from there or pass absolute `--target` paths.
|
||||
134
docs/guides/selfhosted/cloud-emulators.md
Normal file
134
docs/guides/selfhosted/cloud-emulators.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# Cloud emulators (self-hosted dev cloud) — MinIO + LocalStack + Azurite
|
||||
|
||||
Self-hosted cloud services for development, running on **lattepanda**
|
||||
(192.168.0.40) as Docker containers. Part of the "self-hosted first" policy:
|
||||
dev work targets these endpoints; public clouds only when explicitly required.
|
||||
|
||||
## What's deployed
|
||||
|
||||
| Service | Emulates | Endpoint (LAN) | Console |
|
||||
|---|---|---|---|
|
||||
| MinIO | AWS S3 | `http://192.168.0.40:9000` | `http://192.168.0.40:9001` |
|
||||
| LocalStack v3 | AWS (S3, SQS, SNS, IAM, Lambda, DynamoDB, IoT, …) | `http://192.168.0.40:4566` | — |
|
||||
| Azurite | Azure Storage | blob `:10000` · queue `:10001` · table `:10002` | — |
|
||||
|
||||
Pre-created MinIO buckets: `terraform-state`, `firmware-artifacts`, `backups`.
|
||||
|
||||
> **Why LocalStack v3?** `localstack/localstack:latest` (2026+) requires a
|
||||
> `LOCALSTACK_AUTH_TOKEN` (Pro license). The v3 tag is the last community
|
||||
> line that runs token-free.
|
||||
|
||||
## Deploy / manage
|
||||
|
||||
The stack lives at `/opt/cloud-emulators/` on lattepanda:
|
||||
|
||||
```
|
||||
/opt/cloud-emulators/
|
||||
├── cloud-emulators.yml # compose file (source of truth: repo docs/compose/cloud-emulators.yml)
|
||||
└── .env # MINIO_ROOT_USER / MINIO_ROOT_PASSWORD (chmod 600)
|
||||
```
|
||||
|
||||
```bash
|
||||
ssh root@192.168.0.40
|
||||
cd /opt/cloud-emulators
|
||||
docker compose -f cloud-emulators.yml up -d # start/update
|
||||
docker compose -f cloud-emulators.yml ps # status
|
||||
docker compose -f cloud-emulators.yml logs -f # logs
|
||||
```
|
||||
|
||||
After editing `docs/compose/cloud-emulators.yml` in the repo, sync it:
|
||||
|
||||
```bash
|
||||
scp docs/compose/cloud-emulators.yml root@192.168.0.40:/opt/cloud-emulators/
|
||||
ssh root@192.168.0.40 'cd /opt/cloud-emulators && docker compose -f cloud-emulators.yml up -d'
|
||||
```
|
||||
|
||||
## Credentials
|
||||
|
||||
MinIO root credentials are in `/opt/cloud-emulators/.env` on lattepanda
|
||||
(chmod 600). Store a copy in **Vaultwarden** (entry: "MinIO lattepanda").
|
||||
LocalStack and Azurite accept any credentials in dev — use `test`/`test`.
|
||||
|
||||
## CLI wiring
|
||||
|
||||
### aws CLI → MinIO / LocalStack
|
||||
|
||||
Add to `~/.aws/config`:
|
||||
|
||||
```ini
|
||||
[profile localstack]
|
||||
region = eu-west-1
|
||||
output = json
|
||||
|
||||
[profile minio]
|
||||
region = eu-west-1
|
||||
output = json
|
||||
```
|
||||
|
||||
`~/.aws/credentials`:
|
||||
|
||||
```ini
|
||||
[localstack]
|
||||
aws_access_key_id = test
|
||||
aws_secret_access_key = test
|
||||
|
||||
[minio]
|
||||
aws_access_key_id = minioadmin
|
||||
aws_secret_access_key = <from Vaultwarden>
|
||||
```
|
||||
|
||||
Usage:
|
||||
|
||||
```bash
|
||||
aws --profile localstack --endpoint-url http://192.168.0.40:4566 sqs list-queues
|
||||
aws --profile minio --endpoint-url http://192.168.0.40:9000 s3 ls
|
||||
```
|
||||
|
||||
(See `docs/guides/cli/aws.md` for full setup.)
|
||||
|
||||
### az CLI → Azurite
|
||||
|
||||
```bash
|
||||
export AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://192.168.0.40:10000/devstoreaccount1;QueueEndpoint=http://192.168.0.40:10001/devstoreaccount1;TableEndpoint=http://192.168.0.40:10002/devstoreaccount1;"
|
||||
az storage container list --connection-string "$AZURE_STORAGE_CONNECTION_STRING"
|
||||
```
|
||||
|
||||
(The Azurite account key above is the well-known public dev key — fine for LAN dev.)
|
||||
|
||||
### OpenTofu/Terraform state on MinIO
|
||||
|
||||
```hcl
|
||||
terraform {
|
||||
backend "s3" {
|
||||
bucket = "terraform-state"
|
||||
key = "lab/terraform.tfstate"
|
||||
region = "eu-west-1"
|
||||
endpoint = "http://192.168.0.40:9000"
|
||||
access_key = "minioadmin" # or env AWS_ACCESS_KEY_ID
|
||||
secret_key = "…" # or env AWS_SECRET_ACCESS_KEY
|
||||
skip_credentials_validation = true
|
||||
skip_metadata_api_check = true
|
||||
skip_region_validation = true
|
||||
force_path_style = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Verify
|
||||
|
||||
```bash
|
||||
curl -sf http://192.168.0.40:9000/minio/health/live # MinIO → 200
|
||||
curl -sf http://192.168.0.40:4566/_localstack/health | jq # LocalStack → services available
|
||||
curl -s -o /dev/null -w '%{http_code}\n' http://192.168.0.40:10000/ # Azurite → 400 (up, auth required)
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **LocalStack restart loop, exit 55** — you're on `latest` (Pro-only). The
|
||||
compose file pins `localstack/localstack:3`; don't bump without a license.
|
||||
- **MinIO `mc` commands** — exec inside the container:
|
||||
`docker exec minio mc ls local` (alias `local` preconfigured at bootstrap).
|
||||
- **Azurite 400 on root URL** — expected; the service requires an account path.
|
||||
Use the connection string above.
|
||||
- **Disk pressure** — all three volumes live on lattepanda's root disk (85G
|
||||
free at deploy time). `docker system df` to audit.
|
||||
Loading…
Reference in a new issue