Skip to content

nuricanozturk01/gitnode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation


Β GitNode

A simple, self-hosted Git registry β€” your code, your server, your rules.


Release Java Go Spring Boot Angular Tailwind CSS PostgreSQL Redis Prometheus Grafana Docker License


✨ Features Β· πŸ›  Tech Stack Β· πŸš€ Getting Started Β· πŸ“„ License



πŸ” What is GitNode?

GitNode is a simple, open-source, self-hosted Git registry inspired by GitHub. It gives you full control over your repositories, pull requests, and CI/CD pipelines (YAML workflows + self-hosted runner agent) β€” running entirely on your own infrastructure, with zero dependency on third-party platforms.

No subscriptions. No data leaving your servers. No vendor lock-in. Just Git, hosted your way.

GitNode is built for developers and teams who care about ownership β€” whether you're an indie developer running it on a VPS, or an enterprise team deploying it on private infrastructure. If you've ever thought "I wish GitHub ran on my own server", GitNode is for you.


✨ Features

GitNode covers the full Git hosting loop β€” repos, review, browsing, issues, project boards, releases, webhooks, code snippets, and collaborator access β€” plus CI/CD Actions (YAML workflows + Go runner agent), AI code review, commit suggestions, PR description generation, and codebase analysis (OpenAI / Anthropic / Gemini / Ollama), enterprise SAML/LDAP SSO, platform admin tooling, rate limiting, Prometheus/Grafana observability, and audit logging β€” all on your own infrastructure.

πŸ“ Repository Management πŸ‘€ Public Profiles πŸ“₯ GitHub Migration
πŸ—‚ Code Browsing πŸ”€ Pull Requests πŸ› Issues
πŸ“‹ Project Boards πŸ“ Code Snippets 🏷 Tags & Releases
πŸ”” Webhooks πŸ” Authentication πŸ‘₯ Collaborators
🍴 Repository Forks πŸ›‘ Access Policies 🏒 Enterprise SSO
πŸ“Š Admin Panel ⚑ Rate Limiting πŸ“ˆ Observability
πŸ“œ Audit Logging ⚑ Actions πŸ€– AI Features

πŸ“ Repository Management

  • Create, clone, push, and pull repositories
  • Public and private repositories, descriptions, and topics
  • Git over HTTP and HTTPS (TLS): smart HTTP backend at /git/… β€” use http:// or https:// remote URLs with your GitNode host
  • SSH Git on a configurable port (default 2222 in Docker)
  • Per-repo Settings: general metadata, optional auto-delete head branch after PR merge or close

πŸ‘€ Public Profile

  • Every account has a public profile at /:username showing public repositories
  • Optional profile README rendered from the account's special repository
  • Paginated public repository list

πŸ“₯ GitHub Repository Migration

  • Migrate from GitHub with a repository URL and personal access token (classic or fine-grained with repo read)
  • Mirror clone the Git history into your GitNode account
  • Optionally migrate pull requests from GitHub in the same job

πŸ—‚ Code Browsing

  • File tree with breadcrumbs; blob viewer and raw file URLs
  • Markdown README on the repo home (images and relative links resolved like on GitHub)
  • Commit history and diffs

πŸ”€ Pull Requests

  • Open, review, merge, or close PRs
  • Merge strategies: merge commit, squash, rebase
  • Draft PRs, inline discussion, file-level comments

πŸ› Issues

  • Track bugs and feature requests per repository
  • Labels, comments, open/close status
  • Link issues to Kanban tasks β€” resolving a PR can auto-complete linked tasks

πŸ“‹ Project Management (Kanban)

  • Projects with boards and configurable columns (per-project)
  • Tasks and subtasks with types, status, assignee, and ordering
  • Create Git branches from a task or subtask (conventional branch names, e.g. TASK-1 or TASK-1.SUB-1-…)
  • Link a branch's pull request to the task or subtask; see PR status on the card
  • Optional automation (per project): when a linked PR is merged, mark the task or subtask completed
  • Project settings page for the above PR β†’ status behaviour
  • Projects linked to a repository are paginated in the repo's Projects tab

πŸ“ Code Snippets (Gist-like)

  • Create public or private snippets with syntax-highlighted code blocks
  • Multi-file support per snippet
  • Full revision history β€” track edits and diff between revisions
  • Fork any public snippet
  • Paginated snippets per repository in the repo's Snippets tab
  • Manage all your snippets from the Snippets section in the app bar

πŸ”” Webhooks

  • Signed HTTP delivery (X-Hub-Signature-256) to your services for pushes, PR events, and more
  • Automatic retries (3 attempts, exponential back-off) on delivery failure
  • Dead-letter queue (DLQ) β€” permanently failed deliveries are queued and retried on a schedule; admin can inspect and replay from the admin panel
  • Per-host circuit breaker (Resilience4j) β€” when a target endpoint fails repeatedly the circuit opens; subsequent deliveries go straight to the DLQ instead of burning retries; circuit auto-recovers when the endpoint comes back
  • Configured per-repository in Settings β†’ Webhooks

🏷 Tags & Releases

  • Create lightweight and annotated tags on any commit via the UI
  • Draft or publish releases tied to a tag β€” write release notes with Markdown
  • Upload release assets (binaries, archives, checksums) directly from the browser
  • Browse all releases in the repo's Releases tab; latest release shown on the repo home
  • Delete releases or tags from the UI (tag is removed from the underlying Git repo)
  • Release badge on the repo home shows the latest published version at a glance

πŸ‘₯ Collaborators

  • Invite other GitNode users to your repository with fine-grained per-permission roles
  • Available permissions (each toggled independently): Push, Pull Request management, Issue management, * Settings access*, Admin (all permissions)
  • Share an invite link with a configurable expiry β€” recipient accepts via the link, no admin approval needed
  • Manage active collaborators and revoke access at any time from Settings β†’ Collaborators
  • Collaborators inherit the base repo visibility β€” private repos remain private to non-collaborators
  • How to invite: go to your repository β†’ Settings β†’ Collaborators β†’ Invite β†’ pick permissions β†’ copy the generated link and send it to the person you want to add

🍴 Repository Forks

  • Fork any public repository to your own account with a single click
  • Fork preserves the full commit history of the upstream repo at the time of forking
  • Work on your fork independently β€” push branches, open issues, create snippets
  • Open a pull request from your fork back to the upstream repository to propose changes
  • How to fork: navigate to any public repository β†’ click Fork in the top-right area of the repo header

πŸ›‘ Repo Access Policies

  • Define access rules per repository that apply on top of base visibility
  • Policies control what authenticated (non-owner, non-collaborator) users can do β€” e.g. allow public read but restrict push, or allow fork but restrict issue creation
  • Useful for organizations that want open-source-style read access without enabling arbitrary contributions
  • Configured in Settings β†’ Access Policies; changes take effect immediately for all subsequent requests

⚑ Actions β€” CI/CD

  • YAML workflow definitions checked in at .gitnode/workflows/*.yml β€” push, pull_request, and workflow_dispatch triggers
  • Job graph with matrix strategy expansion and needs dependency ordering; concurrency groups with cancellation
  • Runner protocol: runners register via token, receive jobs over WebSocket, report step logs and status back to the server
  • Shell and Docker executors β€” built-in actions/checkout@v1 step; custom run steps execute in a per-job workspace
  • Secrets vault β€” AES-256-GCM encrypted secrets per repo; injected as env vars at job runtime (masked in logs)
  • Artifact store β€” upload/download artifacts by run + name; retained per run
  • Cache store β€” key-based cache for workflow dependencies
  • SSE log streaming β€” real-time step logs via Server-Sent Events ( GET /api/repos/{owner}/{repo}/actions/runs/{runId}/events)
  • Run history β€” list, cancel, and re-run workflows from the UI
  • Runner management β€” register, list, delete runners per repo; runner groups per org
  • Admin panel Actions tab β€” platform-wide runner stats, workflow run counts

Go runner (gitnode-runner/)

Standalone agent that connects to the server. Single static binary (~12 MB), no JRE needed.

cd gitnode-runner
make build         # dist/gitnode-runner (local arch)
make build-all     # Linux amd64/arm64, macOS arm64, Windows amd64

./dist/gitnode-runner start \
  --server-url http://gitnode.company.com \
  --token ghrt_xxxxxxxxxxxx \
  --name my-runner \
  --labels self-hosted,linux,docker \
  --executor docker \       # or: shell
  --work-dir /tmp/gitnode-runner \
  --concurrent-jobs 2

Config file (~/.gitnode-runner/config.yml) is written automatically after first registration β€” subsequent starts use runner_token from that file.

🏒 Enterprise SAML & LDAP SSO

  • Per-organization identity β€” map email domains to a SAML 2.0 IdP or corporate LDAP directory
  • SAML 2.0 service provider β€” metadata URI, connection test, cached IdP XML, SP entity ID override
  • LDAP directory auth β€” manager bind, user search base/filter, email and display-name attributes, optional group mapping
  • Work-email login flow β€” users enter work email on the login page; GitNode routes to the correct org and provisions accounts on first successful sign-in
  • Mutually exclusive per org β€” SAML and LDAP cannot both be enabled on the same organization
  • Configure in the admin panel (gitnode-admin-panel, port 4300 in local dev)

πŸ“Š Admin Panel

Features when enabled:

  • Dashboard β€” users, repositories, organizations, storage; activity tables (daily/weekly); top contributors; cached stats
  • Users β€” search, enable/disable accounts
  • Organizations β€” create, edit, delete; configure SAML or LDAP per org; test connections before enabling
  • Audit log API β€” query application audit events (GET /api/admin/audit-logs)

See gitnode-admin-panel/README.md for setup. Platform admin access needs bootstrap credentials (see Environment Variables in README).

⚑ Rate Limiting

  • Redis-backed sliding-window limits on sensitive endpoints
  • Covers authentication (login, register, password recovery), repo/PR/issue creation, webhooks, tags, snippets, and SSO/LDAP discovery
  • Returns 429 with rateLimitExceeded when limits are hit

πŸ“ˆ Prometheus & Grafana Observability

Optional. Monitoring containers are not started by default β€” run make monitoring when needed.

  • Micrometer metrics exported at /actuator/prometheus (toggle with GITNODE_OBSERVABILITY_ENABLED)
  • Docker Compose profile monitoring β€” Prometheus (9090) and Grafana (3000, admin / admin)
  • See monitoring/README.md for setup
  • Scrape targets: app container (gitnode:8080) or host-run backend (host.docker.internal:8080)
  • Circuit breaker health at /actuator/circuitbreakers β€” real-time CLOSED / OPEN / HALF_OPEN state for webhook delivery and SAML metadata circuit breakers; included in /actuator/health details

πŸ“œ Audit Logging

  • Application audit log β€” @Audited actions persisted to partitioned audit_logs tables (append-only triggers)
  • Admin API β€” paginated queries by actor and recent window
  • pgAudit β€” Postgres image logs write, DDL, and role operations (shared_preload_libraries=pgaudit). Admin log viewer is off by default β€” set GITNODE_ADMIN_PGAUDIT_ENABLED=true and mount the Postgres log volume into the app container.
  • Toggle application audit with GITNODE_AUDIT_ENABLED (default true)

πŸ” Authentication

  • Username + password login with JWT
  • Basic Auth for git repo operations
  • OAuth2: Google, GitHub, GitLab
  • SSH public keys for Git over SSH
  • Enterprise SAML 2.0 and LDAP per organization (see above)

πŸ€– AI Features

AI is opt-in at every layer: users bring their own provider and API key; repositories opt in to automated PR review separately. Nothing runs until you enable it β€” no platform-level LLM key required.

Bring your own model (BYOK)

Provider Models / notes
OpenAI GPT-4o, GPT-4o-mini, GPT-4-turbo, compatible endpoints
Anthropic Claude 3.5 Sonnet, Claude 3 Opus, and newer Claude models
Google Gemini Via OpenAI-compatible API β€” key from Google AI Studio
Local (Ollama) Self-hosted models; set base URL to your Ollama instance

Configure in User Settings β†’ AI: pick provider, model, API key, and optional custom base URL. Keys are encrypted at rest with AES-256-GCM when GITNODE_AI_ENCRYPTION_KEY is set. Use Test connection to validate credentials before saving.

PR AI Code Review

  • Repo opt-in β€” toggle Enable PR AI review in Settings β†’ AI Analysis (off by default)
  • When enabled, opening a PR triggers an async review using the PR author's AI settings, falling back to the repo owner
  • Comments are categorized (BUG, SECURITY, PERFORMANCE, CODE_QUALITY, GENERAL) with severity (CRITICAL β†’ INFO)
  • View results in the PR AI Review tab β€” summary plus paginated inline findings
  • Retry if a review failed or was skipped; uses your account's AI settings
  • Memory-safe diffs β€” large PRs use prioritized, bounded diff sampling (vendor paths and lockfiles skipped)

AI Commit Message

  • Sparkles button on the new-pull-request form suggests a Conventional Commits message from the branch diff
  • Imperative, scoped, ≀72 characters β€” ready to paste into your commit

AI PR Description

  • AI Generate on the new-PR form produces a title plus structured Markdown: summary, motivation, breaking changes, security/config notes, and a test-plan checklist
  • Rate-limited to 10 requests per 10 minutes per user

AI Codebase Analysis

Scores the repository across six dimensions (1–10 each) with reasons, issues, and fixes:

Dimension What it evaluates
Architecture Modularity, layering, coupling, deployability
Code Quality Readability, consistency, error-handling patterns
Performance Hot paths, I/O, caching, algorithmic cost
Memory Usage Allocation patterns, unbounded buffers, leak risk
Scalability Stateless design, pagination, horizontal scaling readiness
Security Authn/authz, secrets, injection, transport β€” includes a dedicated security pass
  • Run from Settings β†’ AI Analysis; history is paginated per branch
  • Memory-safe for large repos β€” bounded tree walk, skips node_modules / target / lockfiles, loads only the highest-priority source files
  • Rate-limited to 3 analyses per hour per user

Production hardening

  • Production-ready prompts β€” structured output for parsing; focused on actionable findings, not noise
  • Bounded inputs β€” diff and codebase samples are truncated with explicit sampling notes sent to the model
  • Per-provider circuit breakers (ai-openai, ai-anthropic, ai-gemini, ai-local) β€” opens at 60% failure rate over 5 calls, 60 s cooldown

Environment variable:

Variable Required Default Description
GITNODE_AI_ENCRYPTION_KEY No (blank = plaintext) Base64-encoded 32-byte AES-256 key for user API keys. Generate with make ai-encryption-key or openssl rand -base64 32. Required in production.

πŸ›  Tech Stack

Layer Technology
Language Java 25
Framework Spring Boot 4, Spring Security, Spring Data JPA
Git Engine Eclipse JGit
SSH Server Apache MINA SSHD
Auth JWT, OAuth2 (Google Β· GitHub Β· GitLab), SAML 2.0, LDAP
Database PostgreSQL 17 + Flyway, pgAudit
Cache Redis (cache + rate limiting)
Observability Micrometer, Prometheus, Grafana
Resilience Resilience4j circuit breakers (webhook delivery, SAML metadata, AI providers)
AI Spring AI 2.0 β€” OpenAI, Anthropic, Gemini (OpenAI-compat), Ollama; BYOK per user; bounded sampling for large repos
Audit Application audit log (partitioned PostgreSQL)
CI/CD Engine Spring Boot actions module β€” WebSocket runner protocol, SSE log streaming, secrets vault (AES-256-GCM), artifact/cache store
Runner Agent Go 1.24 (gitnode-runner) β€” shell + Docker executors, single static binary
Frontend Angular 21, TypeScript 5
Admin UI Angular 21 (gitnode-admin-panel)
Styling Tailwind CSS 4, DaisyUI 5
Container Docker (multi-stage build, single image)

πŸš€ Getting Started

πŸ“– Documentation is available in-app at /docs once GitNode is running.

Developing locally

See CONTRIBUTING.md for run profiles, Makefile commands, and module docs.

Base app (Frontend + Backend):

make dev-setup && make dev-backend          # terminal 1
cd gitnode-frontend && pnpm start         # terminal 2 β†’ :4200

Full app (+ Grafana + Admin): see CONTRIBUTING.md#run-profiles

make test    # unit tests + lint

Option 1 β€” Docker Run

SECRET=$(openssl rand -base64 64 | tr -d '\n')

# Infrastructure (Postgres with pgAudit, Redis) β€” creates the gitnode network
docker compose up -d

# Optional: Prometheus + Grafana
docker compose --profile monitoring up -d

# Optional: admin panel UI (dev, separate terminal)
# cd gitnode-admin-panel && pnpm install && pnpm start   β†’ http://localhost:4300

docker run -d \
  --name gitnode \
  --network gitnode \
  -p 8080:8080 \
  -p 2222:2222 \
  -e SPRING_PROFILES_ACTIVE=os \
  -e "GITNODE_JWT_SECRET=$SECRET" \
  -e SPRING_DATASOURCE_URL=jdbc:postgresql://gitnode-postgres:5432/gitnode \
  -e SPRING_DATASOURCE_USERNAME=admin \
  -e SPRING_DATASOURCE_PASSWORD=admin123 \
  -e SPRING_DATA_REDIS_HOST=gitnode-redis \
  -e SPRING_DATA_REDIS_PORT=6379 \
  -e GITNODE_GIT_REPO__ROOT=/data/repos \
  -e GITNODE_BOOTSTRAP_ADMIN_ENABLED=true \
  -e GITNODE_BOOTSTRAP_ADMIN_USERNAME=admin \
  -e GITNODE_BOOTSTRAP_ADMIN_PASSWORD=Admin123 \
  -e GITNODE_ADMIN_MODULITH_EVENTS_ENABLED=true \
  -e GITNODE_FRONTEND_BASE_URL=http://localhost:8080 \
  -e GITNODE_AUDIT_ENABLED=true \
  -e GITNODE_OBSERVABILITY_ENABLED=false \
  -e GITNODE_CORS_ALLOWED_ORIGINS=http://localhost:8080 \
  -v gitnode-repos:/data/repos \
  repo.repsy.io/nuricanozturk/gitnode/gitnode-os:latest

Option 2 β€” Makefile (recommended)

Base stack β€” Postgres + Redis + app:

make up          # β†’ http://localhost:8080

Optional add-ons:

make monitoring                  # Prometheus + Grafana
cd gitnode-admin-panel && pnpm start   # admin UI β†’ :4300 (API on by default)

All commands: CONTRIBUTING.md

Service URL Default
App http://localhost:8080 βœ…
SSH Git localhost:2222 βœ…
Frontend (dev) http://localhost:4200 manual β€” pnpm start
Admin panel http://localhost:4300 manual β€” pnpm start
Prometheus http://localhost:9090 optional β€” make monitoring
Grafana http://localhost:3000 optional β€” make monitoring

Environment Variables

Variable Required Default Description
GITNODE_JWT_SECRET βœ… β€” Min 32-char secret for JWT signing
GITNODE_BOOTSTRAP_ADMIN_PASSWORD βœ… prod β€” Bootstrap admin password (empty skips bootstrap)
GITNODE_BOOTSTRAP_ADMIN_USERNAME admin First-start platform admin username
GITNODE_BOOTSTRAP_ADMIN_ENABLED true Run bootstrap admin creation on startup
GITNODE_PLATFORM_ADMIN_USERNAMES β€” Comma-separated additional platform admin usernames
GITNODE_GIT_REPO__ROOT ~/.gitnode Git repository storage path (use a volume in Docker)
GITNODE_FRONTEND_BASE_URL http://localhost:4200 Base URL returned after OAuth2/SAML redirects
GITNODE_CORS_ALLOWED_ORIGINS http://localhost:4200,http://localhost:4300 CORS origins β€” add admin panel URL for admin access
GITNODE_AUDIT_ENABLED true Application audit log
GITNODE_OBSERVABILITY_ENABLED true Prometheus /actuator/prometheus
GITNODE_ACTIONS_ENABLED true CI/CD Actions engine
GITNODE_ADMIN_MODULITH_EVENTS_ENABLED false Admin panel event publication viewer
GITNODE_ADMIN_PGAUDIT_ENABLED false Admin panel pgAudit log viewer
GITNODE_ADMIN_PGAUDIT_LOG_DIRECTORY β€” Postgres log dir mounted into the app container
GITNODE_SSO_SAML_ENABLED false Global SAML feature flag
GITNODE_SSO_LDAP_ENABLED false Global LDAP feature flag
GITNODE_SSO_SAML_SP_SIGNING_KEY_PATH β€” SP signing private key path (SAML); make saml-keygen
GITNODE_SSO_SAML_SP_SIGNING_CERT_PATH β€” SP signing certificate path (SAML); make saml-keygen
ACTIONS_ENCRYPTION_KEY β€” AES-256 key (base64) for Actions secrets vault; make actions-encryption-key
GITNODE_AI_ENCRYPTION_KEY β€” AES-256 key (base64) for user AI API keys at rest; make ai-encryption-key
SPRING_DATA_REDIS_HOST localhost Redis hostname
SPRING_DATA_REDIS_PORT 6379 Redis port
SPRING_DATASOURCE_URL jdbc:postgresql://localhost:5432/gitnode Postgres JDBC URL
SPRING_DATASOURCE_USERNAME admin Postgres username
SPRING_DATASOURCE_PASSWORD admin123 Postgres password
OAUTH2_GOOGLE_CLIENT_ID β€” Google OAuth2 client ID
OAUTH2_GOOGLE_CLIENT_SECRET β€” Google OAuth2 client secret
OAUTH2_GITHUB_CLIENT_ID β€” GitHub OAuth2 client ID
OAUTH2_GITHUB_CLIENT_SECRET β€” GitHub OAuth2 client secret
OAUTH2_GITLAB_CLIENT_ID β€” GitLab OAuth2 client ID
OAUTH2_GITLAB_CLIENT_SECRET β€” GitLab OAuth2 client secret

πŸ— Scaling & High Availability

GitNode is designed to run as multiple stateless app instances behind a load balancer.

What is multi-instance safe

Component Storage Multi-instance
Session / JWT Stateless βœ…
Spring Cache (branches, repo-meta, …) Redis βœ…
Actions runtime state (pending uploads, ID allocation) Redis βœ…
Webhook DLQ retry state DB βœ…
Rate-limit counters Redis βœ…

What requires shared storage

Component Default path Multi-instance requirement
Git repositories GITNODE_GIT_REPO__ROOT (default /data/repos) Shared volume β€” all instances must read/write the same path
CI/CD artifacts & cache gitnode.actions.artifacts.local-path Shared volume β€” artifacts committed on one instance must be readable on all others

Without shared storage, requests routed to a different instance than the one that wrote the file will return 404. Mount a network filesystem (NFS, AWS EFS, GCP Filestore, Azure Files) at both paths, or use a ReadWriteMany Kubernetes PVC.

Docker Compose HA (built-in)

make up-ha N=3    # infra + 3 app instances + HAProxy (HTTP :8080, SSH :2222)
make proxy        # start HAProxy only (if instances already running)
make app-scale N=3

HAProxy config is in haproxy.cfg at the project root.

Kubernetes example

# Shared PVC for repos + artifacts β€” mount on all app pods
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: gitnode-data
spec:
  accessModes: [ReadWriteMany]   # requires NFS / EFS / GCP Filestore / Azure Files
  resources:
    requests:
      storage: 100Gi
---
# In your Deployment / StatefulSet:
volumeMounts:
  - name: data
    mountPath: /data/repos          # GITNODE_GIT_REPO__ROOT
  - name: data
    mountPath: /data/artifacts      # gitnode.actions.artifacts.local-path
    subPath: artifacts
volumes:
  - name: data
    persistentVolumeClaim:
      claimName: gitnode-data

Redis and PostgreSQL must also be external (not per-pod) in a multi-instance setup β€” use a managed service or a dedicated StatefulSet with persistence.


πŸ“„ License

Distributed under the MIT License.


β˜• Support

If GitNode saves you time or you just want to say thanks, consider buying me a coffee. It keeps the project alive and the commits coming.

Buy Me A Coffee