NordBastion का polar-bear mascot एक अँधेरे Nordic पत्थर के vault में एक server rack के बग़ल में खड़ा है, एक पंजा एक तैरते हुए cyan होलोग्राफ़िक branch diagram पर टिका है जो तीन मिलती हुई lines वाली एक Git history दिखाता है, उसके बग़ल में मेज़ पर source code का एक सील किया हुआ runic strongbox है, और एक ऊँची मेहराबदार खिड़की से aurora की रोशनी गिर रही है
गाइड · Developer infrastructure·18 मिनट पढ़ने में · 45 मिनट hands-on

आपका अपना Git server।
Repository ही org chart है।

एक private repository इस बात का दर्ज़ रिकॉर्ड है कि आप क्या बना रहे हैं, किसके साथ बना रहे हैं, और कितनी दूर तक पहुँच चुके हैं — और किसी platform पर, वह रिकॉर्ड किसी और के jurisdiction में बैठी एक company के पास होता है। इसे किसी ऐसे box पर ले जाने के छह चरण जिसे आप बेनाम किराए पर लेते हैं: Caddy के पीछे Forgejo, नीचे PostgreSQL, अपने ही port पर SSH push, एक ऐसा Actions runner जो आपके production secrets कभी नहीं देखता, और एक ऐसा backup जिसे आपने सचमुच restore करके देखा है। box की क़ीमत $3.90 महीना है। Debian 12 पर टेस्ट किया गया।

छह चरण
  1. 01

    चुनें

    Bare repo, Forgejo, GitLab

  2. 02

    Provision

    boot से पहले तय हुए ports

  3. 03

    तैनात करें

    Forgejo, Postgres, Caddy

  4. 04

    भेजें

    SSH, deploy keys, signatures

  5. 05

    बनाएँ

    एक runner, दूरी पर रखा हुआ

  6. 06

    Keep

    Mirrors, backups, upgrades

शुरू करने से पहले · Platform के पास क्या रहता है

Code सबसे कम दिलचस्प हिस्सा है। Metadata ही असली asset है।

self-hosting Git को लेकर लगभग हर बहस source code को लेकर होती है, जबकि source code ही सबसे कम मायने रखने वाला हिस्सा है। इसका ज़्यादातर हिस्सा साधारण है, इसका बड़ा भाग open-source libraries के ऊपर एक पतली परत भर है, और अगर यह कल लीक हो जाए तो असली नुक़सान आमतौर पर नुक़सान नहीं बल्कि शर्मिंदगी होगी। यही वजह है कि "मेरा code गुप्त नहीं है" एक पूरा जवाब लगता है, और यही वजह है कि यह पूरा जवाब नहीं है।

code के इर्द-गिर्द जो कुछ है वही दिलचस्प हिस्सा है। एक repository काम का एक दिनांकित, श्रेय-सहित, high-resolution रिकॉर्ड है: commit timestamps बताते हैं कि आप कब सोते हैं, co-author lines बताती हैं कि आप किसके साथ काम करते हैं, branch names बताते हैं कि कौन-से products हैं जिनकी अभी किसी ने घोषणा नहीं की, एक issue tracker बताता है कि क्या टूटा है और कितनी बुरी तरह, और पहला commit पूरे project की तारीख़ तय कर देता है। सौ repositories को इस तरह पढ़ें तो आप अब software नहीं पढ़ रहे — आप एक company, उसका roadmap, उसका headcount और उसकी मुश्किलें पढ़ रहे हैं।

किसी platform पर, वह रिकॉर्ड किसी सार्थक मायने में आपका नहीं होता। यह ऐसे infrastructure पर बैठा है जिसे आप control नहीं करते, ऐसे account के नीचे जो आपकी verify की गई identity से बँधा है, ऐसे jurisdiction में जहाँ की legal process उस तक पहुँचती है, और ऐसे systems से scan होता है जिनका दायरा एक ऐसा document तय करता है जिसे बदला जा सकता है। इनमें से किसी के लिए किसी की बदनीयती ज़रूरी नहीं: tracker किराए पर लेने का मतलब बस यही है। चार तरह के इंतज़ाम, और हर एक असल में क्या उजागर करता है:

Repository कहाँ रहती है History किसके पास रहती है आपकी क़ानूनी identity से बँधा यह कैसे ग़लत होता है
एक platform, निजी accountवह platform, अपने ही jurisdiction मेंहाँ — email, billing, अक्सर एक फ़ोन नंबरएक suspension अपने साथ हर remote ले जाता है
एक platform, organisation accountवह platform, साथ ही जो कोई भी org को administer करता हैहाँ, और आपके employer तक भीOffboarding आपके अपने काम तक की आपकी पहुँच छीन लेता है
Self-hosted, किसी hyperscaler परआप, application layer परहाँ — billing account ही identity हैSnapshot उस account में रहता है जिसे बंद किया जा सकता है
Self-hosted, एक KYC-free VPS परआप, और सिर्फ़ आपनहीं — न ID, न card, crypto-settledअब आप ही sysadmin हैं। एक ख़राब backup आख़िरी होता है

तीसरी row वह row है जो उन teams को पकड़ लेती है जो सोचती हैं कि उन्होंने यह पहले ही हल कर लिया है। एक ऐसा forge जिसे आपने ख़ुद install किया, किसी corporate card से verified company account के तहत किराए पर ली गई machine पर, उसने application को platform से तो बाहर निकाल दिया, पर identity बिल्कुल वहीं छोड़ दी जहाँ थी। यह control में एक असली फ़ायदा है और exposure में बिल्कुल कोई फ़ायदा नहीं।

और चौथी row अपनी क़ीमत साफ़-साफ़ बता देती है, क्योंकि इस guide का बाक़ी हिस्सा ज़्यादातर उसी क़ीमत को चुकाने के बारे में है। Self-hosting का failure mode surveillance नहीं, loss है। एक platform ऐसे backups रखता है जिनके बारे में आप कभी सोचते भी नहीं। आपका server वही backups रखता है जो आपने configure किए। Step 06 आख़िर में कोई वैकल्पिक चमक-दमक नहीं है — यह वह step है जो बाक़ी पाँचों को सुरक्षित बनाता है।

Step 01 · चुनें

आपको कितना forge चाहिए? ईमानदार जवाब अक्सर "कोई नहीं" होता है।

सबसे छोटी उस चीज़ से शुरू करें जो आपकी समस्या हल करती है, क्योंकि उसके ऊपर की हर परत एक ऐसी service है जिसे आपको operate करना होगा। SSH पर एक bare repository आपके पास पहले से मौजूद किसी server पर बस एक command है, और यह आपको authentication, history और push access वाला एक असली Git remote दे देता है। न कोई web application, न कोई database, न कोई upgrade treadmill, sshd से आगे कुछ भी patch करने को नहीं। अगर आप एक अकेले व्यक्ति हैं जो अपने commits को किसी laptop से और किसी platform से बाहर निकालना चाहते हैं, तो यह एक पूरा जवाब है और आप step 02 के बाद पढ़ना बंद कर सकते हैं।

# On the server, as an unprivileged user:
mkdir -p ~/git/project.git && cd ~/git/project.git
git init --bare

# On your laptop:
git remote add origin ssh://user@git.example.com/~/git/project.git
git push -u origin main

आपको forge की ज़रूरत तब पड़ती है जब कोई दूसरा व्यक्ति शामिल हो, या जब आपको उन चार चीज़ों में से कोई चाहिए जो bare repositories की एक directory नहीं कर सकती: history को browser में browse करना, बदलावों को pull requests के तौर पर review करना, code के बग़ल में issues track करना, और एक व्यक्ति को एक repository का access देना। यह क्षमता में एक असली कदम ऊपर है और operational बोझ में भी एक असली कदम ऊपर है। जान-बूझकर चुनें:

विशेषता SSH पर Bare repo Forgejo Gitea GitLab CE
Web UI, pull requests, issuesकोई नहींहांहांहाँ, और इससे कहीं ज़्यादा
Idle में Memoryव्यावहारिक रूप से शून्यकुछ सौ MBकुछ सौ MBकई GB, CI से पहले
अंतर्निहित CIgit hooks, अगर आप उन्हें लिखेंForgejo ActionsGitea ActionsGitLab CI, जो परिपक्व है
Project की दिशा कौन तय करता हैGit projectCodeberg e.V., एक गैर-लाभकारी संस्थाएक for-profit company, open coreएक listed company, open core
लाइसेंसGPLv2v9.0 से GPLv3+ (पहले MIT)MIT, proprietary add-ons के साथMIT core, proprietary tiers
इसे चुनें जबआप अकेले हैं और आपको zero maintenance चाहिएआपको एक छोटे box पर एक असली forge चाहिएआप इसे पहले से चला रहे हैं और यह काम करता हैआपको enterprise feature set चाहिए

Forgejo और Gitea का पुरखा एक ही है और रोज़मर्रा के इस्तेमाल में आज भी लगभग एक जैसे दिखते हैं। Forgejo early 2024 में एक hard fork बना और इसे Codeberg e.V. रखती है, जो Berlin में registered एक गैर-लाभकारी association है; Gitea को एक for-profit company विकसित करती है जो अपने trademark की मालिक है और contributors से copyright assignment माँगती है। दोनों अच्छे software हैं। इनमें से सिर्फ़ एक का custodian ऐसा है जिसकी प्रेरणाएँ उस वजह से मेल खाती हैं जिसके लिए आप यह पेज पढ़ रहे हैं।

इस guide का बाक़ी हिस्सा Forgejo इस्तेमाल करता है। steps 02 से 06 तक सब कुछ Gitea पर लगभग हू-ब-हू लागू होता है — container का नाम और कुछ environment variables बदल जाते हैं, ढाँचा नहीं बदलता।

Step 02 · जुटाएँ

forge के आपके लिए तय करने से पहले ports ख़ुद तय कर लें। इनमें से दो SSH के हैं।

पहले box order करें। panel में: Order → VPS → Sentinel, image Debian 12, जिस भी bastion में आप history को रहते देखना चाहें — Helsinki, Stockholm, Oslo या Reykjavík। account खोलने के लिए किसी email address की ज़रूरत नहीं और invoice Monero, Bitcoin, Lightning या किसी भी दूसरे supported asset में चुकता होता है। यह यहाँ ज़्यादातर workloads से कहीं ज़्यादा मायने रखता है: forge अकेली ऐसी service है जिसका पूरा value proposition ही यह है कि आपके काम का रिकॉर्ड किसी नाम से जुड़ा नहीं है।

फिर पहले घंटे की hardening checklist चलाएँ — किसी हटाए गए port पर key-only SSH, unattended upgrades, एक default-deny firewall — क्योंकि नीचे लिखा सब कुछ यह मान कर चलता है कि box पहले से किसी और का नहीं है।

आप असल में internet पर क्या डाल रहे हैं

forge login वाली कोई static site नहीं है। यह एक ऐसा public web application है जिसके साथ एक code-execution engine जुड़ा हुआ है। दो defaults, अगर छोड़ दिए जाएँ, तो इसे अजनबियों के लिए एक मुफ़्त service बना देते हैं: खुला registration, जो certificate के transparency logs में दिखने के कुछ ही दिनों में instance को spam accounts से भर देता है, और ऐसा CI जो किसी भी pull request खोलने वाले के workflows चला देता है, जिससे एक self-hosted runner किसी और के लिए cryptocurrency mine करने लगता है। न यह कोई सूक्ष्म हमला है, न ही यह दुर्लभ है। दोनों एक-एक setting से बंद हो जाते हैं, step 03 और step 05 में — लेकिन अभी तय कर लें कि आप इन्हें बंद करेंगे, क्योंकि "यह काम करता है" और "इसका इस्तेमाल हो रहा है" के बीच की खिड़की बस कुछ दिनों की होती है।

box पर एक hostname point करें — एक A record, और अगर आप इसे IPv6 पर भी पहुँच लायक बनाना चाहें तो एक AAAA — और शुरू करने से पहले इसे propagate होने दें, क्योंकि reverse proxy पहली बार boot होने पर उस नाम के लिए एक certificate हासिल करने की कोशिश करेगा, और एक असफल challenge शुरुआत करने का उलझा हुआ तरीक़ा है। फिर firewall rules तब लिखें जब अभी कुछ भी listen नहीं कर रहा।

दो-SSH वाली समस्या। एक forge Git के लिए SSH बोलता है, और आपका server administration के लिए पहले से SSH बोलता है। दोनों port 22 के मालिक नहीं हो सकते, और इन्हें मिलाना ही वह तरीक़ा है जिससे लोग एक ऐसे administrative daemon पर पहुँच जाते हैं जिसे Git भी समझना पड़ता है। इन्हें अलग रखें: hardening guide वाले हटाए गए port पर administration, और container में map होने वाले एक dedicated public port पर Git। 2222 पारंपरिक चुनाव है और इसमें कुछ भी पवित्र नहीं है।

ufw default deny incoming
ufw allow 47222/tcp                  # administrative SSH, moved
ufw allow 80/tcp                     # ACME HTTP-01 challenge
ufw allow 443/tcp                    # the web interface
ufw allow 2222/tcp                   # git over SSH, into the container
ufw enable
ufw status numbered

# Nothing else is open. In particular: PostgreSQL stays on the Docker
# network and is never published to the host, let alone the internet.

distribution package के बजाय official repository से Docker install करें, ताकि Compose v2 मौजूद रहे और version मौजूदा हो। फिर stack के लिए एक directory बनाएँ और उसे box की इकलौती ऐसी जगह बनाएँ जो state रखती है — यही वह directory है जिसका backup step 06 लेता है।

curl -fsSL https://get.docker.com | sh
docker compose version

install -d -m 0750 /srv/forgejo
cd /srv/forgejo
Step 03 · तैनात करें

तीन containers। इनमें से एक तक कभी पहुँचा नहीं जा सकना चाहिए।

Forgejo, PostgreSQL और Caddy। Forgejo repositories रखता है और interface serve करता है, PostgreSQL वह सब कुछ रखता है जो कोई Git object नहीं है, और Caddy TLS terminate करता है और बिना दोबारा पूछे certificate हासिल कर लेता है। PostgreSQL को जान-बूझकर host पर publish नहीं किया जाता: यह सिर्फ़ Compose network पर, नाम से, उसी एक container से पहुँच लायक है जिसे इसकी ज़रूरत है।

/srv/forgejo/.env

FORGEJO_DOMAIN=git.example.com
FORGEJO_VERSION=15                             # the LTS line; 16 is current stable
POSTGRES_PASSWORD=$(openssl rand -base64 32)   # paste the value, do not leave the $( )

/srv/forgejo/docker-compose.yml

services:
  forgejo:
    image: codeberg.org/forgejo/forgejo:${FORGEJO_VERSION}
    container_name: forgejo
    environment:
      USER_UID: 1000
      USER_GID: 1000
      FORGEJO__database__DB_TYPE: postgres
      FORGEJO__database__HOST: db:5432
      FORGEJO__database__NAME: forgejo
      FORGEJO__database__USER: forgejo
      FORGEJO__database__PASSWD: ${POSTGRES_PASSWORD}
      FORGEJO__server__DOMAIN: ${FORGEJO_DOMAIN}
      FORGEJO__server__ROOT_URL: https://${FORGEJO_DOMAIN}/
      FORGEJO__server__SSH_DOMAIN: ${FORGEJO_DOMAIN}
      FORGEJO__server__SSH_PORT: "2222"          # what clones will say
      FORGEJO__server__SSH_LISTEN_PORT: "22"     # what the container listens on
      FORGEJO__service__DISABLE_REGISTRATION: "true"
      FORGEJO__repository__DEFAULT_PRIVATE: private
      FORGEJO__security__INSTALL_LOCK: "true"
    restart: unless-stopped
    volumes:
      - ./data:/data
      - /etc/timezone:/etc/timezone:ro
      - /etc/localtime:/etc/localtime:ro
    ports:
      - "127.0.0.1:3000:3000"    # web, reached only by Caddy
      - "2222:22"                # git over SSH, public
    depends_on:
      - db

  db:
    image: postgres:16-alpine
    container_name: forgejo-db
    environment:
      POSTGRES_USER: forgejo
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: forgejo
    restart: unless-stopped
    volumes:
      - ./postgres:/var/lib/postgresql/data
    # No ports: block. This is the point.

  caddy:
    image: caddy:2-alpine
    container_name: forgejo-caddy
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./caddy-data:/data
      - ./caddy-config:/config

/srv/forgejo/Caddyfile

git.example.com {
    encode zstd gzip
    request_body {
        max_size 512MB          # raise it if you push large repositories
    }
    reverse_proxy 127.0.0.1:3000
}

वे दो SSH lines हैं जिन्हें लोग ग़लत कर बैठते हैं, इसलिए इन्हें दो बार पढ़ना उचित है। SSH_LISTEN_PORT वह port है जो container के अंदर है, जहाँ Forgejo का built-in SSH server bind होता है। SSH_PORT वह port है जिसे Forgejo आपको दिखाई गई clone URLs में print करता है — इसे port mapping के public side से मेल खाना चाहिए। इन्हें आपस में उलझा दें तो सब कुछ काम करता है सिवाय उस एक चीज़ के जिसे users copy-paste करते हैं।

इसे up करें, फिर administrator को command line से बनाएँ। web installer इस्तेमाल न करें। किसी नए instance पर यह उस किसी के लिए भी पहुँच लायक होता है जो hostname ढूँढ ले, और इसके ज़रिए बनाया गया पहला account administrator बन जाता है — ऐसी दौड़ जिसमें उतरने की ज़रूरत नहीं। ऊपर वाली file में INSTALL_LOCK container के शुरू होने से पहले ही इसे बंद कर देता है।

docker compose up -d
docker compose logs -f forgejo        # wait for "Starting new Web server"

docker compose exec -u git forgejo forgejo admin user create \
  --admin --username you --email you@example.com --random-password

browser में hostname खोलें, print हुए password से sign in करें और उसे बदल दें। फिर उन settings से गुज़रें जो एक चलते हुए instance को एक बंद instance में बदल देती हैं — इनमें से ज़्यादातर पहले से ही ऊपर वाले environment block से सेट हैं, और मान लेने के बजाय हर एक की पुष्टि करना उचित है:

पंजीकरण

DISABLE_REGISTRATION = true। accounts आप बनाते हैं; कोई खुद से sign up नहीं करता। अगर कभी-कभार sign-ups चाहिए हों, तो दरवाज़ा खोलने के बजाय invitation वाला तरीक़ा इस्तेमाल करें।

डिफ़ॉल्ट visibility

DEFAULT_PRIVATE = private। नई repositories बंद हालत में शुरू होती हैं। publish करना तब किसी डिफ़ॉल्ट का नतीजा नहीं बल्कि एक जान-बूझकर किया गया काम बन जाता है।

अनाम browsing

REQUIRE_SIGNIN_VIEW = true logged-out visitors से public repositories तक को छुपा देता है। किसी private team forge के लिए सही; अगर आपको कुछ भी publish करना है तो ग़लत।

दो-कारक

कुछ भी और करने से पहले इसे administrator account पर enable करें। forge अब वह machine है जो आपकी हर branch को फिर से लिख सकती है।

याद रखने लायक एक path: live configuration host पर ./data/gitea/conf/app.ini पर होता है। मौजूदा installations के साथ compatibility के लिए Forgejo ने gitea directory का नाम रखा रहने दिया, जो हर किसी को ठीक एक बार हैरान करता है। FORGEJO__section__KEY जैसे रूप के environment variables शुरू होते समय उस file में लिख दिए जाते हैं, इसलिए आप पूरा configuration Compose file से manage कर सकते हैं — लेकिन अगर आप app.ini को हाथ से edit करें, तो उसी key का एक environment variable अगले restart पर आपके edit को overwrite कर देगा। दोनों में से एक चुनें और उसी पर टिके रहें।

Step 04 · भेजें

SSH पर push करें। फिर उसे sign करें, ताकि history server पर निर्भर न रहे।

अपनी public key profile settings में paste करें, फिर अपने client को बताएँ कि forge कहाँ है। चूँकि Git एक non-standard port पर है, आपकी SSH config में एक entry के तीस सेकंड लगाना समझदारी है — यह उस port को हर उस URL से बाहर रखता है जिसे आप कभी टाइप करेंगे और remotes को portable बनाता है।

# ~/.ssh/config
Host git.example.com
    Port 2222
    User git
    IdentityFile ~/.ssh/id_ed25519

# Then, in any repository:
git remote set-url origin git@git.example.com:you/project.git
git push -u origin main
ssh -T git@git.example.com        # expect a greeting, not a shell

वह आख़िरी command ही बताती है कि port mapping, container का SSH server और आपकी key, तीनों आपस में मेल खाते हैं या नहीं। Forgejo से मिला अभिवादन बताता है कि पूरी chain काम कर रही है। password का प्रॉम्प्ट बताता है कि आप इसके बजाय host के administrative sshd तक पहुँच गए हैं, और port mapping ग़लत है।

अब अपने commits sign करें। यह वह step है जिसे ज़्यादातर self-hosting guides छोड़ देती हैं, और किसी self-hosted forge पर यह किसी platform से कहीं ज़्यादा मायने रखता है। commit का author field मुक्त text है — जो कोई भी push कर सकता है वह उसमें आपका नाम लिख सकता है। एक signature इस बात का प्रमाण है कि किसी ख़ास key ने कोई ख़ास commit बनाया, और यह प्रमाण तब भी बना रहता है जब जिस server पर push किया गया था वह compromise, migrate या फेंक दिया जा चुका हो। Git उसी SSH key से sign कर सकता है जो आपके पास पहले से है, तो अब PGP का कोई चक्कर नहीं:

git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
git config --global tag.gpgsign true

git commit --allow-empty -m "signed"
git log --show-signature -1

फिर वही public key forge में दोबारा जोड़ें, एक authentication key के बजाय एक signing key के तौर पर। Forgejo signature को server-side verify करता है और commit को verified दिखाता है; उस दूसरी entry के बिना इसके पास signature को आपके account से जोड़ने का कोई तरीक़ा नहीं है, और हर commit unverified दिखता है भले ही वह सही तरीक़े से sign किया गया हो।

Deploy keys, उन machines के लिए जो सिर्फ़ पढ़ती हैं। किसी production server, build box या mirror को forge पर user account की ज़रूरत नहीं। इसके बजाय इसे एक deploy key दें: एक key pair जो एक repository में जोड़ी गई हो, जो तब तक read-only है जब तक आप साफ़ तौर पर write न दें, और instance पर और कुछ नहीं देती। इसे revoke करना बस एक entry मिटाना है। किसी self-hosted forge को साफ़-सुथरा रखने की यह सबसे असरदार आदत है, क्योंकि user accounts में permissions जमा होते जाते हैं और deploy keys में नहीं हो सकते।

किसी platform से migrate करना यह सब कुछ ठीक से करने का अच्छा मौक़ा है। Forgejo का New Migration flow एक repository URL और एक access token लेकर branches, tags, issues, comments, labels, milestones, releases और pull requests पार ले आता है। पहले एक repository चलाकर नतीजे का रूप देखें, बड़े batches के धीमे होने के लिए API rate limits की उम्मीद रखें, और source को उसी दिन मिटाने के बजाय कुछ हफ़्तों तक read-only रखें।

Step 05 · बनाएँ

एक CI runner एक ऐसी machine है जो अजनबियों का code चलाती है। उसे उसी हिसाब से रखें।

Forgejo Actions, GitHub Actions जैसे ही format में workflow files .forgejo/workflows/ से पढ़ता है, और उन्हें एक अलग program को सौंप देता है जिसे Forgejo Runner कहा जाता है। runner forge का हिस्सा नहीं है और उसे उसी machine पर रहने की ज़रूरत नहीं — यही पूरा design है, और यही वजह है कि इस step पर बेपरवाही नहीं बल्कि एक चेतावनी दी गई है।

instance पर Actions enable करें, फिर administration panel से एक registration token लें — पूरे instance के लिए, या किसी एक organisation या एक repository तक scoped — जो कि पक्का न होने पर बेहतर डिफ़ॉल्ट है। runner बाहर की ओर forge से जुड़ता है, इसलिए इसे किसी inbound port की ज़रूरत नहीं और यह किसी भी firewall के पीछे बैठ सकता है, यहाँ तक कि किसी बिना public address वाली machine पर भी।

# In the Compose environment of the forge, or app.ini:
#   FORGEJO__actions__ENABLED: "true"
# Then: Site administration -> Actions -> Runners -> Create new runner

# On the runner machine:
forgejo-runner generate-config > config.yml

forgejo-runner register --no-interactive \
  --instance https://git.example.com \
  --token <REGISTRATION_TOKEN> \
  --name runner-01 \
  --labels docker:docker://node:22-bookworm,debian:docker://debian:12

forgejo-runner --config config.yml daemon

labels ही workflow और runner के बीच का करार हैं: जो job runs-on: docker माँगती है उसे दाईं ओर की image से बना एक container मिलता है। सिर्फ़ वही labels declare करें जिन्हें आप सचमुच serve करने को तैयार हैं, क्योंकि जो job किसी ऐसे label की माँग करती है जिसे कोई नहीं देता, वह असफल होने के बजाय हमेशा के लिए रुकी रहती है, जिसे किसी लंबे दिन के आख़िर में debug करना उलझन भरा होता है।

.forgejo/workflows/ci.yml

on: [push, pull_request]

jobs:
  test:
    runs-on: docker
    container:
      image: node:22-bookworm
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm test
वह नियम जो फ़र्क़ डालता है

एक runner वही करता है जो workflow file कहती है, और workflow file एक pull request में आती है। अगर आपकी team से बाहर कोई भी pull request खोल सकता है, तो runner forge से अलग machine पर होना चाहिए — $3.90 महीने वाला एक दूसरा Sentinel, जिसे forge की data directory का कोई access न हो, कोई database credentials न हों, और उसके environment में ऐसा कुछ भी न हो जिसे किसी build log में पढ़े जाने पर आपको एतराज़ हो। forge पर ही, first-time contributors के लिए workflows चलने से पहले approval ज़रूरी करें। दोनों आम विफलताएँ उतनी ही उबाऊ हैं जितनी महँगी: किसी pull request में दबा हुआ mining workload, और किसी step से जान-बूझकर छपाया गया secret।

secrets को भी उसी तरह scope करें। Forgejo इन्हें repository, organisation और instance स्तर पर रखता है; जिस deployment key की ज़रूरत सिर्फ़ एक repository को है वह सिर्फ़ उसी repository पर होनी चाहिए, ताकि किसी असंबंधित project में compromise हुआ workflow उसे पढ़ न सके। जहाँ भी target support करे वहाँ लंबी उम्र वाले tokens की बजाय छोटी उम्र वाले tokens को तरजीह दें, और कभी किसी workflow file में कोई secret न डालें — workflow file repository में ही है, और repository की एक history होती है।

अगर आपके builds हर run पर वही base images खींचते हैं, तो उन्हें cache करें। एक local registry mirror या एक persistent runner cache दो-मिनट के image pull को दो-सेकंड का बना देता है, और जिन upstream registries पर आप बार-बार बोझ डाल रहे हैं उनके साथ यह शिष्टाचार भी है। और उस pattern पर ग़ौर करें जिसे यह पूरा design न्योता देता है, और यही वजह है कि यह guide agent runtime गाइड के बग़ल में बैठी है: runner एक general-purpose worker है जो आपके forge से jobs खींचता है, इसलिए scheduled maintenance, data pipelines और agent workloads का ठिकाना भी यही है।

Step 06 · रखें

हर clone code का एक backup है। बातचीत का backup कुछ भी नहीं है।

Git यहाँ असामान्य रूप से माफ़ करने वाला है और यह समझना ज़रूरी है कि क्यों। हर clone history की एक पूरी copy है, इसलिए जब तक किसी एक developer के पास मौजूदा working copy है, code server से बचकर रहता है। यह सचमुच तसल्ली देने वाली बात है, और यह आपके forge की रखी दो चीज़ों में से ठीक एक को कवर करती है। दूसरी चीज़ — issues, pull request discussions, review threads, releases, wiki pages, users, teams, permissions, CI history — सिर्फ़ database में मौजूद रहती है, इसकी किसी के पास clone नहीं है, और यह आमतौर पर वह हिस्सा है जिसे जमा होने में तीन साल लगे।

पहले, एक push mirror। यह मुफ़्त है और ख़ुद-ब-ख़ुद चलता है। किसी repository में: Settings → Mirror settings → destination के लिए URL और एक access token के साथ एक push mirror जोड़ें। इसके बाद Forgejo हर push के बाद हर branch और tag को replicate करता है, किसी दूसरे Forgejo को, Codeberg को, या किसी ऐसे platform को जिसे आपने घर के बजाय बस एक शोकेस के तौर पर रखने का फ़ैसला किया है। साफ़ तौर पर कह देने लायक एक बात: एक push mirror history को वफ़ादारी से फिर से publish करता है, उस secret समेत जिसे आप हटाना चाहते थे।

फिर एक असली backup, जो built-in archive नहीं है। Forgejo एक forgejo dump command देता है जो configuration, repositories, data और एक database dump को एक ही zip में पैक कर देता है। किसी maintainer को bug report करते समय सौंपने के लिए यह सचमुच काम की चीज़ है। मरने के बाद वापस लौटने के लिए यह वह चीज़ नहीं है जिस पर आपको भरोसा करना चाहिए: इसका बनाया SQL re-import पर पुरानी जानी-पहचानी समस्याओं से जूझता है, और archive हर run पर पूरा repository set फिर से लिखता है, जिसका किसी असली instance पर मतलब है हर रात नए सिरे से लिखी गई एक बड़ी file। इसके बजाय उबाऊ, verifiable रास्ता अपनाएँ — database को उसी के अपने tool से dump करें, और data directory को files के तौर पर backup करें:

#!/bin/sh
# /usr/local/bin/forgejo-backup — run from a systemd timer, nightly
set -eu
cd /srv/forgejo

# 1. Consistent database dump, written next to the data.
docker compose exec -T db pg_dump -U forgejo -Fc forgejo > ./db.dump

# 2. Everything that matters, to an encrypted offsite repository.
restic backup ./data ./db.dump ./docker-compose.yml ./.env ./Caddyfile

# 3. Retention, then prove the repository is still readable.
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune
restic check

इसे forge से अलग jurisdiction वाली किसी machine को भेजें, एक append-only repository के ज़रिए ताकि forge का compromise होना उसकी अपनी history न मिटा सके — encrypted backups गाइड ऊपर की तीन lines का लंबा रूप है, जिसमें systemd timer और append-only key की पाबंदी भी शामिल है।

फिर इसे एक बार, जान-बूझकर, restore करें। एक scratch VPS order करें, snapshot को उसमें restore करें, restored data directory के सामने वही Compose file up करें, database dump load करें, उस पर एक hosts-file entry point करें और sign in करें। पूरी चीज़ का समय नापें। वह नंबर — backup job के होने भर से नहीं — आपकी असली recovery स्थिति है, और जिस किसी ने भी यह अभ्यास किया है उसे पहली बार include list से कम-से-कम एक चीज़ ग़ायब मिली है।

# restic keeps absolute paths, so the stack reappears under the target.
restic restore latest --target /srv/restore
cd /srv/restore/srv/forgejo

docker compose up -d db                # empty volume: the entrypoint creates the database
docker compose exec -T db pg_restore -U forgejo -d forgejo \
  --clean --if-exists --no-owner < db.dump

docker compose up -d                   # then sign in and walk the issue tracker

Upgrades, संक्षेप में। image को :latest के बजाय किसी major version पर pin करें, ताकि कोई unattended pull आपके सोते समय आपको किसी breaking change के पार न ले जाए। किसी major boundary को पार करने से पहले release notes पढ़ें, पहले एक snapshot लें, और याद रखें कि database migration नए version के पहले start पर चलता है — जो एक one-way door है। किसी static site के लिए Watchtower-जैसा auto-updating एक अच्छा विचार है और जो machine आपकी हर branch रखती है उसके लिए एक बुरा विचार।

इसे पूरा मानने से पहले चार जाँचें। sign out करें और पुष्टि करें कि instance account बनाने का कोई तरीक़ा नहीं देता। बिना session वाले किसी browser से पुष्टि करें कि एक private repository सिर्फ़ मना नहीं बल्कि अदृश्य है। पुष्टि करें कि runner forge की data directory नहीं पढ़ सकता। और पुष्टि करें कि आख़िरी restic check पास हुआ था — जो backup job चुपचाप असफल होता है वही वह है जो हर किसी के पास होता है, ठीक उस दिन तक जब उन्हें इसकी ज़रूरत पड़े।

ईमानदार हिस्सा · यह क्या नहीं करता

आपने एक पक्ष हटा दिया। आपने इमारत नहीं हटाई।

किसी forge को self-host करना इस बात में एक असली बदलाव है कि आपका काम किसके पास रहता है, और यह अदृश्यता नहीं है। ऊपर की सारी बातें पूरी हो जाने के बाद भी चार चीज़ें सच बनी रहती हैं, और इन्हें जानना ही एक असली बचाव और अपने-आप से कही गई कहानी के बीच का फ़र्क़ है।

Disk किसी और की इमारत में है। किराए का एक server दरवाज़ों और staff वाले किसी datacentre के hardware पर चलता है। NordBastion customer workloads का निरीक्षण नहीं करता, और transparency report व warrant canary बताते हैं कि अगर हमसे कुछ पूछा जाए तो क्या होगा — लेकिन ईमानदार बात architectural वाली है: जो बदलता है वह यह है कि अब आपकी repositories का कोई product-level index नहीं, आपके commits पर कोई analytics pipeline नहीं और कोई ऐसी privacy policy नहीं जिसे बदला जा सके। जो नहीं बदलता वह यह है कि machine भौतिक है और यह आपके घर में नहीं है।

Certificate जारी होते ही hostname सार्वजनिक हो जाता है। हर publicly trusted certificate certificate-transparency logs में publish होता है जिन्हें कोई भी खोज सकता है, तो git.yourproject.com खोजा जा सकता है भले ही आप इसे कभी link न करें। यह आपके code का लीक नहीं है, पर यह इस तथ्य का लीक है कि project मौजूद है और मोटे तौर पर कब शुरू हुआ। किसी ऐसे नाम के subdomain का इस्तेमाल करें जिसे आप पहले से publish करते हैं, या public certificate को पूरी तरह छोड़ दें और forge तक WireGuard या किसी onion service पर पहुँचें।

अब आप एक web application patch कर रहे हैं। forge एक login page है, untrusted markup के लिए एक rendering pipeline है, एक SSH server है और एक CI engine है, यह सब internet से पहुँच लायक। यह step 01 वाली bare repository से कहीं बड़ा surface है, और इसे मौजूदा बनाए रखना आपका काम है। release announcements को subscribe करें, और किसी security release को same-quarter नहीं बल्कि same-week काम की तरह बरतें।

Federation अभी यहाँ नहीं पहुँचा है। Forgejo forge federation पर असली काम कर रहा है और इसकी प्रगति publish करता है, लेकिन आज की तारीख़ में आप अपने instance से किसी और के instance पर pull request उस तरह नहीं खोल सकते जैसे किसी shared platform पर खोल सकते हैं। व्यवहार में, इसका मतलब है कि किसी बाहरी contributor को अब भी आपके forge पर एक account चाहिए, या आप patches को email से स्वीकार करें, या drive-by contributions के लिए एक public mirror रखें। इन तीनों में से जो भी आपके project से मेल खाए उसकी योजना बनाएँ, बजाय इसके कि आप इससे चौंक जाएँ।

आपने असल में जो ख़रीदा है, बिल्कुल सटीक रूप से: आप क्या बनाते हैं, किसके साथ, और कब, इसका दर्ज़ रिकॉर्ड अब किसी ऐसी company के पास नहीं है जिसके business model में उसे विश्लेषित करना शामिल है। यह एक संकुचित दावा है, और यह एक असली दावा है। यह अपनी क़ीमत के लायक तभी है जब step 06 पूरा हो चुका हो — बिना जाँचे गए restore वाला एक self-hosted forge कोई privacy सुधार नहीं है, यह बेहतर branding वाला एक single point of failure है।

Sizing · क्या order करें

forge छोटा है। CI नहीं है।

स्तर मासिक संसाधन यह आराम से क्या चला सकता है
Sentinel$3.902 vCPU · 4 GB · 120 GBएक व्यक्ति या छोटी team के लिए Forgejo + PostgreSQL। सही शुरुआत।
एक दूसरा Sentinel$3.90Runner, अपने अलग box परएक coffee की क़ीमत में, वह isolation जो असल में मायने रखता है
Garrison$7.904 vCPU · 8 GB · 240 GBदस लोगों का एक forge, एक container registry और artifacts
Ravelin$16.908 vCPU · 16 GB · 480 GBव्यस्त CI, बड़ी repositories, कई parallel jobs

इस table में कुछ भी Git के हिसाब से sized नहीं है। Forgejo और PostgreSQL मिलकर कुछ सौ megabytes में idle रहते हैं; box को जो भरता है वह CI है — container layers, build caches, artifacts — और repository की वह सामग्री जो source code नहीं है। पहले disk के लिए size करें, फिर cores के लिए, और सबसे बाद में memory के लिए। यहाँ दो छोटे boxes एक बड़े पर भारी पड़ते हैं, क्योंकि दूसरा box capacity नहीं बल्कि एक security boundary है।

Field notes · छह traps

यह छह तरीक़ों से ग़लत हो सकता है। इनमें से दो पैसे खाते हैं।

Trap 01 · ज़ोरदार

खुला registration, और अजनबियों से भरा एक forge

certificate transparency logs में दिखता है, scanners कुछ ही दिनों में पीछे आ जाते हैं, और sign-ups चालू वाला एक instance spam accounts और spam repositories से भर जाता है। पहले boot से पहले DISABLE_REGISTRATION सेट करें, पहली incident के बाद नहीं।

Trap 02 · महँगा

वह runner जो किसी और के लिए cryptocurrency mine करता है

किसी भी pull request से workflows चलाने वाला CI, जिसे भी मिल जाए उसके लिए मुफ़्त compute है। first-time contributors के लिए approval ज़रूरी करें, runner को उसके अपने box पर रखें, और job durations कभी-कभार पढ़ें।

Trap 03 · ख़ामोश

ग़लत ROOT_URL, और सब कुछ आधा-अधूरा चलता है

Clone URLs ग़लत host की ओर जाते हैं, webhooks ग़लत address पर चलते हैं, OAuth callbacks असफल होते हैं और avatars टूट जाते हैं। interface ठीक दिखता है, इसलिए किसी को एक line पर शक़ नहीं होता। DOMAIN, ROOT_URL, SSH_DOMAIN और SSH_PORT एक साथ सेट करें और UI में एक clone URL जाँच लें।

Trap 04 · उलझाने वाला

दो SSH servers, एक port

container को 22 चाहिए और host पहले से उसे इस्तेमाल कर रहा है, इसलिए mapping चुपचाप किसी अनपेक्षित जगह जा बैठती है और git push एक password माँगता है। पहले administrative SSH हटाएँ, container को उसके अपने port पर publish करें, और ssh -T से जाँच लें।

Trap 05 · घातक

एक dump जिसे कभी restore नहीं किया गया

built-in archive एक support artefact है, कोई जाँचा-परखा recovery रास्ता नहीं, और इसके SQL में जानी-पहचानी re-import समस्याएँ हैं। database को pg_dump से dump करें, data directory को files के तौर पर backup करें, और पूरी चीज़ को एक बार किसी scratch box पर restore करें।

Trap 06 · धीमा

Disk build layers से भरता है, code से नहीं

Source code बहुत छोटा होता है; container layers, artifacts और CI caches नहीं। एक उत्साही pipeline वाला 120 GB box हफ़्तों में भर जाता है। किसी timer पर images prune करें, artifact retention की सीमा तय करें, और CPU के बजाय disk पर नज़र रखें।

FAQ · निजी Git hosting

प्रश्न, उत्तरित।

यह बनाते समय जो ग्यारह सवाल उठते हैं — उन दो सवालों से शुरू जो तय करते हैं कि आपको इसे बनाना भी चाहिए या नहीं।

Forgejo या Gitea — असल में install किसे करें?

ज़्यादातर लोगों के लिए Forgejo, और वजह features नहीं बल्कि governance है। दोनों projects का पुरखा एक ही है और इस्तेमाल में आज भी लगभग एक जैसे लगते हैं: वही Go binary, वही हल्का footprint, वही web interface, तुलनीय CI। जो अलग है वह यह कि इन्हें चलाता कौन है। Forgejo Codeberg e.V. के पास है, जो Berlin में registered एक गैर-लाभकारी association है, और यह early 2024 में एक hard fork बना; यह सब कुछ free software के रूप में publish करता है और contributors से copyright assign करने को नहीं कहता। Gitea को एक for-profit company विकसित करती है जो trademark और domain दोनों की मालिक है, contributors से copyright assignment माँगती है, और free base के चारों ओर paid features वाला एक open-core model चलाती है। इनमें से कोई भी तथ्य Gitea को बतौर software कमज़ोर नहीं करता। लेकिन अपनी repositories को किसी platform से हटाने का पूरा मक़सद ही किसी company के roadmap पर निर्भर रहना बंद करना है, इसलिए वह fork चुनना जिसका custodian एक non-profit हो, वही choice है जो आपके यहाँ होने की वजह से मेल खाती है। बाद में switch करने पर एक practical बात: Forgejo को किसी मौजूदा Gitea data directory के ऊपर install किया जा सकता है, लेकिन दूसरी दिशा में जाना supported नहीं है।

क्या मुझे forge की ज़रूरत भी है? क्या SSH पर एक bare repository काफ़ी नहीं है?

एक laptop वाले और अच्छे commit messages लिखने की आदत वाले एक अकेले व्यक्ति के लिए, एक bare repository सचमुच काफ़ी है, और यह इस guide की सबसे मज़बूत चीज़ है: server पर git init --bare, एक सामान्य SSH account, और न कोई web application patch करने को, न कोई database backup करने को, न sshd से आगे कोई attack surface। उस setup में कभी कुछ end-of-life नहीं होगा। आपको forge की ज़रूरत उसी पल पड़ती है जब कोई दूसरा इंसान शामिल हो जाए, या जब आपको उन चार चीज़ों में से कोई चाहिए हो जिनके बारे में एक bare repository कुछ नहीं जानती — browse होने लायक history, review के साथ pull requests, code के बग़ल में रहने वाला issue tracker, और per-repository access control। यह कोई छोटा-सा कदम ऊपर नहीं है; यह storage और collaboration के बीच का फ़र्क़ है। ईमानदारी से देखें कि आप किसके लिए हल ढूँढ रहे हैं, क्योंकि forge अब एक ऐसी service है जिसे आप operate करते हैं, जबकि bare repository महज़ एक directory है।

क्या मैं अपनी GitHub repositories को, issues और pull requests समेत, migrate कर सकता हूँ?

हाँ, और self-hosting में यह बेहतर migration कहानियों में से एक है। Forgejo का built-in migration tool एक repository URL और एक personal access token लेकर सिर्फ़ code से कहीं ज़्यादा खींच लाता है: branches और tags, comments समेत issues, pull requests, labels, milestones और releases। इसे read scope वाला एक token दें, पहले एक repository चलाकर देखें कि नतीजा कैसा दिखता है, फिर बाक़ी पर काम करें। तीन बातों की उम्मीद रखें। बड़ी या कई सारी migrations source platform की API rate limits से टकराएँगी और बस ज़्यादा समय लेंगी — उन्हें शुरू करें और छोड़ दें। issues पर attachments network से fetch होते हैं, इसलिए एक restrictive egress firewall के पीछे बैठा instance टूटी हुई images वाले issues बनाएगा। और review threads हमेशा ठीक वहीं नहीं पहुँचते जहाँ वे थे, क्योंकि दोनों data models एक जैसे नहीं हैं। source repositories को उसी दोपहर मिटाने के बजाय कुछ हफ़्तों तक read-only रखने की योजना बनाएँ।

क्या एक self-hosted forge सचमुच ज़्यादा private है, या बस अलग है?

यह सचमुच एक ख़ास और अहम तरीक़े से अलग है: index सिर्फ़ आपके पास होता है, किसी और के पास नहीं। किसी platform पर, private repository सिर्फ़ दूसरे users के लिए private होती है — वह platform के लिए private नहीं होती, जो उसे स्टोर करता है, स्कैन करता है, उससे एक dependency graph निकालता है, और अपने jurisdiction की किसी court द्वारा उसे पेश करने के लिए बाध्य किया जा सकता है। code के फीका होने पर भी वह index असामान्य रूप से बहुत कुछ उजागर करता है: commit timestamps बताते हैं कि आप कब सोते हैं, co-authors बताते हैं कि आप किसके साथ काम करते हैं, branch names बताते हैं कि कौन-से अनरिलीज़्ड products हैं, और पहला commit उस project की तारीख़ तय कर देता है जिसकी अभी घोषणा भी नहीं हुई। इसे अपने server पर ले जाना उस पूरी तस्वीर से platform को पूरी तरह हटा देता है। जो यह नहीं करता वह है machine को ग़ायब कर देना। आप अब भी किसी datacentre में hardware किराए पर ले रहे हैं, disk अब भी उन लोगों की पहुँच में है जो उस इमारत के मालिक हैं, और आपने जो hostname चुना है वह अब भी certificate-transparency logs में है। ईमानदार सार यह है: आपने एक contractual privacy policy वाली company की जगह एक ऐसे server को रख दिया है जिसकी इकलौती policy आपका अपना configuration है, ऐसे jurisdiction में जिसे आपने जान-बूझकर चुना — और जो account इसका भुगतान करता है उसे आपका नाम ढोने की ज़रूरत नहीं।

VPS को कितना बड़ा होना चाहिए?

उससे कहीं छोटा जितना GitLab की documentation ने सबको उम्मीद करना सिखाया है। Forgejo और Gitea अकेले Go binaries हैं जो कुछ सौ megabytes RAM में idle रहते हैं; PostgreSQL और एक reverse proxy जोड़ने पर भी एक solo developer का forge एक Sentinel में — 2 vCPU, 4 GB, 120 GB NVMe, $3.90 महीना — आराम से समा जाता है, बाक़ी जगह के साथ। दबाव तीन दूसरी जगहों से आता है, और हर एक को जान-बूझकर size करना ज़रूरी है। CI सबसे बड़ी है: containers बनाने वाला एक runner आपका दिया हर core इस्तेमाल कर लेगा और disk को layers से भर देगा। repository का आकार दूसरी है: game assets, notebooks और vendored dependencies source code से कहीं तेज़ी से बढ़ते हैं। artifacts और एक container registry तीसरी हैं। practice में जो नियम अच्छी तरह टिका है — forge को एक Sentinel पर रखें, runner को उसके अपने दूसरे Sentinel पर रखें, और tier तभी बढ़ाएँ जब disk कहे, न कि जब CPU कहे।

क्या Forgejo Actions सचमुच मेरे GitHub Actions workflows के साथ compatible है?

इतना compatible कि ज़्यादातर सीधे-सादे workflows बिना बदले चल जाते हैं, लेकिन इतना भी नहीं कि आप किसी complex pipeline को बिना पढ़े migrate कर दें। workflow file का format वही है, यह .forgejo/workflows/ में रहता है (और .github/workflows/ भी पढ़ा जाता है), और आम building blocks — checkout, language setup, cache, matrix builds — वैसे ही बर्ताव करते हैं जैसी उम्मीद हो, क्योंकि runner उन्हें उसी तरह containers में execute करता है। जो टूटता है वह हर वह चीज़ है जो platform के तौर पर GitHub मान लेती है, न कि format के तौर पर Actions को: github.com URLs पर pinned marketplace actions जिन्हें आपके instance को fetch करने की अनुमति देनी होगी, ऐसे actions जो release या PR metadata के लिए GitHub REST API को कॉल करते हैं, बेहद ख़ास pre-installed toolchain वाली GitHub-hosted runner images, और OIDC-based cloud authentication। जो pattern काम करता है: सिर्फ़ build और test करने वाले एक workflow से शुरू करें, उसे green करें, फिर deployment steps को एक-एक करके वापस जोड़ें।

अगर VPS मर जाए तो मेरे code का क्या होगा?

code अपने-आप में वह हिस्सा है जो ठीक रहता है, और यही Git का लगभग हर दूसरी self-hosted service पर चुपचाप बना रहने वाला फ़ायदा है: हर clone history की पूरी copy है, इसलिए जब तक किसी एक developer के पास मौजूदा working copy है, repository खोई नहीं है। server के साथ जो मरता है वह code के आस-पास की हर चीज़ है — issues, pull request discussions, review comments, releases, wiki, users, access rules, CI history। यह सामग्री सिर्फ़ database में रहती है, इसकी किसी के पास clone नहीं होती, और यह आम तौर पर वह हिस्सा है जिसे जमा होने में सालों लगे। इसलिए दोनों को अलग-अलग तरह से बरतें। code के लिए, किसी दूसरी जगह पर एक push mirror configure कर दें और बिना किसी मेहनत के आपके पास लगातार, अपने-आप चलने वाली, offsite सुरक्षा है। metadata के लिए, आपको एक असली backup चाहिए: एक PostgreSQL dump और data directory दोनों, encrypted, और किसी timer पर किसी दूसरे jurisdiction की एक machine को भेजी हुई। Step 06 दोनों को कवर करता है, और आख़िर में restore drill ही वह हिस्सा है जो इन्हें एक इरादे से एक गारंटी में बदल देता है।

क्या मैं GitHub को पूरी तरह छोड़ने के बजाय एक mirror के तौर पर रख सकता हूँ?

हाँ, और बहुत सारे projects के लिए यह कोई समझौता नहीं बल्कि सही जवाब है। Forgejo push mirrors को support करता है, इसलिए आपका instance वह origin बना रहता है जिसके ख़िलाफ़ आपकी team काम करती है, और हर push अपने-आप GitHub, Codeberg या किसी दूसरे Forgejo की एक repository में replicate हो जाता है। Public visibility, drive-by contributors, GitHub URL की उम्मीद रखने वाली package registries, और किसी पुरानी README में issue-tracker link — यह सब काम करते रहते हैं, जबकि source of truth — और private repositories, और CI logs, और जो कुछ आप publish नहीं करते उसकी issue history — आपके box पर ही रहती है। यह दूसरी दिशा में भी काम करता है: pull mirrors उन upstream projects की एक local, हमेशा-current copy रखते हैं जिन पर आप निर्भर हैं, जो उस हर चीज़ के लिए करने लायक है जिसके बिना आप फँस जाएँगे अगर वह कल मिटा दी जाए। जिस एक बात को लेकर जान-बूझकर सोचना ज़रूरी है वह यह है कि आप mirror क्या कर रहे हैं: किसी ऐसी repository का push mirror जिसकी history में कोई secret है जिसे आप हटाना चाहते थे, उस secret को तुरंत और अपने-आप फिर से publish कर देता है।

मैं किसी contractor को बाक़ी सब कुछ दिए बिना सिर्फ़ एक repository का access कैसे दूँ?

वह layer इस्तेमाल करें जो इस बात से मेल खाए कि access कितने समय के लिए चाहिए। जो व्यक्ति पढ़ेगा, commit करेगा और pull requests खोलेगा, उसके लिए एक user account बनाएँ और उसे ठीक उन्हीं repositories पर एक collaborator के तौर पर जोड़ें जिनकी उसे ज़रूरत है, एक साफ़ permission level के साथ — read, write या admin — न कि उसे किसी organisation team में डालकर, जो चुपचाप ज़्यादा दे देती है। किसी automated system के लिए जिसे सिर्फ़ fetch करना है — कोई deployment target, कोई build box, कोई mirror — user account की जगह एक read-only deploy key इस्तेमाल करें: यह सिर्फ़ एक repository तक scoped है, यह और कुछ नहीं देती, और इसे revoke करना बस एक line मिटाना है। API से बात करने वाली scripts के लिए, password सौंपने के बजाय एक scoped access token जारी करें। दो आदतें ही पूरी बात को टिकाए रखती हैं: registration बंद रखें ताकि सिर्फ़ वही accounts मौजूद हों जो आपने बनाए, और जब भी temporary access दें तो अपने calendar में एक तारीख़ डाल दें, क्योंकि कोई भी forge आपको कभी याद नहीं दिलाएगा कि कोई contract ख़त्म हो गया।

क्या forge को एक domain name चाहिए, और क्या इससे मेरी identity लीक होती है?

web interface के लिए इसे एक hostname चाहिए, क्योंकि TLS certificates नामों के लिए जारी होते हैं और यहाँ किसी browser को किसी IP address पर भरोसा नहीं करना चाहिए। इस नाम का आप तक traceable होना ज़रूरी नहीं। तीन बातों को लेकर जान-बूझकर सोचें। domain कहीं ऐसी जगह register करें जो वह identity न माँगे जिसे लेकर आप कहीं और सतर्क रहे हैं, और WHOIS privacy चालू रखें — registrar, host से अलग एक भरोसे का फ़ैसला है, और यही वह है जिसे लोग भूल जाते हैं। certificate जारी होते ही hostname के सार्वजनिक हो जाने की उम्मीद रखें, क्योंकि हर publicly trusted certificate certificate-transparency logs में publish होता है जिन्हें कोई भी खोज सकता है; जिस domain को आप पहले से इस्तेमाल करते हैं उस पर एक wildcard किसी नए खोजे जा सकने वाले नाम को जुड़ने से बचाता है। और अगर आप बिल्कुल कोई सार्वजनिक नाम ही न रखना चाहें, तो विकल्प असली है: forge को किसी Tor onion service पर डालें या सिर्फ़ WireGuard पर पहुँच लायक बनाएँ, public certificate को पूरी तरह छोड़ दें, और यह मान लें कि इसके साथ कहीं से भी browser खोलने की सुविधा भी चली जाएगी।

अगर मैं किसी VPS पर Git forge और CI runners चलाऊँ तो क्या NordBastion को कोई एतराज़ है?

बिल्कुल नहीं — forge और उसके runners एक सामान्य workload हैं, और यह उन चीज़ों में से एक है जो हमारे customers अक्सर बनाते हैं। acceptable-use policy में source code होस्ट करने या उसे बनाने को लेकर कुछ नहीं कहा गया। policy की नहीं, बल्कि operation की दो बातें। पहली, ऐसा CI runner जो अजनबियों के workflows स्वीकार करता है, वह जिसे भी मिल जाए उसके लिए एक मुफ़्त compute service है: आम दुरुपयोग किसी pull request में cryptocurrency mining है, और खुला होने के कुछ ही दिनों में यह पकड़ में आ जाएगा। registration बंद रखें, और जो अभी collaborator नहीं है उसके लिए workflows चलने से पहले approval ज़रूरी करें। दूसरी, अगर आपके builds हर run पर बड़ी container images खींचते हैं, तो यह सामान्य traffic है और यह शामिल है — लेकिन फिर भी उन्हें locally cache करना समझदारी है, क्योंकि इससे आपकी pipeline तेज़ होती है और जिन upstream registries पर आप निर्भर हैं उनके साथ यह शिष्टाचार भी है।

box लें

आपका अपना एक forge, ऐसे account पर जो आपका नाम नहीं है। KYC-मुक्त, crypto-भुगतान।

Sentinel — 2 vCPU और 4 GB, $3.90 महीने में, Helsinki, Stockholm, Oslo या Reykjavík में। Forgejo, PostgreSQL और reverse proxy के लिए काफ़ी, साथ ही उन repositories के लिए जगह जिन्हें आप हमेशा से ले जाना चाहते थे। runner के लिए एक दूसरा जोड़ लें। signup पर कोई email नहीं, कोई पहचान-पत्र नहीं, और जो कुछ भी आप push करें उसका कोई product-level index नहीं।

अंतिम review · 2026-10-12 · स्रोत · Forgejo administrator documentation (installation, Actions, command line), Gitea के साथ Forgejo की तुलना, Codeberg e.V. governance pages, PostgreSQL और Caddy documentation, git-config(1) · आवृत्ति · वार्षिक

निजी होस्टिंग, उत्तर में निर्मित।