SSD Nodes Learn 🎉 VPS $5.50/aydan başlayan
Rehberler Matt ConnorYazan Matt Connor · Güncellendi 2026-08-21

openGym Kendi Sunucunuzda Docker ile Nasıl Kurulur?

openGym uygulamasını Docker Compose kullanarak VPS üzerinde barındırın. Passkey hatası almamak için TLS yapılandırması, veri dizini yönetimi ve MCP sunucusu detayları.

openGym uygulamasını kendi sunucunuzda barındırdığınızda elde edecekleriniz

openGym uygulamasını, depoyu klonlayarak, .env içindeki iki satırı düzenleyerek ve TLS (taşıma katmanı güvenliği) sonlandırması yapan bir reverse proxy arkasında docker compose up -d --build komutunu çalıştırarak kendi sunucunuzda barındırabilirsiniz. openGym; haftalık planlar, rehberli antrenmanlar, her setin kaydedilmesi ve zaman içindeki ağırlık takibi gibi özellikler sunan bir spor salonu ve vücut ağırlığı takip uygulamasıdır. AGPL-3.0 lisansına sahiptir ve tüm verileri disk üzerinde düz JSON dosyalarında saklar; bu nedenle çalıştırılması gereken bir veritabanı sunucusu bulunmaz.

Yığın; React derlemesini sunan bir nginx container'ı, API'yi barındıran bir Node container'ı ve ilk başlatma sırasında yaklaşık 140 MB boyutundaki egzersiz görselleri ile GIF'lerini indiren tek seferlik bir işten oluşur.

Projenin README dosyasının ima ettiği ancak halka açık bir sunucuda dağıtım yapanlar için açıkça belirtmediği iki husus vardır. Passkey ile giriş bir ana makine adına (hostname) bağlıdır; bu nedenle alan adı ve sertifikası, ilk girişten sonra değil, girişten önce mevcut olmalıdır. İsteğe bağlı MCP sunucusu ise salt okunurdur ve veriler bir VPS üzerinde tutulduğunda yapmanız gerekenleri değiştirecek şekilde, yığının içinde değil, yapay zeka istemcinizin çalıştığı makinede çalışır.

openGym henüz yeni bir projedir. İlk etiketli sürüm olan v1.0.0, 20 Temmuz 2026 tarihlidir ve v1.2.7 sürümü 18 Ağustos 2026 tarihinde yayınlanmıştır. Yaklaşık bir ay içinde on üç etiketin yayınlanması, uygulamanın hala geliştirilme aşamasında olduğunu gösterir; bu nedenle varsayılan dalda ne olduğuna bakmak yerine bir sürüm etiketini kontrol ederek ilerleyin.

İlk oturum açma işleminden önce alan adını planlayın

openGym'de oturum açmak için passkey kullanılır. Bir passkey, kimlik bilgisinin oluşturulduğu alan adı olan bir relying party ID (RP ID) ile ilişkilendirilir ve tarayıcılar passkey'leri yalnızca HTTPS üzerinden oluşturur. Bunun tek istisnası localhost durumudur.

Bu durumun, kullanıcıların telefonlarında karşılaştığı bir sonucu vardır. http://203.0.113.10:8080 uygulamasını başka bir cihazdan açtığınızda hiçbir passkey istemi görünmez; çünkü tarayıcı, düz HTTP kaynağı veya doğrudan IP adresi üzerinde kimlik bilgisi oluşturmayı reddeder. Projenin kendi sorun giderme notlarında da belirtildiği gibi, istemin görünmemesi http:// üzerinde olduğunuz veya bir IP adresi kullandığınız anlamına gelir.

Daha da kötüsü, RP ID kullanıcılarınızın halihazırda kaydettiği her kimlik bilgisinin içine işlenmiştir. RP_ID değerini daha sonra değiştirirseniz, cihazlarda kayıtlı olan passkey'ler artık eşleşmeyeceği için kimse oturum açamaz. Ana bilgisayar adını (hostname) önceden belirleyin, DNS kayıtlarını VPS'e yönlendirin ve kimse "Create profile" düğmesine basmadan önce sertifikanın çalıştığından emin olun.

openGym uygulamasının Docker Compose ile dağıtımı

Compose dosyası, ./data ve ./media dizinlerini kendisine göre bind-mount eder; bu nedenle klonladığınız dizin doğrudan veritabanınızın kendisidir. Bu dizini kalıcı bir alana yerleştirin.

sudo install -d -o "$USER" -g "$USER" /opt/opengym
git clone https://gitea.com/DuarteSantos/openGym /opt/opengym
cd /opt/opengym
cp .env.example .env

README dosyası hala github.com klonlama URL'sini göstermektedir. Bu adres artık çözümlenmemektedir; yukarıda belirtilen Gitea deposu projenin güncel ana merkezidir.

.env dosyasını düzenleyin. Bir VPS üzerinde üç satır önem arz eder.

RP_ID=gym.example.com
ORIGIN=https://gym.example.com
WEB_PORT=127.0.0.1:8080

RP_ID çıplak ana makine adıdır (hostname), ORIGIN ise şema dahil tam URL'dir. Bunlar tarayıcı adres çubuğuyla tam olarak eşleşmelidir, aksi takdirde giriş işlemi verification failed hatasıyla başarısız olur. WEB_PORT değeri, 8080 numaralı portun gizli tutulmasıyla ilgili bölümde açıklanmıştır.

docker compose up -d --build
docker compose ps
docker compose logs media

docker compose ps komutu web ve api servislerinin çalıştığını, media servisinin ise 0 koduyla çıkış yaptığını göstermelidir. Bu çıkış kodu doğrudur: medya işi restart: "no" durumundadır çünkü görevi tek seferlik bir indirme işlemidir. Günlük kaydı ✓ Exercise media ready ile başlayan bir satırla biter ve ls media/img | wc -l komutu 0 yerine birkaç yüz değerini döndürmelidir. Dizin boşsa indirme başarısız olmuş demektir; bu durumda uygulama, egzersiz kartlarını boş görsellerle oluşturur.

--build bayrağı burada isteğe bağlı değildir. Compose dosyası, ghcr.io üzerinde artık yayınlanmayan önceden oluşturulmuş imajları referans alır; bu nedenle docker compose pull komutu denied veya manifest unknown hatasıyla başarısız olur. İki servis, az önce klonladığınız kaynak koddan derlenir. Her ikisi de tam olarak bu amaç için bir build bölümü içerir. Eğer Compose sizin için yeniyse, önce VPS üzerinde Docker Compose bölümünden başlayıp buraya geri dönün.

Sürümü sabitleyin, çünkü bu proje henüz yeni

Söz konusu kayıt defteri ad alanı artık mevcut olmadığından, sabitlenecek bir imaj etiketi kalmamıştır. Bunun yerine disk üzerindeki checkout işlemini sabitlemelisiniz; çünkü konteyner içinde uygulamanın hangi sürümünün yer alacağına bu karar verir.

cd /opt/opengym
git fetch --tags
git checkout v1.2.7

git status artık o etikette detached HEAD durumunu rapor eder; bir sunucuda istediğiniz durum tam olarak budur. Siz farklı bir checkout yapana kadar hiçbir şey değişmez.

Ardından Compose'a kayıt defterine ulaşmayı tamamen bırakmasını söyleyin. Bunu, Compose'un otomatik olarak yüklediği ve takip edilen dosyanın üzerine birleştirdiği docker-compose.override.yml içine ekleyin. Skaler anahtarlar geçersiz kılma (override) dosyasıyla değiştirilir, böylece git içindeki hiçbir şeyin düzenlenmesine gerek kalmaz ve git pull temiz kalır. Birleştirme kurallarının tamamı için Compose'un bir override dosyasını nasıl birleştirdiği bölümüne bakın.

services:
  api:
    pull_policy: build
  web:
    pull_policy: build

Bu yapılandırma ile daha sonra çalıştırılan bir docker compose up -d, bir çekme (pull) işleminde hata vermek yerine elinizdeki kaynaktan derleme yapar. Birleştirmenin etkili olduğunu doğrulayın ve ardından etiketi kullanarak yeniden derleyin.

docker compose config | grep pull_policy
docker compose up -d --build

Reverse proxy ile TLS sonlandırma

Konteynerler düz HTTP üzerinden haberleşir. Ön tarafta bulunan bir bileşenin sertifikayı tutması gerekir. Caddy, Let's Encrypt üzerinden sertifikaları kendi başına talep edip yenilediği için en kısa yoldur.

gym.example.com {
    reverse_proxy 127.0.0.1:8080
}

Nginx, Traefik ve Nginx Proxy Manager aynı mantıkla çalışır. Proje dokümantasyonunda yer alan ve gelen hiçbir portun açılmasını gerektirmeyen Cloudflare Tunnel da aynı şekilde işlev görür.

curl -sI https://gym.example.com | head -1

Bu komut, herhangi bir sertifika uyarısı olmadan HTTP/2 200 döndürmelidir. Şimdi siteyi bir tarayıcıda açın ve Create profile seçeneğine dokunun. Eğer passkey istemi belirir ve ardından giriş işlemi verification failed, RP_ID veya ORIGIN hatası verirse, bu durum adres çubuğundaki URL ile eşleşmiyor demektir. .env değerini düzeltin ve konteynerlerin yeni değerleri okuması için docker compose up -d komutunu tekrar çalıştırın. Bir docker compose restart komutu, .env dosyasını yeniden yüklemez.

8080 numaralı portu genel internete kapatma

Varsayılan olarak web servisi 8080 portunu tüm arayüzlerde yayınlar; bu nedenle proxy aynı sunucuda HTTPS hizmeti verirken uygulama, genel IP adresiniz üzerinden düz HTTP ile erişilebilir durumdadır. Bir güvenlik duvarı kuralı bu durumu düzeltmez. Docker, bir portu nat tablosundaki bir DNAT kuralı ile yayınlar ve bu trafik daha sonra Docker'ın kendi kurallarının kabul ettiği FORWARD zincirinde işlenir; ufw kuralları ise INPUT yolunda kalır. Bu nedenle sudo ufw deny 8080/tcp hiçbir şeyi engellemez.

Çözüm, portu yalnızca loopback adresi üzerinden yayınlamaktır. Compose dosyası "${WEB_PORT:-8080}:${NGINX_PORT:-80}" eşlemesini yapar; bu nedenle WEB_PORT içinde ne ayarlarsanız bu eşlemenin sol tarafına yerleştirilir ve Docker'ın kısa sözdizimi burada bir ip:port çiftini kabul eder. WEB_PORT=127.0.0.1:8080 ifadesinin çalışma nedeni budur.

docker compose config
sudo ss -ltnp | grep 8080

Birleştirilmiş yapılandırmada, web servisinin ports altında host_ip: 127.0.0.1 değerini görmelisiniz. ss çıktısı 0.0.0.0:8080 yerine 127.0.0.1:8080 değerini göstermelidir. Başka bir makineden yapılan curl http://<your-vps-ip>:8080 isteği artık reddedilmeli veya zaman aşımına uğramalıdır; HTTPS ana bilgisayar adı ise çalışmaya devam etmelidir.

Profiliniz oluştuktan sonra kayıtları kapatın

Kayıt özelliği varsayılan olarak açıktır ve misafir modu etkindir. Herkese açık bir ana makine adında bu, URL'yi bulan herkesin sunucunuzda bir profil oluşturabileceği anlamına gelir. Önce kendi profilinizi kaydedin, ardından kullanıcı kimliğinizi bulun: ls data/, her kullanıcı için state-<uid>.json adında bir dosya listeler ve ihtiyacınız olan değer bu <uid> değeridir.

ADMIN_UIDS=<your-uid>
INVITE_ONLY=1
ALLOW_GUEST=0

docker compose up -d komutunu tekrar çalıştırın. Ayarlar artık davet kodları oluşturup iptal edebileceğiniz bir Yönetici paneli gösterir; böylece yalnızca birlikte antrenman yaptığınız kişiler kayıt olabilir ve başkaları erişemez. openGym harici kimlik sağlayıcıları hakkında bilgi sahibi değildir, bu nedenle bu davet kodları yalnızca bu uygulamayı yönetir ve sunucudaki başka hiçbir şeyi etkilemez; çalıştırdığınız tüm servisler için kişi başına tek bir hesap tanımlamayı tercih ederseniz, Authentik'i bir forward auth proxy olarak kullanmak, openGym'in kendi passkey girişi yüklenmeden önce ana makine adını koruma altına alır.

Verilerin konumu ve onları koruyan yedekleme

Her şey ./data dizininde bulunur ve API container'ı içinde /data yoluna mount edilir. Dört tür dosya mevcuttur: db.json profilleri ve genel passkey kimlik bilgilerini tutar, state-<uid>.json tek bir kullanıcının rutinlerini, antrenmanlarını ve vücut ağırlığını saklar, secret oturum çerezi anahtarıdır ve vapid.json ilk çalıştırmada oluşturulan push bildirimi anahtarlarını içerir.

cd /opt/opengym
docker compose stop api
tar czf ~/opengym-$(date +%F).tar.gz data/
docker compose start api

Önce API'yi durdurun; çünkü tar, API bir dosyaya yazma işlemi yaparken kopyalama yapabilir ve yarım kopyalanmış bir JSON dosyası, geri yükleme sırasında bozuk bir JSON dosyası olarak döner. Durdurma ve başlatma işlemleri yaklaşık iki saniye sürer. Ardından arşivi sunucudan başka bir yere kopyalayın; çünkü VPS üzerinde duran bir arşiv, VPS'in başına bir şey gelmesi durumunda kaybolur. media/ dizinini yedekleme dışında tutun: bu dizin, medya işinin ücretsiz olarak tekrar indirebileceği 140 MB boyutunda egzersiz görsellerinden oluşur.

Geri yükleme işlemi, aynı alan adını sunan bir host üzerinde dosyaların aynı yola açılmasını (untar) gerektirir. Telefonunuzda saklanan bir passkey, oluşturulduğu RP ID ile ilişkilidir; bu nedenle yeni bir ana makine adına (hostname) yapılan geri yükleme, kimsenin giriş yapamadığı çalışan bir veritabanı ile sonuçlanır. Alan adını koruyun veya her passkey'i yeniden kaydetmeyi planlayın. Aynı disiplin çalıştırdığınız diğer tüm servisler için de geçerlidir ve Docker Compose yığınını yedekleme ve yükseltme konusu genel prosedürü kapsamaktadır.

MCP sunucusu salt okunurdur ve makinenizde çalışır

MCP (model context protocol), Claude Desktop veya Cursor gibi bir istemcinin yerel bir araç sunucusuyla nasıl iletişim kurduğudur. openGym, mcp/ içinde bir tane sunar. Bu, compose dosyasının bir parçası değildir, bir container değildir ve hiçbir portu dinlemez. İstemci onu bir alt süreç olarak başlatır ve stdio üzerinden iletişim kurar; README dosyasının makinenizden asla ayrılmadığını belirtmesinin nedeni budur.

Sunucuya değil, istemcinin çalıştığı yere kurun:

cd openGym/mcp
npm install

Ardından claude_desktop_config.json dosyasına ekleyin:

{
  "mcpServers": {
    "opengym": {
      "command": "node",
      "args": ["/absolute/path/to/openGym/mcp/src/index.js"],
      "env": {
        "OPENGYM_DATA": "/absolute/path/to/openGym/data",
        "OPENGYM_UID": "<your-uid>"
      }
    }
  }
}

OPENGYM_UID, sunucunun bulduğu tek profili algıladığı tek kullanıcılı kurulumlarda isteğe bağlıdır. Sekiz araç sunar: list_routines, get_routine, get_week_plan, list_workouts, get_workout, get_bodyweight, estimate_1rm ve muscle_balance. Bunların her biri okuma işlemi yapar. Hiçbiri yazma yapmaz; bu sayede bir asistan geçen hafta hangi ağırlıkları kaldırdığınızı yanıtlayabilir ancak bir set kaydedemez, bir rutini düzenleyemez veya hiçbir şeyi silemez.

VPS okuyucusunun çözmesi gereken kısım burasıdır. OPENGYM_DATA bir dosya sistemi yoludur ve verileriniz VPS üzerindeyken yapay zeka istemciniz dizüstü bilgisayarınızdadır. Bu durumu dürüstçe ele alan iki seçenek mevcuttur.

  1. Verileri yerel makinenize kopyalayın ve sunucuyu kopyaya yönlendirin: rsync -a --delete user@gym.example.com:/opt/opengym/data/ ~/opengym-data/, ardından OPENGYM_DATA değerini ~/opengym-data olarak ayarlayın. Sunucu yalnızca okuma yaptığı için kopyalama işlemi herhangi bir veri kaybına yol açmaz. Güncel verilere ihtiyaç duyduğunuzda rsync işlemini tekrar çalıştırın.
  2. Sunucuyu ssh üzerinden çalıştırın; command değerini ssh ve args değerini ["-T", "user@gym.example.com", "OPENGYM_DATA=/opt/opengym/data node /opt/opengym/mcp/src/index.js"] olarak ayarlayın. Bu yöntem, VPS üzerinde Node kurulu olmasını ve stdout'a hiçbir çıktı vermeyen bir oturum açma işlemini gerektirir; çünkü stdout protokol kanalıdır.

Eğer cat data/db.json komutu Permission denied döndürürse, API container'ı bu dosyaları root yetkisiyle yazmıştır ve kullanıcı oturumunuz bunları okuyamaz. Dosyaları sudo ile kopyalayın veya ana makine (host) üzerinde sahiplik bilgilerini değiştirin. stdio yerine ağ üzerinden dinleme yapması amaçlanan sunucular için VPS üzerinde MCP sunucuları çalıştırma bölümüne bakın.

openGym mi wger mı: hangisini çalıştırmalısınız?

wger, bu alanda yerleşik bir seçenektir ve çok daha kapsamlı bir yazılımdır. Compose yığını; nginx arkasında gunicorn ile sunulan bir Django uygulaması, PostgreSQL, Redis ve bir Celery worker içerir. Bunun karşılığında beslenme ve içerik takibi, dokümante edilmiş bir REST API, geniş bir topluluk egzersiz veritabanı ve başkalarının planlarını yöneten eğitmenler için özellikler elde edersiniz.

openGym ise iki container, bir klasör dolusu JSON dosyası ve passkey dışında yönetilecek hesap gerektirmeyen bir yapıdır. Aradaki temel fark budur.

Antrenmanla birlikte besin takibi yapmak istiyorsanız veya üzerinde geliştirme yapabileceğiniz bir API'ye ihtiyacınız varsa wger çalıştırın. Bir öğleden sonra uçtan uca okunabilecek kadar küçük bir yığın ve sızdırılacak parola içermeyen bir giriş yöntemi istiyorsanız openGym tercih edin. Bu seçimin bedeli olgunluktur: 19 Ağustos 2026 itibarıyla openGym'in ilk sürümü bir aylıkken, wger yılların sürüm geçmişine sahiptir. Sürümünüzü sabitleyin, yedeklerinizi alın ve her güncellemeden önce sürüm notlarını okuyun.

Sunucunuzda neye yer vereceğinize hala karar veriyorsanız, 2026 yılında neler self-host etmeye değer başlıklı yazı avantaj ve dezavantajları ele almaktadır; bu uygulama aynı küçük VPS üzerinde yemek tarifleri için Mealie veya finans takibi için Actual Budget ile birlikte rahatlıkla çalışabilir.

Veri kaybı olmadan güncelleme

cd /opt/opengym
docker compose stop api
tar czf ~/opengym-$(date +%F).tar.gz data/
docker compose start api
git fetch --tags

İstediğiniz sürümü git checkout v<new> ile kontrol edin, ardından konteynerlerin o etiket üzerinden yeniden oluşturulması için docker compose up -d --build komutunu çalıştırın. Disk üzerindeki JSON dosyalarının geri yükleme yolu tek bir tar komutuyla saniyeler içinde tamamlandığından, her zaman önce yedekleme yapılmalıdır.

FAQ

openGym telefonumda neden hiçbir zaman geçiş anahtarı (passkey) istemi göstermiyor?

Tarayıcı, http:// üzerinde olduğunuz veya http://192.168.1.20:8080 gibi çıplak bir IP adresi kullandığınız için kimlik bilgisi oluşturmayı reddediyordur. Tarayıcılar geçiş anahtarlarına yalnızca HTTPS kökenlerinde izin verir; localhost bu durumun tek istisnasıdır. openGym'i gerçek bir ana bilgisayar adı için geçerli bir sertifikaya sahip bir reverse proxy arkasına alın, .env dosyasında RP_ID=gym.example.com ve ORIGIN=https://gym.example.com değerlerini ayarlayın ve container'ların yeni değerleri alması için docker compose up -d komutunu çalıştırın. İstek görünmesine rağmen giriş yaparken verification failed hatası alıyorsanız, bu iki değer adres çubuğundaki URL ile tam olarak eşleşmiyor demektir.

openGym verilerimi nerede saklıyor ve nasıl yedekleyebilirim?

Compose dosyasının yanındaki ./data dizininde, API container'ına /data olarak mount edilmiş şekilde saklanır. Bu dizin; profiller ve genel geçiş anahtarı kimlik bilgileri için db.json, antrenmanlar ve vücut ağırlığı için kullanıcı başına bir state-<uid>.json, oturum çerezi anahtarı için secret ve anlık bildirim anahtarları için vapid.json dosyalarını içerir. Yedeklemek için sırasıyla docker compose stop api, tar czf ~/opengym-$(date +%F).tar.gz data/ ve docker compose start api komutlarını kullanın, ardından oluşturulan arşivi sunucudan kopyalayın. Medya işinin kendi kendine tekrar indireceği 140 MB'lık egzersiz görsellerini içeren media/ dizinini yedeklemenize gerek yoktur.

Claude, openGym antrenman geçmişimi okuyabilir mi?

Evet, mcp/ dizinindeki isteğe bağlı MCP sunucusu aracılığıyla ve yalnızca okuma amacıyla okuyabilir. Bu sunucu; rutinleri, haftalık planları, kaydedilmiş antrenmanları, vücut ağırlığını, tahmini tek tekrar maksimumunu ve kas dengesini kapsayan sekiz araç sunar; bunların hiçbiri veri yazmaz. Bu bir container değildir ve herhangi bir port açmaz: istemciniz onu stdio üzerinden başlatır ve OPENGYM_DATA konumundaki JSON dosyalarını doğrudan okur. Bu bir dosya sistemi yolu olduğundan, openGym'i bir VPS üzerinde çalıştırmak, ya data/ dosyasının bir kopyasını istemcinin çalıştığı makineye eşitlemeyi ya da istemci yapılandırmasından ssh aracılığıyla sunucuyu çağırmayı gerektirir.

openGym mi yoksa wger mi self-host etmeliyim?

Antrenman günlüğünüzün yanında beslenme takibi istiyorsanız veya üzerine inşa edebileceğiniz dokümante edilmiş bir REST API arıyorsanız wger'i seçin. wger daha büyük bir yığın çalıştırır: nginx arkasında gunicorn ile Django, PostgreSQL, Redis ve bir Celery worker. İki container, cat ile okuyabileceğiniz JSON dosyaları ve yönetilecek parola gerektirmeyen geçiş anahtarı ile giriş yapmak istiyorsanız openGym'i seçin. 19 Ağustos 2026 itibarıyla openGym'in ilk etiketli sürümü bir aylıktır; bu nedenle her güncellemeden önce bir git etiketini kontrol edin ve data/ dizinini yedekleyin.