Docker'da port yayınlamak (publish), container içindeki bir portu sunucunun bir portuna eşleyip dışarıdan erişilebilir kılmaktır ve -p (--publish) bayrağıyla yapılır. -p 8080:80 sunucunun bütün adreslerindeki 8080 portunu container'ın 80 numaralı TCP portuna bağlar. Docker belgeleri bunun varsayılan olarak güvensiz olduğunu açıkça yazar: sunucu adresi belirtmezseniz port yalnızca sunucuya değil bütün dünyaya açılır. Sadece sunucunun kendisinin erişmesini istiyorsanız -p 127.0.0.1:8080:80 biçimini kullanın.
Bu yazıda -p sözdizimini, -P ile otomatik yayınlamayı, EXPOSE ile yayınlama arasındaki farkı, Compose'daki kısa ve uzun port sözdizimini, varsayılan bağlama adresini daemon ya da ağ düzeyinde nasıl değiştireceğinizi ve bridge sürücüsünün ağ geçidi modlarını (nat, routed, isolated) resmî belgelere dayanarak anlatıyoruz. Güvenlik duvarı tarafı Docker iptables ve UFW yazısında. Serinin tamamı için Docker öğrenme rehberine bakın.
Yayınlanmamış port ile yayınlanmış port
Docker belgelerine göre daemon, hem IPv4 hem IPv6 için yayınlanmamış portlara erişimi varsayılan olarak engeller. docker create ya da docker run ile bir container oluşturduğunuzda bridge ağlarındaki container'ların bütün portlarına sunucudan ve aynı ağdaki diğer container'lardan erişilebilir. Sunucunun dışından ve varsayılan yapılandırmada başka ağlardaki container'lardan ise erişilemez.
-p bayrağı bu durumu değiştirir: portu sunucunun dışına ve diğer bridge ağlarındaki container'lara açar. Bunu yaparken Docker sunucuda güvenlik duvarı kuralları oluşturur ve ağ adresi dönüştürmesi (NAT), port adresi dönüştürmesi (PAT) ve masquerading uygular. Container'dan dışarı giden bağlantılar da sunucunun IP adresiyle masquerade edilir. Bu kuralları Docker kendisi yönetir; bu nedenle yayınlanan bir portun kimlere açık olduğu, sunucudaki güvenlik duvarı aracınızdan çok yayınlama bayrağına yazdığınız adrese bağlıdır.
-p sözdizimi

Belgelerdeki temel örnekler aşağıdaki tabloda. Sözdiziminin genel biçimi [sunucu_ip:][sunucu_port:]container_port[/protokol] şeklindedir; protokol verilmezse TCP kullanılır.
| Bayrak değeri | Anlamı |
|---|---|
| -p 8080:80 | Sunucudaki 8080 portunu container'daki TCP 80 portuna eşler |
| -p 192.168.1.100:8080:80 | Sunucunun 192.168.1.100 adresindeki 8080 portunu container'daki TCP 80 portuna eşler |
| -p 8080:80/udp | Sunucudaki 8080 portunu container'daki UDP 80 portuna eşler |
| -p 8080:80/tcp -p 8080:80/udp | TCP 8080 portunu TCP 80'e, UDP 8080 portunu UDP 80'e eşler |
| -p 127.0.0.1:8080:80 | Yalnızca sunucunun IPv4 loopback adresinde yayınlar |
| -p 8000-9000:5000 | Container 5000 portunu sunucuda 8000 ile 9000 arasındaki boş bir porta bağlar |
| -p 127.0.0.1::5000 | Container 5000 portunu yalnızca loopback üzerinde dinamik bir porta bağlar |
-p bayrağını birden fazla kez kullanarak birden çok port yayınlayabilirsiniz. Eski linkler belgesi, sunucuda belirli bir portu (örneğin 80) sabit olarak kullanmanın o porta yalnızca tek bir container bağlanabilmesi anlamına geldiğini hatırlatır; aynı imajdan birden fazla kopya çalıştıracaksanız aralık ya da dinamik port kullanmak bu kısıtı kaldırır. Aynı belge UDP'nin yanında SCTP portlarının da sona /sctp eklenerek yayınlanabileceğini belirtir.
Yalnızca sunucuya açmak: 127.0.0.1 ve ::1
Belgelerin önemli uyarısı şudur: port yayınlamak varsayılan olarak güvensizdir; yayınladığınız port Docker sunucusuna ek olarak dış dünyaya da açılır. Yayınlama bayrağına localhost adresini (127.0.0.1 ya da ::1) eklerseniz porta yalnızca Docker sunucusu erişebilir. IPv4 ve IPv6 loopback için ayrı ayrı yayınlamak gerekir; IPv6 adresi köşeli parantez içinde ve tırnakla yazılır:
docker run -p 127.0.0.1:8080:80 -p '[::1]:8080:80' nginxBu kalıp, uygulamanın önünde aynı sunucuda çalışan bir reverse proxy (Nginx, Caddy, Traefik) varsa idealdir: dışarıya yalnızca proxy'nin 80 ve 443 portları açılır, uygulama container'ı loopback'e yayınlanır ya da proxy ile aynı Docker ağına konup hiç yayınlanmaz. Reverse proxy kavramı için reverse proxy nedir yazısına bakabilirsiniz.
-P, docker port ve dinamik portlar
-P (--publish-all) imajın bildirdiği bütün portları sunucudaki geçici (ephemeral) port aralığından rastgele yüksek portlara yayınlar. Hangi portun seçildiğini docker ps ya da docker port ile görürsünüz. Eski linkler belgesindeki örnekte 5000 numaralı container portu sunucunun 49155 portuna bağlanmıştır:
docker ps nostalgic_morse
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
bc533791f3f5 training/webapp:latest python app.py 5 seconds ago Up 2 seconds 0.0.0.0:49155->5000/tcp nostalgic_morsedocker port komutu belirli bir portun nereye bağlandığını gösterir. Port loopback'e bağlanmışsa çıktı bunu yansıtır:
docker port nostalgic_morse 5000
127.0.0.1:49155Docker Engine 29.6.0 sürüm notlarına göre Docker, portları dinamik olarak dağıtırken net.ipv4.ip_local_reserved_ports içinde listelenen sunucu portlarını kullanmaz. Engine 29.1.3 ile de container portu 0 olan bir port eşlemesiyle container oluşturmak artık hata döndürür. Compose tarafında dinamik portu öğrenmek için docker compose port web 80 komutu kullanılır; ölçeklenmiş servislerde --index ile belirli bir kopyayı, UDP için --protocol=udp ile protokolü seçersiniz.
EXPOSE yayınlamak değildir

Dockerfile'daki EXPOSE talimatı, Docker'ın derleme en iyi uygulamaları belgesine göre container'ın bağlantıları hangi portlarda dinlediğini belirtir; uygulamanız için yaygın, geleneksel portu kullanmanız önerilir (Apache için 80, MongoDB için 27017 gibi). Dışarıdan erişim için yine kullanıcının docker run sırasında bir eşleme bayrağı vermesi gerekir. Yani EXPOSE 80 tek başına sunucuda hiçbir port açmaz; bu bilgi -P kullanıldığında hangi portların yayınlanacağını belirler ve belgeleme işlevi görür. Dockerfile temelleri için Dockerfile yazma rehberine bakabilirsiniz.
Compose'taki expose anahtarı da aynı mantıktadır: başvuru belgesine göre bu portlar bağlı servislerin erişebileceği iç portlardır ve sunucuya yayınlanmamalıdır; yalnızca container portları yazılabilir. Belgeler ayrıca imajın Dockerfile'ı bir portu zaten EXPOSE ediyorsa Compose'ta expose yazmasanız bile o portun ağdaki diğer container'lara görünür olduğunu not eder.
| Mekanizma | Nerede | Sunucuda port açar mı? | Kimler erişir? |
|---|---|---|---|
| EXPOSE | Dockerfile | Hayır | Bilgi amaçlı, -P için kaynak |
| expose | Compose servisi | Hayır | Aynı ağdaki servisler |
| Yayınsız port (bridge) | - | Hayır | Sunucu ve aynı ağdaki container'lar |
| -p / ports | docker run, Compose | Evet | Sunucu IP'sine ulaşabilen herkes (adres verilmezse) |
| -p 127.0.0.1:... | docker run, Compose | Yalnızca loopback | Sadece sunucunun kendisi |
Compose'ta ports: kısa ve uzun sözdizimi
Compose'un kısa sözdizimi [HOST:]CONTAINER[/PROTOCOL] biçimindedir; HOST kısmı [IP:](port | aralık) olabilir. Başvuru belgesi iki uyarı yapar. Birincisi: sunucu IP'si (örneğin 127.0.0.1) belirtmezseniz Docker bütün arayüzlere bağlanır, sunucu güvenlik duvarı kurallarını atlar ve sunucunun genel IP adresi varsa container doğrudan internete açılabilir. İkincisi: YAML'ın 60 tabanlı sayı yorumuyla çakışmamak için HOST:CONTAINER değerleri her zaman tırnaklı string olarak yazılmalıdır. Sunucu ve container tarafında aralık kullanılırsa aralıklar eşdeğer olmalıdır; yalnızca container portu verirseniz sunucu tarafında boş bir port otomatik seçilir.
Uzun sözdizimi ek alanlar sunar: target (container portu), published (string olarak sunucu portu ya da başlangıç-bitiş aralığı), host_ip, protocol, app_protocol, mode (Swarm için host ya da ingress, varsayılan ingress) ve name. Aşağıdaki dosya iki biçimi birlikte kullanır:
services:
web:
image: nginx:latest
ports:
- "127.0.0.1:8080:80"
- "[::1]:8080:80"
- name: https
target: 443
host_ip: 127.0.0.1
published: "8443"
protocol: tcp
dns:
image: example/dns:latest
ports:
- "5353:53/udp"
app:
image: example/app:latest
expose:
- "3000"Bu dosyayı Docker CLI 29.8.1, Docker Compose v5.5.1 ile docker compose config komutundan geçirdiğinizde Compose kısa sözdizimini uzun biçime çevirir. Aşağıdaki, komutun gerçek çıktısıdır (proje adı klasör adından, port, gelir):
name: port
services:
app:
expose:
- "3000"
image: example/app:latest
networks:
default: null
dns:
image: example/dns:latest
networks:
default: null
ports:
- mode: ingress
target: 53
published: "5353"
protocol: udp
web:
image: nginx:latest
networks:
default: null
ports:
- mode: ingress
host_ip: 127.0.0.1
target: 80
published: "8080"
protocol: tcp
- mode: ingress
host_ip: ::1
target: 80
published: "8080"
protocol: tcp
- name: https
mode: ingress
host_ip: 127.0.0.1
target: 443
published: "8443"
protocol: tcp
networks:
default:
name: port_defaultÇıktıda üç şey dikkat çeker: "[::1]:8080:80" girişi host_ip: ::1 olarak ayrıştırılmıştır, dns servisinin protokolü udp olarak korunmuştur ve app servisinde expose bulunmasına rağmen hiçbir ports girdisi yoktur. Ayrıca Compose port_default adlı varsayılan ağı eklemiştir. Port mantığını değiştirmeden önce bu komutla Compose'un dosyanızı nasıl yorumladığını görmek, tırnak ve IPv6 hatalarını erkenden yakalamanın kolay bir yoludur.
Varsayılan bağlama adresini değiştirmek
Port eşlemesinde sunucu adresi verilmediğinde daemon portu bütün sunucu adreslerine (0.0.0.0 ve [::]) yayınlar. Her komutta 127.0.0.1 yazmayı unutma riskini ortadan kaldırmak için varsayılan bağlama adresini değiştirebilirsiniz. Kullanıcı tanımlı tek bir bridge ağı için com.docker.network.bridge.host_binding_ipv4 sürücü seçeneği kullanılır; adına rağmen IPv6 adresi de verilebilir:
docker network create mybridge \
-o "com.docker.network.bridge.host_binding_ipv4=127.0.0.1"Bütün kullanıcı tanımlı bridge ağları için aynı ayarı daemon düzeyinde default-network-opts ile yaparsınız:
{
"default-network-opts": {
"bridge": {
"com.docker.network.bridge.host_binding_ipv4": "127.0.0.1"
}
}
}Varsayılan bridge ağı için ise daemon.json içindeki "ip" anahtarı ya da dockerd --ip bayrağı kullanılır; değişiklik daemon yeniden başlatılınca etkili olur:
{
"ip": "127.0.0.1"
}Compose'ta aynı ayar, ağ tanımında driver_opts ile verilir. Compose ağ başvurusundaki örnek, projenin varsayılan ağına com.docker.network.bridge.host_binding_ipv4: 127.0.0.1 ekler. Bu ayarlarla ilgili belgelerdeki notlar şunlardır:
- Varsayılan bağlama adresini
::yapmak, adres belirtilmemiş eşlemelerin yalnızca sunucunun IPv6 adreslerinde çalışması demektir;0.0.0.0ise IPv4 ve IPv6 adreslerinin tamamını kapsar. - Bir yayını yalnızca IPv4 ile sınırlamak için adresi eşlemenin içine yazmanız gerekir, örneğin
-p 0.0.0.0:8080:80. - Varsayılan bağlama adresi belirli bir arayüze atanmış bir adresse container portuna yalnızca o adresten erişilir.
- Varsayılan bağlama adresini değiştirmek Swarm servislerini etkilemez; Swarm servisleri her zaman
0.0.0.0üzerinde yayınlanır. - Sunucu adresi verilmemişse, bridge ağı yalnızca IPv4 ise ve
--userland-proxy=true(varsayılan) ise sunucunun IPv6 adreslerindeki portlar container'ın IPv4 adresine eşlenir.
Ağ geçidi modları ve doğrudan yönlendirme

Port eşleme, yayınlanan portların sunucunun ağ adreslerinde erişilebilir olmasını sağlar. Sunucunun ağında container adreslerine giden yollar normalde tanımlı değildir. Özellikle IPv6'da NAT'tan kaçınıp dış makinelerin container adreslerine doğrudan ulaşmasını ("direct routing") isteyebilirsiniz. Bunun için önce sunucu üzerinden bridge ağına bir yol tanımlanmalıdır: statik yollar, BGP ya da ağınıza uygun başka bir yöntem.
Bridge sürücüsünün com.docker.network.bridge.gateway_mode_ipv4 ve com.docker.network.bridge.gateway_mode_ipv6 seçenekleri dört moddan birini alır:
| Mod | NAT/masquerade | Yayınlanmamış portlar | Not |
|---|---|---|---|
| nat (varsayılan) | Var | Korunur | Giden paketler sunucu adresini kullanır |
| nat-unprotected | Var | Doğrudan yönlendirmeyle erişilebilir | Eski varsayılan davranışla uyumluluk için |
| routed | Yok | Korunur | Giden paketler container adresini kullanır; sunucu portu kullanılmaz |
| isolated | - | - | Yalnızca --internal ağlarda; bridge'e adres atanmaz |
routed modunda -p eşlemesindeki sunucu portu kullanılmaz; sunucu adresi yalnızca eşlemenin IPv4'e mi IPv6'ya mı uygulanacağına karar vermek için okunur. Bu yüzden yalnızca routed moda uygulanan bir eşlemede 0.0.0.0 ya da :: kullanılmalı ve sunucu portu verilmemelidir; aksi halde değer etkisiz kalır ve bir uyarı günlüğe yazılır. Belgelerdeki örnek IPv6 için routed, IPv4 için varsayılan nat modunu kullanan bir ağ oluşturur:
docker network create --ipv6 --subnet 2001:db8::/64 -o com.docker.network.bridge.gateway_mode_ipv6=routed mynet
docker run --network=mynet -p 8080:80 myimageSonuçta IPv4 tarafında container'ın 80 portu sunucunun 8080 portundan erişilebilir; IPv6 tarafında ise sunucuda 8080 açılmaz, 80 portu doğrudan container'ın IPv6 adresinde açılır. docker container inspect çıktısında IPv6 için HostPort boş görünür:
docker container inspect <id> --format "{{json .NetworkSettings.Ports}}"
{"80/tcp":[{"HostIp":"0.0.0.0","HostPort":"8080"},{"HostIp":"::","HostPort":""}]}Bütün Linux bridge ağlarında yayınlanmış portlara doğrudan erişime izin vermek için daemon seçeneği "allow-direct-routing": true ya da --allow-direct-routing kullanılır. Belirli sunucu arayüzlerinden belirli bir ağa doğrudan erişim için ağ oluştururken com.docker.network.bridge.trusted_host_interfaces seçeneği verilir. Engine 29.0.0 sürüm notlarına göre routed moddaki ağlarda yayınlanan portlar artık her zaman erişilebilir; önceden bu kurallar yalnızca routed ağ container'ın varsayılan ağ geçidi seçildiğinde ekleniyordu. Engine 29.9.0 ise docker ps çıktısında routed ağların yayınlanmış portlarının görünmemesi hatasını düzeltmiştir.
Nat modunda bir portu loopback adresine yayınlamak uzak makinelerin ona erişememesi demektir. Ancak belgeler bir uyarı ekler: nat modunda port belirli bir sunucu adresine yayınlanmışsa ve sunucuda IP yönlendirme açıksa, porta diğer sunucu arayüzlerinden o adrese doğrudan yönlendirmeyle erişilebilir. İki ağ kartı olan bir sunucuda, bir karta yayınlanan port diğer karttaki alt ağdan yönlendirilerek kullanılabilir.
Host ağı ve port yayınlama
Container host ağ modunda çalışıyorsa kendi IP adresi olmadığı için port eşleme etkisizdir; -p, -P ve ilgili seçenekler yok sayılır ve Docker WARNING: Published ports are discarded when using host network mode uyarısını verir. Bu modda uygulama hangi portu dinliyorsa sunucuda doğrudan o port açılır; Docker'ın port yayınlama kuralları devreye girmez. Ağ modlarının karşılaştırması Docker network türleri yazısında.
Sık yapılan hatalar
- Adres vermeden yayınlamak:
-p 5432:5432veritabanını internete açabilir. Container'lar arası erişim için yayın gerekmez; gerekiyorsa127.0.0.1ile sınırlayın. - UFW'nin bu portu engelleyeceğini sanmak: belgelere göre yayınlanan container trafiği UFW kurallarına ulaşmadan yönlendirilir. Ayrıntılar Docker iptables ve UFW yazısında.
- Compose'ta portu tırnaksız yazmak: belgeler YAML'ın 60 tabanlı sayı yorumu nedeniyle
HOST:CONTAINERdeğerlerinin tırnaklı yazılmasını ister. - EXPOSE ile portun açıldığını düşünmek:
EXPOSEyalnızca bildirimdir; sunucuda port açmak için-pgerekir. - Servisler arası bağlantıda sunucu portunu kullanmak: Compose belgelerine göre ağ içindeki iletişim container portunu kullanır;
8001:5432eşlemesinde diğer servislerdb:5432ile bağlanır.
Sık Sorulan Sorular
-p 8080:80 ile -p 127.0.0.1:8080:80 arasındaki fark nedir?
İlki portu sunucunun bütün IPv4 ve IPv6 adreslerinde açar ve dışarıdan erişilebilir kılar. İkincisi yalnızca sunucunun IPv4 loopback adresinde açar; porta yalnızca sunucunun kendisi erişir.
Container portunu bilmiyorum, nasıl bulurum?
Yayınlanmış eşlemeleri docker port <container> ya da docker ps ile, Compose projelerinde docker compose port <servis> <port> ile görebilirsiniz.
Bütün yeni portların varsayılan olarak 127.0.0.1'e yayınlanmasını sağlayabilir miyim?
Evet. Kullanıcı tanımlı bridge ağları için daemon.json içinde default-network-opts ile host_binding_ipv4 değerini, varsayılan bridge için "ip" anahtarını 127.0.0.1 yapın. Swarm servisleri bu ayardan etkilenmez.
Swarm'da port yayınlama farklı mı?
Compose uzun sözdizimindeki mode alanı Swarm içindir: host portu her düğümde yayınlar, varsayılan ingress düğümler arasında yük dengelemeye izin verir. Ayrıntılar Docker Swarm kurulumu yazısında.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Docker öğrenme rehberi · Docker iptables ve UFW · Docker bridge network · Docker network türleri · Docker IPv6 · Reverse proxy nedir · Docker Compose başlangıç rehberi