Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c9eb0653d | |||
| ed6a35eb86 | |||
| 242677404b | |||
| 8c6159c596 | |||
| c210507951 | |||
| 0799efadae |
29
.gitignore
vendored
29
.gitignore
vendored
@@ -1,3 +1,30 @@
|
||||
.nogit/
|
||||
|
||||
# artifacts
|
||||
coverage/
|
||||
public/
|
||||
|
||||
# installs
|
||||
node_modules/
|
||||
|
||||
# caches
|
||||
.yarn/
|
||||
.cache/
|
||||
.rpt2_cache
|
||||
|
||||
# builds
|
||||
dist/
|
||||
dist_*/
|
||||
|
||||
# rust
|
||||
rust/target/
|
||||
dist_rust/
|
||||
|
||||
# AI
|
||||
.claude/
|
||||
.serena/
|
||||
|
||||
#------# custom
|
||||
# Deno
|
||||
.deno/
|
||||
deno.lock
|
||||
@@ -50,4 +77,4 @@ logs/
|
||||
*.log
|
||||
|
||||
.playwright-mcp
|
||||
./dist/
|
||||
./dist/
|
||||
@@ -7,7 +7,12 @@
|
||||
"outputMode": "base64ts",
|
||||
"bundler": "esbuild",
|
||||
"production": true,
|
||||
"includeFiles": [{"from": "./html/index.html", "to": "index.html"}]
|
||||
"includeFiles": [
|
||||
{
|
||||
"from": "./html/index.html",
|
||||
"to": "index.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -40,7 +45,12 @@
|
||||
"bundler": "esbuild",
|
||||
"production": true,
|
||||
"watchPatterns": ["./ts_web/**/*", "./html/**/*"],
|
||||
"includeFiles": [{"from": "./html/index.html", "to": "index.html"}]
|
||||
"includeFiles": [
|
||||
{
|
||||
"from": "./html/index.html",
|
||||
"to": "index.html"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"watchers": [
|
||||
@@ -53,5 +63,17 @@
|
||||
"runOnStart": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"@git.zone/cli": {
|
||||
"projectType": "denoSaaS",
|
||||
"module": {
|
||||
"githost": "code.foss.global",
|
||||
"gitscope": "serve.zone",
|
||||
"gitrepo": "onebox",
|
||||
"description": "Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers",
|
||||
"npmPackagename": "@serve.zone/onebox",
|
||||
"license": "MIT"
|
||||
}
|
||||
},
|
||||
"@ship.zone/szci": {}
|
||||
}
|
||||
154
changelog.md
154
changelog.md
@@ -1,6 +1,31 @@
|
||||
# Changelog
|
||||
|
||||
## 2026-03-24 - 1.24.2 - fix(deps)
|
||||
bump runtime and build tool dependencies
|
||||
|
||||
- update @design.estate/dees-catalog to ^3.49.0
|
||||
- update development tooling packages @git.zone/tsbundle, @git.zone/tsdeno, and @git.zone/tswatch
|
||||
|
||||
## 2026-03-24 - 1.24.1 - fix(repo)
|
||||
migrate smart build config to .smartconfig.json and tidy repository metadata
|
||||
|
||||
- Rename npmextra.json to .smartconfig.json and extend it with CLI project metadata for the repository.
|
||||
- Mark the package as private and add an empty pnpm overrides block in package.json.
|
||||
- Expand .gitignore to cover common build artifacts, caches, install directories, and local tooling folders.
|
||||
- Reformat changelog and README files for cleaner spacing and Markdown table alignment without changing documented behavior.
|
||||
|
||||
## 2026-03-24 - 1.24.0 - feat(backup)
|
||||
|
||||
add containerarchive-backed backup storage, restore, download, and pruning support
|
||||
|
||||
- add database support for archive snapshot IDs and stored size tracking for backups
|
||||
- initialize and close the backup archive during onebox lifecycle startup and shutdown
|
||||
- allow backup download and restore flows to work with archive snapshots as well as legacy file-based backups
|
||||
- schedule daily archive pruning based on the most generous configured retention policy
|
||||
- replace smarts3 with smartstorage for registry-backed S3-compatible storage
|
||||
|
||||
## 2026-03-21 - 1.23.0 - feat(appstore)
|
||||
|
||||
add remote app store templates with service upgrades and Redis/MariaDB platform support
|
||||
|
||||
- introduces an App Store manager, API handlers, shared request types, and web UI flow for browsing remote templates and deploying services from template metadata
|
||||
@@ -8,6 +33,7 @@ add remote app store templates with service upgrades and Redis/MariaDB platform
|
||||
- adds Redis and MariaDB platform service providers with provisioning plus backup and restore support, and exposes their requirements through service creation and app template config
|
||||
|
||||
## 2026-03-18 - 1.22.2 - fix(web-ui)
|
||||
|
||||
stabilize app store service creation flow and add Ghost sqlite defaults
|
||||
|
||||
- Defers App Store navigation to the services view to avoid destroying the current view during the deploy event handler.
|
||||
@@ -16,10 +42,11 @@ stabilize app store service creation flow and add Ghost sqlite defaults
|
||||
- Removes obsolete Gitea CI and npm publish workflow definitions.
|
||||
|
||||
## 2026-03-18 - 1.22.1 - fix(repo)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-18 - 1.22.0 - feat(web-appstore)
|
||||
|
||||
add an App Store view for quick service deployment from curated templates
|
||||
|
||||
- adds a new App Store tab to the web UI with curated Docker app templates
|
||||
@@ -28,6 +55,7 @@ add an App Store view for quick service deployment from curated templates
|
||||
- updates @serve.zone/catalog to ^2.8.0 to support the new app store view
|
||||
|
||||
## 2026-03-18 - 1.21.0 - feat(opsserver)
|
||||
|
||||
add container workspace API and backend execution environment for services
|
||||
|
||||
- introduces typed workspace handlers for reading, writing, listing, creating, removing, and executing commands inside service containers
|
||||
@@ -35,6 +63,7 @@ add container workspace API and backend execution environment for services
|
||||
- extends Docker exec lookup to resolve Swarm service container IDs when a direct container ID is unavailable
|
||||
|
||||
## 2026-03-17 - 1.20.0 - feat(ops-dashboard)
|
||||
|
||||
stream user service logs to the ops dashboard and resolve service containers for Docker log streaming
|
||||
|
||||
- add typed socket support for pushing live user service log entries to the web app
|
||||
@@ -44,58 +73,61 @@ stream user service logs to the ops dashboard and resolve service containers for
|
||||
- bump @serve.zone/catalog to ^2.7.0
|
||||
|
||||
## 2026-03-17 - 1.19.12 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-17 - 1.19.11 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-17 - 1.19.10 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-17 - 1.19.9 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-17 - 1.19.8 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-17 - 1.19.7 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-17 - 1.19.6 - fix(repository)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-17 - 1.19.5 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-17 - 1.19.4 - fix(repository)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-16 - 1.19.3 - fix(repo)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-16 - 1.19.2 - fix(docs)
|
||||
|
||||
remove outdated UI screenshot assets from project documentation
|
||||
|
||||
- Deletes multiple PNG screenshots that documented previous dashboard, service form, and hello-world states.
|
||||
- Reduces repository clutter by removing obsolete image assets no longer needed in docs.
|
||||
|
||||
## 2026-03-16 - 1.19.1 - fix(dashboard)
|
||||
|
||||
add updated dashboard screenshots for refresh and resource usage states
|
||||
|
||||
- Adds new dashboard screenshots covering post-refresh, resource usage, and populated data views.
|
||||
- Updates visual assets to document current dashboard behavior and UI states.
|
||||
|
||||
## 2026-03-16 - 1.19.1 - fix(dashboard)
|
||||
|
||||
add aggregated resource usage stats to the dashboard
|
||||
|
||||
- Aggregate CPU, memory, and network stats across all running user and platform service containers in getSystemStatus
|
||||
@@ -104,6 +136,7 @@ add aggregated resource usage stats to the dashboard
|
||||
- Wire dashboard resource usage card to display real aggregated data from the backend
|
||||
|
||||
## 2026-03-16 - 1.19.0 - feat(opsserver,web)
|
||||
|
||||
add real-time platform service log streaming to the dashboard
|
||||
|
||||
- stream running platform service container logs from the ops server to connected dashboard clients via TypedSocket
|
||||
@@ -112,6 +145,7 @@ add real-time platform service log streaming to the dashboard
|
||||
- add the typedsocket dependency and update the catalog package for dashboard support
|
||||
|
||||
## 2026-03-16 - 1.18.5 - fix(platform-services)
|
||||
|
||||
fix platform service detail view navigation and log display
|
||||
|
||||
- Add back button to platform service detail view for returning to services list
|
||||
@@ -120,23 +154,25 @@ fix platform service detail view navigation and log display
|
||||
- Clear previous stats/logs state before fetching new platform service data
|
||||
|
||||
## 2026-03-16 - 1.18.4 - fix(repo)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-16 - 1.18.3 - fix(deps)
|
||||
|
||||
bump @serve.zone/catalog to ^2.6.1
|
||||
|
||||
- Updates the @serve.zone/catalog runtime dependency from ^2.6.0 to ^2.6.1.
|
||||
|
||||
## 2026-03-16 - 1.18.2 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-16 - 1.18.1 - fix(repo)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-16 - 1.18.0 - feat(platform-services)
|
||||
|
||||
add platform service log retrieval and display in the services UI
|
||||
|
||||
- add typed request support in the ops server to fetch Docker logs for platform service containers
|
||||
@@ -144,18 +180,21 @@ add platform service log retrieval and display in the services UI
|
||||
- render platform service logs in the services detail view and add sidebar icons for main navigation tabs
|
||||
|
||||
## 2026-03-16 - 1.17.4 - fix(docs)
|
||||
|
||||
add hello world running screenshot for documentation
|
||||
|
||||
- Adds a new PNG asset showing the application in a running hello world state.
|
||||
- Supports project documentation or README usage without changing runtime behavior.
|
||||
|
||||
## 2026-03-16 - 1.17.3 - fix(mongodb)
|
||||
|
||||
downgrade the MongoDB service image to 4.4 and use the legacy mongo shell for container operations
|
||||
|
||||
- changes the default MongoDB container image from mongo:7 to mongo:4.4
|
||||
- replaces mongosh with mongo for health checks, provisioning, and deprovisioning inside the container
|
||||
|
||||
## 2026-03-16 - 1.17.2 - fix(platform-services)
|
||||
|
||||
provision ClickHouse, MinIO, and MongoDB resources via docker exec instead of host port access
|
||||
|
||||
- switch ClickHouse provisioning and teardown to in-container client commands to avoid host port mapping issues
|
||||
@@ -163,10 +202,11 @@ provision ClickHouse, MinIO, and MongoDB resources via docker exec instead of ho
|
||||
- run MongoDB provisioning and deprovisioning through mongosh inside the container and improve docker exec failure reporting
|
||||
|
||||
## 2026-03-16 - 1.17.1 - fix(repo)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-16 - 1.17.0 - feat(web/services)
|
||||
|
||||
add deploy service action to the services view
|
||||
|
||||
- Adds a prominent "Deploy Service" button to the services page header.
|
||||
@@ -174,6 +214,7 @@ add deploy service action to the services view
|
||||
- Includes a new service creation form screenshot asset for the updated interface.
|
||||
|
||||
## 2026-03-16 - 1.16.0 - feat(services)
|
||||
|
||||
add platform service navigation and stats in the services UI
|
||||
|
||||
- add platform service stats state and fetch action
|
||||
@@ -183,24 +224,28 @@ add platform service navigation and stats in the services UI
|
||||
- bump @serve.zone/catalog to ^2.6.0 for the new platform service UI components
|
||||
|
||||
## 2026-03-16 - 1.15.3 - fix(install)
|
||||
|
||||
refresh systemd service configuration before restarting previously running installations
|
||||
|
||||
- Re-enable the systemd service during updates so unit file changes are applied before restart
|
||||
- Add a log message indicating the service configuration is being refreshed
|
||||
|
||||
## 2026-03-16 - 1.15.2 - fix(systemd)
|
||||
|
||||
set HOME and DENO_DIR for the systemd service environment
|
||||
|
||||
- Adds HOME=/root to the generated onebox systemd unit
|
||||
- Adds DENO_DIR=/root/.cache/deno so Deno cache paths are available when running as a service
|
||||
|
||||
## 2026-03-16 - 1.15.1 - fix(systemd)
|
||||
|
||||
move Docker installation and swarm initialization to systemd enable flow
|
||||
|
||||
- Ensures Docker is installed before writing and enabling the systemd unit that depends on docker.service.
|
||||
- Removes Docker auto-installation from Onebox initialization so setup happens in the service management path.
|
||||
|
||||
## 2026-03-16 - 1.15.0 - feat(systemd)
|
||||
|
||||
replace smartdaemon-based service management with native systemd commands
|
||||
|
||||
- adds a dedicated OneboxSystemd manager for enabling, disabling, starting, stopping, checking status, and following logs
|
||||
@@ -208,28 +253,30 @@ replace smartdaemon-based service management with native systemd commands
|
||||
- removes the smartdaemon dependency and related service management code
|
||||
|
||||
## 2026-03-16 - 1.14.10 - fix(services)
|
||||
|
||||
stop auto-update monitoring during shutdown
|
||||
|
||||
- Track the auto-update polling interval in the services manager
|
||||
- Clear the auto-update interval when Onebox shuts down to prevent background checks after shutdown
|
||||
|
||||
## 2026-03-16 - 1.14.9 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-16 - 1.14.8 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-16 - 1.14.7 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-16 - 1.14.6 - fix(project)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-16 - 1.14.5 - fix(onebox)
|
||||
|
||||
move Docker auto-install and swarm initialization into Onebox startup flow
|
||||
|
||||
- removes Docker setup from daemon service installation
|
||||
@@ -237,22 +284,23 @@ move Docker auto-install and swarm initialization into Onebox startup flow
|
||||
- preserves automatic Docker Swarm initialization on fresh servers
|
||||
|
||||
## 2026-03-16 - 1.14.4 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-16 - 1.14.3 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-16 - 1.14.2 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-16 - 1.14.1 - fix(repo)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-16 - 1.14.0 - feat(daemon)
|
||||
|
||||
auto-install Docker and initialize Swarm during daemon service setup
|
||||
|
||||
- Adds a Docker availability check before installing the Onebox daemon service
|
||||
@@ -260,75 +308,83 @@ auto-install Docker and initialize Swarm during daemon service setup
|
||||
- Attempts to initialize Docker Swarm after installation and handles already-initialized environments gracefully
|
||||
|
||||
## 2026-03-16 - 1.13.17 - fix(ci)
|
||||
|
||||
remove forced container image pulling from Gitea workflow jobs
|
||||
|
||||
- Drops the `--pull always` container option from CI, npm publish, and release workflows.
|
||||
- Keeps workflow container images unchanged while avoiding forced pulls on every job run.
|
||||
|
||||
## 2026-03-16 - 1.13.16 - fix(ci)
|
||||
|
||||
refresh workflow container images on every run and bump @apiclient.xyz/docker to ^5.1.1
|
||||
|
||||
- add --pull always to CI, release, and npm publish workflow containers to avoid stale images
|
||||
- update @apiclient.xyz/docker from ^5.1.0 to ^5.1.1 in deno.json
|
||||
|
||||
## 2026-03-15 - 1.13.15 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-15 - 1.13.14 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-15 - 1.13.13 - fix(repo)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-15 - 1.13.12 - fix(ci)
|
||||
|
||||
run pnpm install with --ignore-scripts in CI and release workflows
|
||||
|
||||
- Update CI workflow dependency installation steps to skip lifecycle scripts during builds.
|
||||
- Apply the same install change to the release workflow for consistent automation behavior.
|
||||
|
||||
## 2026-03-15 - 1.13.11 - fix(project)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-15 - 1.13.10 - fix(deps)
|
||||
|
||||
bump @git.zone/tsdeno to ^1.2.0
|
||||
|
||||
- Updates the tsdeno development dependency from ^1.1.1 to ^1.2.0.
|
||||
|
||||
## 2026-03-15 - 1.13.9 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-15 - 1.13.8 - fix(repo)
|
||||
no changes to commit
|
||||
|
||||
no changes to commit
|
||||
|
||||
## 2026-03-15 - 1.13.7 - fix(repo)
|
||||
|
||||
no changes to commit
|
||||
|
||||
|
||||
## 2026-03-15 - 1.13.6 - fix(ci)
|
||||
|
||||
correct workflow container image registry path
|
||||
|
||||
- Update Gitea CI, release, and npm publish workflows to use the corrected ht-docker-node image path
|
||||
- Align all workflow container references from hosttoday to host.today to prevent pipeline image resolution issues
|
||||
|
||||
## 2026-03-15 - 1.13.5 - fix(workflows)
|
||||
|
||||
switch Gitea workflow containers from ht-docker-dbase to ht-docker-node
|
||||
|
||||
- Updates the CI, release, and npm publish workflows to use the Node-focused container image consistently.
|
||||
- Aligns workflow runtime images with the project's Node and Deno build and publish steps.
|
||||
|
||||
## 2026-03-15 - 1.13.4 - fix(ci)
|
||||
|
||||
run workflows in the shared build container and enable corepack for pnpm installs
|
||||
|
||||
- adds the ht-docker-dbase container image to CI, release, and npm publish workflows
|
||||
- enables corepack before pnpm install in build and release jobs to ensure package manager availability
|
||||
|
||||
## 2026-03-15 - 1.13.3 - fix(build)
|
||||
|
||||
replace custom Deno compile scripts with tsdeno-based binary builds in CI and release workflows
|
||||
|
||||
- adds @git.zone/tsdeno as a dev dependency and configures compile targets in npmextra.json
|
||||
@@ -336,18 +392,21 @@ replace custom Deno compile scripts with tsdeno-based binary builds in CI and re
|
||||
- removes the legacy scripts/compile-all.sh script and points the compile task to tsdeno compile
|
||||
|
||||
## 2026-03-15 - 1.13.2 - fix(scripts)
|
||||
|
||||
install production dependencies before compiling binaries and exclude local node_modules from builds
|
||||
|
||||
- Adds a dependency installation step using the application entrypoint before cross-platform compilation
|
||||
- Updates all deno compile targets to use --node-modules-dir=none to avoid bundling local node_modules
|
||||
|
||||
## 2026-03-15 - 1.13.1 - fix(deno)
|
||||
|
||||
remove nodeModulesDir from Deno configuration
|
||||
|
||||
- Drops the explicit nodeModulesDir setting from deno.json.
|
||||
- Keeps the package version unchanged at 1.13.0 while simplifying runtime configuration.
|
||||
|
||||
## 2026-03-15 - 1.13.0 - feat(install)
|
||||
|
||||
improve installer with version selection, service restart handling, and upgrade documentation
|
||||
|
||||
- Adds installer command-line options for help, specific version selection, and custom install directory.
|
||||
@@ -355,12 +414,14 @@ improve installer with version selection, service restart handling, and upgrade
|
||||
- Preserves Onebox data directories, stops and restarts the systemd service during updates, and refreshes installation instructions in the README including upgrade usage.
|
||||
|
||||
## 2026-03-15 - 1.12.1 - fix(package.json)
|
||||
|
||||
update package metadata
|
||||
|
||||
- Single metadata-only file changed (+1, -1)
|
||||
- No source code or runtime behavior modified; safe patch release
|
||||
|
||||
## 2026-03-15 - 1.12.0 - feat(cli,release)
|
||||
|
||||
add self-upgrade command and automate CI, release, and npm publishing workflows
|
||||
|
||||
- adds a new `onebox upgrade` CLI command that checks the latest release and reinstalls the current binary via the installer script
|
||||
@@ -368,6 +429,7 @@ add self-upgrade command and automate CI, release, and npm publishing workflows
|
||||
- adds a reusable release template describing installation options, supported platforms, and checksum availability
|
||||
|
||||
## 2026-03-03 - 1.11.0 - feat(services)
|
||||
|
||||
map backend service data to UI components, add stats & logs parsing, fetch service stats, and fix logs request param
|
||||
|
||||
- Fix: rename service logs request property from 'lines' to 'tail' when calling typedRequest
|
||||
@@ -377,21 +439,24 @@ map backend service data to UI components, add stats & logs parsing, fetch servi
|
||||
- Parse and normalize logs into timestamp/message pairs for the detail view
|
||||
|
||||
## 2026-03-02 - 1.10.3 - fix(bin)
|
||||
|
||||
make bin/onebox-wrapper.js executable
|
||||
|
||||
- Metadata-only change: file mode updated for bin/onebox-wrapper.js to include the executable bit
|
||||
- No source or behavior changes to the code
|
||||
|
||||
## 2026-03-02 - 1.10.2 - fix(build)
|
||||
|
||||
update build/watch configuration, switch to esbuild bundler and tswatch, and bump catalog and tooling dependencies
|
||||
|
||||
- Switch watch script to 'tswatch' (replaced previous concurrently command invoking deno + tswatch).
|
||||
- npmextra.json: set bundler to 'esbuild', enable production mode, include html/index.html in the bundle, and extend watchPatterns to include ./html/**/*.
|
||||
- npmextra.json: set bundler to 'esbuild', enable production mode, include html/index.html in the bundle, and extend watchPatterns to include ./html/\*_/_.
|
||||
- Backend watcher: expanded watch globs and changed command to include --unstable-ffi and runtime flags (--ephemeral --monitor); restart and debounce kept.
|
||||
- Bump runtime deps: @design.estate/dees-catalog -> ^3.43.3, @serve.zone/catalog -> ^2.5.0.
|
||||
- Bump devDependencies: @git.zone/tsbundle -> ^2.9.0, @git.zone/tswatch -> ^3.2.0.
|
||||
|
||||
## 2026-02-24 - 1.10.1 - fix(package.json)
|
||||
|
||||
update package metadata
|
||||
|
||||
- Single metadata-only file changed (+1 -1)
|
||||
@@ -399,6 +464,7 @@ update package metadata
|
||||
- Current package version is 1.10.0; recommend patch bump to 1.10.1
|
||||
|
||||
## 2026-02-24 - 1.10.0 - feat(opsserver)
|
||||
|
||||
introduce OpsServer (TypedRequest API) and new lightweight web UI; replace legacy Angular UI and add typed interfaces
|
||||
|
||||
- Add OpsServer (ts/opsserver) with TypedRequest handlers for admin, services, platform, dns, domains, registry, network, backups, schedules, settings and logs.
|
||||
@@ -411,21 +477,24 @@ introduce OpsServer (TypedRequest API) and new lightweight web UI; replace legac
|
||||
- Note: This adds many new endpoints and internal API changes (TypedRequest-based); consumers of the old UI/HTTP endpoints should migrate to the new OpsServer TypedRequest API and web components.
|
||||
|
||||
## 2025-12-03 - 1.9.2 - fix(ui)
|
||||
|
||||
Add VS Code configs for the UI workspace and normalize dark theme CSS variables
|
||||
|
||||
- Add VS Code workspace files under ui/.vscode:
|
||||
- - extensions.json: recommend the Angular language support extension
|
||||
- - launch.json: Chrome launch configurations for 'ng serve' and 'ng test' (preLaunchTask hooks)
|
||||
- - tasks.json: npm 'start' and 'test' tasks with a background TypeScript problem matcher to improve dev workflow
|
||||
- - extensions.json: recommend the Angular language support extension
|
||||
- - launch.json: Chrome launch configurations for 'ng serve' and 'ng test' (preLaunchTask hooks)
|
||||
- - tasks.json: npm 'start' and 'test' tasks with a background TypeScript problem matcher to improve dev workflow
|
||||
- Update ui/src/styles.css dark theme variables to use neutral black/gray HSL values for background, foreground, cards, popovers, accents, borders, inputs and ring to improve contrast and consistency
|
||||
|
||||
## 2025-11-27 - 1.9.1 - fix(ui)
|
||||
|
||||
Correct import success toast and add VS Code launch/tasks recommendations for the UI
|
||||
|
||||
- Fix backup import success toast in backups-tab.component to reference response.data.service.name (previously response.data.serviceName), preventing incorrect service name display.
|
||||
- Add VS Code workspace settings for the UI: extensions recommendation, launch configurations for 'ng serve' and 'ng test', and npm tasks for start/test to simplify local development and debugging.
|
||||
|
||||
## 2025-11-27 - 1.9.0 - feat(backups)
|
||||
|
||||
Add backup import API and improve backup download/import flow in UI
|
||||
|
||||
- Backend: add /api/backups/import endpoint to accept multipart file uploads or JSON with a URL and import backups (saves temp file, validates .tar.enc, calls backupManager.restoreBackup in import mode).
|
||||
@@ -435,6 +504,7 @@ Add backup import API and improve backup download/import flow in UI
|
||||
- Dev: add VS Code launch, tasks and recommended extensions for the ui workspace to simplify local development.
|
||||
|
||||
## 2025-11-27 - 1.8.0 - feat(backup)
|
||||
|
||||
Add backup scheduling system with GFS retention, API and UI integration
|
||||
|
||||
- Introduce backup scheduling subsystem (BackupScheduler) and integrate it into Onebox lifecycle (init & shutdown)
|
||||
@@ -447,6 +517,7 @@ Add backup scheduling system with GFS retention, API and UI integration
|
||||
- Type and repository updates across codebase to support schedule-aware backups, schedule CRUD, and retention enforcement
|
||||
|
||||
## 2025-11-27 - 1.7.0 - feat(backup)
|
||||
|
||||
Add backup system: BackupManager, DB schema, API endpoints and UI support
|
||||
|
||||
Introduce a complete service backup/restore subsystem with encrypted archives, database records and REST endpoints. Implements BackupManager with export/import for service config, platform resources (MongoDB, MinIO, ClickHouse), and Docker images; adds BackupRepository and migrations for backups table and include_image_in_backup; integrates backup flows into the HTTP API and the UI client; exposes backup password management and restore modes (restore/import/clone). Wire BackupManager into Onebox initialization.
|
||||
@@ -459,6 +530,7 @@ Introduce a complete service backup/restore subsystem with encrypted archives, d
|
||||
- Integrate BackupManager into Onebox core (initialized in Onebox constructor) and wire HTTP handlers to use the new manager; add DB repository export/import glue so backups are stored and referenced by ID.
|
||||
|
||||
## 2025-11-27 - 1.6.0 - feat(ui.dashboard)
|
||||
|
||||
Add Resource Usage card to dashboard and make dashboard cards full-height; add VSCode launch/tasks/config
|
||||
|
||||
- Introduce ResourceUsageCardComponent and include it as a full-width row in the dashboard layout.
|
||||
@@ -467,6 +539,7 @@ Add Resource Usage card to dashboard and make dashboard cards full-height; add V
|
||||
- Add VSCode workspace configuration: recommended Angular extension, launch configurations for ng serve/ng test, and npm tasks to run/start the UI in development.
|
||||
|
||||
## 2025-11-27 - 1.5.0 - feat(network)
|
||||
|
||||
Add traffic stats endpoint and dashboard UI; enhance platform services and certificate health reporting
|
||||
|
||||
- Add /api/network/traffic-stats GET endpoint to the HTTP API with an optional minutes query parameter (validated, 1-60).
|
||||
@@ -478,26 +551,29 @@ Add traffic stats endpoint and dashboard UI; enhance platform services and certi
|
||||
- Add VSCode workspace launch/tasks recommendations for the UI development environment.
|
||||
|
||||
## 2025-11-26 - 1.4.0 - feat(platform-services)
|
||||
|
||||
Add ClickHouse platform service support and improve related healthchecks and tooling
|
||||
|
||||
- Add ClickHouse as a first-class platform service: register provider, provision/cleanup support and env var injection
|
||||
- Expose ClickHouse endpoints in the HTTP API routing (list/get/start/stop/stats) and map default port (8123)
|
||||
- Enable services to request ClickHouse as a platform requirement (enableClickHouse / platformRequirements) during deploy/provision flows
|
||||
- Fix ClickHouse container health check to use absolute wget path (/usr/bin/wget) for more reliable in-container checks
|
||||
- Add VS Code workspace launch/tasks/extensions configs for the UI (ui/.vscode/*) to improve local dev experience
|
||||
- Add VS Code workspace launch/tasks/extensions configs for the UI (ui/.vscode/\*) to improve local dev experience
|
||||
|
||||
## 2025-11-26 - 1.3.0 - feat(platform-services)
|
||||
|
||||
Add ClickHouse platform service support (provider, types, provisioning, UI and port mappings)
|
||||
|
||||
- Introduce ClickHouse as a first-class platform service: added ClickHouseProvider and registered it in PlatformServicesManager
|
||||
- Support provisioning ClickHouse resources for user services and storing encrypted credentials in platform_resources
|
||||
- Add ClickHouse to core types (TPlatformServiceType, IPlatformRequirements, IServiceDeployOptions) and service DB handling so services can request ClickHouse
|
||||
- Inject ClickHouse-related environment variables into deployed services (CLICKHOUSE_* mappings) when provisioning resources
|
||||
- Inject ClickHouse-related environment variables into deployed services (CLICKHOUSE\_\* mappings) when provisioning resources
|
||||
- Expose ClickHouse default port (8123) in platform port mappings / network targets
|
||||
- UI: add checkbox and description for enabling ClickHouse during service creation; form now submits enableClickHouse
|
||||
- Add VS Code recommendations and launch/tasks for the UI development workflow
|
||||
|
||||
## 2025-11-26 - 1.2.1 - fix(platform-services/minio)
|
||||
|
||||
Improve MinIO provider: reuse existing data and credentials, use host-bound port for provisioning, and safer provisioning/deprovisioning
|
||||
|
||||
- MinIO provider now detects existing data directory and will reuse stored admin credentials when available instead of regenerating them.
|
||||
@@ -508,15 +584,17 @@ Improve MinIO provider: reuse existing data and credentials, use host-bound port
|
||||
- Added VSCode workspace files (extensions, launch, tasks) for the ui project to improve developer experience.
|
||||
|
||||
## 2025-11-26 - 1.2.0 - feat(ui)
|
||||
|
||||
Sync UI tab state with URL and update routes/links
|
||||
|
||||
- Add VSCode workspace recommendations, launch and tasks configs for the UI (ui/.vscode/*)
|
||||
- Add VSCode workspace recommendations, launch and tasks configs for the UI (ui/.vscode/\*)
|
||||
- Update Angular routes to support tab URL segments and default redirects for services, network and registries
|
||||
- Change service detail route to use explicit 'detail/:name' path and update links accordingly
|
||||
- Make ServicesList, Registries and Network components read tab from route params and navigate on tab changes; add ngOnDestroy to unsubscribe
|
||||
- Update Domain detail template link to point to the new services detail route
|
||||
|
||||
## 2025-11-26 - 1.1.0 - feat(platform-services)
|
||||
|
||||
Add platform service log streaming, improve health checks and provisioning robustness
|
||||
|
||||
- Add WebSocket log streaming support for platform services (backend + UI) to stream MinIO/MongoDB/Caddy logs in real time
|
||||
@@ -536,6 +614,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Initial project structure
|
||||
- Core architecture classes
|
||||
- Docker container management
|
||||
@@ -554,4 +633,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
## [1.0.0] - TBD
|
||||
|
||||
### Added
|
||||
|
||||
- First stable release
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@serve.zone/onebox",
|
||||
"version": "1.23.0",
|
||||
"version": "1.24.2",
|
||||
"exports": "./mod.ts",
|
||||
"tasks": {
|
||||
"test": "deno test --allow-all test/",
|
||||
@@ -19,14 +19,15 @@
|
||||
"@apiclient.xyz/cloudflare": "npm:@apiclient.xyz/cloudflare@6.4.3",
|
||||
"@push.rocks/smartacme": "npm:@push.rocks/smartacme@^8.0.0",
|
||||
"@push.rocks/smartregistry": "npm:@push.rocks/smartregistry@^2.2.0",
|
||||
"@push.rocks/smarts3": "npm:@push.rocks/smarts3@^5.1.0",
|
||||
"@push.rocks/smartstorage": "npm:@push.rocks/smartstorage@^6.3.0",
|
||||
"@push.rocks/taskbuffer": "npm:@push.rocks/taskbuffer@^3.1.0",
|
||||
"@api.global/typedrequest-interfaces": "npm:@api.global/typedrequest-interfaces@^3.0.19",
|
||||
"@api.global/typedrequest": "npm:@api.global/typedrequest@^3.2.6",
|
||||
"@api.global/typedserver": "npm:@api.global/typedserver@^8.3.1",
|
||||
"@push.rocks/smartguard": "npm:@push.rocks/smartguard@^3.1.0",
|
||||
"@push.rocks/smartjwt": "npm:@push.rocks/smartjwt@^2.2.1",
|
||||
"@api.global/typedsocket": "npm:@api.global/typedsocket@^4.1.2"
|
||||
"@api.global/typedsocket": "npm:@api.global/typedsocket@^4.1.2",
|
||||
"@serve.zone/containerarchive": "npm:@serve.zone/containerarchive@^0.1.3"
|
||||
},
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
|
||||
14
package.json
14
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@serve.zone/onebox",
|
||||
"version": "1.23.0",
|
||||
"version": "1.24.2",
|
||||
"description": "Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers",
|
||||
"main": "mod.ts",
|
||||
"type": "module",
|
||||
@@ -56,13 +56,17 @@
|
||||
"dependencies": {
|
||||
"@api.global/typedrequest-interfaces": "^3.0.19",
|
||||
"@api.global/typedsocket": "^4.1.2",
|
||||
"@design.estate/dees-catalog": "^3.43.3",
|
||||
"@design.estate/dees-catalog": "^3.49.0",
|
||||
"@design.estate/dees-element": "^2.1.6",
|
||||
"@serve.zone/catalog": "^2.9.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@git.zone/tsbundle": "^2.9.0",
|
||||
"@git.zone/tsdeno": "^1.2.0",
|
||||
"@git.zone/tswatch": "^3.2.0"
|
||||
"@git.zone/tsbundle": "^2.10.0",
|
||||
"@git.zone/tsdeno": "^1.3.1",
|
||||
"@git.zone/tswatch": "^3.3.2"
|
||||
},
|
||||
"private": true,
|
||||
"pnpm": {
|
||||
"overrides": {}
|
||||
}
|
||||
}
|
||||
|
||||
634
pnpm-lock.yaml
generated
634
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@
|
||||
## SSL Certificate Storage (November 2025)
|
||||
|
||||
SSL certificates are now stored directly in the SQLite database as PEM content instead of file paths:
|
||||
|
||||
- `ISslCertificate` and `ICertificate` interfaces use `certPem`, `keyPem`, `fullchainPem` properties
|
||||
- Database migration 8 converted the `certificates` table schema
|
||||
- No filesystem storage for certificates - everything in DB
|
||||
@@ -16,6 +17,7 @@ SSL certificates are now stored directly in the SQLite database as PEM content i
|
||||
The database layer has been refactored into a repository pattern:
|
||||
|
||||
**Directory Structure:**
|
||||
|
||||
```
|
||||
ts/database/
|
||||
├── index.ts # Main OneboxDatabase class (composes repositories, handles migrations)
|
||||
@@ -32,10 +34,12 @@ ts/database/
|
||||
```
|
||||
|
||||
**Import paths:**
|
||||
|
||||
- Main: `import { OneboxDatabase } from './database/index.ts'`
|
||||
- Legacy (deprecated): `import { OneboxDatabase } from './classes/database.ts'` (re-exports from new location)
|
||||
|
||||
**API Compatibility:**
|
||||
|
||||
- The `OneboxDatabase` class maintains the same public API
|
||||
- All methods delegate to the appropriate repository
|
||||
- No breaking changes for existing code
|
||||
@@ -49,6 +53,7 @@ Migration 8 converted certificate storage from file paths to PEM content.
|
||||
The reverse proxy uses **Caddy** running as a Docker Swarm service for production-grade reverse proxying with native SNI support, HTTP/2, HTTP/3, and WebSocket handling.
|
||||
|
||||
**Architecture:**
|
||||
|
||||
- Caddy runs as Docker Swarm service (`onebox-caddy`) on the overlay network
|
||||
- No binary download required - uses `caddy:2-alpine` Docker image
|
||||
- Configuration pushed dynamically via Caddy Admin API (port 2019)
|
||||
@@ -57,10 +62,12 @@ The reverse proxy uses **Caddy** running as a Docker Swarm service for productio
|
||||
- Services reached by Docker service name (e.g., `onebox-hello-world:80`)
|
||||
|
||||
**Key files:**
|
||||
|
||||
- `ts/classes/caddy.ts` - CaddyManager class for Docker service and Admin API
|
||||
- `ts/classes/reverseproxy.ts` - Delegates to CaddyManager
|
||||
|
||||
**Certificate workflow:**
|
||||
|
||||
1. `CertRequirementManager` creates requirements for domains
|
||||
2. Daemon processes requirements via `certmanager.ts`
|
||||
3. Certificates stored in database (PEM content)
|
||||
@@ -68,16 +75,19 @@ The reverse proxy uses **Caddy** running as a Docker Swarm service for productio
|
||||
5. Caddy serves TLS with the loaded certificates (no volume mounts needed)
|
||||
|
||||
**Docker Service Configuration:**
|
||||
|
||||
- Service name: `onebox-caddy`
|
||||
- Image: `caddy:2-alpine`
|
||||
- Network: `onebox-network` (overlay, attachable)
|
||||
- Startup: Writes initial config with `admin.listen: 0.0.0.0:2019` for host access
|
||||
|
||||
**Port Mapping:**
|
||||
|
||||
- Dev mode: HTTP on 8080, HTTPS on 8443, Admin on 2019
|
||||
- Production: HTTP on 80, HTTPS on 443, Admin on 2019
|
||||
- All ports use `PublishMode: 'host'` for direct binding
|
||||
|
||||
**Log Receiver:**
|
||||
|
||||
- Caddy sends access logs to `tcp/172.17.0.1:9999` (Docker bridge gateway)
|
||||
- `CaddyLogReceiver` on host receives and processes logs
|
||||
|
||||
121
readme.md
121
readme.md
@@ -22,6 +22,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
||||
## Features ✨
|
||||
|
||||
### Core Platform
|
||||
|
||||
- 🐳 **Docker Swarm Management** - Deploy, scale, and orchestrate services with Swarm mode
|
||||
- 🌐 **Caddy Reverse Proxy** - Production-grade proxy running as Docker service with SNI, HTTP/2, HTTP/3
|
||||
- 🔒 **Automatic SSL Certificates** - Let's Encrypt integration with hot-reload and renewal monitoring
|
||||
@@ -30,6 +31,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
||||
- 🔄 **Real-time WebSocket Updates** - Live service status, logs, and system events
|
||||
|
||||
### Monitoring & Management
|
||||
|
||||
- 📊 **Metrics Collection** - Historical CPU, memory, and network stats (every 60s)
|
||||
- 📝 **Centralized Logging** - Container logs with streaming and retention policies
|
||||
- 🎨 **Angular Web UI** - Modern, responsive interface with real-time updates
|
||||
@@ -37,6 +39,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
||||
- 💾 **SQLite Database** - Embedded, zero-configuration storage
|
||||
|
||||
### Developer Experience
|
||||
|
||||
- 🚀 **Auto-update on Push** - Push to registry and services update automatically
|
||||
- 🔐 **Private Registry Support** - Use Docker Hub, Gitea, or custom registries
|
||||
- 🔄 **Systemd Integration** - Run as a daemon with auto-restart
|
||||
@@ -75,6 +78,7 @@ onebox service add myapp \
|
||||
Open `http://localhost:3000` in your browser.
|
||||
|
||||
**Default credentials:**
|
||||
|
||||
- Username: `admin`
|
||||
- Password: `admin`
|
||||
|
||||
@@ -130,15 +134,15 @@ Onebox is built with modern technologies for performance and developer experienc
|
||||
|
||||
### Core Components
|
||||
|
||||
| Component | Description |
|
||||
|-----------|-------------|
|
||||
| **Deno Runtime** | Modern TypeScript with built-in security |
|
||||
| Component | Description |
|
||||
| ----------------------- | -------------------------------------------------------------------- |
|
||||
| **Deno Runtime** | Modern TypeScript with built-in security |
|
||||
| **Caddy Reverse Proxy** | Docker Swarm service with HTTP/2, HTTP/3, SNI, and WebSocket support |
|
||||
| **Docker Swarm** | Container orchestration (all workloads run as services) |
|
||||
| **SQLite Database** | Configuration, metrics, and user data |
|
||||
| **WebSocket Server** | Real-time bidirectional communication |
|
||||
| **Let's Encrypt** | Automatic SSL certificate management |
|
||||
| **Cloudflare API** | DNS record automation |
|
||||
| **Docker Swarm** | Container orchestration (all workloads run as services) |
|
||||
| **SQLite Database** | Configuration, metrics, and user data |
|
||||
| **WebSocket Server** | Real-time bidirectional communication |
|
||||
| **Let's Encrypt** | Automatic SSL certificate management |
|
||||
| **Cloudflare API** | DNS record automation |
|
||||
|
||||
## CLI Reference 📖
|
||||
|
||||
@@ -262,11 +266,11 @@ sudo onebox upgrade
|
||||
|
||||
### Data Locations
|
||||
|
||||
| Data | Location |
|
||||
|------|----------|
|
||||
| **Database** | `./onebox.db` (or custom path) |
|
||||
| **SSL Certificates** | Managed by CertManager |
|
||||
| **Registry Data** | `./.nogit/registry-data` |
|
||||
| Data | Location |
|
||||
| -------------------- | ------------------------------ |
|
||||
| **Database** | `./onebox.db` (or custom path) |
|
||||
| **SSL Certificates** | Managed by CertManager |
|
||||
| **Registry Data** | `./.nogit/registry-data` |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
@@ -355,62 +359,69 @@ onebox/
|
||||
The HTTP server exposes a comprehensive REST API:
|
||||
|
||||
#### Authentication
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
| ------ | ----------------- | ----------------------------------- |
|
||||
| `POST` | `/api/auth/login` | User authentication (returns token) |
|
||||
|
||||
#### Services
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/services` | List all services |
|
||||
| `POST` | `/api/services` | Create/deploy service |
|
||||
| `GET` | `/api/services/:name` | Get service details |
|
||||
| `PUT` | `/api/services/:name` | Update service |
|
||||
| `DELETE` | `/api/services/:name` | Delete service |
|
||||
| `POST` | `/api/services/:name/start` | Start service |
|
||||
| `POST` | `/api/services/:name/stop` | Stop service |
|
||||
| `POST` | `/api/services/:name/restart` | Restart service |
|
||||
| `GET` | `/api/services/:name/logs` | Get service logs |
|
||||
| `WS` | `/api/services/:name/logs/stream` | Stream logs via WebSocket |
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
| -------- | --------------------------------- | ------------------------- |
|
||||
| `GET` | `/api/services` | List all services |
|
||||
| `POST` | `/api/services` | Create/deploy service |
|
||||
| `GET` | `/api/services/:name` | Get service details |
|
||||
| `PUT` | `/api/services/:name` | Update service |
|
||||
| `DELETE` | `/api/services/:name` | Delete service |
|
||||
| `POST` | `/api/services/:name/start` | Start service |
|
||||
| `POST` | `/api/services/:name/stop` | Stop service |
|
||||
| `POST` | `/api/services/:name/restart` | Restart service |
|
||||
| `GET` | `/api/services/:name/logs` | Get service logs |
|
||||
| `WS` | `/api/services/:name/logs/stream` | Stream logs via WebSocket |
|
||||
|
||||
#### SSL Certificates
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/ssl/list` | List all certificates |
|
||||
| `GET` | `/api/ssl/:domain` | Get certificate details |
|
||||
| `POST` | `/api/ssl/obtain` | Request new certificate |
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
| ------ | ------------------------ | ----------------------- |
|
||||
| `GET` | `/api/ssl/list` | List all certificates |
|
||||
| `GET` | `/api/ssl/:domain` | Get certificate details |
|
||||
| `POST` | `/api/ssl/obtain` | Request new certificate |
|
||||
| `POST` | `/api/ssl/:domain/renew` | Force renew certificate |
|
||||
|
||||
#### Domains
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/domains` | List all domains |
|
||||
| `GET` | `/api/domains/:domain` | Get domain details |
|
||||
| `POST` | `/api/domains/sync` | Sync domains from Cloudflare |
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
| ------ | ---------------------- | ---------------------------- |
|
||||
| `GET` | `/api/domains` | List all domains |
|
||||
| `GET` | `/api/domains/:domain` | Get domain details |
|
||||
| `POST` | `/api/domains/sync` | Sync domains from Cloudflare |
|
||||
|
||||
#### DNS Records
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/dns` | List DNS records |
|
||||
| `POST` | `/api/dns` | Create DNS record |
|
||||
| `DELETE` | `/api/dns/:domain` | Delete DNS record |
|
||||
| `POST` | `/api/dns/sync` | Sync DNS from Cloudflare |
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
| -------- | ------------------ | ------------------------ |
|
||||
| `GET` | `/api/dns` | List DNS records |
|
||||
| `POST` | `/api/dns` | Create DNS record |
|
||||
| `DELETE` | `/api/dns/:domain` | Delete DNS record |
|
||||
| `POST` | `/api/dns/sync` | Sync DNS from Cloudflare |
|
||||
|
||||
#### Registry
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/registry/tags/:service` | Get registry tags for service |
|
||||
| `GET` | `/api/registry/tokens` | List registry tokens |
|
||||
| `POST` | `/api/registry/tokens` | Create registry token |
|
||||
| `DELETE` | `/api/registry/tokens/:id` | Delete registry token |
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
| -------- | ----------------------------- | ----------------------------- |
|
||||
| `GET` | `/api/registry/tags/:service` | Get registry tags for service |
|
||||
| `GET` | `/api/registry/tokens` | List registry tokens |
|
||||
| `POST` | `/api/registry/tokens` | Create registry token |
|
||||
| `DELETE` | `/api/registry/tokens/:id` | Delete registry token |
|
||||
|
||||
#### System
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| `GET` | `/api/status` | System status |
|
||||
| `GET` | `/api/settings` | Get settings |
|
||||
| `PUT` | `/api/settings` | Update settings |
|
||||
| `WS` | `/api/ws` | WebSocket for real-time updates |
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
| ------ | --------------- | ------------------------------- |
|
||||
| `GET` | `/api/status` | System status |
|
||||
| `GET` | `/api/settings` | Get settings |
|
||||
| `PUT` | `/api/settings` | Update settings |
|
||||
| `WS` | `/api/ws` | WebSocket for real-time updates |
|
||||
|
||||
### WebSocket Messages
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/onebox',
|
||||
version: '1.23.0',
|
||||
version: '1.24.2',
|
||||
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -59,6 +59,15 @@ export class BackupScheduler {
|
||||
await this.registerTask(schedule);
|
||||
}
|
||||
|
||||
// Add periodic archive prune task (runs daily at 3 AM)
|
||||
const pruneTask = new plugins.taskbuffer.Task({
|
||||
name: 'backup-archive-prune',
|
||||
taskFunction: async () => {
|
||||
await this.pruneArchive();
|
||||
},
|
||||
});
|
||||
this.taskManager.addAndScheduleTask(pruneTask, '0 3 * * *');
|
||||
|
||||
// Start the task manager (activates cron scheduling)
|
||||
await this.taskManager.start();
|
||||
|
||||
@@ -436,9 +445,11 @@ export class BackupScheduler {
|
||||
if (!toKeep.has(backup.id!)) {
|
||||
try {
|
||||
await this.oneboxRef.backupManager.deleteBackup(backup.id!);
|
||||
logger.info(`Deleted backup ${backup.filename} (retention policy)`);
|
||||
const backupRef = backup.snapshotId || backup.filename;
|
||||
logger.info(`Deleted backup ${backupRef} (retention policy)`);
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to delete old backup ${backup.filename}: ${getErrorMessage(error)}`);
|
||||
const backupRef = backup.snapshotId || backup.filename;
|
||||
logger.warn(`Failed to delete old backup ${backupRef}: ${getErrorMessage(error)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -647,4 +658,48 @@ export class BackupScheduler {
|
||||
private getRetentionDescription(retention: IRetentionPolicy): string {
|
||||
return `H:${retention.hourly} D:${retention.daily} W:${retention.weekly} M:${retention.monthly}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prune the containerarchive repository to reclaim storage.
|
||||
* Uses the most generous retention policy across all schedules.
|
||||
*/
|
||||
private async pruneArchive(): Promise<void> {
|
||||
const archive = this.oneboxRef.backupManager.archive;
|
||||
if (!archive) return;
|
||||
|
||||
try {
|
||||
// Compute the most generous retention across all schedules
|
||||
const schedules = this.oneboxRef.database.getAllBackupSchedules();
|
||||
|
||||
// Default minimums if no schedules exist
|
||||
let maxDays = 7;
|
||||
let maxWeeks = 4;
|
||||
let maxMonths = 12;
|
||||
|
||||
for (const schedule of schedules) {
|
||||
if (schedule.retention.daily > maxDays) maxDays = schedule.retention.daily;
|
||||
if (schedule.retention.weekly > maxWeeks) maxWeeks = schedule.retention.weekly;
|
||||
if (schedule.retention.monthly > maxMonths) maxMonths = schedule.retention.monthly;
|
||||
}
|
||||
|
||||
const result = await archive.prune(
|
||||
{
|
||||
keepDays: maxDays,
|
||||
keepWeeks: maxWeeks,
|
||||
keepMonths: maxMonths,
|
||||
},
|
||||
false, // not dry run
|
||||
);
|
||||
|
||||
if (result.removedSnapshots > 0 || result.freedBytes > 0) {
|
||||
const freedMB = Math.round(result.freedBytes / (1024 * 1024) * 10) / 10;
|
||||
logger.info(
|
||||
`Archive prune: removed ${result.removedSnapshots} snapshot(s), ` +
|
||||
`${result.removedPacks} pack(s), freed ${freedMB} MB`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(`Archive prune failed: ${getErrorMessage(error)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2161,27 +2161,47 @@ export class OneboxHttpServer {
|
||||
*/
|
||||
private async handleDownloadBackupRequest(backupId: number): Promise<Response> {
|
||||
try {
|
||||
const filePath = this.oneboxRef.backupManager.getBackupFilePath(backupId);
|
||||
if (!filePath) {
|
||||
const backup = this.oneboxRef.database.getBackupById(backupId);
|
||||
if (!backup) {
|
||||
return this.jsonResponse({ success: false, error: 'Backup not found' }, 404);
|
||||
}
|
||||
|
||||
let downloadPath: string | null = null;
|
||||
let tempExport = false;
|
||||
|
||||
if (backup.snapshotId) {
|
||||
// ContainerArchive backup: export as encrypted tar
|
||||
downloadPath = await this.oneboxRef.backupManager.getBackupExportPath(backupId);
|
||||
tempExport = true;
|
||||
} else {
|
||||
// Legacy file-based backup
|
||||
downloadPath = this.oneboxRef.backupManager.getBackupFilePath(backupId);
|
||||
}
|
||||
|
||||
if (!downloadPath) {
|
||||
return this.jsonResponse({ success: false, error: 'Backup file not available' }, 404);
|
||||
}
|
||||
|
||||
// Check if file exists
|
||||
try {
|
||||
await Deno.stat(filePath);
|
||||
await Deno.stat(downloadPath);
|
||||
} catch {
|
||||
return this.jsonResponse({ success: false, error: 'Backup file not found on disk' }, 404);
|
||||
}
|
||||
|
||||
// Read file and return as download
|
||||
const backup = this.oneboxRef.database.getBackupById(backupId);
|
||||
const file = await Deno.readFile(filePath);
|
||||
const file = await Deno.readFile(downloadPath);
|
||||
const filename = backup.filename || `${backup.serviceName}-${backup.createdAt}.tar.enc`;
|
||||
|
||||
// Clean up temp export file
|
||||
if (tempExport) {
|
||||
try { await Deno.remove(downloadPath); } catch { /* ignore */ }
|
||||
}
|
||||
|
||||
return new Response(file, {
|
||||
status: 200,
|
||||
headers: {
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Disposition': `attachment; filename="${backup?.filename || 'backup.tar.enc'}"`,
|
||||
'Content-Disposition': `attachment; filename="${filename}"`,
|
||||
'Content-Length': String(file.length),
|
||||
},
|
||||
});
|
||||
@@ -2241,12 +2261,6 @@ export class OneboxHttpServer {
|
||||
}, 400);
|
||||
}
|
||||
|
||||
// Get backup file path
|
||||
const filePath = this.oneboxRef.backupManager.getBackupFilePath(backupId);
|
||||
if (!filePath) {
|
||||
return this.jsonResponse({ success: false, error: 'Backup not found' }, 404);
|
||||
}
|
||||
|
||||
// Validate mode-specific requirements
|
||||
if ((mode === 'import' || mode === 'clone') && !newServiceName) {
|
||||
return this.jsonResponse({
|
||||
@@ -2255,7 +2269,7 @@ export class OneboxHttpServer {
|
||||
}, 400);
|
||||
}
|
||||
|
||||
const result = await this.oneboxRef.backupManager.restoreBackup(filePath, {
|
||||
const result = await this.oneboxRef.backupManager.restoreBackup(backupId, {
|
||||
mode,
|
||||
newServiceName,
|
||||
overwriteExisting: overwriteExisting === true,
|
||||
|
||||
@@ -192,6 +192,14 @@ export class Onebox {
|
||||
// Start auto-update monitoring for registry services
|
||||
this.services.startAutoUpdateMonitoring();
|
||||
|
||||
// Initialize BackupManager (containerarchive repository, non-critical)
|
||||
try {
|
||||
await this.backupManager.init();
|
||||
} catch (error) {
|
||||
logger.warn('BackupManager initialization failed - backups will be limited');
|
||||
logger.warn(`Error: ${getErrorMessage(error)}`);
|
||||
}
|
||||
|
||||
// Initialize Backup Scheduler (non-critical)
|
||||
try {
|
||||
await this.backupScheduler.init();
|
||||
@@ -430,6 +438,9 @@ export class Onebox {
|
||||
// Stop Caddy log receiver
|
||||
await this.caddyLogReceiver.stop();
|
||||
|
||||
// Close backup archive
|
||||
await this.backupManager.close();
|
||||
|
||||
// Close database
|
||||
this.database.close();
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Onebox Registry Manager
|
||||
*
|
||||
* Manages the local Docker registry using:
|
||||
* - @push.rocks/smarts3 (S3-compatible server with filesystem storage)
|
||||
* - @push.rocks/smartstorage (S3-compatible server with filesystem storage)
|
||||
* - @push.rocks/smartregistry (OCI-compliant Docker registry)
|
||||
*/
|
||||
|
||||
@@ -27,7 +27,7 @@ export class RegistryManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the registry (start smarts3 and smartregistry)
|
||||
* Initialize the registry (start smartstorage and smartregistry)
|
||||
*/
|
||||
async init(): Promise<void> {
|
||||
if (this.isInitialized) {
|
||||
@@ -39,10 +39,10 @@ export class RegistryManager {
|
||||
const dataDir = this.options.dataDir || './.nogit/registry-data';
|
||||
const port = this.options.port || 4000;
|
||||
|
||||
logger.info(`Starting smarts3 server on port ${port}...`);
|
||||
logger.info(`Starting smartstorage server on port ${port}...`);
|
||||
|
||||
// 1. Start smarts3 server (S3-compatible storage with filesystem backend)
|
||||
this.s3Server = await plugins.smarts3.Smarts3.createAndStart({
|
||||
// 1. Start smartstorage server (S3-compatible storage with filesystem backend)
|
||||
this.s3Server = await plugins.smartstorage.SmartStorage.createAndStart({
|
||||
server: {
|
||||
port: port,
|
||||
address: '0.0.0.0',
|
||||
@@ -53,16 +53,16 @@ export class RegistryManager {
|
||||
},
|
||||
});
|
||||
|
||||
logger.success(`smarts3 server started on port ${port}`);
|
||||
logger.success(`smartstorage server started on port ${port}`);
|
||||
|
||||
// 2. Configure smartregistry to use smarts3
|
||||
// 2. Configure smartregistry to use smartstorage
|
||||
logger.info('Initializing smartregistry...');
|
||||
|
||||
this.registry = new plugins.smartregistry.SmartRegistry({
|
||||
storage: {
|
||||
endpoint: 'localhost',
|
||||
port: port,
|
||||
accessKey: 'onebox', // smarts3 doesn't validate credentials
|
||||
accessKey: 'onebox', // smartstorage doesn't validate credentials
|
||||
accessSecret: 'onebox',
|
||||
useSsl: false,
|
||||
region: 'us-east-1',
|
||||
@@ -314,15 +314,15 @@ export class RegistryManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the registry and smarts3 server
|
||||
* Stop the registry and smartstorage server
|
||||
*/
|
||||
async stop(): Promise<void> {
|
||||
if (this.s3Server) {
|
||||
try {
|
||||
await this.s3Server.stop();
|
||||
logger.info('smarts3 server stopped');
|
||||
logger.info('smartstorage server stopped');
|
||||
} catch (error) {
|
||||
logger.error(`Error stopping smarts3: ${getErrorMessage(error)}`);
|
||||
logger.error(`Error stopping smartstorage: ${getErrorMessage(error)}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -607,6 +607,10 @@ export class OneboxDatabase {
|
||||
return this.backupRepo.getBySchedule(scheduleId);
|
||||
}
|
||||
|
||||
getBackupBySnapshotId(snapshotId: string): IBackup | null {
|
||||
return this.backupRepo.getBySnapshotId(snapshotId);
|
||||
}
|
||||
|
||||
// ============ Backup Schedules (delegated to repository) ============
|
||||
|
||||
createBackupSchedule(schedule: Omit<IBackupSchedule, 'id'>): IBackupSchedule {
|
||||
|
||||
13
ts/database/migrations/migration-014-containerarchive.ts
Normal file
13
ts/database/migrations/migration-014-containerarchive.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { BaseMigration } from './base-migration.ts';
|
||||
import type { TQueryFunction } from '../types.ts';
|
||||
|
||||
export class Migration014ContainerArchive extends BaseMigration {
|
||||
readonly version = 14;
|
||||
readonly description = 'Add containerarchive snapshot tracking to backups';
|
||||
|
||||
up(query: TQueryFunction): void {
|
||||
query('ALTER TABLE backups ADD COLUMN snapshot_id TEXT');
|
||||
query('ALTER TABLE backups ADD COLUMN stored_size_bytes INTEGER DEFAULT 0');
|
||||
query('CREATE INDEX IF NOT EXISTS idx_backups_snapshot ON backups(snapshot_id)');
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import { Migration010BackupSchedules } from './migration-010-backup-schedules.ts
|
||||
import { Migration011ScopeColumns } from './migration-011-scope-columns.ts';
|
||||
import { Migration012GfsRetention } from './migration-012-gfs-retention.ts';
|
||||
import { Migration013AppTemplateVersion } from './migration-013-app-template-version.ts';
|
||||
import { Migration014ContainerArchive } from './migration-014-containerarchive.ts';
|
||||
import type { BaseMigration } from './base-migration.ts';
|
||||
|
||||
export class MigrationRunner {
|
||||
@@ -44,6 +45,7 @@ export class MigrationRunner {
|
||||
new Migration011ScopeColumns(),
|
||||
new Migration012GfsRetention(),
|
||||
new Migration013AppTemplateVersion(),
|
||||
new Migration014ContainerArchive(),
|
||||
].sort((a, b) => a.version - b.version);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,8 +20,9 @@ export class BackupRepository extends BaseRepository {
|
||||
this.query(
|
||||
`INSERT INTO backups (
|
||||
service_id, service_name, filename, size_bytes, created_at,
|
||||
includes_image, platform_resources, checksum, schedule_id
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
includes_image, platform_resources, checksum, schedule_id,
|
||||
snapshot_id, stored_size_bytes
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
[
|
||||
backup.serviceId,
|
||||
backup.serviceName,
|
||||
@@ -32,6 +33,8 @@ export class BackupRepository extends BaseRepository {
|
||||
JSON.stringify(backup.platformResources),
|
||||
backup.checksum,
|
||||
backup.scheduleId ?? null,
|
||||
backup.snapshotId ?? null,
|
||||
backup.storedSizeBytes ?? 0,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -78,6 +81,14 @@ export class BackupRepository extends BaseRepository {
|
||||
return rows.map((row) => this.rowToBackup(row));
|
||||
}
|
||||
|
||||
getBySnapshotId(snapshotId: string): IBackup | null {
|
||||
const rows = this.query(
|
||||
'SELECT * FROM backups WHERE snapshot_id = ?',
|
||||
[snapshotId]
|
||||
);
|
||||
return rows.length > 0 ? this.rowToBackup(rows[0]) : null;
|
||||
}
|
||||
|
||||
private rowToBackup(row: any): IBackup {
|
||||
let platformResources: TPlatformServiceType[] = [];
|
||||
const platformResourcesRaw = row.platform_resources;
|
||||
@@ -94,7 +105,9 @@ export class BackupRepository extends BaseRepository {
|
||||
serviceId: Number(row.service_id),
|
||||
serviceName: String(row.service_name),
|
||||
filename: String(row.filename),
|
||||
snapshotId: row.snapshot_id ? String(row.snapshot_id) : undefined,
|
||||
sizeBytes: Number(row.size_bytes),
|
||||
storedSizeBytes: row.stored_size_bytes ? Number(row.stored_size_bytes) : undefined,
|
||||
createdAt: Number(row.created_at),
|
||||
includesImage: Boolean(row.includes_image),
|
||||
platformResources,
|
||||
|
||||
@@ -53,12 +53,8 @@ export class BackupsHandler {
|
||||
'restoreBackup',
|
||||
async (dataArg) => {
|
||||
await requireValidIdentity(this.opsServerRef.adminHandler, dataArg);
|
||||
const backupPath = this.opsServerRef.oneboxRef.backupManager.getBackupFilePath(dataArg.backupId);
|
||||
if (!backupPath) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Backup file not found');
|
||||
}
|
||||
const rawResult = await this.opsServerRef.oneboxRef.backupManager.restoreBackup(
|
||||
backupPath,
|
||||
dataArg.backupId,
|
||||
dataArg.options,
|
||||
);
|
||||
return {
|
||||
@@ -84,14 +80,11 @@ export class BackupsHandler {
|
||||
if (!backup) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Backup not found');
|
||||
}
|
||||
const filePath = this.opsServerRef.oneboxRef.backupManager.getBackupFilePath(dataArg.backupId);
|
||||
if (!filePath) {
|
||||
throw new plugins.typedrequest.TypedResponseError('Backup file not found');
|
||||
}
|
||||
// Return a download URL that the client can fetch directly
|
||||
const filename = backup.filename || `${backup.serviceName}-${backup.createdAt}.tar.enc`;
|
||||
return {
|
||||
downloadUrl: `/api/backups/${dataArg.backupId}/download`,
|
||||
filename: backup.filename,
|
||||
filename,
|
||||
};
|
||||
},
|
||||
),
|
||||
|
||||
@@ -34,8 +34,8 @@ import * as smartregistry from '@push.rocks/smartregistry';
|
||||
export { smartregistry };
|
||||
|
||||
// S3-compatible storage server
|
||||
import * as smarts3 from '@push.rocks/smarts3';
|
||||
export { smarts3 };
|
||||
import * as smartstorage from '@push.rocks/smartstorage';
|
||||
export { smartstorage };
|
||||
|
||||
// Task scheduling and cron jobs
|
||||
import * as taskbuffer from '@push.rocks/taskbuffer';
|
||||
@@ -67,3 +67,12 @@ export { typedrequest, typedserver };
|
||||
import * as smartguard from '@push.rocks/smartguard';
|
||||
import * as smartjwt from '@push.rocks/smartjwt';
|
||||
export { smartguard, smartjwt };
|
||||
|
||||
// Backup archive (content-addressed dedup storage)
|
||||
import { ContainerArchive } from '@serve.zone/containerarchive';
|
||||
export { ContainerArchive };
|
||||
|
||||
// Node.js compat for streaming
|
||||
import * as nodeFs from 'node:fs';
|
||||
import * as nodeStream from 'node:stream';
|
||||
export { nodeFs, nodeStream };
|
||||
|
||||
@@ -356,7 +356,9 @@ export interface IBackup {
|
||||
serviceId: number;
|
||||
serviceName: string; // Denormalized for display
|
||||
filename: string;
|
||||
snapshotId?: string; // ContainerArchive snapshot ID (new backups)
|
||||
sizeBytes: number;
|
||||
storedSizeBytes?: number; // Actual stored size after dedup+compression
|
||||
createdAt: number;
|
||||
includesImage: boolean;
|
||||
platformResources: TPlatformServiceType[]; // Which platform types were backed up
|
||||
@@ -399,7 +401,8 @@ export interface IBackupPlatformResource {
|
||||
|
||||
export interface IBackupResult {
|
||||
backup: IBackup;
|
||||
filePath: string;
|
||||
filePath?: string; // Legacy file-based backups only
|
||||
snapshotId?: string; // ContainerArchive snapshot ID
|
||||
}
|
||||
|
||||
export interface IRestoreOptions {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -28,7 +28,9 @@ export interface IBackup {
|
||||
serviceId: number;
|
||||
serviceName: string;
|
||||
filename: string;
|
||||
snapshotId?: string;
|
||||
sizeBytes: number;
|
||||
storedSizeBytes?: number;
|
||||
createdAt: number;
|
||||
includesImage: boolean;
|
||||
platformResources: TPlatformServiceType[];
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@serve.zone/onebox',
|
||||
version: '1.23.0',
|
||||
version: '1.24.2',
|
||||
description: 'Self-hosted container platform with automatic SSL and DNS - a mini Heroku for single servers'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user