A self-hosted Git server and custom web UI inspired by GitHub.
This project was built to understand the fundamentals of how a Git hosting platform works: auth, per-user namespaces, repository creation, SSH key setup, and browsing code/history through a web interface.
Live website: My Github
- Per-user namespaces (repositories live under
username/repo.git) - Bare repository creation from the web UI
- Clone URL generation in SSH format:
git@host:username/repo.git - Push and pull workflow via SSH once keys are configured
- Signup and login
- JWT-based session handling
- Password hashing with
bcryptjs - Account page for SSH key management
- Add/list/delete public keys from the UI
- Stores user keys in each user's
.ssh/authorized_keys - Attempts to mirror keys into system git user authorized keys (
/home/git/.ssh/authorized_keys)
- Explore users and their repository counts
- User repository listing
- Branch-aware repository view
- File tree browsing
- File content viewer with syntax highlighting
- README rendering on repository root
- Commit list grouped by date
- Commit detail metadata (author, date, parent)
- File-level change stats (additions/deletions)
- Inline patch/diff display per changed file
- Backend: Express, simple-git, CORS, jsonwebtoken, bcryptjs
- Frontend: React, React Router, Vite, Tailwind CSS, Lucide icons
.
├── backend/
│ ├── app.js
│ └── package.json
├── client/
│ ├── src/
│ │ ├── components/
│ │ ├── context/
│ │ ├── pages/
│ │ ├── services/
│ │ ├── App.jsx
│ │ ├── config.js
│ │ └── main.jsx
│ └── package.json
└── README.md
cd backend
pnpm install
node app.jsDefault backend URL: http://localhost:3000
cd client
pnpm install
pnpm devDefault frontend URL: http://localhost:5173
Edit client/src/config.js:
API_BASE_URL: backend base URL used by the frontendGIT_SERVER_HOST: host used in generated clone URLsAPP_TITLE: UI title in header
backend/app.js currently defines:
PORT: API port (default3000)ORIGIN: allowed frontend origin for CORSGIT_BASE: filesystem root used to store users and bare reposJWT_SECRET: JWT signing secret
For production, move these values to environment variables.
Base path: /api
POST /api/auth/signupPOST /api/auth/loginGET /api/auth/me
GET /api/account/ssh-keysPOST /api/account/ssh-keysDELETE /api/account/ssh-keys/:keyId
GET /api/users
GET /api/:username/reposGET /api/:username/repo/exists/:namePOST /api/:username/repo/createGET /api/:username/:repoName/infoGET /api/:username/:repoName/treeGET /api/:username/:repoName/blobGET /api/:username/:repoName/commitsGET /api/:username/:repoName/commits/:hash
This project is intentionally lightweight for learning.
Before serious/public deployment, add at least:
- Environment-based secrets and host paths
- Strong input validation and rate limiting
- Tightened CORS and auth hardening
- Operational hardening around SSH key write permissions
node app.js
pnpm devpnpm buildpnpm previewpnpm lint
MIT