create-meith 0.34.0 → 0.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.mjs +217 -12
- package/package.json +1 -1
- package/src/bin.ts +1 -1
- package/src/scaffold.ts +217 -11
package/dist/bin.mjs
CHANGED
|
@@ -349,6 +349,7 @@ var SELF_HOST_DEPLOY_KIT = [
|
|
|
349
349
|
"Dockerfile.prebuilt",
|
|
350
350
|
"docker-compose.yaml",
|
|
351
351
|
"docker-compose.prebuilt.yaml",
|
|
352
|
+
"docker-compose.byhand.yaml",
|
|
352
353
|
"docker-entrypoint.sh",
|
|
353
354
|
"docker-healthcheck.sh"
|
|
354
355
|
];
|
|
@@ -1292,6 +1293,201 @@ services:
|
|
|
1292
1293
|
depends_on:
|
|
1293
1294
|
- web
|
|
1294
1295
|
|
|
1296
|
+
volumes:
|
|
1297
|
+
pgdata:
|
|
1298
|
+
uploads:
|
|
1299
|
+
backups:
|
|
1300
|
+
`
|
|
1301
|
+
);
|
|
1302
|
+
files.set(
|
|
1303
|
+
"docker-compose.byhand.yaml",
|
|
1304
|
+
`# ${name}, deployed by Docker Compose without a panel \u2014 your own \`.env\`,
|
|
1305
|
+
# your own reverse proxy, no Coolify. The same four services as
|
|
1306
|
+
# docker-compose.yaml and docker-compose.prebuilt.yaml above it (db,
|
|
1307
|
+
# migrate, web, worker), reshaped for a machine with nothing generating
|
|
1308
|
+
# secrets for you: every value Coolify would have filled in \u2014 the database
|
|
1309
|
+
# password, AUTH_SECRET, TICK_SECRET, the board's own address \u2014 comes from
|
|
1310
|
+
# a \`.env\` beside this file instead. See the meith repository's
|
|
1311
|
+
# docs/getting-started/deployment/docker-compose.md, which this file is
|
|
1312
|
+
# the last step of.
|
|
1313
|
+
#
|
|
1314
|
+
# \`docker compose\` only auto-discovers a file literally named
|
|
1315
|
+
# docker-compose.yaml, and that name is already spoken for \u2014 Coolify's own
|
|
1316
|
+
# zero-configuration default. Put \`COMPOSE_FILE=docker-compose.byhand.yaml\`
|
|
1317
|
+
# in \`.env\` once, and every plain \`docker compose ...\` command reads this
|
|
1318
|
+
# file without a \`-f\`, including the ones the rest of this project's
|
|
1319
|
+
# documentation already shows you.
|
|
1320
|
+
#
|
|
1321
|
+
# \`docker compose up -d --build\` builds \`Dockerfile\` from this repository,
|
|
1322
|
+
# on this machine \u2014 the same trade the quick-start path above takes. For a
|
|
1323
|
+
# low-spec server, build \`Dockerfile.prebuilt\` somewhere else instead (push
|
|
1324
|
+
# to GitHub and let \`.github/workflows/build.yml\` do it, or run
|
|
1325
|
+
# \`docker build -f Dockerfile.prebuilt ...\` by hand) and change the two
|
|
1326
|
+
# \`build: .\` lines below to \`image: <that image>:<version>\` \u2014 the
|
|
1327
|
+
# substitution docs/getting-started/deployment/docker-compose.md, "Building
|
|
1328
|
+
# somewhere else", walks through.
|
|
1329
|
+
services:
|
|
1330
|
+
postgres:
|
|
1331
|
+
image: postgres:18-alpine@sha256:d3e1620b530c944afa6e887d22eb899824da68e19c52024bf98f5220c88a65b2
|
|
1332
|
+
restart: unless-stopped
|
|
1333
|
+
mem_limit: \${POSTGRES_MEM_LIMIT:-1g}
|
|
1334
|
+
cpus: \${POSTGRES_CPUS:-1}
|
|
1335
|
+
logging:
|
|
1336
|
+
driver: json-file
|
|
1337
|
+
options:
|
|
1338
|
+
max-size: 10m
|
|
1339
|
+
max-file: '3'
|
|
1340
|
+
environment:
|
|
1341
|
+
POSTGRES_USER: community
|
|
1342
|
+
# Generate with \`openssl rand -hex 32\`, not base64 \u2014 this value is
|
|
1343
|
+
# substituted into the postgres:// URL below, and base64's alphabet
|
|
1344
|
+
# includes \`/\` and \`+\`, which make the connection string unparseable.
|
|
1345
|
+
POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-community}
|
|
1346
|
+
POSTGRES_DB: community
|
|
1347
|
+
volumes:
|
|
1348
|
+
- pgdata:/var/lib/postgresql
|
|
1349
|
+
healthcheck:
|
|
1350
|
+
test: ['CMD-SHELL', 'pg_isready -U community -d community']
|
|
1351
|
+
interval: 10s
|
|
1352
|
+
timeout: 5s
|
|
1353
|
+
retries: 5
|
|
1354
|
+
|
|
1355
|
+
# Runs to completion, then exits. web waits for it, so the schema is
|
|
1356
|
+
# always applied before the first request rather than racing it.
|
|
1357
|
+
migrate:
|
|
1358
|
+
build: .
|
|
1359
|
+
image: ${name}
|
|
1360
|
+
environment:
|
|
1361
|
+
MEITH_ROLE: migrate
|
|
1362
|
+
DATABASE_URL: postgres://community:\${POSTGRES_PASSWORD:-community}@postgres:5432/community
|
|
1363
|
+
AUTH_SECRET: \${AUTH_SECRET:?AUTH_SECRET must be set}
|
|
1364
|
+
TICK_SECRET: \${TICK_SECRET:?TICK_SECRET must be set}
|
|
1365
|
+
FILESTORE_DRIVER: local
|
|
1366
|
+
# So that "back up before migrating" (a board setting) can ship the
|
|
1367
|
+
# bundle it takes to the same off-site destination web uses.
|
|
1368
|
+
BACKUP_S3_BUCKET: \${BACKUP_S3_BUCKET:-}
|
|
1369
|
+
BACKUP_S3_REGION: \${BACKUP_S3_REGION:-}
|
|
1370
|
+
BACKUP_S3_ACCESS_KEY_ID: \${BACKUP_S3_ACCESS_KEY_ID:-}
|
|
1371
|
+
BACKUP_S3_SECRET_ACCESS_KEY: \${BACKUP_S3_SECRET_ACCESS_KEY:-}
|
|
1372
|
+
BACKUP_S3_ENDPOINT: \${BACKUP_S3_ENDPOINT:-}
|
|
1373
|
+
BACKUP_S3_PREFIX: \${BACKUP_S3_PREFIX:-}
|
|
1374
|
+
BACKUP_WEBDAV_URL: \${BACKUP_WEBDAV_URL:-}
|
|
1375
|
+
BACKUP_WEBDAV_USERNAME: \${BACKUP_WEBDAV_USERNAME:-}
|
|
1376
|
+
BACKUP_WEBDAV_PASSWORD: \${BACKUP_WEBDAV_PASSWORD:-}
|
|
1377
|
+
volumes:
|
|
1378
|
+
- uploads:/app/.uploads
|
|
1379
|
+
- backups:/backups
|
|
1380
|
+
depends_on:
|
|
1381
|
+
postgres:
|
|
1382
|
+
condition: service_healthy
|
|
1383
|
+
restart: 'no'
|
|
1384
|
+
|
|
1385
|
+
web:
|
|
1386
|
+
build: .
|
|
1387
|
+
image: ${name}
|
|
1388
|
+
restart: unless-stopped
|
|
1389
|
+
mem_limit: \${WEB_MEM_LIMIT:-1g}
|
|
1390
|
+
cpus: \${WEB_CPUS:-2}
|
|
1391
|
+
logging:
|
|
1392
|
+
driver: json-file
|
|
1393
|
+
options:
|
|
1394
|
+
max-size: 10m
|
|
1395
|
+
max-file: '3'
|
|
1396
|
+
ports:
|
|
1397
|
+
- '\${PORT:-127.0.0.1:3000}:3000'
|
|
1398
|
+
environment:
|
|
1399
|
+
DATABASE_URL: postgres://community:\${POSTGRES_PASSWORD:-community}@postgres:5432/community
|
|
1400
|
+
AUTH_SECRET: \${AUTH_SECRET:?AUTH_SECRET must be set}
|
|
1401
|
+
TICK_SECRET: \${TICK_SECRET:?TICK_SECRET must be set}
|
|
1402
|
+
QUEUE_DRIVER: postgres
|
|
1403
|
+
CACHE_DRIVER: \${CACHE_DRIVER:-next}
|
|
1404
|
+
REDIS_URL: \${REDIS_URL:-}
|
|
1405
|
+
FILESTORE_DRIVER: local
|
|
1406
|
+
APP_URL: \${APP_URL:-http://localhost:3000}
|
|
1407
|
+
# One reverse proxy (Caddy, in the guide's own walkthrough) sits in
|
|
1408
|
+
# front of \`web\` \u2014 see "Count your proxies" in
|
|
1409
|
+
# docs/getting-started/deployment/docker-compose.md.
|
|
1410
|
+
TRUSTED_PROXY_HOPS: \${TRUSTED_PROXY_HOPS:-1}
|
|
1411
|
+
# Leaving this at \`log\` does not mean no mail: it means the board
|
|
1412
|
+
# decides, from the installer on first run or from
|
|
1413
|
+
# /admin/settings?group=mail afterwards, with no redeploy. Setting it
|
|
1414
|
+
# here makes this file authoritative instead.
|
|
1415
|
+
MAIL_DRIVER: \${MAIL_DRIVER:-log}
|
|
1416
|
+
MAIL_FROM: \${MAIL_FROM:-}
|
|
1417
|
+
MAIL_HTTP_ENDPOINT: \${MAIL_HTTP_ENDPOINT:-}
|
|
1418
|
+
MAIL_HTTP_TOKEN: \${MAIL_HTTP_TOKEN:-}
|
|
1419
|
+
MAIL_SMTP_HOST: \${MAIL_SMTP_HOST:-}
|
|
1420
|
+
MAIL_SMTP_PORT: \${MAIL_SMTP_PORT:-}
|
|
1421
|
+
MAIL_SMTP_SECURITY: \${MAIL_SMTP_SECURITY:-}
|
|
1422
|
+
MAIL_SMTP_USERNAME: \${MAIL_SMTP_USERNAME:-}
|
|
1423
|
+
MAIL_SMTP_PASSWORD: \${MAIL_SMTP_PASSWORD:-}
|
|
1424
|
+
BACKUP_S3_BUCKET: \${BACKUP_S3_BUCKET:-}
|
|
1425
|
+
BACKUP_S3_REGION: \${BACKUP_S3_REGION:-}
|
|
1426
|
+
BACKUP_S3_ACCESS_KEY_ID: \${BACKUP_S3_ACCESS_KEY_ID:-}
|
|
1427
|
+
BACKUP_S3_SECRET_ACCESS_KEY: \${BACKUP_S3_SECRET_ACCESS_KEY:-}
|
|
1428
|
+
BACKUP_S3_ENDPOINT: \${BACKUP_S3_ENDPOINT:-}
|
|
1429
|
+
BACKUP_S3_PREFIX: \${BACKUP_S3_PREFIX:-}
|
|
1430
|
+
BACKUP_WEBDAV_URL: \${BACKUP_WEBDAV_URL:-}
|
|
1431
|
+
BACKUP_WEBDAV_USERNAME: \${BACKUP_WEBDAV_USERNAME:-}
|
|
1432
|
+
BACKUP_WEBDAV_PASSWORD: \${BACKUP_WEBDAV_PASSWORD:-}
|
|
1433
|
+
volumes:
|
|
1434
|
+
- uploads:/app/.uploads
|
|
1435
|
+
- backups:/backups
|
|
1436
|
+
depends_on:
|
|
1437
|
+
postgres:
|
|
1438
|
+
condition: service_healthy
|
|
1439
|
+
migrate:
|
|
1440
|
+
condition: service_completed_successfully
|
|
1441
|
+
|
|
1442
|
+
# @meith/worker is not published (see the meith repository's
|
|
1443
|
+
# docs/contributing/release.md), so there is no compiled worker binary
|
|
1444
|
+
# this board can run \u2014 a small loop calling /api/system/tick instead, the
|
|
1445
|
+
# same shape docker-compose.yaml and docker-compose.prebuilt.yaml use.
|
|
1446
|
+
worker:
|
|
1447
|
+
image: alpine:3.24@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b
|
|
1448
|
+
restart: unless-stopped
|
|
1449
|
+
mem_limit: \${WORKER_MEM_LIMIT:-64m}
|
|
1450
|
+
cpus: \${WORKER_CPUS:-0.25}
|
|
1451
|
+
logging:
|
|
1452
|
+
driver: json-file
|
|
1453
|
+
options:
|
|
1454
|
+
max-size: 10m
|
|
1455
|
+
max-file: '3'
|
|
1456
|
+
environment:
|
|
1457
|
+
TICK_SECRET: \${TICK_SECRET:?TICK_SECRET must be set}
|
|
1458
|
+
command:
|
|
1459
|
+
- sh
|
|
1460
|
+
- -c
|
|
1461
|
+
- |
|
|
1462
|
+
apk add --no-cache curl >/dev/null
|
|
1463
|
+
while true; do
|
|
1464
|
+
curl -fsS -m 55 -H "Authorization: Bearer $$TICK_SECRET" \\
|
|
1465
|
+
http://web:3000/api/system/tick >/dev/null 2>&1 \\
|
|
1466
|
+
|| echo "tick failed at $$(date -Is)"
|
|
1467
|
+
sleep 60
|
|
1468
|
+
done
|
|
1469
|
+
depends_on:
|
|
1470
|
+
- web
|
|
1471
|
+
|
|
1472
|
+
# Off by default \u2014 see docs/guides/operations/scaling.md before setting
|
|
1473
|
+
# CACHE_DRIVER=redis above. This is the server it needs.
|
|
1474
|
+
redis:
|
|
1475
|
+
profiles: ['redis']
|
|
1476
|
+
image: valkey/valkey:9-alpine@sha256:a174b894902bd3367e330d47cc2054367dc4917701776aaf336f41d83b65ec7a
|
|
1477
|
+
restart: unless-stopped
|
|
1478
|
+
mem_limit: \${REDIS_MEM_LIMIT:-256m}
|
|
1479
|
+
cpus: \${REDIS_CPUS:-0.5}
|
|
1480
|
+
logging:
|
|
1481
|
+
driver: json-file
|
|
1482
|
+
options:
|
|
1483
|
+
max-size: 10m
|
|
1484
|
+
max-file: '3'
|
|
1485
|
+
healthcheck:
|
|
1486
|
+
test: ['CMD', 'valkey-cli', 'ping']
|
|
1487
|
+
interval: 10s
|
|
1488
|
+
timeout: 5s
|
|
1489
|
+
retries: 5
|
|
1490
|
+
|
|
1295
1491
|
volumes:
|
|
1296
1492
|
pgdata:
|
|
1297
1493
|
uploads:
|
|
@@ -1306,11 +1502,13 @@ A forum, built on [Meith](${repositoryUrl}).
|
|
|
1306
1502
|
|
|
1307
1503
|
## Deploy
|
|
1308
1504
|
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
**advanced/prebuilt** moves the build off the server, onto
|
|
1312
|
-
a low-spec build server or a faster deploy
|
|
1313
|
-
|
|
1505
|
+
Three paths onto a server, all ending at the same \`/install\`. **Quick
|
|
1506
|
+
start** onto [Coolify](https://coolify.io) is the default and needs nothing
|
|
1507
|
+
but a push; **advanced/prebuilt** moves the build off the server, onto
|
|
1508
|
+
GitHub Actions, for a low-spec build server or a faster deploy; **without a
|
|
1509
|
+
panel** is the same four containers run by hand, with your own \`.env\` and
|
|
1510
|
+
reverse proxy, and no Coolify at all. Pick one \u2014 a board only ever runs one
|
|
1511
|
+
of them at a time.
|
|
1314
1512
|
|
|
1315
1513
|
### Quick start (default)
|
|
1316
1514
|
|
|
@@ -1398,13 +1596,20 @@ rather not use GitHub Actions for the build \u2014 push the result wherever
|
|
|
1398
1596
|
docker build -f Dockerfile.prebuilt --build-arg MEITH_VERSION=$(node -p "require('./package.json').dependencies['@meith/web']") -t ${name} .
|
|
1399
1597
|
\`\`\`
|
|
1400
1598
|
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1599
|
+
### Without a panel
|
|
1600
|
+
|
|
1601
|
+
\`docker-compose.byhand.yaml\`, beside the two Coolify files above, is the same
|
|
1602
|
+
four containers deployed with nothing generating secrets for you: a \`.env\`
|
|
1603
|
+
you write yourself, a port published for the reverse proxy you already run,
|
|
1604
|
+
and \`docker compose up -d --build\` in place of a panel's Deploy button.
|
|
1605
|
+
[docs/getting-started/deployment/docker-compose.md](${repositoryUrl}/blob/main/docs/getting-started/deployment/docker-compose.md)
|
|
1606
|
+
is the full walkthrough this file is the last step of, including the
|
|
1607
|
+
\`.env\` this repository does not carry \u2014 nothing here belongs in git. Delete
|
|
1608
|
+
this file if you know you will only ever deploy through Coolify; keep it,
|
|
1609
|
+
and it needs nothing else changed, if you later want to move away from
|
|
1610
|
+
Coolify without changing how the board itself is built.
|
|
1406
1611
|
|
|
1407
|
-
Two things nothing configures for you, on
|
|
1612
|
+
Two things nothing configures for you, on any path:
|
|
1408
1613
|
|
|
1409
1614
|
- **Mail.** Until \`MAIL_DRIVER\` and its three settings exist, every message is
|
|
1410
1615
|
written to the log and delivered to nobody, so password reset fails silently.
|
|
@@ -2829,7 +3034,7 @@ async function run(argv, version, updateOptions = {}) {
|
|
|
2829
3034
|
}
|
|
2830
3035
|
|
|
2831
3036
|
// src/bin.ts
|
|
2832
|
-
var result = await run(process.argv.slice(2), "0.
|
|
3037
|
+
var result = await run(process.argv.slice(2), "0.35.1");
|
|
2833
3038
|
for (const line of result.lines) {
|
|
2834
3039
|
if (result.code === 0) console.log(line);
|
|
2835
3040
|
else console.error(line);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-meith",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.35.1",
|
|
4
4
|
"description": "Scaffold a Meith board, plugin or theme — npx create-meith <name> writes a deployable board workspace; --plugin and --theme write extension workspaces built on the published kits.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
package/src/bin.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { run } from './cli'
|
|
3
3
|
|
|
4
|
-
const result = await run(process.argv.slice(2), '0.
|
|
4
|
+
const result = await run(process.argv.slice(2), '0.35.1')
|
|
5
5
|
for (const line of result.lines) {
|
|
6
6
|
if (result.code === 0) console.log(line)
|
|
7
7
|
else console.error(line)
|
package/src/scaffold.ts
CHANGED
|
@@ -377,6 +377,7 @@ const SELF_HOST_DEPLOY_KIT = [
|
|
|
377
377
|
'Dockerfile.prebuilt',
|
|
378
378
|
'docker-compose.yaml',
|
|
379
379
|
'docker-compose.prebuilt.yaml',
|
|
380
|
+
'docker-compose.byhand.yaml',
|
|
380
381
|
'docker-entrypoint.sh',
|
|
381
382
|
'docker-healthcheck.sh',
|
|
382
383
|
] as const
|
|
@@ -1341,6 +1342,202 @@ services:
|
|
|
1341
1342
|
depends_on:
|
|
1342
1343
|
- web
|
|
1343
1344
|
|
|
1345
|
+
volumes:
|
|
1346
|
+
pgdata:
|
|
1347
|
+
uploads:
|
|
1348
|
+
backups:
|
|
1349
|
+
`,
|
|
1350
|
+
)
|
|
1351
|
+
|
|
1352
|
+
files.set(
|
|
1353
|
+
'docker-compose.byhand.yaml',
|
|
1354
|
+
`# ${name}, deployed by Docker Compose without a panel — your own \`.env\`,
|
|
1355
|
+
# your own reverse proxy, no Coolify. The same four services as
|
|
1356
|
+
# docker-compose.yaml and docker-compose.prebuilt.yaml above it (db,
|
|
1357
|
+
# migrate, web, worker), reshaped for a machine with nothing generating
|
|
1358
|
+
# secrets for you: every value Coolify would have filled in — the database
|
|
1359
|
+
# password, AUTH_SECRET, TICK_SECRET, the board's own address — comes from
|
|
1360
|
+
# a \`.env\` beside this file instead. See the meith repository's
|
|
1361
|
+
# docs/getting-started/deployment/docker-compose.md, which this file is
|
|
1362
|
+
# the last step of.
|
|
1363
|
+
#
|
|
1364
|
+
# \`docker compose\` only auto-discovers a file literally named
|
|
1365
|
+
# docker-compose.yaml, and that name is already spoken for — Coolify's own
|
|
1366
|
+
# zero-configuration default. Put \`COMPOSE_FILE=docker-compose.byhand.yaml\`
|
|
1367
|
+
# in \`.env\` once, and every plain \`docker compose ...\` command reads this
|
|
1368
|
+
# file without a \`-f\`, including the ones the rest of this project's
|
|
1369
|
+
# documentation already shows you.
|
|
1370
|
+
#
|
|
1371
|
+
# \`docker compose up -d --build\` builds \`Dockerfile\` from this repository,
|
|
1372
|
+
# on this machine — the same trade the quick-start path above takes. For a
|
|
1373
|
+
# low-spec server, build \`Dockerfile.prebuilt\` somewhere else instead (push
|
|
1374
|
+
# to GitHub and let \`.github/workflows/build.yml\` do it, or run
|
|
1375
|
+
# \`docker build -f Dockerfile.prebuilt ...\` by hand) and change the two
|
|
1376
|
+
# \`build: .\` lines below to \`image: <that image>:<version>\` — the
|
|
1377
|
+
# substitution docs/getting-started/deployment/docker-compose.md, "Building
|
|
1378
|
+
# somewhere else", walks through.
|
|
1379
|
+
services:
|
|
1380
|
+
postgres:
|
|
1381
|
+
image: postgres:18-alpine@sha256:d3e1620b530c944afa6e887d22eb899824da68e19c52024bf98f5220c88a65b2
|
|
1382
|
+
restart: unless-stopped
|
|
1383
|
+
mem_limit: \${POSTGRES_MEM_LIMIT:-1g}
|
|
1384
|
+
cpus: \${POSTGRES_CPUS:-1}
|
|
1385
|
+
logging:
|
|
1386
|
+
driver: json-file
|
|
1387
|
+
options:
|
|
1388
|
+
max-size: 10m
|
|
1389
|
+
max-file: '3'
|
|
1390
|
+
environment:
|
|
1391
|
+
POSTGRES_USER: community
|
|
1392
|
+
# Generate with \`openssl rand -hex 32\`, not base64 — this value is
|
|
1393
|
+
# substituted into the postgres:// URL below, and base64's alphabet
|
|
1394
|
+
# includes \`/\` and \`+\`, which make the connection string unparseable.
|
|
1395
|
+
POSTGRES_PASSWORD: \${POSTGRES_PASSWORD:-community}
|
|
1396
|
+
POSTGRES_DB: community
|
|
1397
|
+
volumes:
|
|
1398
|
+
- pgdata:/var/lib/postgresql
|
|
1399
|
+
healthcheck:
|
|
1400
|
+
test: ['CMD-SHELL', 'pg_isready -U community -d community']
|
|
1401
|
+
interval: 10s
|
|
1402
|
+
timeout: 5s
|
|
1403
|
+
retries: 5
|
|
1404
|
+
|
|
1405
|
+
# Runs to completion, then exits. web waits for it, so the schema is
|
|
1406
|
+
# always applied before the first request rather than racing it.
|
|
1407
|
+
migrate:
|
|
1408
|
+
build: .
|
|
1409
|
+
image: ${name}
|
|
1410
|
+
environment:
|
|
1411
|
+
MEITH_ROLE: migrate
|
|
1412
|
+
DATABASE_URL: postgres://community:\${POSTGRES_PASSWORD:-community}@postgres:5432/community
|
|
1413
|
+
AUTH_SECRET: \${AUTH_SECRET:?AUTH_SECRET must be set}
|
|
1414
|
+
TICK_SECRET: \${TICK_SECRET:?TICK_SECRET must be set}
|
|
1415
|
+
FILESTORE_DRIVER: local
|
|
1416
|
+
# So that "back up before migrating" (a board setting) can ship the
|
|
1417
|
+
# bundle it takes to the same off-site destination web uses.
|
|
1418
|
+
BACKUP_S3_BUCKET: \${BACKUP_S3_BUCKET:-}
|
|
1419
|
+
BACKUP_S3_REGION: \${BACKUP_S3_REGION:-}
|
|
1420
|
+
BACKUP_S3_ACCESS_KEY_ID: \${BACKUP_S3_ACCESS_KEY_ID:-}
|
|
1421
|
+
BACKUP_S3_SECRET_ACCESS_KEY: \${BACKUP_S3_SECRET_ACCESS_KEY:-}
|
|
1422
|
+
BACKUP_S3_ENDPOINT: \${BACKUP_S3_ENDPOINT:-}
|
|
1423
|
+
BACKUP_S3_PREFIX: \${BACKUP_S3_PREFIX:-}
|
|
1424
|
+
BACKUP_WEBDAV_URL: \${BACKUP_WEBDAV_URL:-}
|
|
1425
|
+
BACKUP_WEBDAV_USERNAME: \${BACKUP_WEBDAV_USERNAME:-}
|
|
1426
|
+
BACKUP_WEBDAV_PASSWORD: \${BACKUP_WEBDAV_PASSWORD:-}
|
|
1427
|
+
volumes:
|
|
1428
|
+
- uploads:/app/.uploads
|
|
1429
|
+
- backups:/backups
|
|
1430
|
+
depends_on:
|
|
1431
|
+
postgres:
|
|
1432
|
+
condition: service_healthy
|
|
1433
|
+
restart: 'no'
|
|
1434
|
+
|
|
1435
|
+
web:
|
|
1436
|
+
build: .
|
|
1437
|
+
image: ${name}
|
|
1438
|
+
restart: unless-stopped
|
|
1439
|
+
mem_limit: \${WEB_MEM_LIMIT:-1g}
|
|
1440
|
+
cpus: \${WEB_CPUS:-2}
|
|
1441
|
+
logging:
|
|
1442
|
+
driver: json-file
|
|
1443
|
+
options:
|
|
1444
|
+
max-size: 10m
|
|
1445
|
+
max-file: '3'
|
|
1446
|
+
ports:
|
|
1447
|
+
- '\${PORT:-127.0.0.1:3000}:3000'
|
|
1448
|
+
environment:
|
|
1449
|
+
DATABASE_URL: postgres://community:\${POSTGRES_PASSWORD:-community}@postgres:5432/community
|
|
1450
|
+
AUTH_SECRET: \${AUTH_SECRET:?AUTH_SECRET must be set}
|
|
1451
|
+
TICK_SECRET: \${TICK_SECRET:?TICK_SECRET must be set}
|
|
1452
|
+
QUEUE_DRIVER: postgres
|
|
1453
|
+
CACHE_DRIVER: \${CACHE_DRIVER:-next}
|
|
1454
|
+
REDIS_URL: \${REDIS_URL:-}
|
|
1455
|
+
FILESTORE_DRIVER: local
|
|
1456
|
+
APP_URL: \${APP_URL:-http://localhost:3000}
|
|
1457
|
+
# One reverse proxy (Caddy, in the guide's own walkthrough) sits in
|
|
1458
|
+
# front of \`web\` — see "Count your proxies" in
|
|
1459
|
+
# docs/getting-started/deployment/docker-compose.md.
|
|
1460
|
+
TRUSTED_PROXY_HOPS: \${TRUSTED_PROXY_HOPS:-1}
|
|
1461
|
+
# Leaving this at \`log\` does not mean no mail: it means the board
|
|
1462
|
+
# decides, from the installer on first run or from
|
|
1463
|
+
# /admin/settings?group=mail afterwards, with no redeploy. Setting it
|
|
1464
|
+
# here makes this file authoritative instead.
|
|
1465
|
+
MAIL_DRIVER: \${MAIL_DRIVER:-log}
|
|
1466
|
+
MAIL_FROM: \${MAIL_FROM:-}
|
|
1467
|
+
MAIL_HTTP_ENDPOINT: \${MAIL_HTTP_ENDPOINT:-}
|
|
1468
|
+
MAIL_HTTP_TOKEN: \${MAIL_HTTP_TOKEN:-}
|
|
1469
|
+
MAIL_SMTP_HOST: \${MAIL_SMTP_HOST:-}
|
|
1470
|
+
MAIL_SMTP_PORT: \${MAIL_SMTP_PORT:-}
|
|
1471
|
+
MAIL_SMTP_SECURITY: \${MAIL_SMTP_SECURITY:-}
|
|
1472
|
+
MAIL_SMTP_USERNAME: \${MAIL_SMTP_USERNAME:-}
|
|
1473
|
+
MAIL_SMTP_PASSWORD: \${MAIL_SMTP_PASSWORD:-}
|
|
1474
|
+
BACKUP_S3_BUCKET: \${BACKUP_S3_BUCKET:-}
|
|
1475
|
+
BACKUP_S3_REGION: \${BACKUP_S3_REGION:-}
|
|
1476
|
+
BACKUP_S3_ACCESS_KEY_ID: \${BACKUP_S3_ACCESS_KEY_ID:-}
|
|
1477
|
+
BACKUP_S3_SECRET_ACCESS_KEY: \${BACKUP_S3_SECRET_ACCESS_KEY:-}
|
|
1478
|
+
BACKUP_S3_ENDPOINT: \${BACKUP_S3_ENDPOINT:-}
|
|
1479
|
+
BACKUP_S3_PREFIX: \${BACKUP_S3_PREFIX:-}
|
|
1480
|
+
BACKUP_WEBDAV_URL: \${BACKUP_WEBDAV_URL:-}
|
|
1481
|
+
BACKUP_WEBDAV_USERNAME: \${BACKUP_WEBDAV_USERNAME:-}
|
|
1482
|
+
BACKUP_WEBDAV_PASSWORD: \${BACKUP_WEBDAV_PASSWORD:-}
|
|
1483
|
+
volumes:
|
|
1484
|
+
- uploads:/app/.uploads
|
|
1485
|
+
- backups:/backups
|
|
1486
|
+
depends_on:
|
|
1487
|
+
postgres:
|
|
1488
|
+
condition: service_healthy
|
|
1489
|
+
migrate:
|
|
1490
|
+
condition: service_completed_successfully
|
|
1491
|
+
|
|
1492
|
+
# @meith/worker is not published (see the meith repository's
|
|
1493
|
+
# docs/contributing/release.md), so there is no compiled worker binary
|
|
1494
|
+
# this board can run — a small loop calling /api/system/tick instead, the
|
|
1495
|
+
# same shape docker-compose.yaml and docker-compose.prebuilt.yaml use.
|
|
1496
|
+
worker:
|
|
1497
|
+
image: alpine:3.24@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b
|
|
1498
|
+
restart: unless-stopped
|
|
1499
|
+
mem_limit: \${WORKER_MEM_LIMIT:-64m}
|
|
1500
|
+
cpus: \${WORKER_CPUS:-0.25}
|
|
1501
|
+
logging:
|
|
1502
|
+
driver: json-file
|
|
1503
|
+
options:
|
|
1504
|
+
max-size: 10m
|
|
1505
|
+
max-file: '3'
|
|
1506
|
+
environment:
|
|
1507
|
+
TICK_SECRET: \${TICK_SECRET:?TICK_SECRET must be set}
|
|
1508
|
+
command:
|
|
1509
|
+
- sh
|
|
1510
|
+
- -c
|
|
1511
|
+
- |
|
|
1512
|
+
apk add --no-cache curl >/dev/null
|
|
1513
|
+
while true; do
|
|
1514
|
+
curl -fsS -m 55 -H "Authorization: Bearer $$TICK_SECRET" \\
|
|
1515
|
+
http://web:3000/api/system/tick >/dev/null 2>&1 \\
|
|
1516
|
+
|| echo "tick failed at $$(date -Is)"
|
|
1517
|
+
sleep 60
|
|
1518
|
+
done
|
|
1519
|
+
depends_on:
|
|
1520
|
+
- web
|
|
1521
|
+
|
|
1522
|
+
# Off by default — see docs/guides/operations/scaling.md before setting
|
|
1523
|
+
# CACHE_DRIVER=redis above. This is the server it needs.
|
|
1524
|
+
redis:
|
|
1525
|
+
profiles: ['redis']
|
|
1526
|
+
image: valkey/valkey:9-alpine@sha256:a174b894902bd3367e330d47cc2054367dc4917701776aaf336f41d83b65ec7a
|
|
1527
|
+
restart: unless-stopped
|
|
1528
|
+
mem_limit: \${REDIS_MEM_LIMIT:-256m}
|
|
1529
|
+
cpus: \${REDIS_CPUS:-0.5}
|
|
1530
|
+
logging:
|
|
1531
|
+
driver: json-file
|
|
1532
|
+
options:
|
|
1533
|
+
max-size: 10m
|
|
1534
|
+
max-file: '3'
|
|
1535
|
+
healthcheck:
|
|
1536
|
+
test: ['CMD', 'valkey-cli', 'ping']
|
|
1537
|
+
interval: 10s
|
|
1538
|
+
timeout: 5s
|
|
1539
|
+
retries: 5
|
|
1540
|
+
|
|
1344
1541
|
volumes:
|
|
1345
1542
|
pgdata:
|
|
1346
1543
|
uploads:
|
|
@@ -1356,11 +1553,13 @@ A forum, built on [Meith](${repositoryUrl}).
|
|
|
1356
1553
|
|
|
1357
1554
|
## Deploy
|
|
1358
1555
|
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
**advanced/prebuilt** moves the build off the server, onto
|
|
1362
|
-
a low-spec build server or a faster deploy
|
|
1363
|
-
|
|
1556
|
+
Three paths onto a server, all ending at the same \`/install\`. **Quick
|
|
1557
|
+
start** onto [Coolify](https://coolify.io) is the default and needs nothing
|
|
1558
|
+
but a push; **advanced/prebuilt** moves the build off the server, onto
|
|
1559
|
+
GitHub Actions, for a low-spec build server or a faster deploy; **without a
|
|
1560
|
+
panel** is the same four containers run by hand, with your own \`.env\` and
|
|
1561
|
+
reverse proxy, and no Coolify at all. Pick one — a board only ever runs one
|
|
1562
|
+
of them at a time.
|
|
1364
1563
|
|
|
1365
1564
|
### Quick start (default)
|
|
1366
1565
|
|
|
@@ -1448,13 +1647,20 @@ rather not use GitHub Actions for the build — push the result wherever
|
|
|
1448
1647
|
docker build -f Dockerfile.prebuilt --build-arg MEITH_VERSION=$(node -p "require('./package.json').dependencies['@meith/web']") -t ${name} .
|
|
1449
1648
|
\`\`\`
|
|
1450
1649
|
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1650
|
+
### Without a panel
|
|
1651
|
+
|
|
1652
|
+
\`docker-compose.byhand.yaml\`, beside the two Coolify files above, is the same
|
|
1653
|
+
four containers deployed with nothing generating secrets for you: a \`.env\`
|
|
1654
|
+
you write yourself, a port published for the reverse proxy you already run,
|
|
1655
|
+
and \`docker compose up -d --build\` in place of a panel's Deploy button.
|
|
1656
|
+
[docs/getting-started/deployment/docker-compose.md](${repositoryUrl}/blob/main/docs/getting-started/deployment/docker-compose.md)
|
|
1657
|
+
is the full walkthrough this file is the last step of, including the
|
|
1658
|
+
\`.env\` this repository does not carry — nothing here belongs in git. Delete
|
|
1659
|
+
this file if you know you will only ever deploy through Coolify; keep it,
|
|
1660
|
+
and it needs nothing else changed, if you later want to move away from
|
|
1661
|
+
Coolify without changing how the board itself is built.
|
|
1456
1662
|
|
|
1457
|
-
Two things nothing configures for you, on
|
|
1663
|
+
Two things nothing configures for you, on any path:
|
|
1458
1664
|
|
|
1459
1665
|
- **Mail.** Until \`MAIL_DRIVER\` and its three settings exist, every message is
|
|
1460
1666
|
written to the log and delivered to nobody, so password reset fails silently.
|