@or3/cloud 0.1.15 → 0.1.34
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/README.md +85 -0
- package/assets/Caddyfile +15 -4
- package/assets/compose.public.yaml +26 -1
- package/assets/compose.yaml +33 -2
- package/dist/cli.mjs +1032 -77
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# OR3 Cloud
|
|
2
|
+
|
|
3
|
+
Install and operate a supported OR3 container deployment without cloning the
|
|
4
|
+
application repository or installing its dependencies on the host.
|
|
5
|
+
|
|
6
|
+
## Quick start: local machine
|
|
7
|
+
|
|
8
|
+
You need Docker Engine with Docker Compose v2 and Node.js 20 or later.
|
|
9
|
+
|
|
10
|
+
```sh
|
|
11
|
+
npx @or3/cloud init --local
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The installer asks for the owner email, generates a bootstrap password, and
|
|
15
|
+
saves both values in the mode-`0600`
|
|
16
|
+
`or3-cloud/.or3-initial-credentials` file. It does not print the password.
|
|
17
|
+
Save the file in a password manager, then delete it. Open
|
|
18
|
+
[http://127.0.0.1:3000](http://127.0.0.1:3000) and sign in.
|
|
19
|
+
|
|
20
|
+
The published Cloud image supports `linux/amd64` and `linux/arm64` and uses
|
|
21
|
+
Basic Auth + SQLite + filesystem storage. The CLI checks the image manifest
|
|
22
|
+
before it writes deployment state.
|
|
23
|
+
|
|
24
|
+
## Run it publicly on a VPS
|
|
25
|
+
|
|
26
|
+
Before starting, point a domain at the VPS and allow inbound TCP ports `80`
|
|
27
|
+
and `443` in its firewall. Then run:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npx @or3/cloud init --public --domain cloud.example.com
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
OR3 Cloud uses Caddy to obtain and renew HTTPS certificates. It does not
|
|
34
|
+
change your DNS, firewall, Cloudflare, or Tailscale settings.
|
|
35
|
+
|
|
36
|
+
## Day-to-day commands
|
|
37
|
+
|
|
38
|
+
Run these from the deployment directory created by `init`:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
npx @or3/cloud doctor
|
|
42
|
+
npx @or3/cloud backup
|
|
43
|
+
npx @or3/cloud update
|
|
44
|
+
npx @or3/cloud rollback --yes
|
|
45
|
+
npx @or3/cloud recover
|
|
46
|
+
npx @or3/cloud status
|
|
47
|
+
npx @or3/cloud logs --tail 200
|
|
48
|
+
npx @or3/cloud start
|
|
49
|
+
npx @or3/cloud stop
|
|
50
|
+
npx @or3/cloud restart
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Do not run `docker compose down --volumes` on a normal deployment: it deletes
|
|
54
|
+
the application data. Use `backup` before an update or any destructive action.
|
|
55
|
+
For a destructive purge, export a fresh backup to a new directory on another
|
|
56
|
+
filesystem first; `remove --purge-data --yes` verifies that export before it
|
|
57
|
+
will delete anything.
|
|
58
|
+
|
|
59
|
+
Managed registration is invite-only: the bootstrap owner signs in first and
|
|
60
|
+
invites additional users from the in-product admin flow. Guest access and
|
|
61
|
+
anonymous registration stay disabled. Uploading/installing custom plugins or
|
|
62
|
+
themes is disabled in the immutable image because it cannot rebuild trusted
|
|
63
|
+
source; bundled extensions remain available.
|
|
64
|
+
|
|
65
|
+
Remote OR3 Connect is withheld from the managed Cloud release until its
|
|
66
|
+
Cloudflare/domain staging flow is proved. Local Intern is independently
|
|
67
|
+
supported through the coordinated published release:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
npx @or3/connect@0.1.3 intern
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
See the [Connect release status](https://github.com/Saluana/or3-intern/blob/main/docs/connect-release-status.md).
|
|
74
|
+
Do not substitute a bare package command or paste a generic remote URL/token as
|
|
75
|
+
a workaround. The [Start Here guide](https://github.com/Saluana/or3-chat/blob/main/docs/start-here.md)
|
|
76
|
+
routes each supported setup path.
|
|
77
|
+
|
|
78
|
+
## More help
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
npx @or3/cloud --help
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For VPS requirements, firewall guidance, updates, restores, and migration,
|
|
85
|
+
read the [installation guide](https://github.com/Saluana/or3-chat/blob/main/docs/installation.md).
|
package/assets/Caddyfile
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
{$OR3_PUBLIC_DOMAIN} {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
# Security headers. Caddy 308-redirects plain HTTP to HTTPS before this
|
|
3
|
+
# site handler runs, so Strict-Transport-Security is only ever emitted on
|
|
4
|
+
# HTTPS responses (it is meaningless on plain HTTP).
|
|
5
|
+
header {
|
|
6
|
+
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
|
7
|
+
X-Content-Type-Options "nosniff"
|
|
8
|
+
X-Frame-Options "DENY"
|
|
9
|
+
Referrer-Policy "strict-origin-when-cross-origin"
|
|
10
|
+
Permissions-Policy "camera=(), microphone=(), geolocation=()"
|
|
6
11
|
}
|
|
12
|
+
|
|
13
|
+
encode zstd gzip
|
|
14
|
+
# Caddy recognizes text/event-stream and flushes it immediately. Keeping the
|
|
15
|
+
# default stream behavior also lets client disconnects cancel foreground
|
|
16
|
+
# provider requests instead of leaving a paid generation running.
|
|
17
|
+
reverse_proxy or3:3000
|
|
7
18
|
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
services:
|
|
2
2
|
caddy:
|
|
3
|
-
image
|
|
3
|
+
# Pinned to the exact patch release and image digest so a floating tag
|
|
4
|
+
# cannot silently change proxy behavior or the base image.
|
|
5
|
+
image: caddy:2.10.2-alpine@sha256:4c6e91c6ed0e2fa03efd5b44747b625fec79bc9cd06ac5235a779726618e530d
|
|
4
6
|
depends_on:
|
|
5
7
|
or3:
|
|
8
|
+
# This gates Caddy's initial startup only. A later unhealthy OR3
|
|
9
|
+
# healthcheck does not trigger automatic container restarts; use the
|
|
10
|
+
# Cloud CLI's doctor/status/restart flow for persistent degradation.
|
|
6
11
|
condition: service_healthy
|
|
7
12
|
environment:
|
|
8
13
|
OR3_PUBLIC_DOMAIN: ${OR3_PUBLIC_DOMAIN}
|
|
@@ -15,6 +20,26 @@ services:
|
|
|
15
20
|
- caddy-data:/data
|
|
16
21
|
- caddy-config:/config
|
|
17
22
|
restart: unless-stopped
|
|
23
|
+
# Container hardening. The official image runs as root (no caddy user) and
|
|
24
|
+
# /data + /config are root-owned, so the process stays root but all
|
|
25
|
+
# capabilities are dropped except NET_BIND_SERVICE, which is required to
|
|
26
|
+
# bind the privileged ports 80/443. The root filesystem is read-only;
|
|
27
|
+
# certificates/state live on the caddy-data/caddy-config volumes and
|
|
28
|
+
# scratch space is a small noexec tmpfs at /tmp.
|
|
29
|
+
security_opt:
|
|
30
|
+
- no-new-privileges:true
|
|
31
|
+
cap_drop:
|
|
32
|
+
- ALL
|
|
33
|
+
cap_add:
|
|
34
|
+
- NET_BIND_SERVICE
|
|
35
|
+
read_only: true
|
|
36
|
+
tmpfs:
|
|
37
|
+
- /tmp:size=64m,noexec,nosuid
|
|
38
|
+
logging:
|
|
39
|
+
driver: json-file
|
|
40
|
+
options:
|
|
41
|
+
max-size: "10m"
|
|
42
|
+
max-file: "3"
|
|
18
43
|
|
|
19
44
|
volumes:
|
|
20
45
|
caddy-data:
|
package/assets/compose.yaml
CHANGED
|
@@ -18,12 +18,43 @@ services:
|
|
|
18
18
|
volumes:
|
|
19
19
|
- or3-data:/data
|
|
20
20
|
restart: unless-stopped
|
|
21
|
+
# Leave enough time for Nuxt to close SSE responses and upstream provider
|
|
22
|
+
# connections before Docker sends SIGKILL.
|
|
23
|
+
stop_grace_period: 25s
|
|
24
|
+
# Container hardening: the runtime image already runs as a non-root user and
|
|
25
|
+
# listens on port 3000 (no privileged ports), so all capabilities are
|
|
26
|
+
# dropped and the root filesystem is read-only. Persistent state lives on
|
|
27
|
+
# the or3-data volume (/data: SQLite, storage, admin data, extensions);
|
|
28
|
+
# scratch space (SQLite WAL, H3 multipart uploads, Nuxt server caches)
|
|
29
|
+
# is a 256m tmpfs at /tmp. Phase-5 smokes must re-verify uploads and
|
|
30
|
+
# plugin installs against this read-only profile.
|
|
31
|
+
security_opt:
|
|
32
|
+
- no-new-privileges:true
|
|
33
|
+
cap_drop:
|
|
34
|
+
- ALL
|
|
35
|
+
read_only: true
|
|
36
|
+
tmpfs:
|
|
37
|
+
- /tmp:size=256m
|
|
38
|
+
logging:
|
|
39
|
+
driver: json-file
|
|
40
|
+
options:
|
|
41
|
+
max-size: "10m"
|
|
42
|
+
max-file: "3"
|
|
21
43
|
healthcheck:
|
|
44
|
+
# Deep health, mirroring the CLI's HEALTH_SCRIPT: exit non-zero unless
|
|
45
|
+
# the response is HTTP ok AND the parsed body status is exactly 'ok'.
|
|
46
|
+
# A degraded provider (e.g. sync/storage/auth down) reports HTTP 200
|
|
47
|
+
# with status 'degraded' and is therefore marked unhealthy. Docker
|
|
48
|
+
# Compose uses that state for startup dependencies and `or3 status`
|
|
49
|
+
# reports it, but Docker does not restart a running container solely
|
|
50
|
+
# because a healthcheck fails; `restart: unless-stopped` covers process
|
|
51
|
+
# exits only. Operators should run `or3 doctor`/`or3 restart` for a
|
|
52
|
+
# persistent degraded state.
|
|
22
53
|
test:
|
|
23
54
|
- CMD
|
|
24
|
-
- node
|
|
55
|
+
- /nodejs/bin/node
|
|
25
56
|
- -e
|
|
26
|
-
- "fetch('http://127.0.0.1:3000/api/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"
|
|
57
|
+
- "fetch('http://127.0.0.1:3000/api/health?deep=true').then(async r=>{const b=await r.json().catch(()=>({}));if(!r.ok||b.status!=='ok')process.exit(1)}).catch(()=>process.exit(1))"
|
|
27
58
|
interval: 10s
|
|
28
59
|
timeout: 5s
|
|
29
60
|
retries: 12
|