An open API service indexing awesome lists of open source software.

https://github.com/melonamin/ghvault

Comprehensive GitHub backup tool with CLI, TUI, and Web interfaces for homelabs and personal setups
https://github.com/melonamin/ghvault

backup cli docker git github go golang homelab self-hosted tui

Last synced: 6 months ago
JSON representation

Comprehensive GitHub backup tool with CLI, TUI, and Web interfaces for homelabs and personal setups

Awesome Lists containing this project

README

          

# GHVault

[![Release](https://img.shields.io/github/v/release/melonamin/ghvault?style=flat-square)](https://github.com/melonamin/ghvault/releases)
[![Go Version](https://img.shields.io/github/go-mod/go-version/melonamin/ghvault?style=flat-square)](https://go.dev/)
[![License](https://img.shields.io/github/license/melonamin/ghvault?style=flat-square)](LICENSE)
[![Docker Image](https://img.shields.io/badge/ghcr.io-melonamin%2Fghvault-blue?style=flat-square&logo=docker)](https://ghcr.io/melonamin/ghvault)
[![Go Reference](https://pkg.go.dev/badge/github.com/melonamin/ghvault.svg)](https://pkg.go.dev/github.com/melonamin/ghvault)
[![Go Report Card](https://goreportcard.com/badge/github.com/melonamin/ghvault)](https://goreportcard.com/report/github.com/melonamin/ghvault)


ghv Logo

## Overview

GHVault is a comprehensive GitHub backup tool for homelabs and personal setups. It mirrors repositories (including LFS and wikis), exports metadata such as issues and PRs, and gives you CLI, TUI, and Web interfaces so you can keep copies of everything you care about.

### Table of Contents
- [Why GHVault](#why-ghvault)
- [Install](#install)
- [Quick Start](#quick-start)
- [Interfaces](#interfaces)
- [Advanced & Deployment](#advanced--deployment)
- [License](#license)
- [Contributing](#contributing)

## Why GHVault

- **Complete coverage** – repositories (bare or mirror), wikis, gists, releases, release assets, labels, milestones, and issue/PR metadata.
- **Multiple workflows** – unattended CLI jobs, an interactive TUI dashboard, and a browser-based UI.
- **Homelab friendly** – multi-arch Docker image, persistent storage mounts, and built-in scheduling flags.
- **Secure auth** – OAuth device flow plus optional encrypted token storage when keychains are unavailable.
- **Efficient backups** – incremental syncs, Git LFS support, and concurrency tuning.
- **Flexible filters** – limit by visibility, language, archived status, forks, or glob patterns.

## Install

### Choose your path

| You're… | Start with |
|---------|------------|
| Running a homelab or NAS | Docker container for easy persistence |
| Automating from scripts | Prebuilt binary download |
| Already in the Go toolchain | `go install github.com/melonamin/ghvault/cmd/ghv@latest` |
| Hacking on GHVault itself | Clone + `just build` |

### Docker (recommended for homelabs)

Pull the latest multi-arch image and run it with persistent volumes:

```bash
docker run -d \
--name ghvault \
-p 8080:8080 \
-v ghvault-backups:/home/ghvault/backups \
-v ghvault-config:/home/ghvault/.config/ghvault \
-e GHVAULT_SERVER_PASSWORD="change-me" \
-e GHVAULT_SECRET="$(openssl rand -base64 48)" \
ghcr.io/melonamin/ghvault:latest
```

Then authenticate via the web UI at http://localhost:8080 or run:

```bash
docker exec -it ghvault ghv login --headless
```

Need compose files, scheduling, or alternative ports? See [Advanced & Deployment](#advanced--deployment).

### Download binary

Grab the latest release from [GitHub Releases](https://github.com/melonamin/ghvault/releases):

| Platform | Architecture | Artifact |
|----------|--------------|----------|
| macOS | Universal (Intel + Apple Silicon) | `ghv-macos-universal.zip` |
| Linux | x86_64 | `ghv-linux-amd64.tar.gz` |
| Linux | ARM64 | `ghv-linux-arm64.tar.gz` |

```bash
# macOS
curl -L https://github.com/melonamin/ghvault/releases/latest/download/ghv-macos-universal.zip -o ghv.zip
unzip ghv.zip && chmod +x ghv && sudo mv ghv /usr/local/bin/

# Linux (amd64)
curl -L https://github.com/melonamin/ghvault/releases/latest/download/ghv-linux-amd64.tar.gz | tar xz
chmod +x ghv-linux-amd64 && sudo mv ghv-linux-amd64 /usr/local/bin/ghv
```

### Go install

```bash
go install github.com/melonamin/ghvault/cmd/ghv@latest
```

### Build from source

```bash
git clone https://github.com/melonamin/ghvault.git
cd ghvault
just build # Requires the 'just' command runner
# or
go build -o ghv ./cmd/ghv
```

## Quick Start

### 1. Authenticate

Most setups should run the OAuth **device flow** once and let GHVault store the resulting token (keychain on desktops, encrypted config file on servers). Other options are available when you need non-interactive automation:

| Method | How to trigger | Pros | Considerations |
|--------|----------------|------|----------------|
| OAuth device flow *(recommended)* | `ghv login` or `ghv login --headless` | No PAT management, works for CLI/TUI, Docker surfaces codes via logs/API, tokens encrypted locally | Requires a one-time browser visit during setup, needs outbound access to GitHub |
| GitHub App installation | Configure `auth.github_app` + run `ghv backup` | Ideal for org-managed backups; scoped installation token without user interaction | Requires maintaining the app’s private key and installation ID |
| Personal access token | Set `GITHUB_TOKEN` or `auth.token` in config (classic or fine-grained PAT) | Works in CI or fully air-gapped environments, no interactive prompts | You must create and rotate the token yourself; scopes must cover repos/orgs/gists you back up |

```bash
# Interactive login (opens browser)
ghv login

# Headless login (for servers/Docker)
ghv login --headless
```

Tokens are stored securely in your system keychain. When that's unavailable (Docker, headless servers, CI), set `GHVAULT_SECRET` (32+ characters) before running GHVault. The CLI/server refuses to write the fallback `~/.config/ghvault/token.enc` unless this secret is present so the cached OAuth token remains encrypted. Example:

```bash
export GHVAULT_SECRET=$(openssl rand -base64 48)
```

### 2. Run your first backup

```bash
# Backup everything tied to your account
ghv backup

# Focus on a specific org or repo
ghv backup --org kubernetes
ghv backup --repo owner/repo

# Preview changes without writing data
ghv backup --dry-run
```

### 3. Pick an interface

Use whatever fits your workflow—CLI for automation, TUI for quick status checks, or Web UI for browser-based control. Details and navigation tips live in the [Interfaces](#interfaces) section below.

## Interfaces

### CLI

Perfect for cron jobs and scripting. A few staples:

```bash
ghv backup [username|org] [flags] # Run backups
ghv list repos --org example # Inspect repositories
ghv history log -n 10 # Recent backup runs
ghv status # Authentication state
```

For the full flag reference, see [CLI Reference](#cli-reference).

### TUI (Terminal UI)

`ghv tui` launches an interactive dashboard showing repositories, backup progress, and logs. Navigation shortcuts:
- `1` / `d` – Dashboard
- `2` / `r` – Repositories
- `3` / `b` – Backup view
- `4` / `l` – Logs
- `Tab` – Next view
- `q` – Quit

### Web UI

Start the web server with:

```bash
ghv serve # Default 127.0.0.1:8080
ghv serve --addr :3000 --open
```

Authenticate directly in the browser via **Sign in from this browser** if you haven’t logged in with the CLI.

- The server binds to `127.0.0.1` by default to keep the UI private on desktop machines.
- When binding to any other interface (e.g. `--addr :8080` inside Docker), set `server.password` (or `GHVAULT_SERVER_PASSWORD`) or GHVault will refuse to start. The password protects every page/API call.
- Always set `GHVAULT_SECRET` and `GHVAULT_SERVER_PASSWORD` in your shell (or service unit) before starting the server so the fallback token store remains encrypted:

```bash
export GHVAULT_SECRET=$(openssl rand -base64 48)
export GHVAULT_SERVER_PASSWORD='change-me'
ghv serve --addr :8080
```

## Advanced & Deployment

Use these references when tailoring GHVault to your environment.

### Docker deployment

#### Compose with persistence and optional scheduling

```yaml
services:
ghvault:
image: ghcr.io/melonamin/ghvault:latest
container_name: ghvault
restart: unless-stopped
ports:
- "8080:8080"
volumes:
- ghvault-backups:/home/ghvault/backups
- ghvault-config:/home/ghvault/.config/ghvault
environment:
GHVAULT_SERVER_PASSWORD: "please-change-me"
GHVAULT_SECRET: "generate-a-long-random-string"
GHVAULT_SCHEDULE_ENABLED: "true"
GHVAULT_SCHEDULE_CRON: "0 2 * * *" # Daily at 2 AM

volumes:
ghvault-backups:
ghvault-config:
```

Images are published as `latest` and `vX.Y.Z`, supporting both `linux/amd64` and `linux/arm64` architectures.

### Configuration

Default config path: `~/.config/ghvault/config.yaml`

```yaml
# Storage
storage:
output_directory: ./backups
structure: nested # or "flat"

# Backup filters
backup:
filters:
include_forks: false
include_archived: true
visibility: all

repository:
git:
enabled: true
bare: true
lfs: true
wiki: true

metadata:
issues: true
pull_requests: true
releases: true
release_assets: true
milestones: true
labels: true

attachments:
enabled: true
max_size_mb: 100

concurrency:
repos: 4
api_requests: 2

server:
address: "127.0.0.1:8080"
password: ""
trust_proxy: false

schedule:
enabled: false
cron: "0 2 * * *"

logging:
level: info
format: text
```

#### Environment variables

| Variable | Description |
|----------|-------------|
| `GHVAULT_CONFIG` | Path to config file |
| `GITHUB_TOKEN` | GitHub token (alternative auth) |
| `GHVAULT_SERVER_ADDRESS` | Web server bind address |
| `GHVAULT_SERVER_PASSWORD` | Protect the Web UI |
| `GHVAULT_SECRET` | Required when the OS keyring isn't available; encrypts the token file |
| `GHVAULT_SCHEDULE_ENABLED` | Enable scheduled backups |
| `GHVAULT_SCHEDULE_CRON` | Cron expression for the scheduler |

### Backup structure

```
backups/
├── owner/
│ ├── repo.git/ # Bare git repository
│ ├── repo.metadata.json # Issues, PRs, releases, etc.
│ ├── repo.manifest.json # Backup manifest
│ ├── repo.wiki.git/ # Wiki (if enabled)
│ └── repo.assets/ # Release assets
│ └── v1.0.0/
│ └── binary.tar.gz
└── gists/
└── abc123/
├── gist.git/ # Bare gist clone
└── gist.metadata.json
```

### CLI reference

#### `ghv backup`

```
Usage:
ghv backup [username] [flags]

Flags:
-o, --output string Output directory (default "./backups")
--structure string Directory structure: flat or nested (default "nested")
-j, --concurrency int Number of concurrent backups (default 4)
-n, --dry-run Show what would be backed up
--incremental Only backup repos changed since last backup

Repository Selection:
--org string Backup organization repositories
-r, --repo string Backup a single repo (owner/repo)
--gists Backup gists instead of repos
--starred Backup starred repositories

Filters:
--forks Include forked repos (default false)
--archived Include archived repos (default true)
--visibility string Filter: all, public, private (default "all")
--language string Filter by programming language

Git Options:
--bare Clone as bare repositories (default true)
--mirror Clone as mirror (includes all refs)

Metadata:
--issues Export issues (default true)
--prs Export pull requests (default true)
--releases Export releases (default true)
--labels Export labels (default true)
--milestones Export milestones (default true)
```

#### Other helpful commands

```bash
ghv list repos # List your repositories
ghv list repos octocat # User repositories
ghv list repos --org k8s # Organization repositories
ghv list orgs # Your organizations
ghv list gists # Your gists
ghv history log -n 10 # Last 10 backups
ghv history diff # Show changes between backup snapshots
ghv history restore
```

### Development

Prerequisites: Go 1.23+, [just](https://github.com/casey/just), [templ](https://templ.guide/), Docker with buildx for multi-arch builds.

```bash
just build # Build binary
just dev # Run web server in dev mode
just dev-tui # Run TUI in dev mode
just test # Run tests
just lint # Run linter
just fmt # Format code

just release # Build binaries (macOS signed + Linux)
just release-all # Build binaries + push Docker image
just docker-push # Push multi-arch Docker image to GHCR
```

## License

MIT License – see [LICENSE](LICENSE) for details.

## Contributing

Contributions are welcome! Please open issues or pull requests with improvements, features, or bug fixes.