Portainer: deploy from the Git repository (web editor cannot build)
Verified on Portainer 2.45: an inline/web-editor stack with `build: .` fails with "compose build operation failed: failed to solve: failed to read dockerfile: open …/Dockerfile: no such file or directory". - README + docs/QUICKSTART-PORTAINER: Route 1 = Repository deploy (Portainer clones the repo, so build: . resolves), staged so NocoDB comes up first and the base id/token are added afterwards; Route 2 = web editor with a hand-built image and the build: line removed - docker-compose.allinone.yml header: same correction - validated with: docker compose -f docker-compose.allinone.yml config
This commit is contained in:
@@ -1,52 +1,39 @@
|
||||
# Quick start on Portainer (click-by-click)
|
||||
|
||||
For a fresh machine, no shell needed. Portainer runs the same compose file as the CLI flow — see the [README](../README.md) for that version.
|
||||
For a fresh machine, no shell needed. Portainer runs the same compose file as the CLI flow — see the [README](../README.md#quick-start-cli) for that version.
|
||||
|
||||
**Before you start:** Portainer must already be up and connected to a Docker endpoint, and Portainer's own container needs access to the Docker socket (the standard install does). NocoDB will need one free host port — `8080` by default.
|
||||
**Before you start:** Portainer must already be up and connected to a Docker endpoint, and its container needs access to the Docker socket (the standard install does). NocoDB needs one free host port — `8080` by default.
|
||||
|
||||
**One thing to know up front:** the monitor's image is built from this repository (`build: .`). Portainer's *Web editor* and *Upload* options have no build context, so they cannot build it:
|
||||
|
||||
```
|
||||
compose build operation failed: failed to solve: failed to read dockerfile:
|
||||
open /volume1/@docker/tmp/buildkit-mount…/Dockerfile: no such file or directory
|
||||
```
|
||||
|
||||
That leaves two routes. **Route 1 needs no shell.**
|
||||
|
||||
---
|
||||
|
||||
## 1. Create the NocoDB container first
|
||||
|
||||
Because you cannot paste the base id and token until NocoDB exists, do this in two deploys.
|
||||
## Route 1 — deploy from the Git repository (recommended)
|
||||
|
||||
1. **Stacks → Add stack**
|
||||
2. **Name:** `carousell-monitor`
|
||||
3. **Build method:** *Web editor*
|
||||
4. Paste the **first service only** for now — the `nocodb:` block from [`docker-compose.allinone.yml`](../docker-compose.allinone.yml) plus the closing `volumes:` / `networks:` sections:
|
||||
3. **Build method:** *Repository*
|
||||
4. **Repository URL:** `https://github.com/hoelee/carousell-monitor`
|
||||
**Reference:** `refs/heads/main`
|
||||
**Compose path:** `docker-compose.allinone.yml`
|
||||
5. **Environment variables** — add:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
nocodb:
|
||||
image: nocodb/nocodb:2026.09.0
|
||||
container_name: carousell-nocodb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
PORT: "8080"
|
||||
NC_AUTH_JWT_SECRET: <paste output of: openssl rand -hex 32>
|
||||
NC_DISABLE_TELE: "true"
|
||||
NC_ALLOW_LOCAL_HOOKS: "false"
|
||||
volumes:
|
||||
- nocodb-data:/usr/app/data
|
||||
ports:
|
||||
- "8080:8080"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:8080/api/v1/health >/dev/null 2>&1 || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 5
|
||||
start_period: 60s
|
||||
networks:
|
||||
- carousell
|
||||
| Variable | Value |
|
||||
|---|---|
|
||||
| `NC_AUTH_JWT_SECRET` | output of `openssl rand -hex 32` |
|
||||
| `TELEGRAM_BOT_TOKEN` | from @BotFather |
|
||||
| `TELEGRAM_CHAT_ID` | from @userinfobot |
|
||||
| `NOCODB_PORT` | optional, default `8080` |
|
||||
|
||||
volumes:
|
||||
nocodb-data:
|
||||
|
||||
networks:
|
||||
carousell:
|
||||
```
|
||||
|
||||
5. **Deploy the stack.** Wait for `carousell-nocodb` to show as running/healthy.
|
||||
Add `NOCODB_TOKEN` and `NOCODB_BASE_ID` too if you already have them (e.g. you are reusing an existing NocoDB). On a fresh install you cannot: they do not exist yet. Leave them empty.
|
||||
6. **Deploy the stack.** `carousell-nocodb` comes up healthy. `carousell-monitor` will restart in a short loop logging `NOCODB_TOKEN not set` — expected, it needs the values from step 8. Stop that container for now if you prefer a clean list.
|
||||
|
||||
## 2. Create the base and collect the two values
|
||||
|
||||
@@ -55,52 +42,70 @@ Open `http://<your-host>:8080`:
|
||||
1. Create the admin account.
|
||||
2. Create a base (`+ New Base`) — call it `Carousell`.
|
||||
3. Copy the **base id** from the URL (`…/nc/base/<BASE_ID>/…`).
|
||||
4. Avatar (bottom-left) → **Account Settings → Tokens → Create token**, and copy the `nc_pat_…` value. It is shown once.
|
||||
4. Avatar (bottom-left) → **Account Settings → Tokens → Create token**, copy the `nc_pat_…` value. It is shown once.
|
||||
5. Do not create tables by hand — the monitor does that on start.
|
||||
|
||||
## 3. Add the monitor to the same stack
|
||||
## 3. Hand the values to the monitor
|
||||
|
||||
1. Get the Telegram values first ([docs/TELEGRAM-SETUP.md](TELEGRAM-SETUP.md)) — bot token from @BotFather, chat id from @userinfobot.
|
||||
2. Back in Portainer: **Stacks → carousell-monitor → Editor** tab.
|
||||
3. Replace the whole file with the content of [`docker-compose.allinone.yml`](../docker-compose.allinone.yml), **with the real values written in directly** instead of `${...}` placeholders:
|
||||
1. **Stacks → carousell-monitor → Editor** (or *Environment variables*).
|
||||
2. Fill in `NOCODB_BASE_ID` and `NOCODB_TOKEN`, then **Update the stack**.
|
||||
3. Portainer recreates the monitor. **Containers → carousell-monitor → Logs** should now end with one line:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
NOCODB_URL: http://nocodb:8080
|
||||
NOCODB_TOKEN: nc_pat_your_token_here
|
||||
NOCODB_BASE_ID: your_base_id_here
|
||||
TELEGRAM_BOT_TOKEN: 8123456789:AAF...
|
||||
TELEGRAM_CHAT_ID: 123456789
|
||||
```
|
||||
ready: listings=… settings=… ignored_sellers=… ignored_keywords=… seen=0
|
||||
```
|
||||
|
||||
and the same for `NC_AUTH_JWT_SECRET` / `NC_DISABLE_TELE` in the `nocodb` service.
|
||||
and the container status should be `healthy` within a couple of minutes.
|
||||
|
||||
> **Why inline values instead of Portainer's environment panel?** Portainer CE masks secret-looking values that are entered through the UI and stores the mask with the stack. On the next stack update the container receives `***` and silently stops authenticating. Editing the YAML keeps the real value on your Portainer host, which is where a stack file's secrets live anyway.
|
||||
4. **Update the stack.** Portainer recreates the services that changed and adds `carousell-monitor`.
|
||||
5. **Containers → carousell-monitor → Logs**: expect one line starting with `ready: listings=… settings=… seen=0`.
|
||||
> ⚠️ **Portainer masks secret-looking values typed into its environment panel** and stores the mask (`***`) with the stack — on a later stack update the container receives `***` and authentication silently fails. If that happens, put the real values directly in the YAML in the **Editor** tab instead of the panel.
|
||||
|
||||
## 4. Start using it
|
||||
|
||||
In NocoDB, open the base — four tables are now present. Add your first watch to **`Settings`** (see [docs/NOCODB-SETUP.md](NOCODB-SETUP.md#3-the-tables-the-monitor-creates)) and give it a minute. Then untick `notified` on any `Listings` row to force a test alert.
|
||||
In NocoDB, open the base — four tables now exist (`Listings`, `Settings`, `IgnoredSellers`, `IgnoredKeywords`). Add your first watch to **`Settings`** ([details](../docs/NOCODB-SETUP.md#3-the-tables-the-monitor-creates)), give it a minute, then untick `notified` on any `Listings` row to force a test alert into Telegram.
|
||||
|
||||
## 5. Everyday maintenance in Portainer
|
||||
---
|
||||
|
||||
## Route 2 — Web editor, with the image built by hand first
|
||||
|
||||
Use this when Portainer cannot reach your Git host, or you want a self-contained stack file.
|
||||
|
||||
```bash
|
||||
# on the Docker host (or anywhere with access to its daemon)
|
||||
git clone https://github.com/hoelee/carousell-monitor.git
|
||||
cd carousell-monitor
|
||||
docker build -t carousell-monitor:latest .
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
1. **Stacks → Add stack → Web editor**, name it `carousell-monitor`.
|
||||
2. Paste [`docker-compose.allinone.yml`](../docker-compose.allinone.yml) and **remove the `build: .` line** from the `carousell-monitor` service — a `build:` entry in a web-editor stack can only fail (no Dockerfile in Portainer's stack directory).
|
||||
3. Fill in `NC_AUTH_JWT_SECRET`, `NOCODB_PORT`, and the Telegram values. Deploy, then follow §2 and §3 above to add the base id and token.
|
||||
|
||||
Updating the code later:
|
||||
|
||||
```bash
|
||||
git pull && docker build -t carousell-monitor:latest .
|
||||
```
|
||||
|
||||
then **Update the stack** in Portainer.
|
||||
|
||||
---
|
||||
|
||||
## Everyday maintenance in Portainer
|
||||
|
||||
| Task | Where |
|
||||
|---|---|
|
||||
| Change a search / filters | NocoDB UI — nothing to redeploy |
|
||||
| Change credentials or tuning | **Stacks → carousell-monitor → Editor** → edit YAML → **Update the stack** |
|
||||
| See why it is unhealthy | **Containers → carousell-monitor → Logs**, then the `Listings`/`Settings` tables for real progress |
|
||||
| Restart | **Containers → carousell-monitor → Restart** (state is in NocoDB, nothing is lost) |
|
||||
| Update this project | pull the new code on the host, then **Editor** → *Update the stack* with `Re-pull image`/rebuild enabled, or `docker compose up -d --build` on the CLI |
|
||||
| Back up | **Volumes → nocodb-data** (all data) — or NocoDB's own base export |
|
||||
| Change a search / filter | NocoDB UI — nothing to redeploy |
|
||||
| Change credentials or tuning | **Stacks → carousell-monitor → Editor** → **Update the stack** |
|
||||
| Deploy a code change | Route 1: **Update the stack** (Portainer re-clones). Route 2: `git pull && docker build …`, then **Update the stack** |
|
||||
| See why it is unhealthy | **Containers → carousell-monitor → Logs**, then `Listings` / `Settings` in NocoDB for the real progress |
|
||||
| Restart | **Containers → carousell-monitor → Restart** — state is in NocoDB, nothing is lost |
|
||||
| Back up | **Volumes → nocodb-data** (all data), or NocoDB's own base export |
|
||||
| Upgrade NocoDB | edit the image tag in the Editor → **Update the stack**; back the volume up first |
|
||||
|
||||
## 6. Optional: deploy from the repository instead
|
||||
## Notes and limits
|
||||
|
||||
**Stacks → Add stack → Repository**, with:
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Repository URL | `https://github.com/hoelee/carousell-monitor` |
|
||||
| Reference | `refs/heads/main` |
|
||||
| Compose path | `docker-compose.allinone.yml` |
|
||||
|
||||
Set `NOCODB_BASE_ID` / `NOCODB_TOKEN` / `TELEGRAM_*` / `NC_AUTH_JWT_SECRET` in the environment panel for this one (they are not in git). Be aware of the masking caveat above, and that Portainer clones the repository on every deploy.
|
||||
- A **Repository** stack re-clones the repo on every deploy, so the update is always a full fetch of `main`. That is fine here (the repo is small) and it means you get fixes by pressing one button.
|
||||
- Portainer deploys standalone compose stacks for this — no Swarm involved.
|
||||
- GitOps updates (auto-redeploy when the repo changes) work too: enable them in the stack settings after the first deploy.
|
||||
|
||||
Reference in New Issue
Block a user