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-backendandgit-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 pushboth— 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 Project — Making a safer internet
Installation
How to install GitFlare.
Installation
GitFlare runs on any system with Python 3.11+ and Git installed.
Building from Source (Recommended)
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 — configure
gitflare.toml - Authentication — set up token or SSH auth
- Deployment — deploy to a VPS
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
- Admin generates a token for a repo:
gitflare-admin token generate myproject - Token is shown once — store it securely
- User runs
gitflare-admin login http://yourhost:3000— stores token in system keychain - From then on, every
git clone/push/pulljust 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
- User submits public key:
gitflare-admin ssh-key add "ssh-ed25519 AAAA..." - Key is appended to
authorized_keyswithgit-shellrestriction - Standard
git clone git@host:repo.gitflow — 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:
- Parses the
SSH_ORIGINAL_COMMANDto extract the repo name - Checks if the repo exists
- Validates the command is allowed (
git-upload-pack,git-receive-pack) - Delegates to
git-shellfor 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:
- Prompts for a token (hidden input)
- Validates the token against the server
- Stores the token in the system keychain
- Registers
git-credential-gitflarein~/.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
- Git client sends request to GitFlare
- GitFlare extracts the repo name from the path
- Auth check:
- For push: verify token if
auth_modeis"token"or"both" - For push: return 403 if
auth_modeis"ssh" - For clone/fetch: always allowed (public read)
- For push: verify token if
- GitFlare pipes the request to
git http-backendvia subprocess git http-backendprocesses the request and returns a CGI response- 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
- SSH client connects to the server
sshdmatches the key againstauthorized_keys- The forced command (
git-shell -c "$SSH_ORIGINAL_COMMAND") is executed git-shellreceives the original command (e.g.,git-upload-pack '/repo.git')git-shellvalidates 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:
- Parses
SSH_ORIGINAL_COMMANDto extract the repo name - Checks if the repo exists
- Validates the command is allowed
- 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
- No Git object manipulation — GitFlare delegates to
git http-backendandgit-shell - Minimal dependencies — FastAPI, uvicorn, bcrypt, keyring. No ORM, no database.
- Flat file storage — Each repo has a
gitflare.jsonfor metadata. No SQLite until v0.3 if needed. - 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.tomlpaths - Check systemd user:
User=gitflarein 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
- Log into your router (usually
192.168.1.1or192.168.0.1) - Find “Port Forwarding” or “Virtual Server” settings
- 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 |
- 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
cloudflaredinstalled
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
Recommended Setup
For production with a domain:
- Cloudflare Tunnel — easiest, free, no public IP needed
- Router port forwarding — if you have a static public IP
- FRP — if you want full control and have a VPS
For development/testing:
- Tailscale — private, secure, zero config
- ngrok — quick and dirty for testing
Troubleshooting
Connection refused
- Check if GitFlare is running:
curl http://localhost:3000/ - Check firewall:
sudo ufw statusorsudo 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_keyshas 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