Skip to content

melonamin/ghvault

Repository files navigation

GHVault

Release Go Version License Docker Image Go Reference Go Report Card

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

  • 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:

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:

docker exec -it ghvault ghv login --headless

Need compose files, scheduling, or alternative ports? See Advanced & Deployment.

Download binary

Grab the latest release from GitHub 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
# 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

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

Build from source

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
# 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:

export GHVAULT_SECRET=$(openssl rand -base64 48)

2. Run your first backup

# 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 section below.

Interfaces

CLI

Perfect for cron jobs and scripting. A few staples:

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.

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:

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:
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

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

# 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

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 <commit>   # Show changes between backup snapshots
ghv history restore <commit> <path>

Development

Prerequisites: Go 1.23+, just, templ, Docker with buildx for multi-arch builds.

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 for details.

Contributing

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

About

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

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors