Gluetun container ağ yapılandırması ve port yönlendirme
Gluetun ağ ad alanına katılan container birimlerinin port yönetimi ve güvenlik duvarı kurallarını nasıl yapılandıracağınızı öğrenin. VPN tüneli dışındaki ağ erişimini sınırlayın.
Bir container gluetun ağ yapısına katıldığında ne olur
network_mode: service:gluetun ayarını kullanan bir container'ın kendine ait ağ arayüzleri bulunmaz. Bu container, gluetun'ın ağ ad alanına (network namespace) katılır; bu nedenle port yayınlama ve güvenlik duvarı kuralları artık o container'ın değil, gluetun servisinin bir özelliği haline gelir. Aşağıdaki tüm yanıtlar bu temel gerçeğe dayanmaktadır.
Ağ ad alanı, çekirdeğin ağ yığınının özel bir kopyasıdır: kendi arayüzleri, kendi yönlendirme tablosu, kendi güvenlik duvarı kuralları ve kendi dinleme soketleri bulunur. Docker, varsayılan olarak her container'a bir tane atar. network_mode: service:gluetun yazdığınızda, Docker bu adımı atlar ve yeni container'ı gluetun'ın halihazırda sahip olduğu ad alanının içine yerleştirir. Container kendi dosya sistemini ve kendi /etc/hosts dosyasını korur; bu ikinci dosya daha sonra önem kazanacaktır.
Bunu doğrudan görebilirsiniz.
docker inspect -f '{{.HostConfig.NetworkMode}}' qbittorrentBu komut, normal bir container'ın bridge çıktısını vermesi gerekirken, gluetun container kimliğini takiben container: çıktısını verir. Bu rehber, Docker trafiğini gluetun ile VPN üzerinden yönlendirme konusunun kaldığı yerden devam eder: tünel çalışır durumdadır ve artık hiçbir şey container ile iletişim kuramaz.
Portu uygulama üzerinde değil, gluetun üzerinde yayınlayın
Servis üzerinde network_mode ayarını yapan bir ports: bloğu bırakırsanız, Docker konteyneri oluşturmayı reddeder:
Error response from daemon: conflicting options: port publishing and the container type network modeBunun nedeni açıktır. Bir portu yayınlamak, ana makine portunu konteynerin kendi ağ ad alanına (network namespace) yönlendiren bir NAT (ağ adresi çevirisi) kuralı eklemek anlamına gelir; ancak bu konteynerin kendine ait bir ağ ad alanı yoktur. Port eşleştirmesini gluetun servisine taşıyın. Uygulama hala paylaşılan ad alanı içinde aynı portu dinlediği için port numarası değişmez.
services:
gluetun:
ports:
- "8080:8080/tcp" # qBittorrent web UI
qbittorrent:
network_mode: "service:gluetun"
# no ports: block hereBağımlı servis üzerindeki bir expose: bloğu da aynı şekilde anlamsızdır ve oradaki bir networks: bloğu kesin bir engeldir: Compose, servisin birbirini dışlayan network_mode ve networks tanımladığını bildirir ve dosyanın yüklenmesini tamamen reddeder.
Bunun bir sonucu daha sonra ortaya çıkar. Ad alanındaki her konteyner tek bir port alanını paylaşır; bu nedenle varsayılan olarak 8080 portunu kullanan iki uygulama çakışır ve başlatılan ikinci uygulama, adresin zaten kullanımda olduğuna dair bir hata vererek başarısız olur. Bunlardan birini kendi yapılandırması üzerinden değiştirin; örneğin LinuxServer qBittorrent imajındaki WEBUI_PORT değişkenini değiştirin ve ardından yeni numarayı gluetun üzerinde yayınlayın.
Gluetun arkasındaki container'lar birbirine nasıl ulaşır?
Namespace içerisinde zaten bir loopback arayüzünü paylaşırlar. Gluetun arkasındaki bir container, kardeşine 127.0.0.1:<port> üzerinden, herhangi bir Docker ağına dahil olmadan ulaşır.
Namespace dışından bakıldığında container'ın bir ismi yoktur. Docker'ın gömülü DNS'i, bir servis ismini kullanıcı tanımlı bir ağdaki o servisin adresine çözümler; ancak bu container'ın herhangi bir ağda adresi bulunmaz. Bu nedenle, Sonarr gibi normal bir container, torrent istemcisine http://qbittorrent:8080 üzerinden ulaşamaz. İstemciye http://gluetun:8080 üzerinden ulaşır; çünkü soket, gluetun'un namespace'inde ve gluetun'un adresi üzerinde dinleme yapmaktadır. Bu durum, Docker Compose ağlarının ve servis isimlerinin nasıl çalıştığını bilen ve standart isimlendirme kurallarının geçerli olacağını bekleyen kullanıcılar için şaşırtıcı olabilir. Her iki container da aynı Compose ağında olduğu için, host tarafında herhangi bir port yayınlamaya gerek kalmadan da çalışır.
Başka bir hata ayıklama işlemine geçmeden önce DNS ayarlarını kontrol edin. Gluetun kendi çözümleyicisini çalıştırır ve kendi container'ı içerisindeki /etc/resolv.conf dosyasını yeniden yazar; ancak /etc/resolv.conf container bazlı bir dosya olduğundan, gluetun'un yazdığı dosya ile uygulamanızın okuduğu dosya aynı değildir.
docker exec qbittorrent cat /etc/resolv.confDocker ana makinesinde çalışan bir servise nasıl erişirim?
host.docker.internal kullanın. İki farklı şey hatalı olduğu için, iki farklı yerde iki ayar yapılması gerekir.
İsim ilk sırada yer alır. /etc/hosts her container için ayrıdır, bu nedenle extra_hosts girdisi gluetun üzerinde değil, uygulama container'ı üzerinde bulunmalıdır.
prowlarr:
network_mode: "service:gluetun"
extra_hosts:
- "host.docker.internal:host-gateway"host-gateway, Docker'ın ana makinenin kendi dahili adresiyle değiştirdiği özel bir değerdir. Standart bir Linux Docker kurulumunda bu, genellikle 172.17.0.1 olan docker0 köprüsünün adresidir. Kendi adresinizi VPS üzerinde ip -4 addr show docker0 ile doğrulayın. Docker Desktop bu ismi kendi başına çözümler; dizüstü bilgisayarlar için yazılan rehberlerin extra_hosts satırını atlamasının ve aynı dosyanın sunucuda başarısız olmasının nedeni budur.
Rota ikinci sırada yer alır. İsmi eklemek, container'a yalnızca hangi adresi kullanacağını söyler. Paket yine de gluetun'ın varsayılan rotası olan tünel üzerinden çıkar ve gluetun'ın güvenlik duvarı tarafından düşürülür. Belirti, reddedilen bir bağlantıdan ziyade, bekleyip zaman aşımına uğrayan bir bağlantıdır. Reddedilme, paketin ulaştığı ve bir yanıt döndüğü anlamına gelir. Zaman aşımı ise paketin hiç ulaşmadığı anlamına gelir.
gluetun:
environment:
- FIREWALL_OUTBOUND_SUBNETS=172.17.0.1/32Ardından, ana makine servisinin gerçekten bu adresi dinlediğinden emin olun. Yalnızca 127.0.0.1 adresine bağlı bir PostgreSQL sunucusu, tünel olsun ya da olmasın hiçbir container'dan erişilemez durumdadır; çünkü isim alanı (namespace) içindeki 127.0.0.1, o isim alanının kendi loopback adresidir. Bunun yerine servisi 172.17.0.1 adresine bağlayın: bu adres, genel arayüzden uzak dururken container'lardan gelen bağlantıları kabul eder. Ana makine üzerinde ss -lntp | grep 5432 ile doğrulama yapın.
FIREWALL_OUTBOUND_SUBNETS ayarı gerçekte neleri değiştirir
gluetun belgeleri bu ayarı, gluetun ve onun ağ yığınını paylaşan container'ların erişimine izin verilen, virgülle ayrılmış alt ağlar olarak tanımlar ve bunun güvenlik duvarı ile yönlendirme değişikliklerini içerdiğini belirtir. Her iki kısım da önemlidir. gluetun, listelenen her alt ağ için Docker köprü ağ geçidi üzerinden bir rota ekler; böylece bu adreslere yönelik paketler tünel yerine eth0 üzerinden çıkar. Ayrıca bu adresler için güvenlik duvarını açar, çünkü gluetun aksi takdirde VPN sunucusuna yönlendirilmeyen giden trafiği düşürür.
Değeri, virgüllerden sonra boşluk bırakmadan yazın.
- FIREWALL_OUTBOUND_SUBNETS=172.17.0.1/32,192.168.1.0/24,100.64.7.9/32İki özellik gözden kaçırılmaya müsaittir. Bu, namespace düzeyinde bir ayardır; dolayısıyla yalnızca hedeflediğiniz container için değil, gluetun arkasındaki her container için geçerlidir. Ayrıca bu ayar yalnızca giden trafik içindir; bir container'ın başlattığı bağlantıları yönetir. Yayınlanmış bir porta gelen bağlantılar farklı bir yol izler ve burada bir giriş gerektirmez.
Bir Tailscale eşinden web arayüzüne erişim
Tailscale, her makineye taşıyıcı sınıfı NAT için ayrılmış 100.64.0.0/10 aralığında bir adres verir. Kişisel bir tailnet üzerinde bunların hiçbiri ücretli değildir. Ancak diğer kişilerin aynı arayüzlere erişmesi gerektiğinde bunun geçerli olup olmayacağını ücretsiz planın kullanıcı ve cihaz sınırları belirler. Ücretlendirme makine sayısına göre değil, kullanıcı sayısına göre yapılır. Bu nedenle ücretli bir tailnetin gerçekte ne kadara mal olduğu, erişime davet edilen kişi sayısına bağlıdır. Kaç container'ın erişime açıldığı bu maliyeti belirlemez. Bu iki yön için farklı işlemler gerekir.
Gelen trafik (inbound) en basit olanıdır. 8080:8080 üzerinde bir port yayınlamak, o portu ana makinenin tüm adreslerinde bağlar; ana makinenin tailscale0 arayüzü de bunlardan biri olduğu için bir eş http://<machine-name>:8080 adresini açarak konteynere ulaşır. Docker'ın NAT kuralı isim alanının dışında, ana makine üzerinde yer aldığından, bu yolda gluetun'ın bir rolü yoktur.
Arayüzün yalnızca tailnet üzerinden erişilebilir olmasını sağlamak için, yayınlanan portu tüm adreslere değil, yalnızca ana makinenin Tailscale adresine bağlayın.
ports:
- "100.101.102.103:8080:8080/tcp"Bu adresi ana makinede tailscale ip -4 komutuyla bulun. Bağlama işlemi, bir güvenlik duvarı kuralından daha güçlü bir denetim sağlar; çünkü port, genel arayüzde hiçbir şekilde açılmaz. Arayüze bir ana makine ve port yerine bir HTTPS ismiyle erişmeyi tercih ederseniz, tailscale serve bu yayınlanan portun önünde çalışabilir; ancak serve ve funnel özelliklerinin erişim yetkileri farklıdır ve bu ikisinden yalnızca biri arayüzü tailnet üzerinde tutar. Bu yöntem ayrıca Docker'ın ufw kurallarını atlayarak port yayınlaması sorununu da devre dışı bırakır.
Giden trafik (outbound) ise FIREWALL_OUTBOUND_SUBNETS konusunun tekrar gündeme geldiği yerdir. Bir konteynerin bir eşi araması gerekiyorsa, o eşin adresini ekleyin ve tüm /10 aralığı yerine eş başına bir /32 tanımlamayı tercih edin. Aradığınız makine, tailnet'inize o alt ağı duyuran bir VPS aracılığıyla erişilen özel bir ağda bulunuyorsa, yönlendiricinin kendi 100.x adresi yerine duyurulan aralığı listeleyin ve ana makinenin bu rotaları kabul ettiğini doğrulayın. Konteyner ana makinenin çözümleyicisini kullanmadığı için MagicDNS isimleri konteyner içinde çözümlenmeyecektir; bu nedenle sayısal 100.x adresini kullanın veya bir extra_hosts satırı ile sabitleyin. Aynı durum, kendi Tailscale kontrol sunucunuzu Headscale ile çalıştırdığınızda da geçerlidir.
Yaygın bir yapı için eksiksiz bir compose dosyası
VPN arkasında bir indirme istemcisi, yalnızca tailnet üzerinde yanıt veren iki web arayüzü ve ana makinede çalışan bir PostgreSQL veritabanını okuyan bir container.
services:
gluetun:
image: qmcgaw/gluetun:latest
container_name: gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
ports:
- "127.0.0.1:8000:8000/tcp" # gluetun control server, host only
- "100.101.102.103:8080:8080/tcp" # qBittorrent UI, tailnet only
- "100.101.102.103:9696:9696/tcp" # Prowlarr UI, tailnet only
volumes:
- ./gluetun:/gluetun
environment:
- VPN_SERVICE_PROVIDER=mullvad
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
- WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES}
- SERVER_CITIES=Amsterdam
- FIREWALL_OUTBOUND_SUBNETS=172.17.0.1/32,100.64.7.9/32
- TZ=Europe/Amsterdam
restart: unless-stopped
qbittorrent:
image: lscr.io/linuxserver/qbittorrent:latest
network_mode: "service:gluetun"
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
- WEBUI_PORT=8080
volumes:
- ./qbittorrent:/config
- /srv/downloads:/downloads
depends_on:
gluetun:
condition: service_healthy
restart: unless-stopped
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
network_mode: "service:gluetun"
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Amsterdam
- PROWLARR__POSTGRES__HOST=host.docker.internal
- PROWLARR__POSTGRES__PORT=5432
- PROWLARR__POSTGRES__USER=prowlarr
- PROWLARR__POSTGRES__PASSWORD=${PROWLARR_DB_PASSWORD}
- PROWLARR__POSTGRES__MAINDB=prowlarr-main
- PROWLARR__POSTGRES__LOGDB=prowlarr-log
volumes:
- ./prowlarr:/config
depends_on:
gluetun:
condition: service_healthy
restart: unless-stoppedDosyayı ürün isimlerinden ziyade yapısal model için inceleyin. Her iki arayüz de gluetun üzerinde yayınlanır ve ana makinenin tailnet adresine bağlanır; bu sayede yalnızca Tailscale üzerinden yanıt verirler. Yalnızca Prowlarr extra_hosts satırını içerir, çünkü host.docker.internal çözümlemesini yapan container Prowlarr'dır. FIREWALL_OUTBOUND_SUBNETS iki tekil adresi tanımlar: Prowlarr'ın veritabanı bağlantısı açabilmesi için ana makinenin Docker köprü adresi ve bir tailnet eşi.
PostgreSQL sunucusu dosyada kasten yer almamaktadır. VPS üzerinde 172.17.0.1:5432 adresini dinleyen olağan bir sistem servisi olarak çalışır. Bu, veritabanının Docker dışına taşındığı Docker Compose üzerinde bir arr yığını ile aynı katmanlama mantığıdır.
WireGuard özel anahtarını compose dosyasının dışında tutun. ${WIREGUARD_PRIVATE_KEY}, yanında bulunan bir .env dosyasından okuma yapar; bu model Docker Compose için env dosyaları ve sırlar bölümünde ele alınmıştır. condition: service_healthy ifadesi, gluetun imajının halihazırda sunduğu sağlık kontrolünü (healthcheck) kullanır, böylece tünel aktif olduğunu bildirene kadar hiçbir şey başlamaz. Compose sağlık kontrolleri genel yapıyı açıklar.
Yalnızca tailnet yerine her adreste yayınlama
VPS genel IP adresini de içeren 0.0.0.0 üzerindeki adres önekini ve port bağlamalarını kaldırın. Bunu yalnızca kontrolünüz altındaki bir güvenlik duvarının arkasında yapın ve öncesinde yukarıdaki ufw notunu okuyun.
ports:
- "8080:8080/tcp"Tünelin trafik taşıdığını doğrulama
Aynı isteği bir kez namespace içinden, bir kez de host üzerinden çalıştırın ve sonuçları karşılaştırın.
docker run --rm --network=container:gluetun curlimages/curl:latest -s https://api.ipify.org
curl -s https://api.ipify.orgİlk komut, VPN sağlayıcınızın çıkış adresini yazdırmalıdır. İkinci komut ise VPS adresini yazdırmalıdır. Eğer bu adresler aynıysa, container trafiği tünel üzerinden geçmiyor demektir; bu durum düzeltilene kadar bu kılavuzdaki diğer tüm çözüm önerileri geçersizdir.
Yönlendirme tablosu, hangi trafiğin tünel dışına çıktığını gösterir.
docker run --rm --network=container:gluetun alpine:3.22 ip route showVarsayılan rota, tun0 tünel arayüzünü işaret etmelidir. Bunun altında, FIREWALL_OUTBOUND_SUBNETS içindeki her bir girdi için Docker bridge ağ geçidini işaret eden birer rota görmelisiniz. eth0 üzerinden çıkan diğer tüm rotalar, VPN'i atlayan trafik anlamına gelir.
Gluetun kontrol sunucusu, /v1/publicip/ip adresindeki 8000 numaralı port üzerinden aynı genel IP adresini raporlar. Güncel sürümler, kontrol sunucusu rotaları için kimlik doğrulama yapılandırmanızı gerektirir; bu nedenle, bu veriye güvenmeden önce ilgili ayarları yapın.
Yanlış bir alt ağın oluşturduğu sızıntı
FIREWALL_OUTBOUND_SUBNETS, güvenlik duvarında bilerek açtığınız bir deliktir; dolayısıyla deliğin boyutu, riskin boyutunu belirler. Bu deliği gereğinden fazla büyütmenin dört yolu şunlardır:
0.0.0.0/0, tünel dışındaki her şeyi dışarı gönderir. Yukarıdaki iki IP denetimi, aynı adresi döndürecekleri için bu durumu ilk çalıştırmada yakalar.- Hedeften daha geniş bir aralık.
10.0.1.7adresindeki tek bir makineye ulaşmak için10.0.0.0/8aralığını açmak, bir torrent eşinin bu aralıkta duyurabileceği her adresi de açar. Bunun yerine10.0.1.7/32yazın. - Tünelin kendi adresleriyle çakışan bir aralık. gluetun belgeleri, bunun gluetun'un VPN trafiğini köprü üzerinden dışarı göndermesine neden olduğu ve port yönlendirmeyi bozduğu konusunda uyarır. Herhangi bir özel aralığı açmadan önce
WIREGUARD_ADDRESSESdeğerinizi kontrol edin. - Tailscale için
100.64.0.0/10. Bu, tek bir eşe ulaşılabilmesi için yaklaşık dört milyon adresin açılması anlamına gelir. İhtiyacınız olan eşleri/32girdileri olarak listeleyin.
Bu ayarın tüm ad alanını kapsadığını unutmayın. Bir dizinleyicinin (indexer) bir ana bilgisayar servisine ulaşabilmesi için bir alt ağ açmak, aynı alt ağı o ad alanını paylaşan torrent istemcisi için de açar. Bu değişkende yapılan her değişiklikten sonra genel IP denetimini yeniden çalıştırın; çünkü değişikliğin amaçladığınız sonucu verip vermediğini gösteren tek test budur.
gluetun yeniden başlatıldığında ne bozulur
gluetun, namespace üzerinde hak sahibidir; dolayısıyla gluetun'un yaşam döngüsü, namespace'in yaşam döngüsüdür. gluetun kapalıyken bağımlı bir container başlatılmaya çalışılırsa işlem anında başarısız olur:
Error response from daemon: cannot join network of a non running containergluetun'u yerinde yeniden başlatmak daha sessiz bir hata türüdür. Bağımlı container'lar çalışmaya devam ederken, bağlı oldukları namespace altlarında yeniden oluşturulur; bu durumda docker ps her şeyin sağlıklı olduğunu raporlar ancak hiçbir servis yanıt vermez. gluetun servisinde herhangi bir değişiklik yapıldıktan sonra, parçalardan birini yeniden başlatmak yerine tüm grubu yeniden oluşturun.
docker compose up -d --force-recreateAynı durum imaj güncellemeleri için de geçerlidir. Yeni bir gluetun imajı çekip sadece o servisi yeniden oluşturmak, diğer servislerin artık var olmayan bir namespace'e işaret etmesine neden olur.
FAQ
Docker neden "port publishing and the container type network mode" hatası veriyor?
Çünkü ports: bloğu, aynı zamanda network_mode: service:gluetun ayarını yapan bir serviste tanımlanmıştır. Bir portu dışarı açmak, ana makine portunu container'ın kendi ağ ad alanına (network namespace) yönlendiren bir NAT kuralı ekler; ancak bu moddaki bir container'ın kendine ait bir ağ ad alanı yoktur. İlgili servisten ports: bloğunu silin ve aynı eşleştirmeyi gluetun servisine ekleyin. Uygulama paylaşılan ad alanı içinde aynı portu dinlemeye devam ettiği için port numarası değişmez.
Diğer container'lar gluetun arkasındaki bir servise nasıl ulaşır?
Aynı ad alanındaki container'lar birbirine 127.0.0.1 üzerinden ulaşır. Dışarıdaki container'lar ise gluetun servis adını kullanır; bu nedenle http://qbittorrent:8080 çalışmazken http://gluetun:8080 çalışır. Uygulama container'ı herhangi bir Docker ağında bir adrese sahip olmadığından, gömülü DNS sunucusu onun ismi için çözümleme yapamaz. Her iki container aynı Compose ağını paylaştığı sürece bunun için port açılmasına gerek yoktur.
FIREWALL_OUTBOUND_SUBNETS içine ne yazmalıyım?
Yalnızca gluetun arkasındaki bir container'ın bağlantı başlatması gereken adresleri, mümkün olduğunca dar kapsamlı şekilde yazın. Tek bir makine için /32 kullanılır. En yaygın iki giriş, 172.17.0.1/32 adresindeki Docker ana makinesi ve eriştiğiniz her bir Tailscale eşi için bir adet /32 adresidir. Asla 0.0.0.0/0 eklemeyin ve VPN tünel adreslerinizle çakışan bir aralık tanımlamayın. Dışarıdan açılan bir porta gelen bağlantılar için burada bir giriş yapılmasına gerek yoktur.
Container neden Tailscale MagicDNS isimlerini çözümleyemiyor?
MagicDNS, ana makinenin çözümleyicisini Tailscale'in DNS sunucusuna yönlendirerek çalışır; ancak container ana makinenin çözümleyicisini kullanmaz. Container, kendi /etc/resolv.conf ayarında ne tanımlıysa onu kullanır; gluetun arkasında bu, gluetun'un DNS yapılandırmasıdır. Bunu docker exec <container> cat /etc/resolv.conf ile doğrulayın. Eşin sayısal 100.x adresini kullanın veya o container üzerinde bir extra_hosts girişi ile ismi sabitleyin.
Trafiğin hala VPN üzerinden geçtiğini nasıl doğrularım?
Ad alanı içinden bir istek gönderin, aynı isteği ana makineden de yapın ve yanıtları karşılaştırın. docker run --rm --network=container:gluetun curlimages/curl:latest -s https://api.ipify.org, VPN sağlayıcınızın çıkış adresini döndürmelidir; VPS üzerindeki curl -s https://api.ipify.org ise VPS adresini döndürmelidir. İki yanıtın aynı olması, tünelin container trafiğini taşımadığı anlamına gelir. Bu kontrolü FIREWALL_OUTBOUND_SUBNETS üzerinde yapılan her değişiklikten sonra tekrar çalıştırın.