docs: describe current state only, and fill in the stub READMEs

Drop the history and roadmap asides: which services predate the collection's
conventions, the unwired Open Web UI plan, the generic clone-and-troubleshoot
boilerplate. Services that publish ports or set `restart:` now simply say so.

couchbase, openvpn-as and traffmonetizer had two-line READMEs; give them the
ports, variables and storage the root README promises. traffmonetizer reads
${TOKEN} and had no .env.example, so add one.
This commit is contained in:
tiennm99 committed 2026-09-16 20:45:18 +07:00
1 parent 04ccc93969
commit 23b9bf8bf6
13 files changed
+324 -374

No files matched your search

+16 -18
View File
@@ -1,19 +1,19 @@
# composes
My docker compose collection — one directory per service, each self-contained.
Tuned to my own setup rather than written as general-purpose templates.
These are tuned to my own setup, not written as general-purpose templates. They
are deployed through [Coolify](https://coolify.io) and
[Dokploy](https://dokploy.com), so they lean on the platform for things a
standalone compose file would normally declare:
Services are deployed through [Coolify](https://coolify.io) and
[Dokploy](https://dokploy.com), which own what a standalone compose file would
otherwise declare:
- **No published ports.** Both platforms attach the container to their proxy
network and map a domain directly to the internal port, so `ports:` is
unnecessary — and adding it would expose the host port as well.
- **No published ports.** The platform attaches the container to its proxy
network and maps a domain to the internal port. Publishing one would also
expose it on the host.
- **No `restart:` policy.** The platform manages the container lifecycle.
- **No `container_name:`.** Compose derives it from the directory.
Treat them as working examples rather than drop-in configs. Running one with
plain `docker compose` means adding whatever your setup needs.
Services that do publish ports or set `restart:` say so in their own README.
## Layout
@@ -33,7 +33,7 @@ the `code-server` project with its own network and volumes.
In Coolify or Dokploy, point a Docker Compose resource at the service directory
and set the environment variables from its `.env.example`.
Locally, for a quick check:
Locally:
```sh
cd <service>
@@ -43,8 +43,8 @@ docker compose logs -f
docker compose down
```
`.env` is picked up automatically because it sits next to `compose.yml`.
Never commit it — the root `.gitignore` covers `.env`/`*.env` and re-includes
`.env` is picked up automatically because it sits next to `compose.yml`. Never
commit it — the root `.gitignore` covers `.env`/`*.env` and re-includes
`.env.example`.
## Services
@@ -53,17 +53,15 @@ Each links to its own README for variables, ports, and storage.
| Service | What it is |
| --- | --- |
| [alloy](alloy/README.md) | Grafana Alloy shipping host + Docker metrics/logs to Grafana Cloud |
| [alloy](alloy/README.md) | Grafana Alloy shipping host and Docker telemetry to Grafana Cloud |
| [code-server](code-server/README.md) | VS Code in the browser, as a remote dev box |
| [couchbase](couchbase/README.md) | Couchbase Server |
| [gitea-mirror-local](gitea-mirror-local/README.md) | Self-hosted Gitea + PostgreSQL + gitea-mirror for mirroring GitHub repos |
| [gitea-mirror-local](gitea-mirror-local/README.md) | Gitea + PostgreSQL + gitea-mirror, mirroring GitHub repos |
| [netdata](netdata/README.md) | Netdata monitoring agent |
| [ollama](ollama/README.md) | Ollama, optionally with a web UI |
| [ollama](ollama/README.md) | Ollama LLM server |
| [openvpn-as](openvpn-as/README.md) | OpenVPN Access Server |
| [paseo](paseo/README.md) | Paseo coding-agent daemon and web UI |
| [tastyigniter](tastyigniter/README.md) | TastyIgniter restaurant ordering platform |
| [traffmonetizer](traffmonetizer/README.md) | TraffMonetizer bandwidth-sharing client |
The absorbed services (everything but `code-server`) predate this collection's
conventions — some still publish ports or set `restart:`; align them as they
get touched.
Licensed under Apache 2.0 — see [LICENSE](LICENSE).
+63 -50
View File
@@ -1,77 +1,90 @@
# alloy-docker-compose
# alloy
One-file [Grafana Alloy](https://grafana.com/docs/alloy/latest/) setup that ships host (linux) and container (docker) telemetry to Grafana Cloud, plus pulls remote config from Grafana Fleet Management.
[Grafana Alloy](https://grafana.com/docs/alloy/latest/) shipping host and
container telemetry to Grafana Cloud, with remote config from Grafana Fleet
Management.
- **Single container** running both `node_exporter` (host) and `cadvisor` (containers) collectors.
- **Config embedded inline** via Compose `configs:` — no sidecar `config.alloy` file on disk.
- **Env-driven** — nine shell variables, no `.env` file.
- **Remote config** via `remotecfg` block (Grafana Fleet Management).
One container runs both the `node_exporter` (host) and `cadvisor` (container)
collectors. The Alloy config is embedded inline via Compose `configs:`, so
there is no `config.alloy` on disk, and every setting comes from a shell
variable rather than a `.env` file.
Uses `docker-compose.yml`, and sets `restart: unless-stopped` and
`container_name: alloy` — unlike the platform-managed services described in the
[root README](../README.md).
## What it collects
| Source | Component | Notes |
|---|---|---|
| Host metrics | `prometheus.exporter.unix` | CPU, memory, load, disk I/O, filesystem, network, uname, boot time, systemd, vmstat, sockstat — full default-collector set minus `ipvs/btrfs/infiniband/xfs/zfs` |
| Host metrics | `prometheus.exporter.unix` | CPU, memory, load, disk I/O, filesystem, network, uname, boot time, systemd, vmstat, sockstat — the default collector set minus `ipvs/btrfs/infiniband/xfs/zfs` |
| Container metrics | `prometheus.exporter.cadvisor` | CPU, memory, fs usage/limit, network, `last_seen` |
| Container logs | `loki.source.docker` | all running containers, labeled with `container`, `stream`, `instance` |
| System logs (journal) | `loki.source.journal` (via `journal_module`) | systemd journal with `unit`, `boot_id`, `transport`, `level` labels |
| System logs (files) | `loki.source.file` | `/var/log/syslog`, `/var/log/messages`, `/var/log/*.log` |
| Remote config | `remotecfg` | polls Grafana Fleet Management every 60s |
| Container logs | `loki.source.docker` | All running containers, labeled `container`, `stream`, `instance` |
| Journal logs | `loki.source.journal` | systemd journal, labeled `unit`, `boot_id`, `transport`, `level` |
| File logs | `loki.source.file` | `/var/log/syslog`, `/var/log/messages`, `/var/log/*.log` |
| Remote config | `remotecfg` | Polls Grafana Fleet Management every 60s |
Filtering follows the upstream Grafana Cloud integration configs verbatim — `keep`-lists copied from each integration's **Metrics** section ([Linux Node](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-linux-node/#metrics), [Docker](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-docker/#metrics)). Logs are unfiltered.
Metric filtering copies the `keep`-lists from the upstream Grafana Cloud
integrations verbatim ([Linux Node](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-linux-node/#metrics),
[Docker](https://grafana.com/docs/grafana-cloud/monitor-infrastructure/integrations/integration-reference/integration-docker/#metrics)).
Logs are unfiltered.
> **Log duplication caveat.** On systems where rsyslog mirrors journald to `/var/log/syslog` (e.g. Debian/Ubuntu defaults), enabling both pipelines double-ships the same lines. If that's the case for your hosts, drop one source — typically the file-based one is redundant on systemd-only stacks.
Where rsyslog mirrors journald into `/var/log/syslog` — the Debian and Ubuntu
default — the journal and file pipelines double-ship the same lines. Drop one
source on those hosts; the file-based one is the redundant one on systemd-only
stacks.
## Quick start
## Environment
All nine are required; `docker compose up` fails fast if any is unset.
| Variable | Purpose |
| --- | --- |
| `ALLOY_HOSTNAME` | Container hostname, and the Loki/Prometheus `instance` label |
| `REMOTECFG_URL` | Fleet Management endpoint |
| `REMOTECFG_ID` | Fleet Management agent id |
| `REMOTECFG_USER` | Fleet Management user id |
| `PROM_URL` / `PROM_USER` | Prometheus remote-write endpoint and user id |
| `LOKI_URL` / `LOKI_USER` | Loki push endpoint and user id |
| `GRAFANA_TOKEN` | One Cloud Access Policy token, scopes `metrics:write` + `logs:write` + `fleet-management:read` |
Find the values under Grafana Cloud → your stack → **Details** on each data
source, and under Fleet Management. The same token serves `remotecfg`,
Prometheus and Loki basic-auth.
```bash
export ALLOY_HOSTNAME=miti-jp # also used as Loki/Prometheus instance label
export REMOTECFG_URL=https://fleet-management-prod-013.grafana.net
export REMOTECFG_ID=miti-jp # fleet-management agent id
export REMOTECFG_USER=1431677 # fleet-management user id
export PROM_URL=https://prometheus-prod-XX-<region>.grafana.net/api/prom/push
export PROM_USER=<prometheus-user-id>
export LOKI_URL=https://logs-prod-XXX.grafana.net/loki/api/v1/push
export LOKI_USER=<loki-user-id>
export GRAFANA_TOKEN=glc_... # one Cloud Access Policy token, scopes: metrics:write + logs:write + fleet-management:read
export ALLOY_HOSTNAME=miti-jp REMOTECFG_ID=miti-jp ...
docker compose up -d
```
Find the `PROM_*` / `LOKI_*` / `REMOTECFG_*` values under Grafana Cloud → your stack → **Details** on each data source / Fleet Management. The same token is reused for `remotecfg`, Prometheus, and Loki basic-auth.
Run the same file on every host, changing `ALLOY_HOSTNAME` and `REMOTECFG_ID`
per host. Filter in Grafana with `instance=~"..."`.
Any unset required variable makes `docker compose up` fail fast.
## Privileges
## Multi-host
Same compose file on every host — change `ALLOY_HOSTNAME` and `REMOTECFG_ID` per host. Filter in Grafana with `instance=~"..."`.
## Security note
Runs `privileged: true` + `network_mode: host`, matching the upstream Grafana Cloud docker integration. `network_mode: host` is required so `prometheus.exporter.unix` reports the host's real network interfaces (eth0…) instead of the alloy container's veth pair. If you need least-privilege, see the upstream Alloy docker integration docs and tighten capabilities.
Runs `privileged: true` with `network_mode: host`, matching the upstream
Grafana Cloud docker integration. Host networking is what lets
`prometheus.exporter.unix` report the host's real interfaces (`eth0`…) instead
of the container's veth pair. To tighten this, see the upstream Alloy docker
integration docs.
## Mounts
| Mount | Why |
|---|---|
| `/proc:/rootproc:ro` | node-exporter cpu/mem/load (referenced via `procfs_path`) |
| `/sys:/sys:ro` | node-exporter + cadvisor cgroups |
| `/:/rootfs:ro` | filesystem collector (referenced via `rootfs_path`) |
| `/proc:/rootproc:ro` | node-exporter cpu/mem/load, via `procfs_path` |
| `/sys:/sys:ro` | node-exporter and cadvisor cgroups |
| `/:/rootfs:ro` | filesystem collector, via `rootfs_path` |
| `/dev/disk/:/dev/disk:ro` | node-exporter diskstats device labels |
| `/var/run/docker.sock` | `discovery.docker` + `loki.source.docker` |
| `/var/run/docker.sock` | `discovery.docker` and `loki.source.docker` |
| `/var/lib/docker:ro` | cadvisor container metadata |
| `/var/log:/var/log:ro` | `loki.source.journal` (`/var/log/journal`) + `loki.source.file` (syslog/messages/*.log) |
| `/etc/machine-id:ro` | stable host id for the journal reader |
| `alloy-data` (named volume) | WAL + remotecfg cache |
| `/var/log:/var/log:ro` | `loki.source.journal` and `loki.source.file` |
| `/etc/machine-id:ro` | Stable host id for the journal reader |
| `alloy-data` | WAL and remotecfg cache |
## Design
## Notes
- [Upstream sources of truth](docs/upstream-sources-of-truth.md) — what we follow, what's in scope, how to audit dashboard metric needs.
## Known noise (special cases)
- [Coolify SSH session spam](docs/known-noise-coolify-ssh-sessions.md) — only relevant if Coolify manages the host. Safe to ignore otherwise.
## License
Apache 2.0 — see [LICENSE](LICENSE).
- [Upstream sources of truth](docs/upstream-sources-of-truth.md) — what this
follows, what is in scope, how to audit dashboard metric needs.
- [Coolify SSH session noise](docs/known-noise-coolify-ssh-sessions.md) — only
relevant on Coolify-managed hosts.
+22 -2
View File
@@ -1,2 +1,22 @@
# couchbase-docker-compose
docker-compose.yml to run couchbase
# couchbase
[Couchbase Server](https://www.couchbase.com), single node.
Uses `docker-compose.yml`, publishes ports, and sets `restart: unless-stopped`
and `container_name: db` — unlike the platform-managed services described in
the [root README](../README.md).
## Networking
| Ports | Purpose |
| --- | --- |
| `8091-8097` | Cluster manager, views, query, search, analytics, eventing |
| `18091-18097` | The same, over TLS |
| `11207`, `11210` | Data service (TLS, plain) |
| `11280`, `9123` | Internal services |
The admin console is on `8091`. Complete the first-run setup there.
## Storage
`couchbase_data` at `/opt/couchbase/var` — data, indexes, config, logs.
+30 -44
View File
@@ -1,21 +1,21 @@
# gitea-mirror-docker-compose
# gitea-mirror-local
A small Docker Compose stack that runs a self-hosted [Gitea](https://about.gitea.com/)
instance backed by PostgreSQL, alongside
[gitea-mirror](https://github.com/RayLabsHQ/gitea-mirror) for mirroring
repositories from GitHub into it.
Self-hosted [Gitea](https://about.gitea.com/) backed by PostgreSQL, with
[gitea-mirror](https://github.com/RayLabsHQ/gitea-mirror) mirroring GitHub
repositories into it.
Publishes ports, unlike the platform-managed services described in the
[root README](../README.md) — but binds them all to `127.0.0.1`, so nothing is
reachable from outside the host. Put a reverse proxy in front for remote
access.
## Services
| Service | Image | Host address |
| -------------- | ----------------------------------------- | ------------------------ |
| `db` | `postgres:16-alpine` | internal only |
| `gitea` | `gitea/gitea:latest` | `127.0.0.1:3000` (HTTP) |
| | | `127.0.0.1:2222` (SSH) |
| `gitea-mirror` | `ghcr.io/raylabshq/gitea-mirror:latest` | `127.0.0.1:4321` |
All published ports are bound to `127.0.0.1`, so nothing is reachable from
outside the host. Put a reverse proxy in front if you need remote access.
| Service | Image | Address |
| --- | --- | --- |
| `db` | `postgres:16-alpine` | internal only |
| `gitea` | `gitea/gitea:latest` | `127.0.0.1:3000` (HTTP), `127.0.0.1:2222` (SSH) |
| `gitea-mirror` | `ghcr.io/raylabshq/gitea-mirror:latest` | `127.0.0.1:4321` |
`gitea` waits for `db` to pass its health check before starting.
@@ -25,45 +25,31 @@ outside the host. Put a reverse proxy in front if you need remote access.
docker compose up -d
```
Then open <http://127.0.0.1:3000> to complete Gitea's first-run setup, and
<http://127.0.0.1:4321> to configure mirroring.
Complete Gitea's first-run setup at <http://127.0.0.1:3000>, then configure
mirroring at <http://127.0.0.1:4321>.
To clone over SSH, note that Gitea advertises port `2222`:
Gitea advertises SSH port `2222`:
```sh
git clone ssh://git@127.0.0.1:2222/<owner>/<repo>.git
```
Stop the stack with `docker compose down`. State lives in named volumes
(`db-data`, `gitea-data`, `gitea-mirror-data`), so it survives a restart; add
`-v` to that command to delete it.
## Configuration
`compose.yml` currently hardcodes its settings — database credentials, ports,
and the Gitea SSH port are written inline rather than read from the
environment. The stack runs as-is with no additional setup.
`compose.yml` hardcodes everything — database credentials, ports and the Gitea
SSH port are written inline and read no environment variables. `.env.example`
is not wired up: editing a `.env` has no effect until the compose file consumes
it via `env_file:` or `${VAR}` substitution.
`.env.example` documents the keys of a `.env` for this deployment, with sample
values. Copy it and fill in your own:
The Postgres credentials are `gitea` / `gitea`. Change them before exposing
this stack beyond localhost.
```sh
cp .env.example .env
```
## Storage
The real `.env` is gitignored and never committed. Replace
`BETTER_AUTH_SECRET` with a freshly generated random value rather than the
sample string.
| Volume | Holds |
| --- | --- |
| `db-data` | PostgreSQL data |
| `gitea-data` | Repositories, Gitea config and state |
| `gitea-mirror-data` | Mirror job database |
Note that **`compose.yml` does not currently reference these variables**, so
editing `.env` has no effect until the compose file is wired up to consume it
(via `env_file:` or `${VAR}` substitution). The sample values also differ from
the hardcoded ones in a couple of places — for example `GITEA_SSH_PORT=8022`
versus the `2222` currently published by `compose.yml`.
## Security notes
- The Postgres credentials in `compose.yml` are the default `gitea` / `gitea`.
Change them before exposing this stack beyond localhost.
- `BETTER_AUTH_SECRET` in `.env.example` is a secret. Generate a fresh random
value per deployment and keep it out of version control.
`docker compose down -v` deletes all three.
+26 -26
View File
@@ -1,36 +1,36 @@
# netdata-docker-compose
# netdata
Docker Compose setup to run the [Netdata](https://www.netdata.cloud) monitoring agent.
[Netdata](https://www.netdata.cloud) monitoring agent.
## Quick start
Uses `docker-compose.yml`, and sets `restart: unless-stopped` and
`container_name: netdata` — unlike the platform-managed services described in
the [root README](../README.md).
```bash
docker compose up -d
Runs with `network_mode: host` and `pid: host`, plus `SYS_PTRACE`/`SYS_ADMIN`
and an unconfined AppArmor profile, so it can read host processes and metrics.
The dashboard is therefore on the host's own `19999`, not a published port.
## Environment
| Variable | Purpose |
| --- | --- |
| `NETDATA_CLAIM_TOKEN` | Netdata Cloud claim token. Without it the agent runs standalone. |
```sh
NETDATA_CLAIM_TOKEN=<token> docker compose up -d
```
Access the dashboard at `http://localhost:19999`.
## Storage
## Customization
| Volume | Mount | Holds |
| --- | --- | --- |
| `netdataconfig` | `/etc/netdata` | Agent configuration |
| `netdatalib` | `/var/lib/netdata` | Metrics database, claim state |
| `netdatacache` | `/var/cache/netdata` | Cache |
Set your Netdata Cloud claim token to link the agent to your cloud account:
```bash
NETDATA_CLAIM_TOKEN=your-token docker compose up -d
```
Key defaults you may want to override in `docker-compose.yml`:
| Setting | Default | Notes |
|---------|---------|-------|
| Dashboard port | `19999` | Map to a different host port if needed |
| Volumes | `/proc`, `/sys`, host root | Required for full host metrics |
Host paths (`/`, `/proc`, `/sys`, `/var/log`, the Docker socket, dbus) are
mounted read-only for collection.
## Related
- [alloy](../alloy/README.md) — Grafana Alloy collector (ships metrics to Grafana Cloud)
- [grafana-git-sync](https://github.com/tiennm99/grafana-git-sync) — sync Grafana dashboards to git
- [ollama](../ollama/README.md) — Ollama LLM server compose setup
## License
Apache-2.0 — see [LICENSE](LICENSE).
- [alloy](../alloy/README.md) — ships metrics to Grafana Cloud instead
+13 -38
View File
@@ -1,32 +1,21 @@
# ollama-docker-compose
# ollama
Minimal Docker Compose setup for running [Ollama](https://ollama.com) locally — exposes the API on `:11434` with a named volume so pulled models persist across restarts.
[Ollama](https://ollama.com) LLM server. CPU-only.
> The "optionally with a web UI" phrase from the description is **not yet wired**. Open Web UI sidecar can be added — see [Roadmap](#roadmap).
Uses `docker-compose.yml`, publishes `11434`, and sets
`restart: unless-stopped` and `container_name: ollama` — unlike the
platform-managed services described in the [root README](../README.md).
## Quick start
## Usage
```bash
docker compose up -d
```
Ollama API → `http://localhost:11434`.
Pull a model:
```bash
```sh
docker compose exec ollama ollama pull llama3.2
```
Chat from CLI:
```bash
docker compose exec ollama ollama run llama3.2
```
Smoke test via API:
The API is on `http://localhost:11434`:
```bash
```sh
curl http://localhost:11434/api/generate -d '{
"model": "llama3.2",
"prompt": "Why is the sky blue?",
@@ -34,23 +23,9 @@ curl http://localhost:11434/api/generate -d '{
}'
```
## What's inside
For GPU, add `deploy.resources.reservations.devices` for the NVIDIA runtime —
see the [Ollama Docker docs](https://hub.docker.com/r/ollama/ollama).
| Field | Value |
|---|---|
| Image | `ollama/ollama` (latest) |
| Port | `11434:11434` |
| Volume | `ollama:/root/.ollama` (models, manifests) |
| Restart policy | `unless-stopped` |
## Storage
## GPU
To enable GPU, add `deploy.resources.reservations.devices` for the NVIDIA runtime — see the [Ollama Docker docs](https://hub.docker.com/r/ollama/ollama). CPU-only by default.
## Roadmap
- Add Open Web UI sidecar (`ghcr.io/open-webui/open-webui:main`) on `:3000` wired to this Ollama instance.
## License
Apache-2.0
`ollama` at `/root/.ollama` — pulled models and manifests.
+25 -2
View File
@@ -1,2 +1,25 @@
# openvpn-as-docker-compose
Run OpenVPN Access Server with Docker compose
# openvpn-as
[OpenVPN Access Server](https://openvpn.net/access-server/).
Uses `docker-compose.yml`, publishes ports, and sets `restart: unless-stopped`
and `container_name: openvpn-as` — unlike the platform-managed services
described in the [root README](../README.md).
Needs `/dev/net/tun` plus the `MKNOD` and `NET_ADMIN` capabilities to create
the VPN interface.
## Networking
| Port | Purpose |
| --- | --- |
| `943` | Admin and client web UI |
| `443` | OpenVPN over TCP |
| `1194/udp` | OpenVPN over UDP |
Admin UI at `https://<host>:943/admin`. The initial credentials are printed to
the container logs on first start.
## Storage
`openvpn-as-data` at `/openvpn` — config, certificates, user database.
+11 -14
View File
@@ -2,8 +2,8 @@
#
# cp .env.example .env
# Password for the daemon API and web UI. Doubles as the paseo user's login
# password, so it is also what `sudo` asks for inside a terminal.
# Password for the daemon API and web UI. Also the paseo user's login password,
# so it is what `sudo` asks for inside a terminal.
# Generate one with: openssl rand -base64 24
PASEO_PASSWORD=
@@ -11,27 +11,24 @@ PASEO_PASSWORD=
# Coolify/Dokploy must be listed here. IPs and localhost are always allowed.
PASEO_HOSTNAMES=
# Proxy addresses whose X-Forwarded-Proto the daemon trusts. Without this the
# daemon only trusts loopback, so behind Coolify/Dokploy it sees plain HTTP,
# tells the web UI the connection is not TLS, and the UI falls back to trying
# ws://...:6767 from an HTTPS page -- which the browser blocks.
# Proxy source IPs whose X-Forwarded-Proto the daemon trusts. Without this it
# trusts loopback only, reads the request as plain HTTP behind Coolify/Dokploy,
# and tells the web UI to open ws:// from an HTTPS page -- which browsers block.
# `uniquelocal` covers the private ranges Docker bridge networks use.
PASEO_TRUSTED_PROXIES=uniquelocal
# Container hostname. Paseo shows it as the host label in the web UI, so
# without it you get a random container ID.
# Container hostname, shown as the host label in the web UI. Without it the
# label is a random container ID.
PASEO_LABEL=paseo
# Timezone for logs and agent shells.
TZ=Asia/Ho_Chi_Minh
# Git identity for agents and terminals, as author and committer. These reach
# git as environment variables, so they need no `git config` and survive a
# rebuild -- unlike a ~/.gitconfig, which only lives in the /home/paseo volume.
# Git identity for agents and terminals, as author and committer. git reads
# these directly, so no `git config` step is needed.
GIT_NAME=tiennm99
GIT_EMAIL=tiennm99@outlook.com
# Shell for Paseo's terminals. Paseo reads $SHELL and falls back to /bin/sh
# (dash), ignoring the user's login shell, so set it here rather than running
# chsh -- which would be reverted by the next rebuild anyway.
# Shell for Paseo's terminals. Paseo reads $SHELL and otherwise falls back to
# /bin/sh (dash); it ignores the user's login shell, so `chsh` has no effect.
SHELL=/bin/zsh
+45 -50
View File
@@ -9,23 +9,23 @@ Python, and shell tooling to the
1. Set the variables from `.env.example` in Coolify or Dokploy.
2. Point the domain at port `6767` and deploy.
3. Open the domain. At the pairing screen enter the host **with the port**:
3. Open the domain. At the pairing screen enter the host **with the port**,
then the `PASEO_PASSWORD` value:
```
paseo.example.com:443
```
Then the `PASEO_PASSWORD` value.
4. In a terminal inside Paseo, log in once per tool you use — see the
[agents](#agents) table — plus `gh auth login`.
4. In a terminal inside Paseo, log in once per tool you use — see
[Agents](#agents) — plus `gh auth login`.
The port is required — the UI rejects a bare hostname. You must type the
address yourself: the daemon builds its auto-connect hint from the `Host`
header, browsers drop the default `:443`, and the UI discards a hint with no
port. It then shows its built-in `localhost:6767` placeholder, which in a
browser means your own machine.
The port must be typed by hand. The UI rejects a bare hostname, and the
auto-connect hint does not help: the daemon builds it from the `Host` header,
browsers drop the default `:443`, and the UI discards a hint with no port. What
you see instead is its `localhost:6767` placeholder, which in a browser means
your own machine.
Still stuck on `localhost:6767` after entering the address? Clear site data —
If it stays on `localhost:6767` after you enter the address, clear site data —
the old entry is cached in `localStorage`.
## Environment
@@ -35,18 +35,18 @@ the old entry is cached in `localStorage`.
| `PASEO_PASSWORD` | Web UI and API login, and the `paseo` user's `sudo` password. Generate with `openssl rand -base64 24`. |
| `PASEO_HOSTNAMES` | Domains allowed to reach the daemon, comma-separated. Your domain must be listed. |
| `PASEO_TRUSTED_PROXIES` | Set to `uniquelocal`, or the UI loads but never connects. |
| `PASEO_LABEL` | Container hostname. Paseo shows it as the host label in the UI; without it you get a random container ID. |
| `PASEO_LABEL` | Container hostname, shown as the host label in the UI. Without it the label is a random container ID. |
| `GIT_NAME` / `GIT_EMAIL` | Git author and committer identity for agents and terminals. |
| `TZ` | Timezone for logs and agent shells. |
| `SHELL` | Shell for Paseo's terminals. Paseo reads `$SHELL` and falls back to `/bin/sh`, ignoring the login shell, so `chsh` has no effect. |
`PASEO_TRUSTED_PROXIES` matches the *source IP* of the proxy, so hostnames are
rejected. By default the daemon believes `X-Forwarded-Proto` only from
loopback, but Coolify's Traefik reaches it from the Docker bridge network. It
therefore reads the request as plain HTTP, tells the UI to use `ws://` on an
`https://` page, and the browser blocks that as mixed content. `uniquelocal`
covers the private ranges Docker uses; an exact CIDR works too, but Coolify
assigns a fresh subnet per project.
`PASEO_TRUSTED_PROXIES` matches the proxy's *source IP*, so hostnames are
rejected. The daemon trusts `X-Forwarded-Proto` from loopback only, but
Coolify's Traefik reaches it from the Docker bridge network — so it reads the
request as plain HTTP, tells the UI to use `ws://` on an `https://` page, and
the browser blocks that as mixed content. `uniquelocal` covers the private
ranges Docker uses. An exact CIDR works too, but Coolify assigns a fresh subnet
per project.
## Networking
@@ -56,9 +56,6 @@ Listens on `6767`, published nowhere — the platform maps the domain to it, so
## Agents
All six come from npm, so new providers are one more entry on the `npm
install` line.
| Agent | Command | Package | Log in with |
| --- | --- | --- | --- |
| Claude Code | `claude` | `@anthropic-ai/claude-code` | `claude` |
@@ -68,8 +65,9 @@ install` line.
| Pi | `pi` | `@earendil-works/pi-coding-agent` | `pi` |
| Oh My Pi | `omp` | `@oh-my-pi/pi-coding-agent` | `omp` |
Pi and Oh My Pi are separate projects sharing an ancestor, so they install side
by side and their commands do not collide.
All six come from npm, so another provider is one more entry on the `npm
install` line. Pi and Oh My Pi are separate projects sharing an ancestor; their
commands do not collide.
## Storage
@@ -79,10 +77,10 @@ by side and their commands do not collide.
| `paseo-workspace` | `/workspace` | Code the agents work on |
Every agent CLI and `gh` keep their config under `/home/paseo`, so all logins
survive a redeploy. The base image already points `CLAUDE_CONFIG_DIR`,
`CODEX_HOME` and the `XDG_*` variables (which the rest follow) into it.
Dotfiles live there too — a `.zshrc` or oh-my-zsh install persists, but
anything written outside `$HOME` (`chsh`, `apt install`) is lost on rebuild.
survive a redeploy — the base image points `CLAUDE_CONFIG_DIR`, `CODEX_HOME`
and the `XDG_*` variables into it. Dotfiles live there too, so a `.zshrc` or
oh-my-zsh install persists. Anything written outside `$HOME` (`chsh`,
`apt install`) is lost on rebuild.
## Image
@@ -96,28 +94,25 @@ anything written outside `$HOME` (`chsh`, `apt install`) is lost on rebuild.
| `less nano jq unzip zip lsof psmisc ugrep bfs zsh sudo` | apt | — |
Bump a language with a build arg, e.g. `--build-arg GO_VERSION=1.27.1`. `uv`
itself is installed too. Notes for anyone tempted to change things:
itself is installed too.
- npm installs the same native binaries the vendors' own installers do — each
package is a thin launcher with the real binary as a per-platform optional
dependency. Don't swap in `curl | bash`: those write to `$HOME/.local`, and
`$HOME` is `/home/paseo`, a volume mount that hides anything baked in at
build time.
- Bun is there for `omp` alone. That package is Bun-compiled and its bin opens
with `#!/usr/bin/env bun`, so dropping Bun leaves an `omp` that won't start.
Nothing else in the image uses it — Node still runs the other five.
- The agent CLIs can't auto-update (`paseo` can't write `/usr/local`), so
Constraints worth knowing before changing the `Dockerfile`:
- `$HOME` is `/home/paseo`, a volume that masks anything the build writes
there. Hence `/opt/python` and `/usr/local/go` rather than the defaults, and
hence npm rather than each vendor's `curl | bash` installer, which writes to
`$HOME/.local`. npm delivers the same native binaries regardless — every one
of these packages is a thin launcher with the real binary as a per-platform
optional dependency.
- Bun exists for `omp` alone, whose bin opens with `#!/usr/bin/env bun`.
Node runs the other five.
- The agent CLIs cannot auto-update, since `paseo` cannot write `/usr/local`.
Claude Code shows a notice at startup. Rebuild to update.
- The image stays root on purpose: the entrypoint chowns the volumes, then
drops to the `paseo` user (uid 1000) with `gosu`.
- `sudo` prompts for `PASEO_PASSWORD`. `entrypoint.sh` wraps the image's own
entrypoint to set it — it has to run at start, since baking a password into a
layer would commit the secret and `/etc/shadow` is not on a volume, so it
reverts on every recreate. Leave `PASEO_PASSWORD` empty and the account stays
locked, which means no `sudo`.
- `sudo` resets `PATH` to its `secure_path`, which does not include
`/usr/local/go/bin`. `sudo go ...` therefore fails; use `sudo env PATH="$PATH"
go ...` or the full path.
- Nothing installs into `$HOME`. That is `/home/paseo`, a volume mount that
hides anything baked in at build time — hence `/opt/python` and
`/usr/local/go` rather than the defaults.
- The image stays root: the entrypoint chowns the volumes, then drops to the
`paseo` user (uid 1000) with `gosu`.
- `entrypoint.sh` sets the `paseo` password from `PASEO_PASSWORD` on every
start, while still root. `/etc/shadow` is not on a volume, so it reverts on
each recreate. An empty `PASEO_PASSWORD` leaves the account locked and `sudo`
unusable.
- `sudo` resets `PATH` to its `secure_path`, which excludes
`/usr/local/go/bin`. Use `sudo env PATH="$PATH" go ...` or the full path.
+5 -6
View File
@@ -2,12 +2,11 @@
# Sets the paseo user's login password from PASEO_PASSWORD, then hands off to
# the image's own entrypoint.
#
# Has to happen at start, not build: the password is a secret and would
# otherwise be baked into a layer. Has to happen here, not in a later hook: the
# base entrypoint ends in `exec gosu paseo`, so it never comes back, and by then
# we are no longer root and cannot write /etc/shadow. And it has to run every
# time -- /etc/shadow sits in the image, not in the /home/paseo volume, so it
# reverts on every container recreate.
# At start rather than at build, so the password never lands in a layer. Here
# rather than after the base entrypoint, which ends in `exec gosu paseo` and so
# never returns, and by then is no longer root. Every start, because
# /etc/shadow is in the image, not the /home/paseo volume, and reverts on each
# container recreate.
set -euo pipefail
if [[ "$(id -u)" == "0" && -n "${PASEO_PASSWORD:-}" ]]; then
+42 -122
View File
@@ -1,130 +1,50 @@
# TastyIgniter Docker Compose
# tastyigniter
This repository contains a Docker Compose setup for TastyIgniter, making it easy to deploy on Coolify or any other Docker-compatible platform.
[TastyIgniter](https://tastyigniter.com) restaurant ordering platform, built
from the local `Dockerfile` (PHP 8.3 FPM) and served by nginx.
## Features
Uses `docker-compose.yml`, publishes `${PORT:-80}`, and sets `restart:` and
`container_name:` on every service — unlike the platform-managed services
described in the [root README](../README.md).
- PHP 8.3 with FPM
- Nginx web server
- MySQL 8 database
- Queue worker for background jobs
- Cron job for scheduled tasks
- Persistent volumes for data storage
- Health checks for all services
- Environment variable configuration
## Services
## Prerequisites
| Service | Image | Role |
| --- | --- | --- |
| `app` | local `Dockerfile` | PHP-FPM application |
| `nginx` | `nginx:alpine` | Web server, published on `${PORT:-80}` |
| `db` | `mysql:8` | Database |
| `queue` | local `Dockerfile` | `artisan queue:work` for background jobs |
| `cron` | local `Dockerfile` | `artisan schedule:run` every 60s |
- Docker
- Docker Compose
- Coolify (for deployment)
All five have health checks; `app`, `queue` and `cron` wait on `db`.
## Quick Start
## Environment
1. Clone this repository:
```bash
git clone https://github.com/yourusername/tastyigniter-docker-compose.git
cd tastyigniter-docker-compose
| Variable | Purpose |
| --- | --- |
| `APP_KEY` | Laravel application key, 32 random characters. Required. |
| `APP_URL` | Public URL. Required. |
| `APP_NAME` / `APP_ENV` / `APP_DEBUG` | Defaults `TastyIgniter` / `production` / `false`. |
| `IGNITER_CARTE_KEY` | TastyIgniter Carte key, if used. |
| `IGNITER_LOCATION_MODE` | `single` or `multiple`. Defaults to `multiple`. |
| `DB_DATABASE` / `DB_USERNAME` / `DB_PASSWORD` | Database credentials. Defaults `tastyigniter` / `tastyigniter` / unset. |
| `DB_PREFIX` | Table prefix. Defaults to `ti_`. |
| `MYSQL_ROOT_PASSWORD` | MySQL root password. Required. |
| `MAIL_MAILER` / `MAIL_FROM_ADDRESS` / `MAIL_FROM_NAME` | Mail delivery. Defaults to the `log` driver. |
| `PORT` | Host port for nginx. Defaults to `80`. |
| `STACK_NAME` | Prefix for volume and network names. Defaults to `tastyigniter`. |
## Storage
| Volume | Holds |
| --- | --- |
| `${STACK_NAME}_dbdata` | MySQL data |
| `${STACK_NAME}_app` | Application files |
| `${STACK_NAME}_storage` | Uploads, cache, logs |
Back up the database with:
```sh
docker compose exec db mysqldump -u root -p tastyigniter > backup.sql
```
2. Copy the example environment file:
```bash
cp .env.example .env
```
3. Edit the `.env` file with your configuration:
```bash
nano .env
```
4. Start the containers:
```bash
docker-compose up -d
```
## Deployment on Coolify
1. Push this repository to your Git provider (GitHub, GitLab, etc.)
2. In Coolify:
- Create a new service
- Select "Docker Compose" as the deployment method
- Connect your Git repository
- Set the following environment variables from the `.env.example` file
- Deploy the service
### Required Environment Variables
Make sure to set these environment variables in Coolify:
- `APP_KEY`: Generate a random 32-character string
- `APP_URL`: Your domain name
- `DB_PASSWORD`: Secure database password
- `MYSQL_ROOT_PASSWORD`: Secure root password
- `IGNITER_CARTE_KEY`: Your TastyIgniter Carte key (if using)
### Volume Management
The following volumes are automatically managed by Coolify:
- `dbdata`: MySQL database data
- `tastyigniter`: Application files
- `tastyigniter-storage`: Application storage
### Health Checks
The deployment includes health checks for:
- Application container (PHP-FPM)
- Nginx web server
- MySQL database
## Development
To run in development mode:
1. Set `APP_ENV=local` in your `.env` file
2. Set `APP_DEBUG=true` in your `.env` file
3. Run `docker-compose up -d`
## Maintenance
### Database Backup
To backup the database:
```bash
docker-compose exec db mysqldump -u root -p tastyigniter > backup.sql
```
### Logs
View logs for all services:
```bash
docker-compose logs -f
```
View logs for a specific service:
```bash
docker-compose logs -f app
docker-compose logs -f nginx
docker-compose logs -f db
```
## Troubleshooting
1. If the application fails to start:
- Check the logs: `docker-compose logs -f app`
- Verify environment variables are set correctly
- Ensure all required ports are available
2. If the database connection fails:
- Check the database logs: `docker-compose logs -f db`
- Verify database credentials in `.env`
- Ensure the database container is running: `docker-compose ps`
3. If the web server is not accessible:
- Check nginx logs: `docker-compose logs -f nginx`
- Verify port configuration in `.env`
- Check if the domain is properly configured
## License
This project is licensed under the MIT License - see the LICENSE file for details.
+6
View File
@@ -0,0 +1,6 @@
# Copy to .env and fill in. Never commit .env.
#
# cp .env.example .env
# Application token from the TraffMonetizer dashboard, under "Your token".
TOKEN=
+20 -2
View File
@@ -1,2 +1,20 @@
# traffmonetizer-docker-compose
Sample docker-compose.yml for TraffMonetizer
# traffmonetizer
[TraffMonetizer](https://traffmonetizer.com) bandwidth-sharing client.
Uses `docker-compose.yml`, and sets `restart: always` and
`container_name: tm` — unlike the platform-managed services described in the
[root README](../README.md). Publishes no ports; the client only makes outbound
connections.
The image tag is `arm64v8`. Change it to match the host architecture.
## Environment
| Variable | Purpose |
| --- | --- |
| `TOKEN` | Application token from the TraffMonetizer dashboard. Passed both as an environment variable and on the `start accept --token` command line. |
## Storage
None — the client keeps no state worth persisting.