01Kimlik doğrulama
Okuma herkese açık, değiştirme anahtar ister. Bir updater istemcisi yeni sürüm var mı diye bakarken kimlik taşımak zorunda değil; depoya bir şey yazan veya silen her çağrı ise anahtarsız çalışmaz.
| İşlem | Anahtar | Kapsam |
|---|---|---|
| Proje / dosya / sürüm listeleme | gerekmez | — |
İndirme, latest, verify, arama, changelog | gerekmez | — |
| Yükleme (yeni sürüm) | gerekir | write |
| Proje oluşturma | gerekir | write |
| Dosya / sürüm silme | gerekir | delete |
| Proje silme | gerekir | admin |
| Anahtar yönetimi | gerekir | admin |
Adresi bilen herkes projeleri listeleyebilir ve artifaktları indirebilir. Depoya gizli bir şey koyma. Kapatmak istersen tek ayar yeter: config/config.php içinde public_read değerini false yap, ya da PB_PUBLIC_READ=0 ver — o zaman okuma da read kapsamlı bir anahtar ister.
Anahtar gönderme
Yazma çağrılarında üç taşıma biçiminden herhangi biri kabul edilir.
# başlık (önerilen)
curl -H "X-Api-Key: pb_xxx" https://bin.bariskeser.com/api/projects
# bearer
curl -H "Authorization: Bearer pb_xxx" https://bin.bariskeser.com/api/projects
# sorgu dizesi (log'lara düşer, dikkatli kullan)
curl "https://bin.bariskeser.com/api/projects?apikey=pb_xxx"
Anahtarlar diskte yalnızca sha256 özeti olarak tutulur. Düz metin hâli üretildiği anda bir kez gösterilir ve sonradan geri alınamaz — kaybedilirse yenisi üretilir.
Kapsamlar
Dört kapsam var: read, write, delete ve admin — sonuncusu diğer üçünü de kapsar. Bir anahtar ayrıca belirli projelere kilitlenebilir; * tüm projeler demektir.
Okuma açıkken read kapsamı ve proje kilidi okumalarda uygulanmaz — aksi hâlde dar kapsamlı bir anahtar, anahtarsız bir çağrıdan daha az görürdü. Proje kilidi yazma ve silmede tam olarak geçerlidir: projects=myapp ile üretilmiş bir anahtar başka bir projeye yükleme yapamaz.
| Kod | error | Anlam |
|---|---|---|
| 401 | unauthorized | Yazma çağrısında anahtar gönderilmemiş |
| 401 | invalid_key | Anahtar tanınmıyor — okuma açık olsa da geçersiz anahtar reddedilir, sessizce anonime düşmez |
| 403 | forbidden | Kapsam veya proje yetkisi yetersiz |
| 403 | key_expired | Anahtarın süresi dolmuş |
| 503 | not_initialised | Hiç anahtar yok → php cli/pb.php init |
02Kavramlar
Dört kavram var ve hepsi dosya sisteminde düz karşılığa sahip — özel bir araç olmadan okunabilir.
- Proje —
projectname=ile belirlenir, bir klasöre karşılık gelir. Ad sadeleştirilir:"MyApp Web"→myapp-web. Proje yoksa otomatik oluşturulur. - Dosya — proje içindeki mantıksal ad, örneğin
app.zip. - Sürüm — aynı dosyaya her yeni yükleme
v1 → v2 → v3diye otomatik artar. Numaraflockaltında ayrılır, eşzamanlı iki yükleme aynı numarayı almaz. - build — projedeki her kabul edilen yüklemede artan proje geneli sayaç.
Yanıtların tamamı JSON'dur. Başarılı yanıtlar "ok": true ve alanları düz biçimde döner; hatalar tek bir zarf paylaşır:
{ "ok": false, "error": "checksum_mismatch", "message": "...", "status": 422, "details": {} }
03Uç noktalar
Tümü /api altında. Kapsam sütunu, o çağrı için anahtarın taşıması gereken yetkiyi gösterir.
Sistem
| Metot | Yol | Kapsam | Açıklama |
|---|---|---|---|
| GET | /api/health | — | Canlılık, PHP sürümü, limitler |
| GET | /api/whoami | açık | Çağıran anahtarın kimliği |
| GET | /api/stats | açık | Depo geneli toplamlar |
Projeler
| Metot | Yol | Kapsam |
|---|---|---|
| GET | /api/projects | açık |
| POST | /api/projects?projectname=X | write |
| GET | /api/projects/{project} | açık |
| DELETE | /api/projects/{project}?confirm=1 | admin |
Dosyalar ve sürümler
| Metot | Yol | Kapsam |
|---|---|---|
| GET | /api/files?projectname=X | açık |
| GET | /api/files/{project}/{file} | açık |
| DELETE | /api/files/{project}/{file}?confirm=1 | delete |
| DELETE | /api/files/{project}/{file}/{version} | delete |
Yükleme, indirme, denetim
| Metot | Yol | Kapsam |
|---|---|---|
| POST | /api/upload?projectname=X | write |
| GET | /api/download?projectname=X&file=Y | açık |
| GET | /api/latest?projectname=X&file=Y | açık |
| GET | /api/verify?projectname=X | açık |
| GET | /api/sha/{sha256} | açık |
| GET | /api/search?q=X | açık |
| GET | /api/changelog?projectname=X | açık |
Anahtar yönetimi
| Metot | Yol | Kapsam |
|---|---|---|
| GET | /api/keys | admin |
| POST | /api/keys?label=ci&scopes=read,write&projects=* | admin |
| DELETE | /api/keys/{id|prefix} | admin |
04Yükleme
İki taşıma biçimi desteklenir. İkisi de aynı sonucu verir: yeni bir sürüm numarası.
multipart/form-data
curl -H "X-Api-Key: pb_xxx" \
-F "file=@dist/app.zip" \
"https://bin.bariskeser.com/api/upload?projectname=myapp¬es=nightly"
Ham gövde — script ve CI için en kolayı
SHA=$(sha256sum dist/app.zip | cut -d' ' -f1)
curl -H "X-Api-Key: pb_xxx" \
-H "Content-Type: application/octet-stream" \
--data-binary @dist/app.zip \
"...?projectname=myapp&filename=app.zip&sha256=$SHA"
Parametreler
| Parametre | Zorunlu | Açıklama |
|---|---|---|
| projectname | evet | Hedef proje; yoksa oluşturulur. project de kabul edilir |
| filename | ham gövdede | Dosya adı |
| sha256 | hayır, ama önerilir | Beklenen özet. Tutmazsa 422 ve hiçbir şey yazılmaz |
| as | hayır | Mantıksal ad. app-1.0.4.zip → as=app.zip ile tek dosyanın sürümü olur |
| notes | hayır | Sürüm notu; changelog'a ve sürüm listesine düşer |
| force | hayır | 1 ise aynı içerik olsa da yeni sürüm aç |
Yanıt 201
{
"ok": true,
"deduplicated": false,
"project": "myapp",
"file": "app.zip",
"version": 7,
"latest_version": 7,
"version_count": 7,
"size": 4821903,
"sha256": "2c44186f12b8aaca70da7a7dd5acc5cbc70db...",
"md5": "...", "sha1": "...",
"content_type": "application/zip",
"build": 42,
"uploaded_at": "2026-08-18T08:15:19Z",
"uploaded_by": "ci (pb_8743bcb)",
"notes": "nightly",
"download_url": "https://bin.bariskeser.com/api/download?..."
}
Aynı baytlar tekrar yüklenirse yeni sürüm açılmaz; mevcut sürüm "deduplicated": true ile 200 döner. Bu, aynı CI işinin iki kez koşmasının sürüm numarasını şişirmesini engeller. Zorlamak için force=1.
05SHA kontrolleri
sha256 bu sistemdeki kimliktir. Bir baytın depoya girmesi ve orada kalması üç ayrı kapıdan geçer.
- Yükleme kapısı.
sha256=gönderirsen, alınan baytlar hesaplanır ve karşılaştırılır. Tutmazsa 422 checksum_mismatch döner, geçici dosya silinir ve hiçbir sürüm oluşmaz. - Yazma sonrası doğrulama. Dosya diske yazıldıktan sonra diskten yeniden hash'lenir. Tutmazsa sürüm geri alınır ve 500 write_corrupted döner — yarım yazılmış bir sürüm asla kayda geçmez.
- Sonradan denetim.
/api/verifydepodaki baytları istediğin zaman yeniden hash'ler ve kayıtla karşılaştırır.
Ayrıca her sürüm için md5 ve sha1 da kaydedilir, indirmede başlıkla döner. Bir özeti bilip dosyayı aramak için /api/sha/{sha256} tüm depoda arar.
06İndirme
version verilmezse latest gelir. version=3 veya version=first de geçerlidir.
curl -H "X-Api-Key: pb_xxx" -OJ \
"https://bin.bariskeser.com/api/download?projectname=myapp&file=app.zip"
Dönen başlıklar transferi ikinci bir istek olmadan doğrulamanı sağlar:
Content-Type: application/zip
Content-Disposition: attachment; filename="app.zip"
ETag: "2c44186f12b8..."
X-Checksum-SHA256: 2c44186f12b8...
X-Checksum-MD5: b1f3ee2e57af...
X-Version: 7
Digest: sha-256=LEQYbxK4qspw2np91azFy8cNtjd4pcv/9JWqSU9CqDc=
If-None-Match ile koşullu istek 304 döner — CI'de aynı artifakt tekrar indirilmez.
07Bütünlük denetimi
Depodaki baytları yeniden hash'ler. Proje, tek dosya veya tek sürüm kapsamında çalışır.
curl -H "X-Api-Key: pb_xxx" \
"https://bin.bariskeser.com/api/verify?projectname=myapp"
{ "ok": true, "checked": 12, "intact": 12,
"failed": 0, "healthy": true, "failures": [] }
Bozulma varsa 500 ve dolu bir failures[] döner — problem alanı missing, checksum_mismatch veya size_mismatch olur. Böylece bir cron işi curl -f ile depo sağlığını sessizce izleyebilir.
08Hata kodları
Her hata sabit bir error kodu taşır; mesaj metni değişebilir, kod değişmez.
| HTTP | error | Anlam |
|---|---|---|
| 400 | no_file / missing_filename / empty_body | Gövde veya ad eksik |
| 401 | unauthorized / invalid_key | Kimlik |
| 403 | forbidden | Kapsam veya proje yetkisi |
| 404 | project_not_found / file_not_found / version_not_found | Bulunamadı |
| 405 | method_not_allowed | Yanlış metot |
| 413 | too_large | Boyut limiti aşıldı |
| 415 | blocked_extension | Uzantı reddedildi |
| 422 | checksum_mismatch | SHA tutmadı — kayıt yapılmadı |
| 422 | invalid_project / missing_parameter | Parametre hatası |
| 428 | confirmation_required | Silme için confirm=1 gerekli |
| 500 | write_corrupted | Diske yazım bozuldu, sürüm geri alındı |
| 503 | not_initialised | Hiç anahtar yok |
09CLI ve otonom kullanım
Sunucuda doğrudan depoya, uzaktan ise HTTP üzerinden çalışır. Uzak mod için --url + --key, ya da PB_URL / PB_KEY / PB_PROJECT ortam değişkenleri.
# kurulum ve anahtarlar
php cli/pb.php init
php cli/pb.php keygen --label=ci --scopes=read,write --projects=myapp
php cli/pb.php keys
php cli/pb.php revoke <prefix>
# gezinme
php cli/pb.php projects
php cli/pb.php ls --project=myapp
php cli/pb.php versions --project=myapp --file=app.zip
php cli/pb.php changelog --project=myapp
php cli/pb.php stats
# veri
php cli/pb.php upload --project=myapp dist/app.zip --notes="rc1"
php cli/pb.php push --project=myapp dist/ --pattern="*.zip" --recursive
php cli/pb.php watch --project=myapp dist/ --interval=5
php cli/pb.php pull --project=myapp --file=app.zip --version=3 -o out.zip
php cli/pb.php verify --project=myapp
Her komuta --json eklenirse çıktı makine okunur olur.
Bir dizini izler ve içerik hash'i değiştiğinde yükler — mtime'a değil sha256'ya bakar, yani aynı çıktıyı üreten bir rebuild yeni sürüm açmaz. Hâlâ yazılmakta olan dosyaları atlamak için boyutun iki okuma arasında sabit kalmasını bekler.
export PB_URL=https://bin.bariskeser.com
export PB_KEY=pb_xxx
php cli/pb.php watch --project=myapp ./dist --pattern="*.zip" --recursive
Updater entegrasyonu
Okuma açık olduğu için bir updater istemcisi anahtar taşımadan sürüm kontrolü yapabilir. Tek çağrı hem sürüm numarasını, hem sha256'yı, hem de indirme adresini verir:
curl -s "$PB/api/latest?projectname=myapp&file=app.zip"
{
"ok": true,
"version": 7,
"latest_version": 7,
"size": 4821903,
"sha256": "2c44186f12b8...",
"uploaded_at": "2026-08-18T08:15:19Z",
"notes": "rc1",
"download_url": "https://.../api/download?...&version=7"
}
Tipik bir updater döngüsü — kurulu sürümü karşılaştır, yeniyse indir, çalıştırmadan önce sha256'yı doğrula:
PB=https://bin.bariskeser.com
CURRENT=$(cat /opt/myapp/VERSION 2>/dev/null || echo 0)
META=$(curl -fsS "$PB/api/latest?projectname=myapp&file=app.zip")
LATEST=$(echo "$META" | grep -o '"version": [0-9]*' | grep -o '[0-9]*')
WANT=$(echo "$META" | grep -o '"sha256": "[a-f0-9]*"' | cut -d'"' -f4)
if [ "$LATEST" -le "$CURRENT" ]; then exit 0; fi
curl -fsS -o /tmp/app.zip \
"$PB/api/download?projectname=myapp&file=app.zip&version=$LATEST"
GOT=$(sha256sum /tmp/app.zip | cut -d' ' -f1)
if [ "$GOT" != "$WANT" ]; then
echo "checksum mismatch, aborting" >&2; exit 1
fi
# ... kur ...
echo "$LATEST" > /opt/myapp/VERSION
İndirme ETag döner. Updater aynı sürümü tekrar çekmesin diye If-None-Match gönderirse 304 alır ve gövde hiç aktarılmaz. Sürüm numarasını karşılaştırmak da aynı işi görür — ikisinden biri yeterli.
CI adımı olarak
SHA=$(sha256sum build/app.zip | cut -d' ' -f1)
curl -f -H "X-Api-Key: $PB_KEY" \
-H "Content-Type: application/octet-stream" \
--data-binary @build/app.zip \
"$PB_URL/api/upload?projectname=myapp&filename=app.zip&sha256=$SHA¬es=$GIT_SHA"
10Kurulum notları
Bu sunucuya özgü ayarlar — taşınırsa gözden geçirilmesi gerekenler.
- Yol:
/home/DEPO/pi/SİTELER/bariskeser/projectbin. Birincil adreshttps://bin.bariskeser.com; eskihttps://bariskeser.com/projectbinyolu da çalışır ve ikisi aynı depoyu paylaşır —download_urlistekte kullanılan alan adına göre üretilir. - Neden ayrı vhost:
binDNS kaydı Cloudflare üzerinden geçmiyor, yüklemeler doğrudan origin'e ulaşıyor — 100 MB gövde sınırı ve proxy zaman aşımı yok. Ölçüm: 4 MB Cloudflare üzerinden 81.9 sn (51 KB/s), doğrudan 0.27 sn (15.7 MB/s); 150 MB dosya 5.8 sn. - Vhost:
/etc/apache2/sites-available/020-projectbin.conf(+ certbot'un ürettiği-le-ssl.conf). Kopyası repodadeploy/altında. - DocumentRoot
public/—config/,data/,src/,cli/fiziksel olarak web kökünün dışında. AllowOverride Nonetüm yol boyunca. Apache üst dizinlerdeki.htaccessdosyalarını da okur; ana sitenin.htaccess'iDirectoryIndex disabledve hataları bakım sayfasına yönlendirenErrorDocumentsatırları içeriyor. Bunlar bir API'ye sızmamalı ve.htaccessvhost ayarını ezdiği için override'ları kapatmak tek gerçek çözüm.- TLS: Let's Encrypt. HTTP → HTTPS 301 yönlendirmesi vhost kapsamında
RewriteEngine Onile birlikte tanımlı — certbot bu satırı eklemediği için yönlendirme başta etkisizdi. - Apache burada
www-data:bariskeserolarak koşuyor (APACHE_RUN_GROUP=bariskeser), bu yüzden ağaçbariskeser:bariskeser; dizinler2750, yazılabilir olandata/veconfig/2770,keys.json0660. - Depo hem web sunucusu hem CLI tarafından yazıldığı için uygulama, oluşturduğu dizin ve dosyalara
0770 / 0660uygular — kilit ve log dosyaları dâhil. Aksi hâlde ilk yazan kimlik diğerini kilitler. config/,data/,src/,cli/HTTP'den erişilemez: kök.htaccessyönlendirmesi, her dizindeRequire all deniedvephp_flag engine off.- Yükleme limitleri vhost içindeki
php_valueile 2048M (sunucu mod_php kullanıyor). PHP-FPM'e geçilirse bunlar.user.ini'ye taşınmalı. - Okuma herkese açık (
public_read= true). Kapatmak içinconfig/config.phpiçindefalseyap ya daPB_PUBLIC_READ=0ver. - Yedek:
data/klasörünü kopyalamak tam yedektir — tüm sürümler, meta veriler ve changelog orada.config/keys.jsonayrıca saklanmalı.