@cyaxis/ulvia 0.0.0-stage → 0.0.2

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.
@@ -0,0 +1,182 @@
1
+ # Install Ulvia
2
+
3
+ This guide installs the Ulvia CLI and creates a first CMS instance on Ubuntu.
4
+ It is for operators and site owners; workspace contributors should use the
5
+ [development guide](../development/README.md).
6
+
7
+ > **Prerelease availability:** `@cyaxis/ulvia` is the official release package.
8
+ > Prereleases use the npm `next` tag; stable releases use `latest`.
9
+
10
+ ## 1. Prerequisites On Ubuntu
11
+
12
+ Ulvia requires a supported Ubuntu host, Docker Engine with the Docker Compose
13
+ plugin, and Bun. Follow the upstream instructions rather than copying an
14
+ unversioned third-party installation script:
15
+
16
+ - [Install Docker Engine on Ubuntu](https://docs.docker.com/engine/install/ubuntu/)
17
+ - [Install the Docker Compose plugin on Linux](https://docs.docker.com/compose/install/linux/)
18
+ - [Run Docker without `sudo` and configure startup](https://docs.docker.com/engine/install/linux-postinstall/)
19
+ - [Install Bun on Linux](https://bun.com/docs/installation)
20
+
21
+ Docker's Ubuntu packages include the Compose plugin when
22
+ `docker-compose-plugin` is installed. Verify the complete toolchain:
23
+
24
+ ```bash
25
+ docker version
26
+ docker compose version
27
+ bun --version
28
+ ```
29
+
30
+ The current release toolchain targets Bun 1.4.2 or newer. Docker must be running
31
+ and accessible to the account that executes `ulvia`.
32
+
33
+ ## 2. Install The CLI
34
+
35
+ Install the current prerelease globally from the public npm registry:
36
+
37
+ ```bash
38
+ bun add --global @cyaxis/ulvia@next
39
+ ulvia --help
40
+ ```
41
+
42
+ If `ulvia` is not found, reopen the terminal and check that `~/.bun/bin` is in
43
+ `PATH`, as described by the Bun installation guide.
44
+
45
+ ## 3. Create A Local Site
46
+
47
+ Start the shared infrastructure, then create one named instance:
48
+
49
+ ```bash
50
+ ulvia services start
51
+ ulvia instance create my-site --label "My site"
52
+ ulvia instance credentials my-site
53
+ ```
54
+
55
+ The first start uses the exact software version bundled into the installed CLI.
56
+ To bootstrap a different exact prerelease explicitly, use
57
+ `ulvia services start --version 0.0.1-beta`. This option never upgrades an
58
+ existing installation.
59
+
60
+ The site is available at `http://my-site.localhost:5100`. The credentials
61
+ command prints the initial administrator email and password. It never prints
62
+ the Provider, Repository, encryption, or instance service secrets.
63
+
64
+ Ulvia deliberately separates shared services from sites:
65
+
66
+ | Command | Responsibility |
67
+ | --- | --- |
68
+ | `ulvia services start` | Starts the proxy, MongoDB, Official Repository, and Provider. |
69
+ | `ulvia instance create <name>` | Provisions one Provider tenant and starts its Kernel. |
70
+ | `ulvia instance start <name>` | Restarts an existing instance without provisioning it again. |
71
+ | `ulvia start` | Starts shared services and every existing instance; it creates nothing. |
72
+
73
+ List and inspect the installation at any time:
74
+
75
+ ```bash
76
+ ulvia services status
77
+ ulvia instance list
78
+ ulvia instance status my-site
79
+ ```
80
+
81
+ Persistent data lives below `$XDG_DATA_HOME/ulvia` or
82
+ `~/.local/share/ulvia`. Commands can be run from any working directory.
83
+
84
+ ## 4. Daily Operations
85
+
86
+ ```bash
87
+ ulvia start
88
+ ulvia instance stop my-site
89
+ ulvia instance start my-site
90
+ ulvia services logs all --level warn
91
+ ulvia instance logs my-site kernel
92
+ ulvia services stop
93
+ ```
94
+
95
+ Stopping containers preserves persistent data. `services stop` also makes every
96
+ site unavailable because Kernels depend on the shared Provider and proxy.
97
+
98
+ ## 5. Upgrade Ulvia
99
+
100
+ Upgrade the host CLI through Bun:
101
+
102
+ ```bash
103
+ bun update --global @cyaxis/ulvia
104
+ ```
105
+
106
+ Upgrade deployable components independently with exact versions:
107
+
108
+ ```bash
109
+ ulvia upgrade kernel --version 0.0.1-beta
110
+ ulvia upgrade provider --version 0.0.1-beta
111
+ ulvia upgrade repository --version 0.0.1-beta
112
+ ```
113
+
114
+ Ulvia resolves each official Docker Hub tag to an immutable digest and reuses
115
+ that digest on subsequent starts. Registry channels such as `next` or `latest`
116
+ may identify releases for humans, but an installation never persists or
117
+ silently follows those mutable tags.
118
+
119
+ ## 6. Public Domain And HTTPS
120
+
121
+ Configure public networking before creating the first instance because the
122
+ canonical Kernel URLs become part of Provider provisioning:
123
+
124
+ ```bash
125
+ ulvia configure network \
126
+ --bind 0.0.0.0 \
127
+ --http-port 80 \
128
+ --tls acme \
129
+ --https-port 443 \
130
+ --acme-email ops@example.com
131
+
132
+ ulvia services start
133
+ ulvia instance create website --domain example.com
134
+ ulvia instance credentials website
135
+ ```
136
+
137
+ Before starting, point the domain's DNS records to the host and allow inbound
138
+ TCP traffic on ports 80 and 443. Review Docker's documented firewall behavior:
139
+ published container ports can bypass some `ufw` and `firewalld` rules unless
140
+ the host policy uses Docker's supported chains.
141
+
142
+ Repository and Provider management endpoints remain bound to loopback. Only the
143
+ shared proxy is exposed publicly.
144
+
145
+ ## 7. Backup, Reset, And Removal
146
+
147
+ Stop the installation before taking a filesystem-level backup of the Ulvia data
148
+ directory. Preserve the complete directory, including MongoDB, files,
149
+ credentials, encryption material, Repository state, and instance definitions.
150
+ Do not restore only selected secret or database files from different snapshots.
151
+
152
+ `reset` permanently removes Ulvia-owned local state:
153
+
154
+ ```bash
155
+ ulvia reset --yes
156
+ ```
157
+
158
+ Remove the CLI separately after stopping or resetting the installation:
159
+
160
+ ```bash
161
+ bun remove --global @cyaxis/ulvia
162
+ ```
163
+
164
+ Removing the CLI alone does not delete persistent CMS data or Docker resources.
165
+
166
+ ## 8. Troubleshooting
167
+
168
+ - **Docker permission denied:** complete Docker's Linux post-installation steps,
169
+ then start a new login session.
170
+ - **`docker compose` is unknown:** install the official Compose plugin rather
171
+ than the retired standalone `docker-compose` package.
172
+ - **Port 5100, 80, or 443 is occupied:** inspect the owner before changing the
173
+ persisted network configuration.
174
+ - **An image cannot be pulled:** verify network access and that the requested
175
+ exact Cyaxis image version has been published.
176
+ - **An instance returns 503:** check `ulvia services status`, then the Provider
177
+ and instance Kernel logs.
178
+ - **Stored encrypted data cannot be opened:** do not generate replacement keys
179
+ over an existing data directory; restore the matching complete backup.
180
+
181
+ For implementation diagnostics and contributor-only environment overrides, see
182
+ the [development and validation guide](../development/README.md).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 matthias-bernouy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,240 @@
1
- # Temporary Holding Version
1
+ # Ulvia CLI
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Ulvia installation and release CLI.
4
+
5
+ For the operator journey from a fresh Ubuntu host to a running local or public
6
+ site, follow the [canonical installation guide](INSTALLATION.md).
7
+
8
+ The workspace package contains private source code. Official releases are
9
+ bundled without workspace dependencies and published publicly as
10
+ `@cyaxis/ulvia`:
11
+
12
+ ```bash
13
+ bun add --global @cyaxis/ulvia@next
14
+ ulvia --help
15
+ ```
16
+
17
+ From the workspace, build and publish one exact release with:
18
+
19
+ ```bash
20
+ bun run cli:build --version 0.0.1-beta
21
+ bun run cli:publish --version 0.0.1-beta
22
+ ```
23
+
24
+ The build creates a checked npm archive and SHA-256 receipt below
25
+ `artifacts/cli`. Publishing accepts only that exact pair, targets the public npm
26
+ registry, and uses the `next` tag for prereleases or `latest` for stable versions.
27
+ It requires npm credentials configured outside the repository.
28
+
29
+ ```bash
30
+ bun run ulvia -- start
31
+ bun run ulvia -- configure network
32
+ bun run ulvia -- services status
33
+ bun run ulvia -- instance create preview --label "Preview site"
34
+ bun run ulvia -- instance list
35
+ bun run ulvia -- instance credentials preview
36
+ bun run ulvia -- instance stop preview
37
+ bun run ulvia -- instance delete preview --yes
38
+ bun run ulvia -- services stop
39
+ bun run ulvia -- upgrade kernel --version 0.0.1-beta
40
+ bun run ulvia -- upgrade provider --version 0.0.1-beta
41
+ bun run ulvia -- upgrade repository --version 0.0.1-beta
42
+ bun run ulvia -- reset --yes
43
+ bun run ulvia -- release packages/official-repository/collections/ulvia-official
44
+ bun run ulvia -- release /path/to/contract-directory
45
+ bun run ulvia -- release /path/to/provider-directory
46
+ bun run ulvia -- push contract ulvia.official/ulvia.cms.installations@1.0.0 --repository https://repository.example
47
+ bun run ulvia -- pull collection ulvia.official/ulvia-official@1.0.0 --repository https://repository.example
48
+ bun run ulvia -- yank collection ulvia.official/ulvia-official@1.0.0 --repository https://repository.example --reason "Superseded"
49
+ bun run ulvia -- restore collection ulvia.official/ulvia-official@1.0.0 --repository https://repository.example
50
+ bun run ulvia -- prune
51
+ ```
52
+
53
+ The lifecycle commands manage the same Docker Compose projects for loopback and
54
+ public installations from any directory. Persistent
55
+ data lives below `$XDG_DATA_HOME/ulvia` or `~/.local/share/ulvia`;
56
+ `ULVIA_DATA_DIR` remains an explicit isolation override for tests and CI. The
57
+ CLI stores authored releases in `<data>/repository`. Shared Provider, Repository,
58
+ MongoDB, proxy, files, secrets and logs live below `<data>/services`; each
59
+ stateless Kernel has independent state and logs below `<data>/instances/<name>`.
60
+ The CLI never starts application servers, supervises their PIDs, or builds
61
+ software images. It pulls only the canonical public images under
62
+ `docker.io/cyaxis`, validates their Ulvia component and stack-API labels, and
63
+ stores the immutable repository digest selected for each component.
64
+
65
+ The first lifecycle command creates a safe installation configuration bound to
66
+ `127.0.0.1:5100`. Configure public exposure before creating an instance:
67
+
68
+ ```bash
69
+ ulvia configure network \
70
+ --bind 0.0.0.0 \
71
+ --http-port 80 \
72
+ --tls acme \
73
+ --https-port 443 \
74
+ --acme-email ops@example.com
75
+ ulvia start
76
+ ulvia instance create website --domain example.com
77
+ ```
78
+
79
+ The configuration is persisted under `<data>/services/installation.json` and
80
+ is not a per-start mode. ACME requires `0.0.0.0` and every instance in an ACME
81
+ installation requires an explicit DNS domain. Network configuration is locked
82
+ after the first instance because its canonical Kernel URL is part of Provider
83
+ provisioning. Repository and Provider management ports remain loopback-only.
84
+
85
+ `services start` starts only the shared proxy, MongoDB, Repository and Provider.
86
+ On first initialization it uses the exact version embedded by `cli:build`, or
87
+ an explicit `services start --version <version>` override. Later starts reuse
88
+ the persisted digests and reject a conflicting `--version`; component changes
89
+ must go through `upgrade`.
90
+ `instance create` provisions one isolated Provider tenant and immediately starts
91
+ its dedicated Kernel. `instance start` restarts only an already-provisioned
92
+ instance's Kernel. All Kernels use the shared proxy port: an instance named
93
+ `default` is available at `http://localhost:5100`, while any other instance such
94
+ as `preview` uses `http://preview.localhost:5100`.
95
+ `ULVIA_HTTP_PORT`, `ULVIA_REPOSITORY_PORT`, and `ULVIA_PROVIDER_PORT` provide
96
+ initial isolation defaults for tests and CI. Interactive configuration belongs
97
+ to `ulvia configure network`. The Provider still listens on its canonical port
98
+ 5103 inside the private Docker network; only its operator port on the host
99
+ changes.
100
+ `start` is the idempotent convenience command for shared services plus every
101
+ previously created local instance; it never creates an implicit instance.
102
+
103
+ The lifecycle boundary is deliberate:
104
+
105
+ | Command | Provider tenant | Kernel container |
106
+ | --- | --- | --- |
107
+ | `services start` | Does not create one | Does not start one |
108
+ | `instance create <name>` | Provisions one durable tenant | Creates and starts its Kernel |
109
+ | `instance start <name>` | Reuses the existing tenant | Starts only that Kernel |
110
+ | `start` | Never provisions | Starts every existing Kernel after shared services |
111
+
112
+ `instance credentials <name>` prints only that administrator's email and
113
+ password. Repository, Provider operator and instance bearer tokens remain in
114
+ private runtime files. Shared services and every instance have independent
115
+ `stop`, `status`, and `logs` boundaries. Software upgrades are explicit and
116
+ component-scoped through `upgrade <component> --version <exact-version>`.
117
+ Normal starts always reuse the installed digest and never follow a newer tag.
118
+ `reset --yes`
119
+ removes every Compose project, instance, shared state and repository
120
+ release. It does not inspect or modify the current working directory.
121
+ `release <resource-directory>` reads `definition.json` and routes by `kind`:
122
+ `collection`, `contract`, or `provider-manifest`. It validates and stores one
123
+ immutable release. A provider manifest must reference exact contract releases
124
+ already in the local repository. Release does not connect to or test a provider.
125
+ Contract fixture assets declared in `definition.json` are read from
126
+ `fixtures/<asset-id>` and verified by digest. Releasing the same coordinate with
127
+ different content fails. The local Repository serves stored resources
128
+ at `/v1/collections`, `/v1/contracts`, and `/v1/providers` on loopback port
129
+ 5102, with declared contract fixtures at
130
+ `/v1/contracts/<publisher>/<contract>/<version>/fixtures/<asset-id>`, and sees
131
+ new releases without restarting. The CMS consumes the collection and provider
132
+ repository endpoints. The Provider administration Page imports an exact
133
+ manifest, approves an account connection and replaces the site's exact contract
134
+ selections for Gateway calls. `prune` empties all local repository content
135
+ without deleting service or instance data.
136
+
137
+ Contract authors may keep only release metadata in `definition.json` and split
138
+ capabilities recursively below `capabilities/`. Each capability is one JSON
139
+ object. Optional `mocks/**/*.json` fragments contain one mock plus its explicit
140
+ `capabilityId`; mocks embedded in capability fragments reject. The compiler
141
+ sorts capabilities and mocks by their declared IDs, so paths never affect the
142
+ immutable digest. `definition.json` cannot contain an inline `capabilities`
143
+ array: the recursive source tree is the only authored contract format.
144
+
145
+ An optional conformance companion uses `conformance/definition.json`, recursive
146
+ `conformance/scenarios/**/*.json` scenario objects and recursive
147
+ `conformance/exemptions/**/*.json` coverage-exemption objects. Optional suite
148
+ fixture bytes live below `conformance/fixtures/<asset-id>`. The release command
149
+ assembles and admits a present suite, including exact locally released
150
+ dependencies, before storing the contract. Conformance publication and live
151
+ execution are separate Gateway/repository APIs; the CLI does not yet orchestrate
152
+ a disposable provider environment.
153
+
154
+ `push` publishes one exact local coordinate, and `pull` downloads and re-admits
155
+ one exact remote coordinate before storing it locally. Both support
156
+ `collection`, `contract`, and `provider`; dependencies must be transferred
157
+ first. `ULVIA_REPOSITORY_URL` can replace `--repository`.
158
+ Repository writes require `ULVIA_REPOSITORY_TOKEN`; the token is never accepted
159
+ as a command-line argument. Every mutation carries a timestamp, one-time nonce,
160
+ body digest, and HMAC-SHA-256 signature. The server rejects stale or replayed
161
+ requests, serializes writes across processes, re-runs admission and evolution
162
+ rules, and stages every declared asset as a separately signed raw stream. A final
163
+ idempotent commit makes the immutable artifact visible only after all byte lengths
164
+ and SHA-256 digests pass. Interrupted and rejected sessions never expose a partial
165
+ release. An exact republish is idempotent; different bytes at an existing coordinate
166
+ reject.
167
+
168
+ The protocol, exact-coordinate client and mutation endpoint live in
169
+ `@bernouy/cms-repository/repository/publication`; the CLI only composes them with
170
+ the reference filesystem adapter and its loopback listener. The filesystem
171
+ composition persists upload sessions and replay claims below the repository root.
172
+ A production repository can replace those ports without depending on this
173
+ executable package.
174
+
175
+ `yank` is reversible catalogue metadata: it hides a release from new catalogue
176
+ resolution without deleting its exact historical bytes. `restore` exposes it
177
+ again. Contract yanks block new dependent publications while previously
178
+ published provider manifests remain readable. The loopback Repository uses the
179
+ same write protocol and keeps its generated repository token in the private
180
+ runtime directory. The removed integration repository/Supabase bridge is not
181
+ run.
182
+
183
+ A collection keeps immutable administration copy in recursive locale
184
+ directories such as `translations/en/collection.json` and
185
+ `translations/en/theme/colors.json`. Every JSON object below
186
+ `translations/<locale>/` contributes to that locale's flat catalogue.
187
+ Collection, Bloc, setting, text, theme and Page metadata stores
188
+ reusable keys from those catalogues rather than inline labels. A key may occur
189
+ in only one fragment per locale. The collection locale must define every
190
+ referenced key; additional locale directories may be partial and fall back to
191
+ it.
192
+
193
+ A collection theme is authored as an ordered set of files. Its
194
+ `theme/definition.json` contains the theme label key and the ordered list of
195
+ category IDs. Category files may be organized recursively below `theme/`; the
196
+ scanner finds them by their internal `id`, while the manifest remains the only
197
+ source of display order. A category filename must match its ID, duplicate IDs
198
+ and orphan files reject, and category/token metadata uses the shared translation
199
+ keys. Categories use an `entries` array containing ordinary tokens and optional
200
+ typed `font-face` entries backed by local WOFF2 assets.
201
+
202
+ Collection assets are discovered recursively below `assets/`; their lowercase
203
+ relative paths are their stable IDs. They are not declared in the collection
204
+ `definition.json`. An optional root `assets/definition.json` accepts only a
205
+ `generations` object keyed by those paths. The compiler derives media type,
206
+ size and digest. Safe presentation-only SVG files receive the `inline-svg`
207
+ profile automatically; other SVGs remain downloadable assets but cannot be
208
+ expanded into authored Page DOM.
209
+
210
+ Collection texts use recursive `texts/definitions/**/*.json` arrays for stable
211
+ IDs and administration metadata, plus recursive
212
+ `texts/locales/<locale>/**/*.json` objects for content values. The release
213
+ command joins them into ordinary collection text records. Paths never prefix a
214
+ text ID; duplicate definitions, duplicate per-locale values and unknown value
215
+ IDs reject.
216
+
217
+ Bloc roots are discovered recursively below `blocs/`. A folder becomes a Bloc
218
+ when it contains `definition.json`, its basename must match the declared Bloc
219
+ ID, and discovery stops there so `settings/definition.json` is never mistaken
220
+ for a nested Bloc. Intermediate grouping directories contain only directories
221
+ and do not affect release identity.
222
+
223
+ The Official Repository image contains the admitted CMS contracts, provider
224
+ manifest, and administration collection. It installs that snapshot only into
225
+ empty persistent storage. To publish the same resources manually, release the
226
+ CMS contracts before the manifest:
227
+
228
+ ```bash
229
+ bun run ulvia -- release packages/official-repository/contracts/ulvia.cms.access
230
+ bun run ulvia -- release packages/official-repository/contracts/ulvia.cms.installations
231
+ bun run ulvia -- release packages/official-repository/contracts/ulvia.cms.content
232
+ bun run ulvia -- release packages/official-repository/contracts/ulvia.cms.files
233
+ bun run ulvia -- release packages/official-repository/contracts/ulvia.provider.cms-instances
234
+ bun run ulvia -- release packages/official-repository/providers/ulvia.official
235
+ bun run ulvia -- start
236
+ ```
237
+
238
+ `instance create` provisions the named instance through the Provider operator
239
+ API, then starts its Kernel. Connection review validates the runtime report and
240
+ exact manifest claims; it does not yet execute a live conformance suite.
@@ -0,0 +1,5 @@
1
+ services:
2
+ kernel:
3
+ environment:
4
+ ACME_HOST: ${ULVIA_INSTANCE_HOSTNAME}
5
+ LETSENCRYPT_HOST: ${ULVIA_INSTANCE_HOSTNAME}
@@ -0,0 +1,40 @@
1
+ services:
2
+ kernel:
3
+ image: ${KERNEL_IMAGE}
4
+ restart: unless-stopped
5
+ init: true
6
+ user: "${ULVIA_UID}:${ULVIA_GID}"
7
+ environment:
8
+ MODE: PROD
9
+ NODE_ENV: production
10
+ KERNEL_HOST: 0.0.0.0
11
+ KERNEL_PORT: "3000"
12
+ KERNEL_PUBLIC_URL: ${ULVIA_INSTANCE_URL}
13
+ CMS_INSTALLATIONS_PROVIDER_URL: http://ulvia-provider:5103
14
+ CMS_INSTALLATIONS_PROVIDER_TOKEN: ${CMS_INSTALLATIONS_PROVIDER_TOKEN}
15
+ ULVIA_LOG_FILE: /var/log/ulvia/kernel.ndjson
16
+ VIRTUAL_HOST: ${ULVIA_INSTANCE_HOSTNAME}
17
+ VIRTUAL_PORT: "3000"
18
+ volumes:
19
+ - type: bind
20
+ source: ${ULVIA_LOGS_DIR}
21
+ target: /var/log/ulvia
22
+ networks:
23
+ - instances
24
+ read_only: true
25
+ tmpfs:
26
+ - /tmp:rw,nosuid,nodev,noexec,size=256m
27
+ cap_drop: [ALL]
28
+ security_opt: [no-new-privileges:true]
29
+ healthcheck:
30
+ test: ["CMD", "bun", "-e", "const r=await fetch('http://127.0.0.1:3000/readyz'); if(!r.ok) process.exit(1); await r.body?.cancel()"]
31
+ interval: 30s
32
+ timeout: 5s
33
+ retries: 3
34
+ start_period: 10s
35
+ stop_grace_period: 30s
36
+
37
+ networks:
38
+ instances:
39
+ external: true
40
+ name: ${ULVIA_INSTANCE_NETWORK}
@@ -0,0 +1,21 @@
1
+ const environment = { ...process.env };
2
+
3
+ function required(name) {
4
+ const value = String(environment[name] ?? "").trim();
5
+ if (!value) {
6
+ throw new Error(`Missing ${name}`);
7
+ }
8
+ return value;
9
+ }
10
+
11
+ const username = required("MONGO_PROVIDER_USERNAME");
12
+ const password = required("MONGO_PROVIDER_PASSWORD");
13
+ const admin = db.getSiblingDB("admin");
14
+ const existing = admin.getUser(username);
15
+ const roles = [{ role: "readWriteAnyDatabase", db: "admin" }];
16
+
17
+ if (existing) {
18
+ admin.updateUser(username, { pwd: password, roles });
19
+ } else {
20
+ admin.createUser({ user: username, pwd: password, roles });
21
+ }
@@ -0,0 +1,13 @@
1
+ # Cache only generic capability routes. Provider Cache-Control headers remain
2
+ # authoritative, so private and no-store responses are never retained.
3
+ proxy_cache_path /var/cache/nginx/cms levels=1:2 keys_zone=cms_capabilities:16m max_size=1g inactive=1h use_temp_path=off;
4
+
5
+ map $uri $cms_skip_capability_cache {
6
+ default 1;
7
+ ~^/(?:[^/]+/)*\.cms/call/ 0;
8
+ }
9
+
10
+ map $request_method $cms_cache_method {
11
+ default $request_method;
12
+ HEAD GET;
13
+ }
@@ -0,0 +1,2 @@
1
+ # The application accepts 100 MiB files plus at most 1 MiB of multipart framing.
2
+ client_max_body_size 101m;
@@ -0,0 +1,8 @@
1
+ # Included inside every generated proxy location by nginx-proxy.
2
+ proxy_cache cms_capabilities;
3
+ proxy_cache_methods GET HEAD;
4
+ proxy_cache_key "$scheme|$cms_cache_method|$host|$uri|$is_args$args";
5
+ proxy_cache_bypass $cms_skip_capability_cache $http_authorization;
6
+ proxy_no_cache $cms_skip_capability_cache $http_authorization;
7
+ proxy_cache_valid 200 206 1h;
8
+ add_header X-Cache-Status $upstream_cache_status always;
@@ -0,0 +1,4 @@
1
+ # Never record query strings. Signed file access tokens are carried in queries.
2
+ log_format cms_query_safe '$remote_addr - $remote_user [$time_local] "$request_method $uri $server_protocol" '
3
+ '$status $body_bytes_sent "$http_referer" "$http_user_agent"';
4
+ access_log /var/log/nginx/access.log cms_query_safe;
@@ -0,0 +1,20 @@
1
+ services:
2
+ proxy:
3
+ ports:
4
+ - "${ULVIA_BIND_ADDRESS}:${ULVIA_HTTPS_PORT}:443"
5
+
6
+ acme:
7
+ image: nginxproxy/acme-companion:2.8.1@sha256:ccfceb9798b9f6586d47eeeadbb8e185c8897b34e011a2739a9b82d5e92a8b6c
8
+ restart: unless-stopped
9
+ depends_on:
10
+ proxy:
11
+ condition: service_healthy
12
+ volumes_from:
13
+ - proxy
14
+ volumes:
15
+ - /var/run/docker.sock:/var/run/docker.sock:ro
16
+ - ${ULVIA_PROXY_ACME_DIR}:/etc/acme.sh
17
+ environment:
18
+ DEFAULT_EMAIL: ${ULVIA_ACME_EMAIL}
19
+ networks:
20
+ - instances