GITFLARE Documentation

Introduction

Overview of GitFlare — self-hosted Git repository hosting.

GitFlare

Self-hosted Git repository hosting server — The Cinder Project | GPLv3

GitFlare is a lean, self-hosted Git server built in Python. It sits as a thin layer on top of Git’s own tooling — delegating all object storage and protocol handling to Git itself, while providing auth, repo management, and (eventually) a web UI on top.

What is GitFlare?

GitFlare is a self-hosted Git repository hosting server designed for personal and small-team use. It handles HTTP clone, fetch, and push via Git’s smart HTTP protocol, and provides SSH key authentication for secure access.

It is not a GitHub/GitLab replacement. GitFlare is a minimal, auditable Git server — no databases, no ORM, no unnecessary infrastructure. Just Git, Python, and your bare repos.

Philosophy

  • GitFlare never touches Git objects directly — all protocol handling is delegated to git http-backend and git-shell
  • Every line of code is auditable — no pre-compiled binaries, build from source recommended
  • Per-repo auth modes let you choose between SSH-only, token-only, or both
  • Tokens are never handled manually — the credential helper stores them in your system keychain
  • Designed to be lean, transparent, and free of unnecessary infrastructure

Features

HTTP Smart Protocol

Full clone, fetch, and push over HTTP using Git’s own http-backend. No proprietary protocols — just standard Git.

Token-Based Authentication

Per-repo access tokens with bcrypt hashing. Tokens are stored in your system keychain via the credential helper — no plaintext, no manual entry.

SSH Key Authentication

SSH key management via the admin CLI. Keys are added to authorized_keys with git-shell restriction for secure, passwordless access.

Per-Repo Auth Modes

Choose the auth mode for each repository:

  • ssh — SSH key auth only (recommended default)
  • token — HTTP token auth required for push
  • both — SSH or token auth accepted

Credential Helper

git-credential-gitflare stores tokens in your system keychain (libsecret on Linux, Keychain on macOS, Windows Credential Manager on Windows). Once logged in, every git clone/push/pull just works — no prompts.

Admin CLI

Full repo and token management from the command line:

  • Create, list, delete repos
  • Generate and revoke access tokens
  • Manage SSH keys

Lightweight

FastAPI + uvicorn, no database, no ORM, flat JSON metadata. Just bare Git repos with a gitflare.json file for auth configuration.

Quick Start

# Clone and install
git clone https://github.com/TheCinderProject/gitflare.git
cd gitflare
python -m venv .venv
source .venv/bin/activate
pip install -e .

# Start the server
uvicorn gitflare.main:app --host 0.0.0.0 --port 3000

# Create a repo
gitflare-admin repo create myproject --auth ssh

# Clone it
git clone http://localhost:3000/myproject.git

Requirements

  • Python 3.11+
  • Git installed on the system
  • pip for package installation

Roadmap

Version Scope
v0.1 HTTP clone/fetch/push, repo init, basic config, token infra
v0.2 HTTP push with token auth + credential helper + gitflare-admin login
v0.3 SSH key auth, per-repo auth mode selection
v0.4 Branch listing, multi-repo support, admin API
v0.5 Stable core — full push/pull/branch over HTTP + SSH
v1.0 Web UI — file browser, commit log, branch switcher

Made By

Owner/Main Developer: Sabeeir Sharrma

Maintainer/Assistant Developer: trigered02

Made under The Cinder ProjectMaking a safer internet


Installation

How to install GitFlare.

Installation

GitFlare runs on any system with Python 3.11+ and Git installed.

GitFlare is built transparently from source. No pre-compiled code is embedded in this repository.

Prerequisites

  • Python 3.11 or later
  • Git
  • pip

Install

git clone https://github.com/TheCinderProject/gitflare.git
cd gitflare
python -m venv .venv
source .venv/bin/activate
pip install -e .

This installs GitFlare in editable mode, so changes to the source code take effect immediately.

Verify Installation

gitflare --help
gitflare-admin --help

Pre-built Artifacts

Pre-built wheels and source distributions are available on the Releases page. While functional, building from source is the recommended and preferred method — it ensures full transparency and allows you to inspect the code before installation.

Install from wheel

pip install gitflare-0.3.0-py3-none-any.whl

Verify checksums

Every release includes sha256sums.txt for verification:

sha256sum -c sha256sums.txt

System Dependencies

GitFlare requires Git to be installed on the system. The git http-backend and git-shell commands must be available on PATH.

Debian/Ubuntu

sudo apt install git

Arch Linux

sudo pacman -S git

macOS

brew install git

Credential Helper (Optional)

The credential helper git-credential-gitflare is included in the repository. To make it available system-wide, copy it to a directory on your PATH:

cp git-credential-gitflare /usr/local/bin/
chmod +x /usr/local/bin/git-credential-gitflare

Or install via the package:

pip install -e .
# The helper is available as git-credential-gitflare in the venv

Next Steps


Configuration

Configuring GitFlare via gitflare.toml.

Configuration

GitFlare stores its configuration at gitflare.toml in the project root. The file is loaded on server startup.

Configuration File

[server]
host = "0.0.0.0"
port = 3000
repos_path = "/srv/gitflare/repos"

# Optional — only set if you want GitFlare to emit full clone URLs
# base_url = "https://git.yourdomain.com"

[auth]
admin_token = "your-secret-admin-token"

[ssh]
enabled = true
port = 2222
authorized_keys_path = "/srv/gitflare/authorized_keys"

Options

[server]

Key Type Default Description
host string "0.0.0.0" Address to bind the server to
port integer 3000 Port to listen on
repos_path string "/srv/gitflare/repos" Directory where bare Git repos are stored
base_url string None Optional base URL for emitting full clone URLs in API responses

host

The network address to bind to. Use "0.0.0.0" to listen on all interfaces, or "127.0.0.1" for local-only access.

port

The port the HTTP server listens on. Default is 3000.

repos_path

Directory where bare Git repositories are stored. Each repo is a subdirectory ending in .git (e.g., myproject.git). The directory is created automatically if it doesn’t exist.

base_url

Optional. If set, GitFlare will use this URL when generating clone URLs in admin API responses or the future web UI. If unset, GitFlare works purely locally with no absolute URL generation.

[auth]

Key Type Default Description
admin_token string "" Admin token for API access

admin_token

The admin token is used for Bearer authentication on admin API routes. In v0.4+, this will be required for all admin API calls.

For now, the admin token is used by gitflare-admin login to validate credentials before storing them.

[ssh]

Key Type Default Description
enabled boolean true Enable SSH support
port integer 2222 Port for the SSH server
authorized_keys_path string "/srv/gitflare/authorized_keys" Path to the authorized_keys file

enabled

Controls whether SSH support is enabled. When enabled, GitFlare manages the authorized_keys file for SSH key authentication.

port

The port for the SSH server. Since port 22 is typically used by the system SSH daemon, GitFlare uses port 2222 by default.

authorized_keys_path

Path to the authorized_keys file where SSH public keys are stored. GitFlare appends keys with git-shell restriction for security.

Environment Variables

GitFlare does not use environment variables for configuration. All configuration is in gitflare.toml.

Default Configuration

If no gitflare.toml file exists, GitFlare uses these defaults:

[server]
host = "0.0.0.0"
port = 3000
repos_path = "/srv/gitflare/repos"

[auth]
admin_token = ""

[ssh]
enabled = true
port = 2222
authorized_keys_path = "/srv/gitflare/authorized_keys"

Authentication

Token and SSH authentication in GitFlare.

Authentication

GitFlare supports two authentication methods: HTTP tokens and SSH keys. Each repository can be configured with one of three auth modes.

Auth Modes

Mode Clone/Fetch Push (HTTP) Push (SSH)
ssh Public 403 (use SSH) Key required
token Public Token required N/A
both Public Token required Key required

Set the auth mode when creating a repo:

gitflare-admin repo create myproject --auth ssh
gitflare-admin repo create myproject --auth token
gitflare-admin repo create myproject --auth both

Token Authentication

How It Works

  1. Admin generates a token for a repo: gitflare-admin token generate myproject
  2. Token is shown once — store it securely
  3. User runs gitflare-admin login http://yourhost:3000 — stores token in system keychain
  4. From then on, every git clone/push/pull just works — Git calls the credential helper automatically

Token Flow

git clone http://yourhost/myproject.git
  └─▶ git asks credential helper for http://yourhost
        └─▶ git-credential-gitflare get
              └─▶ keyring.get_password("gitflare:yourhost", username)
                    └─▶ returns token silently
                          └─▶ clone proceeds, no prompt

HTTP Basic Auth

GitFlare receives the token as HTTP Basic auth:

Authorization: Basic base64(gitflare:<token>)

The token is bcrypt-verified against the repo’s stored hash in gitflare.json.

Per-Repo Token Storage

Each repo stores its tokens in gitflare.json:

{
  "name": "myproject",
  "auth_mode": "token",
  "tokens": ["bcrypt_hashed_token_1", "bcrypt_hashed_token_2"],
  "ssh_keys": []
}

Tokens are bcrypt-hashed — the plaintext is never stored.

SSH Key Authentication

How It Works

  1. User submits public key: gitflare-admin ssh-key add "ssh-ed25519 AAAA..."
  2. Key is appended to authorized_keys with git-shell restriction
  3. Standard git clone git@host:repo.git flow — no credential prompts

SSH Key Management

# Add a key
gitflare-admin ssh-key add "ssh-ed25519 AAAA..."

# List keys
gitflare-admin ssh-key list

# Remove a key
gitflare-admin ssh-key remove <key_id>

authorized_keys Format

Each key is added with command restriction:

command="git-shell -c \"$SSH_ORIGINAL_COMMAND\"",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA...

This ensures:

  • The key can only execute git commands via git-shell
  • No port forwarding, X11 forwarding, or agent forwarding
  • The original command (e.g., git-upload-pack '/repo.git') is passed to git-shell

SSH Handler

git/ssh_handler.py validates SSH access and delegates to git-shell:

  1. Parses the SSH_ORIGINAL_COMMAND to extract the repo name
  2. Checks if the repo exists
  3. Validates the command is allowed (git-upload-pack, git-receive-pack)
  4. Delegates to git-shell for execution

Credential Helper

git-credential-gitflare

The credential helper stores tokens in your system keychain:

  • Linux: libsecret (GNOME Keyring, KWallet)
  • macOS: Keychain
  • Windows: Windows Credential Manager

How It Works

Git calls the helper as a subprocess with three actions:

Action Description
get Retrieve token from keychain
store Save token to keychain
erase Delete token from keychain

Manual Setup

The helper can be registered manually in ~/.gitconfig:

[credential "http://yourhost:3000"]
    helper = gitflare

Login/Logout

Use the admin CLI for one-time setup:

# Store token in keychain + register helper
gitflare-admin login http://yourhost:3000

# Remove from keychain + unregister helper
gitflare-admin logout http://yourhost:3000

Per-Repo Metadata

Each repo stores its configuration in gitflare.json:

{
  "name": "myproject",
  "auth_mode": "ssh",
  "tokens": ["bcrypt_hashed_token"],
  "ssh_keys": ["ssh-ed25519 AAAA..."]
}
Field Type Description
name string Repository name
auth_mode string "ssh", "token", or "both"
tokens list bcrypt-hashed access tokens
ssh_keys list Authorized SSH public keys

Admin CLI

Reference for the gitflare-admin command-line tool.

Admin CLI

gitflare-admin is the command-line tool for managing GitFlare repositories, tokens, and SSH keys.

Usage

gitflare-admin <command> [subcommand] [options]

Commands

Authentication

login

Store credentials for a GitFlare host in the system keychain.

gitflare-admin login <url>
Argument Description
url GitFlare server URL (e.g., http://yourhost:3000)

What it does:

  1. Prompts for a token (hidden input)
  2. Validates the token against the server
  3. Stores the token in the system keychain
  4. Registers git-credential-gitflare in ~/.gitconfig

Example:

$ gitflare-admin login http://yourhost:3000
Token: ████████████████
 Token stored in system keychain for yourhost:3000
 Registered git-credential-gitflare for http://yourhost:3000

logout

Remove credentials for a GitFlare host.

gitflare-admin logout <url>
Argument Description
url GitFlare server URL

Example:

$ gitflare-admin logout http://yourhost:3000
 Credentials removed from keychain for yourhost:3000
 Removed credential helper entry from ~/.gitconfig

Repository Management

repo create

Create a new bare Git repository.

gitflare-admin repo create <name> [--auth ssh|token|both]
Argument Description
name Repository name
--auth Auth mode (default: ssh)

Example:

$ gitflare-admin repo create myproject --auth ssh
 Repository 'myproject' created at /srv/gitflare/repos/myproject.git
  Auth mode: ssh

repo list

List all repositories with their auth modes.

gitflare-admin repo list

Example:

$ gitflare-admin repo list
Repositories:
  - myproject (auth: ssh)
  - cpac (auth: token)

repo delete

Delete a repository.

gitflare-admin repo delete <name>
Argument Description
name Repository name

Example:

$ gitflare-admin repo delete myproject
 Repository 'myproject' deleted

Token Management

token generate

Generate an access token for a repository.

gitflare-admin token generate <repo>
Argument Description
repo Repository name

Example:

$ gitflare-admin token generate myproject
 Token generated for 'myproject'
  Token: af539193f3331eade5f059c7d35e46255823ba613baaef27e294a132b651c8dd
  Store this securely. It will not be shown again.

Important: The token is shown only once. Store it securely.

token revoke

Revoke all tokens for a repository.

gitflare-admin token revoke <repo>
Argument Description
repo Repository name

Example:

$ gitflare-admin token revoke myproject
 Revoked 2 token(s) for 'myproject'

SSH Key Management

ssh-key add

Add an SSH public key to the authorized_keys file.

gitflare-admin ssh-key add "<public_key>"
Argument Description
public_key SSH public key (e.g., ssh-ed25519 AAAA...)

Example:

$ gitflare-admin ssh-key add "ssh-ed25519 AAAA..."
 SSH key added (ID: a1b2c3d4e5f6)

ssh-key list

List all SSH keys.

gitflare-admin ssh-key list

Example:

$ gitflare-admin ssh-key list
SSH Keys:
  [a1b2c3d4e5f6] ssh-ed25519 user@host
  [f6e5d4c3b2a1] ssh-rsa user@machine

ssh-key remove

Remove an SSH key by ID.

gitflare-admin ssh-key remove <key_id>
Argument Description
key_id Key ID (from ssh-key list)

Example:

$ gitflare-admin ssh-key remove a1b2c3d4e5f6
 SSH key a1b2c3d4e5f6 removed

Exit Codes

Code Description
0 Success
1 Error (invalid arguments, not found, auth failed)

Examples

Complete Workflow

# 1. Create a repo with token auth
gitflare-admin repo create myproject --auth token

# 2. Generate a token
gitflare-admin token generate myproject

# 3. On the client machine, login
gitflare-admin login http://yourhost:3000

# 4. Clone and push — just works
git clone http://yourhost:3000/myproject.git
cd myproject
echo "hello" > README.md
git add . && git commit -m "init" && git push origin master

SSH Workflow

# 1. Create a repo with SSH auth
gitflare-admin repo create myproject --auth ssh

# 2. Add your SSH key
gitflare-admin ssh-key add "ssh-ed25519 AAAA..."

# 3. Clone via SSH
git clone ssh://git@yourhost:2222/myproject.git

Architecture

How GitFlare works internally.

Architecture

GitFlare is designed as a thin layer on top of Git’s own tooling. It never touches Git objects directly — all protocol handling is delegated to git http-backend (for HTTP) and git-shell (for SSH).

Overview

                        ┌─────────────────────────────┐
  git push/pull/clone   │         GitFlare             │
─────────────────────▶  │        (FastAPI)             │
  over HTTP or SSH       │                             │
                        │  ┌──────────┐  ┌─────────┐  │
                        │  │ Auth     │  │  Admin  │  │
                        │  │ Layer    │  │  API    │  │
                        │  └────┬─────┘  └────┬────┘  │
                        │       │              │       │
                        │  ┌────▼─────────────▼────┐  │
                        │  │     git http-backend   │  │
                        │  │     (subprocess/CGI)   │  │
                        │  └────────────┬───────────┘  │
                        │               │              │
                        │  ┌────────────▼───────────┐  │
                        │  │   /repos/<name>.git    │  │
                        │  │   (bare git repos)     │  │
                        │  └────────────────────────┘  │
                        └─────────────────────────────┘

SSH path:
  git@host:repo.git  ──▶  sshd  ──▶  git-shell  ──▶  /repos/<name>.git

HTTP Protocol

Smart HTTP Endpoints

Git’s smart HTTP protocol uses four endpoints:

GET  /repo.git/info/refs?service=git-upload-pack   # clone/fetch
POST /repo.git/git-upload-pack                      # clone/fetch data
GET  /repo.git/info/refs?service=git-receive-pack  # push
POST /repo.git/git-receive-pack                    # push data

Request Flow

  1. Git client sends request to GitFlare
  2. GitFlare extracts the repo name from the path
  3. Auth check:
    • For push: verify token if auth_mode is "token" or "both"
    • For push: return 403 if auth_mode is "ssh"
    • For clone/fetch: always allowed (public read)
  4. GitFlare pipes the request to git http-backend via subprocess
  5. git http-backend processes the request and returns a CGI response
  6. GitFlare parses the CGI response and returns it to the client

Git HTTP Backend Wrapper

gitflare/git/backend.py handles the subprocess communication:

env = {
    "GIT_PROJECT_ROOT": repos_path,
    "GIT_HTTP_EXPORT_ALL": "1",
    "PATH_INFO": f"/{repo_path}",
    "REQUEST_METHOD": request.method,
    "QUERY_STRING": str(request.url.query),
    "CONTENT_TYPE": request.headers.get("content-type", ""),
}

proc = subprocess.Popen(
    ["git", "http-backend"],
    env=env,
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE
)

stdout, stderr = proc.communicate(input=body)
return parse_cgi_response(stdout)

CGI Response Parsing

git http-backend outputs CGI format:

Status: 200 OK
Content-Type: application/x-git-upload-pack-advertisement

<binary data>

GitFlare splits on \r\n\r\n to separate headers from the binary body.

SSH Protocol

How SSH Works

git@host:repo.git  ──▶  sshd  ──▶  git-shell  ──▶  /repos/<name>.git
  1. SSH client connects to the server
  2. sshd matches the key against authorized_keys
  3. The forced command (git-shell -c "$SSH_ORIGINAL_COMMAND") is executed
  4. git-shell receives the original command (e.g., git-upload-pack '/repo.git')
  5. git-shell validates and executes the git command on the bare repo

authorized_keys Format

Each key is added with command restriction:

command="git-shell -c \"$SSH_ORIGINAL_COMMAND\"",no-port-forwarding,no-X11-forwarding,no-agent-forwarding ssh-ed25519 AAAA...

This ensures:

  • The key can only execute git commands
  • No port forwarding, X11 forwarding, or agent forwarding
  • The original command is passed to git-shell

SSH Handler

gitflare/git/ssh_handler.py validates SSH access:

  1. Parses SSH_ORIGINAL_COMMAND to extract the repo name
  2. Checks if the repo exists
  3. Validates the command is allowed
  4. Delegates to git-shell

Project Structure

gitflare/
├── gitflare/
│   ├── main.py               # FastAPI app entrypoint
│   ├── config.py             # Loads gitflare.toml
│   ├── models.py             # Pydantic models
│   ├── auth/
│   │   ├── tokens.py         # Token generation & bcrypt hashing
│   │   └── ssh.py            # SSH key management
│   ├── git/
│   │   ├── backend.py        # Wraps git http-backend via subprocess
│   │   ├── repo.py           # Repo init, delete, list, metadata
│   │   └── ssh_handler.py    # git-shell integration
│   └── routes/
│       ├── git_http.py       # Smart HTTP protocol routes + token auth
│       └── admin.py          # Admin API (/admin/auth/verify)
├── git-credential-gitflare    # Git credential helper
├── gitflare.toml              # Config file
├── pyproject.toml
└── SPEC.md

Key Principles

  1. No Git object manipulation — GitFlare delegates to git http-backend and git-shell
  2. Minimal dependencies — FastAPI, uvicorn, bcrypt, keyring. No ORM, no database.
  3. Flat file storage — Each repo has a gitflare.json for metadata. No SQLite until v0.3 if needed.
  4. Transparent — Every line of code is auditable. Build from source recommended.

Deployment

Deploying GitFlare to a VPS.

Deployment

GitFlare is designed to run on a VPS with minimal setup. This guide covers systemd, Caddy reverse proxy, and SSH configuration.

Prerequisites

  • A VPS running Linux (Ubuntu, Debian, Arch, etc.)
  • Python 3.11+ installed
  • Git installed
  • A domain name pointed at your VPS

1. Install GitFlare

# On the VPS
git clone https://github.com/TheCinderProject/gitflare.git /opt/gitflare
cd /opt/gitflare
python -m venv .venv
source .venv/bin/activate
pip install -e .

2. Configure

Edit /opt/gitflare/gitflare.toml:

[server]
host = "0.0.0.0"
port = 3000
repos_path = "/srv/gitflare/repos"
base_url = "https://git.yourdomain.com"

[auth]
admin_token = "your-secret-admin-token"

[ssh]
enabled = true
port = 2222
authorized_keys_path = "/srv/gitflare/authorized_keys"

Generate a secure admin token:

python3 -c "import secrets; print(secrets.token_hex(32))"

3. Create Directories

sudo mkdir -p /srv/gitflare/repos
sudo useradd -r -s /bin/false gitflare
sudo chown -R gitflare:gitflare /srv/gitflare
sudo chown -R gitflare:gitflare /opt/gitflare

4. systemd Service

Create /etc/systemd/system/gitflare.service:

[Unit]
Description=GitFlare Git Server
After=network.target

[Service]
Type=simple
User=gitflare
WorkingDirectory=/opt/gitflare
ExecStart=/opt/gitflare/.venv/bin/uvicorn gitflare.main:app --host 0.0.0.0 --port 3000
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl daemon-reload
sudo systemctl enable gitflare
sudo systemctl start gitflare

Check status:

sudo systemctl status gitflare

5. Caddy Reverse Proxy

Install Caddy:

# Debian/Ubuntu
sudo apt install caddy

# Arch
sudo pacman -S caddy

Edit /etc/caddy/Caddyfile:

git.yourdomain.com {
    reverse_proxy localhost:3000
}

Caddy automatically handles HTTPS via Let’s Encrypt.

Restart Caddy:

sudo systemctl restart caddy

6. SSH Configuration

Since the system SSH daemon is likely on port 22, run GitFlare’s SSH on port 2222.

Configure sshd

Edit /etc/ssh/sshd_config:

# Add GitFlare's authorized_keys
Match User gitflare
    AuthorizedKeysFile /srv/gitflare/authorized_keys

Restart sshd:

sudo systemctl restart sshd

Client Configuration

Users connect via SSH on port 2222:

git clone ssh://git@yourdomain.com:2222/myproject.git

Or add to ~/.ssh/config:

Host gitflare
    HostName yourdomain.com
    Port 2222
    User git

Then:

git clone gitflare:myproject.git

7. First Use

# On the server
gitflare-admin repo create myproject --auth ssh
gitflare-admin token generate myproject

# On the client
git clone https://git.yourdomain.com/myproject.git
# or
git clone ssh://git@yourdomain.com:2222/myproject.git

Firewall

Ensure these ports are open:

Port Protocol Service
80 TCP HTTP (Caddy)
443 TCP HTTPS (Caddy)
2222 TCP SSH (GitFlare)

ufw

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 2222/tcp
sudo ufw enable

firewalld

sudo firewall-cmd --permanent --add-port=80/tcp
sudo firewall-cmd --permanent --add-port=443/tcp
sudo firewall-cmd --permanent --add-port=2222/tcp
sudo firewall-cmd --reload

Troubleshooting

Server won’t start

Check logs:

sudo journalctl -u gitflare -f

Can’t clone via HTTP

  • Check if GitFlare is running: curl http://localhost:3000/
  • Check Caddy config: sudo systemctl status caddy
  • Check firewall: sudo ufw status

Can’t clone via SSH

  • Check if the key is in authorized_keys: gitflare-admin ssh-key list
  • Check sshd config: sudo systemctl status sshd
  • Test SSH: ssh -p 2222 git@yourdomain.com

Permission denied

  • Check repo ownership: ls -la /srv/gitflare/repos/
  • Check gitflare.toml paths
  • Check systemd user: User=gitflare in the service file

Port Forwarding

Exposing GitFlare through NAT, tunnels, and reverse proxies.

Port Forwarding

If your GitFlare instance runs behind NAT (home server, VPS without public IP, etc.), you need a way to expose it to the internet. This guide covers several approaches.

Quick Reference

Method Best For Requires Public IP Difficulty
Router Port Forwarding Home servers with static IP Yes Easy
Cloudflare Tunnel Anyone with a domain No Easy
FRP Self-hosted reverse proxy Yes (on server) Medium
Reverse SSH Tunnel Quick temporary access Yes (on server) Medium
Tailscale Private networks, dev No Easy
ngrok Testing only No Easy

1. Router Port Forwarding

The simplest method if you have a public IP and can configure your router.

Setup

  1. Log into your router (usually 192.168.1.1 or 192.168.0.1)
  2. Find “Port Forwarding” or “Virtual Server” settings
  3. Add rules:
Service External Port Internal IP Internal Port Protocol
GitFlare HTTP 443 (or 80) 192.168.1.x 3000 TCP
GitFlare SSH 2222 192.168.1.x 2222 TCP
  1. Save and apply

DNS

Point your domain to your public IP:

git.yourdomain.com  →  YOUR_PUBLIC_IP

Behind CGNAT?

If your ISP uses CGNAT (you get a 10.x.x.x or 100.x.x.x public IP), port forwarding won’t work. Use one of the tunnel methods below.


2. Cloudflare Tunnel

Recommended. Free, secure, no public IP needed. Works behind NAT/CGNAT.

Prerequisites

  • A Cloudflare account
  • A domain added to Cloudflare
  • cloudflared installed

Install cloudflared

# Debian/Ubuntu
curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o cloudflared.deb
sudo dpkg -i cloudflared.deb

# Arch
sudo pacman -S cloudflared

# macOS
brew install cloudflare/cloudflare/cloudflared

Authenticate

cloudflared tunnel login

This opens a browser. Select your domain.

Create a tunnel

cloudflared tunnel create gitflare

Note the tunnel ID from the output.

Configure

Create ~/.cloudflared/config.yml:

tunnel: <TUNNEL_ID>
credentials-file: /home/user/.cloudflared/<TUNNEL_ID>.json

ingress:
  - hostname: git.yourdomain.com
    service: http://localhost:3000
  - service: http_status:404

Route DNS

cloudflared tunnel route dns gitflare git.yourdomain.com

Run the tunnel

cloudflared tunnel run gitflare

Run as service

sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared

SSH over Cloudflare Tunnel

Cloudflare Tunnels can also proxy SSH. Add to your config:

ingress:
  - hostname: git.yourdomain.com
    service: http://localhost:3000
  - hostname: ssh.yourdomain.com
    service: ssh://localhost:2222
  - service: http_status:404

Then configure your SSH client (~/.ssh/config):

Host gitflare
    HostName ssh.yourdomain.com
    User git
    ProxyCommand cloudflared access ssh --hostname %h

3. FRP (Fast Reverse Proxy)

Self-hosted reverse proxy. Requires a VPS with a public IP.

Architecture

Home Server (NAT)  ──▶  frpc  ──▶  VPS (public IP)  ──▶  Internet
                                    frps

Setup on VPS (server)

Install frps:

# Download
wget https://github.com/fatedier/frp/releases/download/v0.61.1/frp_0.61.1_linux_amd64.tar.gz
tar xzf frp_0.61.1_linux_amd64.tar.gz
cd frp_0.61.1_linux_amd64

# Install
sudo cp frps /usr/local/bin/
sudo mkdir -p /etc/frp

Create /etc/frp/frps.toml:

bindPort = 7000
auth.token = "your-secret-token"

Create systemd service /etc/systemd/system/frps.service:

[Unit]
Description=FRP Server
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/frps -c /etc/frp/frps.toml
Restart=on-failure

[Install]
WantedBy=multi-user.target

Start:

sudo systemctl enable frps
sudo systemctl start frps

Setup on Home Server (client)

Install frpc:

# Same download as above, but use frpc binary
sudo cp frpc /usr/local/bin/

Create /etc/frp/frpc.toml:

serverAddr = "your-vps-ip.com"
serverPort = 7000
auth.token = "your-secret-token"

[[proxies]]
name = "gitflare-http"
type = "tcp"
localIP = "127.0.0.1"
localPort = 3000
remotePort = 80

[[proxies]]
name = "gitflare-ssh"
type = "tcp"
localIP = "127.0.0.1"
localPort = 2222
remotePort = 2222

Start:

frpc -c /etc/frp/frpc.toml

DNS

Point your domain to the VPS:

git.yourdomain.com  →  VPS_PUBLIC_IP

4. Reverse SSH Tunnel

Quick and temporary. Requires a VPS with a public IP.

Setup

On your home server, run:

ssh -R 0.0.0.0:80:localhost:3000 -R 0.0.0.0:2222:localhost:2222 user@your-vps.com -N

This forwards:

  • VPS port 80 → Home server port 3000 (GitFlare HTTP)
  • VPS port 2222 → Home server port 2222 (GitFlare SSH)

Make it persistent

Use autossh for automatic reconnection:

sudo apt install autossh

autossh -M 0 -f -N -R 0.0.0.0:80:localhost:3000 -R 0.0.0.0:2222:localhost:2222 user@your-vps.com

Systemd service

Create /etc/systemd/system/gitflare-tunnel.service:

[Unit]
Description=GitFlare Reverse SSH Tunnel
After=network.target

[Service]
Type=simple
User=gitflare
ExecStart=/usr/bin/autossh -M 0 -N -R 0.0.0.0:80:localhost:3000 -R 0.0.0.0:2222:localhost:2222 user@your-vps.com
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

VPS sshd config

On the VPS, ensure /etc/ssh/sshd_config allows binding to privileged ports:

GatewayPorts yes

5. Tailscale

Mesh VPN. Best for private networks or development. No public IP needed.

Install Tailscale

# Debian/Ubuntu
curl -fsSL https://tailscale.com/install.sh | sh

# Arch
sudo pacman -S tailscale

# macOS
brew install tailscale

Start Tailscale

sudo tailscale up

Follow the auth URL to log in.

Install on all devices

Install Tailscale on both the server running GitFlare and your client machines.

Access GitFlare

Get the Tailscale IP of your GitFlare server:

tailscale ip -4
# Example output: 100.64.0.1

Clone using the Tailscale IP:

git clone http://100.64.0.1:3000/myproject.git

Custom DNS (optional)

In the Tailscale admin console, you can set a custom domain name for your device. Then use:

git clone http://gitflare:3000/myproject.git

Tailscale Funnel (public access)

To expose GitFlare publicly through Tailscale:

sudo tailscale funnel --bg 3000

This gives you a public URL like https://your-device.tail12345.ts.net.


6. ngrok

Quick testing only. Not recommended for production.

Install ngrok

# Debian/Ubuntu
curl -s https://bin.equinox.io/c/bNyj1mQVY4c/ngrok-v3-stable-linux-amd64.tgz | sudo tar -xz -C /usr/local/bin

# Arch
sudo pacman -S ngrok

Authenticate

ngrok config add-authtoken YOUR_TOKEN

Run

ngrok http 3000

ngrok gives you a public URL like https://abc123.ngrok-free.app.

Use with GitFlare

git clone https://abc123.ngrok-free.app/myproject.git

For production with a domain:

  1. Cloudflare Tunnel — easiest, free, no public IP needed
  2. Router port forwarding — if you have a static public IP
  3. FRP — if you want full control and have a VPS

For development/testing:

  1. Tailscale — private, secure, zero config
  2. ngrok — quick and dirty for testing

Troubleshooting

Connection refused

  • Check if GitFlare is running: curl http://localhost:3000/
  • Check firewall: sudo ufw status or sudo iptables -L
  • Check tunnel status (if using)

DNS not resolving

  • Check DNS propagation: dig git.yourdomain.com
  • Wait for DNS TTL (usually 5-15 minutes)

SSH connection fails

  • Ensure port 2222 is open on all firewalls
  • Check SSH config: ssh -vvv -p 2222 git@yourdomain.com
  • Verify authorized_keys has the correct key

Cloudflare Tunnel 502 error

  • Ensure GitFlare is running and responding on localhost:3000
  • Check cloudflared logs: journalctl -u cloudflared -f
  • Verify the tunnel config points to the correct port