{"id":50703890,"url":"https://github.com/niki-on-github/volsync-webui","last_synced_at":"2026-06-09T10:01:56.615Z","repository":{"id":357184909,"uuid":"1235797153","full_name":"niki-on-github/volsync-webui","owner":"niki-on-github","description":"A web-based management interface for VolSync replication and backup operations on Kubernetes.","archived":false,"fork":false,"pushed_at":"2026-05-11T19:03:47.000Z","size":45,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-11T19:08:45.974Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/niki-on-github.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-05-11T17:01:09.000Z","updated_at":"2026-05-11T19:03:30.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/niki-on-github/volsync-webui","commit_stats":null,"previous_names":["niki-on-github/volsync-webui"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/niki-on-github/volsync-webui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niki-on-github%2Fvolsync-webui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niki-on-github%2Fvolsync-webui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niki-on-github%2Fvolsync-webui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niki-on-github%2Fvolsync-webui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/niki-on-github","download_url":"https://codeload.github.com/niki-on-github/volsync-webui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/niki-on-github%2Fvolsync-webui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34101070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-09T10:01:55.751Z","updated_at":"2026-06-09T10:01:56.608Z","avatar_url":"https://github.com/niki-on-github.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# VolSync WebUI\n\nA web-based management interface for VolSync replication and backup operations on Kubernetes.\n\n\u003e [!WARNING]  \n\u003e The code was specificaly designed for my k8s setup. It is not a universal tool that covers every situation. If you would like to use this project, please review the conditions carefully or create a fork with the necessary modifications.\n\n![Screenshot](preview.png)\n\n## Features\n\n- **Dashboard Table**: View all ReplicationSources in a sortable table with status, last backup time, duration, and result\n- **Detail Panel**: Click a row to see snapshot history, backup status, and restore controls\n- **Backup Operations**: Trigger manual backups for individual apps\n- **Restore Operations**: Restore from any available snapshot timestamp via the detail panel\n- **Auto-Refresh**: Periodically updates the app list with configurable interval (default: 1 hour, no-overlap guard)\n- **Manual Refresh**: Refresh button in header to fetch latest data on demand\n\n## Deployment\n\nA example deployment of this repository is in the `./example/` direcotry.\n\n### Kubernetes\n\nThe container expects to run inside a Kubernetes cluster with access to the Kubernetes API.\n\nApply the RBAC configuration from the section below, then deploy the container:\n\n```bash\n# Create the ClusterRole and ClusterRoleBinding (see RBAC section below)\nkubectl apply -f - \u003c\u003cEOF\n# ... paste the YAML from the RBAC section ...\nEOF\nkubectl apply -f your-deployment.yaml\n```\n\n## RBAC Permissions\n\nThe ServiceAccount requires these permissions. Create a `ClusterRole` + `ClusterRoleBinding`:\n\n```yaml\napiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\nmetadata:\n  name: volsync-webui\nrules:\n  - apiGroups: [\"volsync.backube\"]\n    resources: [\"replicationsources\", \"replicationdestinations\", \"replicationdestinations/status\"]\n    verbs: [\"get\", \"list\", \"patch\", \"watch\"]\n  - apiGroups: [\"\"]\n    resources: [\"pods\", \"pods/log\"]\n    verbs: [\"get\", \"list\", \"create\", \"delete\"]\n  - apiGroups: [\"\"]\n    resources: [\"namespaces\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"apps\"]\n    resources: [\"deployments\", \"deployments/scale\"]\n    verbs: [\"get\", \"list\", \"patch\"]\n  - apiGroups: [\"helm.toolkit.fluxcd.io\"]\n    resources: [\"helmreleases\"]\n    verbs: [\"get\", \"list\", \"patch\"]\n  - apiGroups: [\"\"]\n    resources: [\"persistentvolumeclaims\"]\n    verbs: [\"get\", \"list\"]\n  - apiGroups: [\"kustomize.toolkit.fluxcd.io\"]\n    resources: [\"kustomizations\"]\n    verbs: [\"get\", \"patch\", \"list\"]\n```\n\nThe app runs a startup RBAC check that probes each API endpoint and logs whether permissions are present. Missing permissions are non-fatal (logged as errors but the app continues).\n\n## Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `RUST_LOG` | `info` | Logging level (trace, debug, info, warn, error) |\n| `KUBERNETES_SERVICE_HOST` | auto-detected | Kubernetes API server host |\n| `VOLSYNC_API_GROUP` | `volsync.backube` | API group for VolSync CRDs (set to `replication.storage.io` for older clusters) |\n| `VOLSYNC_SOURCE_SUFFIX` | `-backup` | Suffix on ReplicationSource CRD names (e.g. `gitea-backup`) |\n| `VOLSYNC_DEST_SUFFIX` | `-bootstrap` | Suffix on ReplicationDestination CRD names (e.g. `gitea-bootstrap`) |\n| `VOLSYNC_PVC_SUFFIX` | `-pvc` | Suffix on PVC name (e.g. `gitea-pvc`). The PVC name is derived as `{base_app_name}{suffix}`. |\n| `BACKUP_ALL_CONCURRENCY` | `5` | Max concurrent backups for backup-all |\n| `POLL_TIMEOUT_SECS` | `300` | Backup/restore poll timeout in seconds |\n| `POLL_INTERVAL_SECS` | `2` | Backup/restore poll interval in seconds |\n| `POD_STARTUP_TIMEOUT_SECS` | `60` | Snapshot pod startup timeout in seconds |\n| `RESTIC_IMAGE` | `restic/restic:latest` | Restic container image for snapshot pods |\n| `VOLSYNC_KUSTOMIZATION_NAMESPACE` | `flux-system` | Namespace for Flux Kustomizations (suspend/unsuspend during restore) |\n\n### Suffix Configuration\n\nThe app name shown in the dashboard is the ReplicationSource CRD name (e.g. `gitea-backup`).\nThe destination CRD name is derived by stripping `VOLSYNC_SOURCE_SUFFIX` and appending `VOLSYNC_DEST_SUFFIX`:\n\n```\ngitea-backup  → strips -backup  → gitea  → appends -bootstrap  → gitea-bootstrap\n```\n\n## Restore Workflow\n\nThe restore operation uses VolSync's `copyMethod: Direct` to write backup data directly into the application's existing PVC. This bypasses VolumeSnapshots entirely, making it compatible with all storage backends including OpenEBS ZFS LocalPV (where snapshots are destroyed when their parent PVC is deleted).\n\n### Prerequisites\n\nThe application must be managed by a **Flux HelmRelease** (Kustomization support is optional but recommended). The ReplicationDestination CRD must exist and have `spec.trigger.manual` set by the HelmRelease values.\n\nThe PVC name must follow the convention: `{base_app_name}{VOLSYNC_PVC_SUFFIX}` (default `{app_name}-pvc`).\n\n### Restore Flow\n\n```\n 0. Check HelmRelease exists (REQUIRED)               ← fail if missing\n 0.5 Suspend Flux Kustomization (best-effort)          ← pauses GitOps reconciliation\n 1. Suspend HelmRelease                                ← prevents Flux from reverting changes\n 2. Scale down ALL deployments to 0                    ← detach app from PVC (multi-deployment safe)\n 3. Save original RD fields:                           ← copyMethod, destinationPVC, restoreAsOf\n 4. PATCH RD: copyMethod=Direct, destinationPVC=\u003cpvc\u003e  ← VolSync writes directly into app PVC\n 5. PATCH RD: restoreAsOf=\u003ctimestamp\u003e (if provided)\n 6. Nullify status.lastManualSync                      ← triggers VolSync restore\n 7. Poll until restore completes\n 8. PATCH RD revert: restore original values           ← reverts copyMethod, destinationPVC, restoreAsOf\n 9. Scale ALL deployments back to original replicas    ← pre-scales before Flux wakes up\n10. Unsuspend HelmRelease                              ← Flux sees no drift\n11. Unsuspend Kustomization (best-effort)              ← resumes GitOps reconciliation\n```\n\nThe restore supports **multiple deployments per app** — all deployments matching `app.kubernetes.io/instance={base_app}` are scaled down and restored independently with their original replica counts.\n\n### Storage Backend Compatibility\n\n| Backend | Compatible | Notes |\n|---------|-----------|-------|\n| OpenEBS ZFS LocalPV | Yes | `copyMethod: Direct` writes directly into the app PVC, avoiding ZFS snapshot dependency issues |\n| CSI drivers with working VolumePopulators | Yes | Works without snapshots |\n| Any storage that supports PVC cloning | Yes | Direct method avoids cloning altogether |\n\n**Important for ZFS users**: VolSync's default `copyMethod: Snapshot` creates a temporary PVC, restores data into it, takes a VolumeSnapshot, then deletes the temporary PVC. With OpenEBS ZFS, deleting the temp PVC destroys the ZFS dataset and its snapshots, making the snapshot unusable. `copyMethod: Direct` avoids this by writing directly into the application PVC.\n\n### Error Handling\n\n- If any step before the poll fails, the operation returns an error. The PVC and deployments are unchanged (restore was not triggered).\n- If the restore poll fails (VolSync error or timeout), the ReplicationDestination spec still has `copyMethod: Direct` set. A subsequent retry will overwrite it. You can also trigger a HelmRelease reconciliation via Flux to reset the spec.\n- If the RD revert fails after a successful restore, the data is already written to the PVC, but the ReplicationDestination spec may need manual cleanup (e.g., remove `copyMethod: Direct` and `destinationPVC`).\n\n### Flux Kustomization Support\n\nIf your application is managed by a Flux Kustomization (e.g., in the `flux-system` namespace), set `VOLSYNC_KUSTOMIZATION_NAMESPACE` to the namespace where the Kustomization lives (default: `flux-system`). The restore will suspend the Kustomization to prevent GitOps reconciliation during the restore, then unsuspend it afterward.\n\nThe Kustomization name must match the base app name (e.g., app `gitea-backup` → base name `gitea` → Kustomization `gitea`).\n\n### API Group Configuration\n\nThe default `VOLSYNC_API_GROUP=volsync.backube` matches modern VolSync installations. For older clusters still using the legacy API group, set:\n\n```yaml\nenv:\n  - name: VOLSYNC_API_GROUP\n    value: \"replication.storage.io\"\n```\n\n## Kubernetes Compatibility\n\n- Tested with Kubernetes 1.25+\n- Uses `volsync.backube/v1alpha1` for VolSync CRDs (configurable via `VOLSYNC_API_GROUP`)\n- Uses `helm.toolkit.fluxcd.io/v2` for HelmRelease (required for restore; backups work without it)\n\n## Security Considerations\n\n1. **ServiceAccount**: Runs with a dedicated SA, not default\n2. **ClusterRole**: Requires broad read access — restrict in production\n3. **No TLS**: Backend runs HTTP; TLS should be handled by ingress/controller\n4. **No Authentication**: Currently no auth — expose via auth proxy (e.g., OAuth2 proxy) in production\n5. **Secret Access**: Reads the actual secret name from `spec.restic.repository` on each ReplicationSource at snapshot time, so it always uses the correct credentials regardless of naming convention\n\n## Developer Documentation\n\nsee `./docs`\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniki-on-github%2Fvolsync-webui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fniki-on-github%2Fvolsync-webui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fniki-on-github%2Fvolsync-webui/lists"}