Maskot beruang kutub NordBastion berdiri di dalam ruang bawah tanah batu ala Nordik yang gelap di samping rak server, satu cakarnya bertumpu pada diagram branch holografik cyan yang melayang dari sebuah riwayat Git dengan tiga garis yang saling bergabung, sebuah peti besi berukir rune berisi kode sumber yang tersegel di atas meja kerja di sampingnya, dan cahaya aurora jatuh menembus jendela melengkung yang tinggi
How-to · Infrastruktur developer·18 menit baca · 45 menit praktik

Server Git milik Anda sendiri.
Repositori adalah bagan organisasi.

Repositori pribadi adalah catatan bertanggal tentang apa yang sedang Anda bangun, dengan siapa Anda membangunnya, dan sejauh mana progresnya — dan di sebuah platform, catatan itu dipegang oleh sebuah perusahaan di yurisdiksi milik orang lain. Enam langkah untuk memindahkannya ke mesin yang Anda sewa secara anonim: Forgejo di balik Caddy, PostgreSQL di baliknya, push SSH pada port tersendiri, runner Actions yang tidak pernah melihat secret produksi Anda, dan backup yang benar-benar sudah Anda pulihkan. Mesinnya seharga $3.90 sebulan. Diuji di Debian 12.

Enam langkah
  1. 01

    Pilih

    Repo bare, Forgejo, GitLab

  2. 02

    Sediakan

    Port ditentukan sebelum boot

  3. 03

    Deploy

    Forgejo, Postgres, Caddy

  4. 04

    Push

    SSH, deploy key, tanda tangan

  5. 05

    Build

    Runner, dijaga berjarak

  6. 06

    Simpan

    Mirror, backup, upgrade

Sebelum Anda mulai · Apa yang dipegang platform

Kodenya adalah bagian yang paling tidak menarik. Metadata-lah asetnya.

Hampir setiap perdebatan tentang self-hosting Git adalah perdebatan tentang kode sumber, padahal kode sumber adalah bagian yang paling tidak penting. Sebagian besarnya biasa-biasa saja, banyak di antaranya hanyalah lapisan tipis di atas library open-source, dan jika ia bocor besok, kerugian praktisnya biasanya hanya rasa malu, bukan kerugian nyata. Itulah sebabnya "kode saya tidak rahasia" terasa seperti jawaban yang lengkap — dan mengapa sebenarnya bukan.

Yang mengelilingi kode itulah bagian yang menarik. Sebuah repositori adalah catatan kerja yang bertanggal, beratribusi, dan beresolusi tinggi: timestamp commit yang menggambarkan kapan Anda tidur, baris co-author yang menggambarkan dengan siapa Anda bekerja, nama branch yang menggambarkan produk yang belum diumumkan siapa pun, issue tracker yang menggambarkan apa yang rusak dan separah apa, dan commit pertama yang menandai tanggal seluruh proyek itu dimulai. Baca seratus repositori dengan cara ini dan Anda bukan lagi membaca perangkat lunak — Anda sedang membaca sebuah perusahaan, roadmap-nya, jumlah karyawannya, dan masalahnya.

Di sebuah platform, catatan itu bukan lagi milik Anda dalam pengertian yang sesungguhnya. Ia berada di infrastruktur yang tidak Anda kendalikan, di bawah akun yang terikat pada identitas yang telah Anda verifikasi, di yurisdiksi yang proses hukumnya bisa menjangkaunya, dipindai oleh sistem yang cakupannya ditentukan oleh sebuah dokumen yang bisa diubah sewaktu-waktu. Tidak satu pun dari itu membutuhkan itikad buruk dari siapa pun: itu hanyalah konsekuensi dari menyewa tracker-nya. Empat skema, dan apa yang sebenarnya diungkap oleh masing-masing:

Di mana repositori itu berada Siapa yang memegang riwayatnya Terikat pada identitas hukum Anda Cara ini bisa gagal
Sebuah platform, akun pribadiPlatform itu, di yurisdiksinya sendiriYa — email, informasi penagihan, sering kali juga nomor teleponSatu kali penangguhan akun membawa serta semua remote-nya
Sebuah platform, akun organisasiPlatform itu, ditambah siapa pun yang mengelola organisasinyaYa, dan juga ke pemberi kerja AndaOffboarding menghapus akses Anda ke pekerjaan Anda sendiri
Self-hosted, di sebuah hyperscalerAnda, di lapisan aplikasiYa — akun penagihan itulah identitasnyaSnapshot-nya berada di akun yang bisa ditutup
Self-hosted, di VPS bebas KYCAnda, dan hanya AndaTidak — tanpa ID, tanpa kartu, diselesaikan dalam kriptoSekarang Anda adalah sysadmin-nya. Backup yang buruk bersifat final

Baris ketiga adalah baris yang menjebak tim-tim yang mengira mereka sudah menyelesaikan masalah ini. Forge yang Anda instal sendiri, di sebuah mesin yang disewa dengan kartu korporat di bawah akun perusahaan yang terverifikasi, telah memindahkan aplikasinya keluar dari platform tetapi meninggalkan identitasnya persis di tempat semula. Itu adalah keuntungan nyata dalam hal kontrol, dan sama sekali bukan keuntungan dalam hal keterpaparan.

Dan baris keempat menyatakan biayanya sendiri secara terang-terangan, karena sebagian besar dari sisa panduan ini adalah tentang cara membayarnya. Mode kegagalan dari self-hosting bukanlah pengawasan, melainkan kehilangan. Sebuah platform menyimpan backup yang tidak pernah Anda pikirkan. Server Anda hanya menyimpan backup yang Anda konfigurasikan sendiri. Langkah 06 bukanlah polesan opsional di bagian akhir — itu adalah langkah yang membuat lima langkah lainnya aman.

Langkah 01 · Pilih

Seberapa banyak forge yang Anda butuhkan? Jawaban jujurnya sering kali adalah "tidak sama sekali".

Mulailah dengan hal terkecil yang menyelesaikan masalah Anda, karena setiap lapisan di atasnya adalah layanan yang harus Anda operasikan sendiri. Repositori bare lewat SSH hanya satu perintah di server yang sudah Anda miliki, dan itu memberi Anda remote Git sungguhan lengkap dengan autentikasi, riwayat, dan akses push. Tidak ada aplikasi web, tidak ada database, tidak ada treadmill upgrade, tidak ada yang perlu ditambal selain sshd. Jika Anda adalah satu orang yang hanya ingin commit Anda keluar dari laptop dan keluar dari sebuah platform, ini sudah jawaban yang lengkap dan Anda bisa berhenti membaca setelah langkah 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

Anda membutuhkan forge ketika orang kedua terlibat, atau ketika Anda menginginkan salah satu dari empat hal yang tidak bisa dilakukan oleh sekumpulan direktori repositori bare: menjelajahi riwayat lewat browser, mereview perubahan sebagai pull request, melacak issue di samping kodenya, dan memberi satu orang akses ke satu repositori. Itu adalah peningkatan nyata dalam hal kemampuan, sekaligus peningkatan nyata dalam hal beban operasional. Pilihlah dengan sengaja:

Properti Repo bare lewat SSH Forgejo Gitea GitLab CE
Web UI, pull request, issueTidak adaYaYaYa, dan jauh lebih banyak lagi
Memori saat idlePraktis nolBeberapa ratus MBBeberapa ratus MBBeberapa GB, sebelum CI
CI bawaangit hooks, jika Anda menulisnya sendiriForgejo ActionsGitea ActionsGitLab CI, yang paling matang
Siapa yang mengendalikan proyeknyaProyek Git itu sendiriCodeberg e.V., organisasi nirlabaPerusahaan komersial, open corePerusahaan terbuka, open core
LisensiGPLv2GPLv3+ sejak v9.0 (MIT sebelumnya)MIT, dengan add-on proprietaryInti MIT, tier proprietary
Pilih ini jikaAnda sendirian dan ingin tidak ada maintenance sama sekaliAnda menginginkan forge sungguhan di mesin kecilAnda sudah menjalankannya dan itu berfungsi baikAnda membutuhkan kumpulan fitur enterprise

Forgejo dan Gitea berbagi leluhur yang sama dan penggunaannya sehari-hari masih terlihat hampir identik. Forgejo menjadi hard fork pada awal 2024 dan dipegang oleh Codeberg e.V., asosiasi nirlaba terdaftar di Berlin; Gitea dikembangkan oleh perusahaan komersial yang memiliki merek dagangnya sendiri dan meminta kontributor untuk menyerahkan hak cipta mereka. Keduanya adalah perangkat lunak yang baik. Hanya satu di antaranya yang punya pengelola dengan insentif yang selaras dengan alasan Anda membaca halaman ini.

Sisa panduan ini menggunakan Forgejo. Semua yang ada di langkah 02 sampai 06 berlaku hampir apa adanya untuk Gitea juga — nama container-nya dan beberapa variabel lingkungan berubah, tetapi bentuk dasarnya tidak.

Langkah 02 · Siapkan

Tentukan port-nya sebelum forge yang menentukannya untuk Anda. Dua di antaranya adalah SSH.

Pesan mesinnya terlebih dahulu. Di panel: Order → VPS → Sentinel, image Debian 12, di bastion mana pun tempat Anda ingin riwayatnya berada — Helsinki, Stockholm, Oslo, atau Reykjavík. Tidak perlu alamat email untuk membuka akun, dan invoice-nya diselesaikan dalam Monero, Bitcoin, Lightning, atau aset lain yang didukung. Ini lebih penting di sini dibanding untuk sebagian besar beban kerja lainnya: forge adalah satu-satunya layanan yang seluruh nilai proposisinya justru adalah bahwa catatan pekerjaan Anda tidak terikat pada sebuah nama.

Setelah itu, jalankan checklist hardening jam pertama — SSH khusus kunci pada port yang telah dipindah, unattended upgrade, firewall default-deny — karena semua yang ada di bawah ini mengasumsikan sebuah mesin yang belum menjadi milik orang lain.

Apa yang sebenarnya Anda taruh di internet

Forge bukanlah situs statis dengan halaman login. Ia adalah aplikasi web publik dengan mesin eksekusi kode yang menempel padanya. Dua pengaturan default, jika dibiarkan begitu saja, mengubahnya menjadi layanan gratis bagi orang asing: registrasi terbuka, yang memenuhi instance dengan akun spam dalam hitungan hari sejak sertifikatnya muncul di log transparansi, dan CI yang menjalankan workflow dari siapa pun yang bisa membuka pull request, yang menjadi cara sebuah runner self-hosted berakhir menambang cryptocurrency untuk orang lain. Tidak satu pun dari keduanya adalah serangan yang halus, dan tidak satu pun yang langka. Keduanya bisa ditutup masing-masing dengan satu pengaturan saja, di langkah 03 dan langkah 05 — tetapi putuskan sekarang bahwa Anda akan menutup keduanya, karena jendela antara "ini berfungsi" dan "ini sedang dipakai" hanya terhitung dalam hitungan hari.

Arahkan sebuah hostname ke mesin itu — sebuah A record, dan AAAA jika Anda ingin bisa dijangkau lewat IPv6 — dan biarkan propagasinya selesai dulu sebelum Anda mulai, karena reverse proxy-nya akan mencoba memperoleh sertifikat untuk nama tersebut pada boot pertamanya, dan sebuah challenge yang gagal adalah cara yang membingungkan untuk memulai. Setelah itu, tulis aturan firewall-nya selagi belum ada apa pun yang listening.

Masalah dua-SSH. Forge menggunakan SSH untuk Git, dan server Anda sudah menggunakan SSH untuk administrasi. Keduanya tidak bisa sama-sama memiliki port 22, dan mencampur keduanya adalah cara orang berakhir dengan daemon administratif yang juga harus memahami Git. Pisahkan keduanya: administrasi di port yang sudah dipindah dari panduan hardening, Git di port publik khusus yang dipetakan ke dalam container. 2222 adalah pilihan konvensional dan tidak ada yang sakral soal itu.

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.

Instal Docker dari repository resminya, bukan dari paket distro, supaya Compose v2 tersedia dan versinya mutakhir. Setelah itu, buat sebuah direktori untuk stack ini dan jadikan itu satu-satunya tempat di mesin yang menyimpan state — inilah direktori yang di-backup oleh langkah 06.

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

install -d -m 0750 /srv/forgejo
cd /srv/forgejo
Langkah 03 · Deploy

Tiga container. Satu di antaranya tidak boleh pernah bisa dijangkau.

Forgejo, PostgreSQL, dan Caddy. Forgejo menyimpan repositori-repositori dan menyajikan antarmukanya, PostgreSQL menyimpan segala sesuatu yang bukan objek Git, dan Caddy mengakhiri TLS serta memperoleh sertifikatnya tanpa perlu diminta dua kali. PostgreSQL dengan sengaja tidak dipublikasikan ke host: ia hanya bisa dijangkau lewat jaringan Compose, berdasarkan nama, dari satu-satunya container yang membutuhkannya.

/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
}

Dua baris SSH ini adalah yang paling sering salah dipahami orang, jadi patut dibaca dua kali. SSH_LISTEN_PORT adalah port di dalam container, tempat server SSH bawaan Forgejo melakukan binding. SSH_PORT adalah port yang dicetak Forgejo di URL clone yang ditampilkannya kepada Anda — ini harus cocok dengan sisi publik dari port mapping-nya. Jika keduanya tidak selaras, semuanya akan berfungsi kecuali satu hal yang benar-benar disalin-tempel oleh pengguna.

Jalankan semuanya, lalu buat administrator lewat command line. Jangan gunakan installer web. Pada instance yang baru, ia bisa diakses oleh siapa pun yang menemukan hostname-nya, dan akun pertama yang dibuat lewatnya akan menjadi administrator — sebuah perlombaan yang tidak perlu Anda ikuti. INSTALL_LOCK pada file di atas menutupnya bahkan sebelum container-nya mulai berjalan.

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

Buka hostname-nya di browser, masuk dengan kata sandi yang tercetak lalu ganti kata sandi itu. Setelah itu, telusuri pengaturan-pengaturan yang mengubah instance yang sudah berfungsi menjadi instance yang tertutup — sebagian besar sudah diatur oleh blok environment di atas, dan ada baiknya memastikan masing-masing daripada sekadar berasumsi:

Registrasi

DISABLE_REGISTRATION = true. Anda yang membuat akun; tidak ada yang mendaftar sendiri. Jika sesekali Anda butuh pendaftaran, gunakan alur undangan alih-alih membuka pintu lebar-lebar.

Visibilitas default

DEFAULT_PRIVATE = private. Repositori baru dimulai dalam keadaan tertutup. Publikasi pun menjadi tindakan yang disengaja, bukan sekadar konsekuensi dari sebuah pengaturan default.

Penjelajahan anonim

REQUIRE_SIGNIN_VIEW = true menyembunyikan bahkan repositori publik dari pengunjung yang belum masuk (logged-out). Tepat untuk forge tim pribadi; keliru jika Anda ingin mempublikasikan apa pun.

Dua faktor

Aktifkan fitur itu pada akun administrator sebelum melakukan hal lain apa pun. Forge kini menjadi mesin yang bisa menulis ulang setiap branch yang Anda miliki.

Satu path yang layak dihafalkan: konfigurasi yang aktif berada di ./data/gitea/conf/app.ini pada host. Forgejo mempertahankan nama direktori gitea demi kompatibilitas dengan instalasi yang sudah ada, yang selalu mengejutkan semua orang — tapi hanya sekali. Variabel lingkungan berbentuk FORGEJO__section__KEY dituliskan ke file itu saat start, sehingga Anda bisa mengelola seluruh konfigurasi dari file Compose — tetapi jika Anda mengedit app.ini secara manual, variabel lingkungan untuk key yang sama akan menimpa suntingan Anda pada restart berikutnya. Pilih salah satu dari keduanya dan konsistenlah.

Langkah 04 · Push

Push lewat SSH. Lalu tanda tangani, agar riwayatnya tidak bergantung pada server.

Tempelkan kunci publik Anda ke pengaturan profil, lalu beri tahu klien Anda di mana forge itu berada. Karena Git berjalan di port non-standar, sebuah entri di SSH config Anda sepadan dengan tiga puluh detik yang dibutuhkan — itu menjaga agar port-nya tidak perlu muncul di setiap URL yang akan Anda ketik, dan membuat remote-nya portabel.

# ~/.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

Perintah terakhir itulah yang memberi tahu Anda apakah port mapping, server SSH container, dan kunci Anda semuanya sudah selaras. Pesan salam dari Forgejo berarti seluruh rantainya berfungsi. Sebuah prompt kata sandi berarti Anda malah mencapai sshd administratif milik host, dan port mapping-nya keliru.

Sekarang, tanda tangani commit Anda. Ini adalah langkah yang dilewatkan oleh sebagian besar panduan self-hosting, padahal pada forge yang self-hosted, langkah ini justru lebih penting dibanding pada sebuah platform. Kolom author pada sebuah commit adalah teks bebas — siapa pun yang bisa melakukan push bisa menuliskan nama Anda di sana. Sebuah tanda tangan adalah bukti bahwa kunci tertentu yang membuat commit tertentu, dan bukti itu tetap berlaku bahkan setelah server tempatnya di-push telah diretas, dimigrasikan, atau dibuang. Git bisa menandatangani dengan kunci SSH yang sudah Anda miliki, jadi tidak perlu lagi memutar lewat 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

Setelah itu, tambahkan kunci publik yang sama sekali lagi di forge, sebagai signing key, bukan authentication key. Forgejo memverifikasi tanda tangannya di sisi server dan menampilkan commit tersebut sebagai verified; tanpa entri kedua itu, forge tidak memiliki cara untuk menghubungkan tanda tangan itu dengan akun Anda, dan setiap commit akan tampil sebagai unverified meskipun sudah ditandatangani dengan benar.

Deploy key, untuk mesin-mesin yang hanya membaca. Server produksi, mesin build, atau sebuah mirror tidak membutuhkan akun pengguna di forge. Berikan deploy key sebagai gantinya: sepasang kunci yang ditambahkan ke satu repositori, read-only kecuali Anda secara eksplisit memberi izin write, dan tidak memberi akses apa pun lagi ke bagian lain instance tersebut. Mencabutnya cukup dengan menghapus satu entri. Ini adalah kebiasaan tunggal paling efektif untuk menjaga forge self-hosted tetap rapi, karena akun pengguna mengumpulkan izin dari waktu ke waktu, sedangkan deploy key tidak bisa begitu.

Migrasi dari sebuah platform adalah momen yang baik untuk melakukan semua ini dengan benar. Alur New Migration milik Forgejo mengambil URL repositori dan sebuah token akses, lalu membawa serta branch, tag, issue, komentar, label, milestone, release, dan pull request. Jalankan satu repositori dulu untuk melihat bentuk hasilnya, perkirakan rate limit API akan memperlambat batch yang besar, dan biarkan sumbernya tetap read-only selama beberapa minggu alih-alih menghapusnya di hari yang sama.

Langkah 05 · Build

Runner CI adalah mesin yang menjalankan kode milik orang asing. Tempatkan sesuai dengan itu.

Forgejo Actions membaca file workflow dalam format yang sama dengan GitHub Actions, dari .forgejo/workflows/, dan menyerahkannya ke sebuah program terpisah bernama Forgejo Runner. Runner ini bukan bagian dari forge dan tidak harus berada di mesin yang sama — itu justru keseluruhan desainnya, dan itulah alasan mengapa langkah ini disertai peringatan, bukan sekadar dianggap remeh.

Aktifkan Actions pada instance-nya, lalu ambil registration token dari panel administrasi — berlaku untuk seluruh instance, atau dibatasi pada satu organisasi atau satu repositori, yang merupakan default lebih baik ketika Anda tidak yakin. Runner-nya melakukan koneksi keluar menuju forge, jadi ia sama sekali tidak membutuhkan port masuk (inbound), dan bisa ditempatkan di belakang firewall apa pun yang Anda suka, termasuk pada mesin tanpa alamat publik.

# 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

Label-label ini adalah kontrak antara workflow dan runner: sebuah job yang meminta runs-on: docker akan mendapat container yang dibangun dari image di sisi kanan. Deklarasikan hanya label yang benar-benar siap Anda layani, karena sebuah job yang meminta label yang tidak ditawarkan siapa pun akan menunggu selamanya alih-alih gagal — hal yang membingungkan untuk di-debug di penghujung hari yang panjang.

.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
Aturan yang membuat perbedaan

Runner menjalankan apa pun yang dikatakan file workflow-nya, dan file workflow itu datang lewat sebuah pull request. Jika ada siapa pun di luar tim Anda yang bisa membuka satu pull request, maka runner itu harus berada di mesin yang berbeda dari forge-nya — sebuah Sentinel kedua seharga $3.90 sebulan, tanpa akses ke direktori data forge, tanpa kredensial database, dan tanpa apa pun di environment-nya yang akan Anda keberatan jika terbaca di build log. Pada forge itu sendiri, wajibkan persetujuan sebelum workflow dijalankan untuk kontributor yang baru pertama kali. Dua kegagalan standarnya sama-sama membosankan dan sama-sama mahal: sebuah beban kerja mining yang terkubur dalam sebuah pull request, dan sebuah secret yang tercetak oleh sebuah step yang sengaja ditambahkan seseorang.

Batasi cakupan secret dengan cara yang sama. Forgejo menyimpannya pada level repositori, organisasi, dan instance; sebuah deployment key yang hanya dibutuhkan satu repositori seharusnya hanya ada pada repositori itu saja, sehingga workflow yang telah disusupi pada proyek yang tidak terkait tidak bisa membacanya. Utamakan token berumur pendek dibanding token berumur panjang di mana pun target-nya mendukung itu, dan jangan pernah meletakkan secret di dalam file workflow — file workflow itu berada di dalam repositori, dan repositori punya riwayat.

Jika build Anda menarik base image yang sama pada setiap kali dijalankan, simpanlah dalam cache. Sebuah registry mirror lokal atau cache runner yang persisten mengubah image pull yang tadinya dua menit menjadi dua detik saja, dan itu adalah hal yang sopan untuk dilakukan terhadap registry upstream yang terus-menerus Anda bebani. Perhatikan juga pola yang diundang oleh keseluruhan desain ini, yang menjadi alasan mengapa panduan ini diletakkan berdampingan dengan panduan agent runtime: runner adalah worker serbaguna yang menarik job dari forge Anda, sehingga di situ jugalah tempat semestinya maintenance terjadwal, data pipeline, dan beban kerja agent berada.

Langkah 06 · Jaga

Setiap clone adalah backup dari kodenya. Tidak ada yang menjadi backup dari percakapannya.

Git luar biasa pemaaf di sini, dan ada baiknya bersikap presisi tentang alasannya. Setiap clone adalah salinan lengkap dari riwayatnya, jadi selama satu developer saja memiliki working copy yang mutakhir, kodenya akan bertahan hidup melampaui server itu sendiri. Itu benar-benar melegakan, dan itu mencakup persis satu dari dua hal yang dipegang oleh forge Anda. Yang satunya lagi — issue, diskusi pull request, thread review, release, halaman wiki, pengguna, tim, izin, riwayat CI — hanya ada di dalam database, tidak ada seorang pun yang punya salinannya, dan biasanya itulah bagian yang butuh waktu tiga tahun untuk terkumpul.

Pertama, sebuah push mirror. Gratis, dan berjalan dengan sendirinya. Di sebuah repositori: Settings → Mirror settings → tambahkan push mirror dengan URL dan sebuah token akses untuk tujuannya. Forgejo kemudian mereplikasi setiap branch dan tag setelah setiap push, ke Forgejo kedua, ke Codeberg, atau ke sebuah platform yang telah Anda putuskan untuk dijadikan sekadar etalase, bukan rumah. Satu peringatan yang layak dinyatakan dengan jelas: sebuah push mirror mempublikasikan ulang riwayat dengan setia, termasuk sebuah secret yang sebenarnya ingin Anda hapus.

Lalu backup sungguhan, yang bukan arsip bawaan. Forgejo menyediakan perintah forgejo dump yang mengemas konfigurasi, repositori, data, dan sebuah dump database ke dalam satu file zip. Ini adalah hal yang sungguh berguna untuk diserahkan ke seorang maintainer saat melaporkan bug. Tetapi ini bukan yang seharusnya Anda andalkan untuk bangkit kembali dari kematian: SQL yang dihasilkannya memiliki masalah yang sudah lama diketahui saat re-import, dan arsipnya menulis ulang seluruh kumpulan repositori pada setiap kali dijalankan, yang pada instance sungguhan berarti sebuah file besar yang ditulis dari nol setiap malam. Gunakan jalur yang membosankan tapi bisa diverifikasi ini sebagai gantinya — dump database-nya dengan tool bawaan database itu sendiri, dan backup direktori data-nya sebagai file-file:

#!/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

Kirim ke sebuah mesin di yurisdiksi yang berbeda dari forge-nya, lewat repositori append-only sehingga sebuah kompromi pada forge tidak bisa menghapus riwayatnya sendiri — panduan backup terenkripsi adalah versi panjang dari tiga baris di atas, termasuk systemd timer dan pembatasan key append-only-nya.

Lalu pulihkan sekali, dengan sengaja. Pesan sebuah VPS uji coba, pulihkan snapshot-nya ke situ, jalankan file Compose yang sama terhadap direktori data yang telah dipulihkan, muat dump database-nya, arahkan sebuah entri hosts-file ke situ, dan masuk (sign in). Hitung waktu keseluruhan prosesnya. Angka itu — bukan sekadar keberadaan job backup-nya — adalah posisi pemulihan Anda yang sesungguhnya, dan semua orang yang pernah melakukan latihan ini menemukan setidaknya satu hal yang hilang dari daftar include-nya pada percobaan pertama.

# 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

Upgrade, secara singkat. Kunci image-nya ke sebuah versi major, bukan ke :latest, supaya sebuah pull yang tidak diawasi tidak bisa membawa Anda melewati breaking change sementara Anda tidur. Baca release notes sebelum melintasi batas versi major, ambil snapshot dulu, dan ingat bahwa migrasi database berjalan pada start pertama versi baru — dan itu adalah pintu satu arah. Auto-update ala Watchtower adalah ide yang bagus untuk situs statis, tetapi ide yang buruk untuk mesin yang menyimpan setiap branch yang Anda miliki.

Empat pemeriksaan sebelum Anda menyatakannya selesai. Keluar (sign out), lalu pastikan instance-nya tidak menawarkan cara apa pun untuk membuat akun. Dari sebuah browser tanpa sesi, pastikan sebuah repositori pribadi benar-benar tidak terlihat, bukan sekadar terlarang. Pastikan runner-nya tidak bisa membaca direktori data forge. Dan pastikan pemeriksaan restic terakhir lolos — job backup yang gagal secara diam-diam adalah yang dimiliki semua orang, sampai hari mereka benar-benar membutuhkannya.

Bagian yang jujur · Apa yang tidak dilakukan ini

Anda menghilangkan satu pihak. Anda tidak menghilangkan gedungnya.

Self-hosting sebuah forge adalah perubahan nyata dalam siapa yang memegang pekerjaan Anda, dan itu bukan berarti ketidaktampakan. Empat hal berikut tetap benar setelah semua yang di atas selesai dilakukan, dan mengetahuinya adalah perbedaan antara sebuah pertahanan sungguhan dan sekadar cerita yang Anda yakini sendiri.

Disknya berada di gedung milik orang lain. Server sewaan berjalan di atas perangkat keras dalam sebuah pusat data yang punya pintu dan staf. NordBastion tidak memeriksa beban kerja pelanggan, dan laporan transparansi serta warrant canary kami menjelaskan apa yang akan terjadi jika kami diminta melakukannya — tetapi pernyataan arsitekturalnya adalah yang jujur: yang berubah adalah tidak ada lagi indeks tingkat produk atas repositori Anda, tidak ada pipeline analitik atas commit Anda, dan tidak ada kebijakan privasi yang bisa diubah sewaktu-waktu. Yang tidak berubah adalah bahwa mesinnya tetap fisik, dan ia tidak berada di rumah Anda.

Hostname-nya menjadi publik begitu sertifikatnya diterbitkan. Setiap sertifikat yang dipercaya publik dipublikasikan di log transparansi sertifikat yang bisa dicari siapa saja, sehingga git.yourproject.com bisa ditemukan bahkan jika Anda tidak pernah menautkannya ke mana pun. Itu bukan kebocoran kode Anda, tetapi kebocoran fakta bahwa proyek itu ada dan kira-kira kapan proyek itu dimulai. Gunakan subdomain dari nama yang sudah Anda publikasikan, atau lewati sertifikat publik sepenuhnya dan jangkau forge-nya lewat WireGuard atau sebuah layanan onion.

Sekarang Anda sedang menambal sebuah aplikasi web. Forge adalah sebuah halaman login, sebuah rendering pipeline untuk markup yang tidak tepercaya, sebuah server SSH, dan sebuah mesin CI — semuanya bisa dijangkau dari internet. Itu adalah permukaan yang jauh lebih besar dibanding repositori bare dari langkah 01, dan itu adalah permukaan yang harus Anda jaga tetap mutakhir. Berlangganan pengumuman rilis, dan perlakukan sebuah rilis keamanan sebagai pekerjaan yang harus selesai minggu itu juga, bukan kuartal itu juga.

Federasi belum hadir di sini. Forgejo sedang mengerjakan hal yang sungguhan pada federasi forge dan mempublikasikan progresnya, tetapi hingga hari ini Anda tidak bisa membuka pull request pada instance milik orang lain dari instance Anda sendiri seperti yang bisa Anda lakukan pada sebuah platform bersama. Secara praktis, itu berarti kontributor eksternal tetap membutuhkan akun di forge Anda, atau Anda menerima patch lewat email, atau Anda mempertahankan sebuah mirror publik untuk kontribusi drive-by. Rencanakan salah satu dari ketiganya yang sesuai dengan proyek Anda, alih-alih dikejutkan olehnya nanti.

Apa yang sebenarnya Anda beli, secara presisi: catatan bertanggal tentang apa yang Anda bangun, dengan siapa, dan kapan, tidak lagi dipegang oleh sebuah perusahaan yang model bisnisnya mencakup menganalisisnya. Itu adalah klaim yang sempit, dan itu klaim yang nyata. Itu sepadan dengan biayanya hanya jika langkah 06 sudah dilakukan — sebuah forge self-hosted tanpa restore yang teruji bukanlah peningkatan privasi, melainkan sebuah single point of failure dengan branding yang lebih baik.

Ukuran · Apa yang perlu dipesan

Forge-nya kecil. CI-nya tidak.

Tingkatan Bulanan Sumber daya Apa yang bisa dijalankannya dengan nyaman
Sentinel$3.902 vCPU · 4 GB · 120 GBForgejo + PostgreSQL untuk satu orang atau tim kecil. Titik awal yang tepat.
Sentinel kedua$3.90Runner-nya, di mesinnya sendiriIsolasi yang benar-benar penting, seharga secangkir kopi
Garrison$7.904 vCPU · 8 GB · 240 GBForge untuk sepuluh orang, sebuah container registry, dan artifact
Ravelin$16.908 vCPU · 16 GB · 480 GBCI yang sibuk, repositori besar, beberapa job paralel

Tidak ada satu pun di tabel ini yang diukur berdasarkan kebutuhan Git. Forgejo dan PostgreSQL bersama-sama idle di kisaran beberapa ratus megabyte; yang memenuhi sebuah mesin adalah CI — layer container, build cache, artifact — dan konten repositori yang bukan kode sumber. Ukur berdasarkan disk terlebih dahulu, lalu core, dan terakhir memori. Dua mesin kecil mengalahkan satu mesin besar di sini, karena mesin kedua itu adalah batas keamanan, bukan sekadar kapasitas tambahan.

Catatan lapangan · Enam jebakan

Enam cara ini bisa berjalan salah. Dua di antaranya menghabiskan uang.

Jebakan 01 · Berisik

Registrasi terbuka, dan forge penuh orang asing

Sertifikatnya muncul di log transparansi, para scanner mengikuti dalam hitungan hari, dan sebuah instance dengan pendaftaran yang aktif akan dipenuhi akun spam dan repositori spam. Atur DISABLE_REGISTRATION sebelum boot pertama, bukan setelah insiden pertama.

Jebakan 02 · Mahal

Runner yang menambang cryptocurrency untuk orang lain

CI yang menjalankan workflow dari pull request mana pun adalah komputasi gratis bagi siapa pun yang menemukannya. Wajibkan persetujuan untuk kontributor yang baru pertama kali, jaga runner-nya tetap di mesinnya sendiri, dan sesekali baca durasi job-nya.

Jebakan 03 · Senyap

ROOT_URL keliru, dan semuanya berfungsi setengah-setengah

URL clone mengarah ke host yang salah, webhook terpicu ke alamat yang salah, callback OAuth gagal, dan avatar rusak. Antarmukanya terlihat baik-baik saja, sehingga tidak ada yang mencurigai satu baris itu. Atur DOMAIN, ROOT_URL, SSH_DOMAIN, dan SSH_PORT secara bersamaan, lalu periksa sebuah URL clone di UI-nya.

Jebakan 04 · Membingungkan

Dua server SSH, satu port

Container-nya menginginkan port 22, padahal host sudah memakainya, sehingga mapping-nya diam-diam mendarat di tempat yang tidak terduga dan git push malah meminta kata sandi. Pindahkan SSH administratif terlebih dahulu, publikasikan container-nya di port tersendiri, dan verifikasi dengan ssh -T.

Jebakan 05 · Fatal

Dump yang tidak pernah dipulihkan

Arsip bawaan adalah artefak dukungan, bukan jalur pemulihan yang teruji, dan SQL-nya memiliki masalah re-import yang sudah diketahui. Dump database-nya dengan pg_dump, backup direktori datanya sebagai file-file, dan pulihkan semuanya ke sebuah mesin uji coba satu kali.

Jebakan 06 · Lambat

Disknya terisi penuh oleh layer build, bukan oleh kode

Kode sumber itu kecil; layer container, artifact, dan cache CI tidak. Sebuah mesin 120 GB dengan pipeline yang antusias akan penuh dalam hitungan minggu. Pangkas image secara terjadwal, batasi retensi artifact, dan awasi disknya, bukan CPU-nya.

FAQ · Hosting Git pribadi

Pertanyaan, dijawab.

Sebelas pertanyaan yang muncul selagi membangun ini — dimulai dari dua pertanyaan yang menentukan apakah Anda sebaiknya membangunnya sama sekali.

Forgejo atau Gitea — mana yang sebenarnya harus saya instal?

Forgejo, bagi kebanyakan orang, dan alasannya adalah tata kelola, bukan fitur. Kedua proyek ini berbagi leluhur yang sama dan penggunaannya masih terasa hampir identik: binary Go yang sama, footprint yang sama ringannya, antarmuka web yang sama, CI yang setara. Yang berbeda adalah siapa yang mengendalikannya. Forgejo dipegang oleh Codeberg e.V., asosiasi nirlaba terdaftar di Berlin, dan menjadi hard fork pada awal 2024; ia menerbitkan semuanya sebagai perangkat lunak bebas dan tidak meminta kontributor menyerahkan hak cipta. Gitea dikembangkan oleh perusahaan komersial yang memiliki merek dagang dan domainnya, mewajibkan penyerahan hak cipta dari kontributor, dan menjalankan model open-core dengan fitur berbayar mengelilingi basis gratisnya. Tak satu pun dari fakta-fakta tersebut merusak Gitea sebagai perangkat lunak. Tetapi inti dari memindahkan repositori Anda keluar dari sebuah platform adalah agar berhenti bergantung pada roadmap sebuah perusahaan, jadi memilih fork yang pengelolanya adalah organisasi nirlaba adalah pilihan yang sesuai dengan alasan Anda berada di sini. Satu catatan praktis jika Anda ingin berpindah nanti: Forgejo bisa diinstal di atas direktori data Gitea yang sudah ada, sementara arah sebaliknya tidak didukung.

Apakah saya benar-benar butuh forge? Apakah repositori bare lewat SSH saja tidak cukup?

Bagi satu orang dengan satu laptop dan kebiasaan menulis pesan commit yang baik, repositori bare benar-benar sudah cukup, dan inilah hal paling tangguh di seluruh panduan ini: git init --bare di server, akun SSH biasa, dan tidak ada aplikasi web yang perlu ditambal, tidak ada database yang perlu di-backup, dan tidak ada permukaan serangan selain sshd. Tidak ada satu pun bagian dari susunan ini yang akan pernah mengalami end-of-life. Anda membutuhkan forge begitu orang kedua terlibat, atau begitu Anda menginginkan salah satu dari empat hal yang sama sekali tidak diketahui oleh repositori bare — riwayat yang bisa dijelajahi lewat browser, pull request dengan review, issue tracker yang menyatu di samping kodenya, dan kontrol akses per repositori. Itu bukan peningkatan kecil; itu adalah perbedaan antara penyimpanan dan kolaborasi. Bersikaplah jujur tentang masalah mana yang sebenarnya ingin Anda pecahkan, karena forge adalah layanan yang kini Anda operasikan, sedangkan repositori bare hanyalah sebuah direktori.

Bisakah saya memigrasikan repositori GitHub saya, termasuk issue dan pull request-nya?

Ya, dan ini salah satu kisah migrasi terbaik dalam dunia self-hosting. Alat migrasi bawaan Forgejo mengambil URL repositori dan sebuah token akses pribadi, lalu menarik jauh lebih banyak daripada sekadar kode: branch dan tag, issue beserta komentarnya, pull request, label, milestone, dan release. Berikan token dengan scope read, jalankan satu repositori dulu untuk melihat seperti apa hasilnya, baru kerjakan sisanya. Ada tiga hal yang perlu diantisipasi. Migrasi yang besar atau berjumlah banyak akan terkena rate limit API platform sumbernya dan sekadar butuh waktu lebih lama — mulai saja lalu biarkan berjalan. Lampiran pada issue diambil lewat jaringan, sehingga instance di belakang firewall egress yang ketat akan menghasilkan issue dengan gambar yang rusak. Dan thread review tidak selalu mendarat persis di tempat semula, karena kedua model data itu tidak identik. Rencanakan untuk menjaga repositori sumber tetap read-only selama beberapa minggu, alih-alih menghapusnya sore itu juga.

Apakah forge yang self-hosted benar-benar lebih pribadi, atau sekadar berbeda?

Ini benar-benar berbeda dalam satu hal yang spesifik dan penting: tidak ada seorang pun selain Anda yang memegang indeksnya. Di sebuah platform, repositori pribadi itu memang pribadi dari pengguna lain — tetapi tidak pribadi dari platform itu sendiri, yang menyimpannya, memindainya, menghitung dependency graph darinya, dan bisa dipaksa untuk menyerahkannya oleh pengadilan di yurisdiksinya sendiri. Indeks itu luar biasa mengungkap banyak hal bahkan ketika kodenya membosankan: timestamp commit menggambarkan jam kerja Anda, baris co-author menggambarkan siapa saja tim Anda, nama branch menggambarkan produk yang belum dirilis, dan commit pertama menandai tanggal sebuah proyek yang belum diumumkan. Memindahkannya ke server Anda sendiri menghilangkan platform itu sepenuhnya dari gambaran ini. Yang tidak dilakukannya adalah membuat mesinnya menghilang. Anda tetap menyewa perangkat keras di sebuah pusat data, disknya tetap bisa dijangkau secara fisik oleh orang-orang yang memiliki gedung itu, dan hostname yang Anda pilih tetap ada di log transparansi sertifikat. Ringkasan jujurnya: Anda telah mengganti sebuah perusahaan dengan kebijakan privasi kontraktual dengan sebuah server yang satu-satunya kebijakannya adalah konfigurasi Anda sendiri, di yurisdiksi yang Anda pilih dengan sengaja — dan akun yang membayarnya tidak harus membawa nama Anda.

Seberapa besar VPS yang dibutuhkan?

Lebih kecil dari yang telah dilatih oleh dokumentasi GitLab untuk diharapkan semua orang. Forgejo dan Gitea adalah binary Go tunggal yang idle di kisaran beberapa ratus megabyte RAM; tambahkan PostgreSQL dan sebuah reverse proxy, dan forge milik seorang developer solo akan duduk dengan nyaman di sebuah Sentinel — 2 vCPU, 4 GB, 120 GB NVMe, $3.90 sebulan — dengan ruang tersisa. Tekanannya datang dari tiga tempat lain, dan masing-masing layak diukur secara sengaja. CI adalah yang terbesar: sebuah runner yang membangun container akan memakai setiap core yang Anda berikan dan memenuhi disk dengan layer. Ukuran repositori adalah yang kedua: aset game, notebook, dan vendored dependency tumbuh jauh lebih cepat dibanding kode sumber. Artifact dan sebuah container registry adalah yang ketiga. Sebuah aturan yang terbukti bertahan dengan baik dalam praktiknya — taruh forge di sebuah Sentinel, taruh runner di Sentinel kedua miliknya sendiri, dan hanya naik tier ketika disk yang memberi tahu Anda untuk itu, bukan ketika CPU yang melakukannya.

Apakah Forgejo Actions benar-benar kompatibel dengan workflow GitHub Actions saya?

Cukup kompatibel sehingga sebagian besar workflow yang sederhana berjalan tanpa perubahan, tetapi tidak cukup kompatibel untuk memigrasikan pipeline yang kompleks tanpa membacanya lebih dulu. Format file workflow-nya sama, berada di .forgejo/workflows/ (dan .github/workflows/ juga dibaca), dan blok-blok pembangun yang umum — checkout, penyiapan bahasa, cache, matrix build — berperilaku sebagaimana yang Anda harapkan karena runner-nya mengeksekusinya dalam container dengan cara yang sama. Yang tidak berfungsi adalah apa pun yang mengasumsikan GitHub sebagai platform, bukan Actions sebagai format: marketplace action yang terpaku pada URL github.com yang harus diizinkan diakses oleh instance Anda, action yang memanggil GitHub REST API untuk metadata release atau PR, image runner yang di-hosting GitHub dengan toolchain bawaan yang sangat spesifik, dan autentikasi cloud berbasis OIDC. Pola migrasi yang berhasil: mulai dengan workflow yang hanya melakukan build dan test, buat itu hijau, baru tambahkan kembali langkah-langkah deployment satu per satu.

Apa yang terjadi pada kode saya jika VPS-nya mati?

Kodenya sendiri adalah bagian yang aman-aman saja, dan inilah keunggulan tersembunyi Git dibanding hampir semua layanan self-hosted lainnya: setiap clone adalah salinan lengkap dari riwayatnya, jadi selama satu developer saja memiliki working copy yang mutakhir, repositorinya tidak akan hilang. Yang ikut mati bersama server adalah segala hal di sekitar kodenya — issue, diskusi pull request, komentar review, release, wiki, pengguna, aturan akses, riwayat CI. Materi itu hanya ada di database, tidak ada seorang pun yang memiliki salinannya, dan biasanya itulah bagian yang butuh bertahun-tahun untuk terkumpul. Jadi perlakukan keduanya secara berbeda. Untuk kodenya, atur sebuah push mirror ke lokasi kedua dan Anda mendapatkan perlindungan offsite yang berkelanjutan dan otomatis tanpa usaha tambahan. Untuk metadatanya, Anda butuh backup sungguhan: dump PostgreSQL ditambah direktori data, dienkripsi dan dikirim ke mesin di yurisdiksi lain lewat timer. Langkah 06 membahas keduanya, dan latihan pemulihan di bagian akhir adalah yang mengubah keduanya dari sekadar niat menjadi jaminan.

Bisakah saya tetap mempertahankan GitHub sebagai mirror, alih-alih meninggalkannya sepenuhnya?

Ya, dan untuk banyak proyek itu justru jawaban yang tepat, bukan sekadar kompromi. Forgejo mendukung push mirror, sehingga instance Anda menjadi origin tempat tim Anda bekerja, dan setiap push direplikasi secara otomatis ke sebuah repositori di GitHub, Codeberg, atau Forgejo kedua. Visibilitas publik, kontributor drive-by, package registry yang mengharapkan URL GitHub, dan tautan issue tracker di README lama — semuanya tetap berfungsi, sementara sumber kebenarannya — beserta repositori pribadi, log CI, dan riwayat issue dari apa pun yang tidak Anda publikasikan — tetap berada di mesin Anda sendiri. Ini juga berlaku ke arah sebaliknya: pull mirror menjaga salinan lokal yang selalu mutakhir dari proyek upstream yang Anda andalkan, yang layak dilakukan untuk apa pun yang akan membuat Anda kesulitan jika tiba-tiba dihapus besok. Satu hal yang perlu benar-benar disengaja adalah apa yang Anda jadikan mirror: push mirror dari sebuah repositori yang riwayatnya mengandung secret yang seharusnya sudah Anda hapus, akan mempublikasikan ulang secret itu — seketika dan otomatis.

Bagaimana cara memberi kontraktor akses ke satu repositori tanpa memberi mereka akses ke sisanya?

Gunakan lapisan yang sesuai dengan berapa lama akses itu seharusnya berlaku. Untuk orang yang akan membaca, melakukan commit, dan membuka pull request, buat akun pengguna dan tambahkan mereka sebagai kolaborator persis pada repositori yang mereka butuhkan, dengan level izin yang eksplisit — read, write, atau admin — alih-alih memasukkan mereka ke tim organisasi yang diam-diam memberi lebih banyak akses. Untuk sistem otomatis yang hanya perlu melakukan fetch — target deployment, mesin build, sebuah mirror — gunakan deploy key read-only alih-alih akun pengguna: cakupannya terbatas pada satu repositori, tidak memberi akses apa pun selain itu, dan mencabutnya cukup dengan menghapus satu baris. Untuk script yang berbicara dengan API, terbitkan token akses yang cakupannya dibatasi, alih-alih menyerahkan kata sandi. Dua kebiasaan yang membuat semua ini bertahan: jaga registrasi tetap tertutup sehingga satu-satunya akun yang ada adalah yang Anda buat sendiri, dan catat tanggal di kalender Anda saat memberi akses sementara, karena tidak ada satu forge pun yang akan pernah mengingatkan Anda bahwa sebuah kontrak telah berakhir.

Apakah forge membutuhkan nama domain, dan apakah itu membocorkan identitas saya?

Forge membutuhkan hostname untuk antarmuka webnya, karena sertifikat TLS diterbitkan untuk nama, dan tidak ada browser yang seharusnya mempercayai alamat IP di sini. Nama itu tidak perlu bisa dilacak kembali ke Anda. Ada tiga hal yang perlu disikapi dengan sengaja. Daftarkan domain di tempat yang tidak menuntut identitas yang sudah susah payah Anda jaga di tempat lain, dan pertahankan privasi WHOIS tetap aktif — registrar adalah keputusan kepercayaan yang terpisah dari host, dan inilah yang paling sering dilupakan orang. Perkirakan hostname akan menjadi publik begitu sertifikatnya diterbitkan, karena setiap sertifikat yang dipercaya publik dipublikasikan di log transparansi sertifikat yang bisa dicari siapa saja; sebuah wildcard pada domain yang sudah Anda gunakan menghindari penambahan nama baru yang bisa dicari. Dan jika Anda lebih memilih untuk sama sekali tidak punya nama publik, alternatifnya nyata: taruh forge di layanan onion Tor atau buat hanya bisa dijangkau lewat WireGuard, lewati sertifikat publik sepenuhnya, dan terimalah bahwa kenyamanan membuka browser dari mana saja ikut hilang bersamanya.

Apakah NordBastion keberatan jika saya menjalankan forge Git dan runner CI di VPS?

Sama sekali tidak — forge beserta runner-nya adalah beban kerja yang biasa, dan itu salah satu hal yang paling umum dibangun oleh pelanggan kami. Kebijakan penggunaan yang dapat diterima tidak menyebutkan apa-apa soal hosting kode sumber atau melakukan build atasnya. Ada dua catatan operasional, bukan catatan kebijakan. Pertama, runner CI yang menerima workflow dari orang asing adalah layanan komputasi gratis bagi siapa pun yang menemukannya: penyalahgunaan yang paling umum adalah penambangan cryptocurrency lewat sebuah pull request, dan itu akan ditemukan dalam hitungan hari setelah terbuka. Jaga registrasi tetap tertutup, dan wajibkan persetujuan sebelum workflow dijalankan untuk siapa pun yang belum menjadi kolaborator. Kedua, jika build Anda menarik image container besar di setiap kali dijalankan, itu adalah traffic yang normal dan sudah termasuk dalam paket — tetapi tetap ada baiknya menyimpannya dalam cache secara lokal, karena itu membuat pipeline Anda lebih cepat dan merupakan hal yang sopan untuk dilakukan terhadap registry upstream yang Anda andalkan.

Dapatkan mesinnya

Forge milik Anda sendiri, di akun yang bukan nama Anda. Bebas KYC, berbayar kripto.

Sentinel — 2 vCPU dan 4 GB seharga $3.90 sebulan, di Helsinki, Stockholm, Oslo, atau Reykjavík. Cukup untuk Forgejo, PostgreSQL, dan reverse proxy-nya, dengan ruang tersisa untuk repositori-repositori yang sudah lama ingin Anda pindahkan. Tambahkan satu lagi untuk runner-nya. Tanpa email saat mendaftar, tanpa dokumen identitas, dan tanpa indeks tingkat produk atas apa pun yang Anda push.

Terakhir ditinjau · 2026-10-12 · Sumber · Dokumentasi administrator Forgejo (instalasi, Actions, command line), perbandingan Forgejo dengan Gitea, halaman tata kelola Codeberg e.V., dokumentasi PostgreSQL dan Caddy, git-config(1) · Kadence · tahunan

Hosting privat, dibangun di Utara.