Docker, Nginx ve Letsencrypt ile kolay ve güvenli bir ters proxy nasıl kurulur

Giriş

Hiç evde bir tür sunucu kurmayı denediniz mi? Her hizmet için yeni bir bağlantı noktası açmanız gereken yer? Ve hangi bağlantı noktasının hangi hizmete gittiğini ve ev ipinizin ne olduğunu hatırlamanız mı gerekiyor? Bu kesinlikle işe yarayan bir şey ve insanlar bunu en uzun süredir yapıyor.

Ancak, plex.example.com yazıp medya sunucunuza anında erişim sağlamak güzel olmaz mıydı ? Bu tam olarak bir ters proxy'nin sizin için yapacağı şeydir ve bunu Docker ile birleştirmek her zamankinden daha kolay.

Önkoşullar

Docker ve Docker-Compose

Docker sürüm 17.12.0+ ve Compose sürüm 1.21.0+ olmalıdır.

Alan adı

Bir etki alanı oluşturmalı ve onunla ilişkili bir SSL Sertifikasına sahip olmalısınız. Bir hesabınız yoksa, LetsEncrypt ile nasıl ücretsiz bir tane alacağınızla ilgili kılavuzumu buradan takip edin.

Bu Makale Neleri Kapsayacak

Ben ne yaptığınızı anlamaya inanan biriyim Kılavuzları takip edeceğim ve arızaları nasıl gidereceğime dair hiçbir fikrim olmadığı bir zaman vardı. Bunu nasıl yapmak istiyorsanız, işte nasıl kurulacağını anlatan harika bir eğitim. Yazılarım uzun olsa da, hepsinin nasıl çalıştığını anlamanız gerekir.

Burada öğreneceğiniz şey, ters proxy'nin ne olduğu, nasıl kurulacağı ve nasıl güvence altına alınacağıdır. Konuyu başlıklara bölerek bölümlere ayırmak için elimden gelenin en iyisini yapıyorum, bu yüzden isterseniz bir bölümün üzerinden atlayabilirsiniz. Kurmaya başlamadan önce tüm makaleyi bir kez okumanızı tavsiye ederim.

Ters Proxy nedir?

Normal Proxy

Normal bir proxy konseptiyle başlayalım. Bu, teknoloji topluluğunda çok yaygın olan bir terim olsa da, kullanıldığı tek yer değil. Proxy, konuma gelmeden önce bilginin üçüncü bir şahıstan geçmekte olduğu anlamına gelir.

Bir hizmetin IP'nizi bilmesini istemediğinizi, bir proxy kullanabilirsiniz. Proxy, özellikle bu amaç için kurulmuş bir sunucudur. Kullandığınız proxy sunucusu Amsterdam'da bulunuyorsa, dış dünyaya gösterilecek IP Amsterdam'daki sunucudan gelen IP'dir. IP'nizi bilenler, proxy sunucusunun kontrolünde olanlardır.

Ters Proxy

Basit terimlere ayırmak için, proxy bir maskeleme katmanı ekleyecektir. Ters proxy'de aynı kavramdır, ancak giden bağlantıları maskelemek (bir web sunucusuna erişiyorsanız), maskelenecek olan gelen bağlantılardır (web sunucunuza erişen kişiler). Siz sadece example.com gibi bir URL sağlarsınız ve insanlar bu URL'ye her eriştiğinde, ters proxy'niz bu isteğin nereye gittiğiyle ilgilenir.

Dahili ağınızda kurulu iki sunucunuz olduğunu varsayalım. Sunucu1 192.168.1.10'da ve Sunucu2 192.168.1.20'de. Şu anda ters proxy'niz example.com'dan Sunucu1'e gelen istekleri gönderiyor . Bir gün web sayfasında bazı güncellemeleriniz var. Web sitesini bakım için kapatmak yerine, yeni kurulumu Sunucu2'de yapmanız yeterlidir. Bitirdikten sonra, ters proxy'nizdeki tek bir satırı değiştirirsiniz ve şimdi istekler Sunucu2'ye gönderilir. Ters proxy'nin doğru şekilde kurulduğunu varsayarsak, kesinlikle kesinti süreniz olmamalıdır.

Ancak, ters proxy'ye sahip olmanın belki de en büyük avantajı, çok sayıda bağlantı noktasında çalışan hizmetlere sahip olabilmenizdir, ancak yalnızca sırasıyla 80 ve 443, HTTP ve HTTPS bağlantı noktalarını açmanız gerekir. Tüm istekler bu iki bağlantı noktasından ağınıza gelecek ve gerisini ters proxy halledecektir. Proxy'yi kurmaya başladığımızda tüm bunlar mantıklı olacaktır.

Konteyneri Kurmak

Ne yapalım

docker-compose.yaml:

version: '3' services: reverse: container_name: reverse hostname: reverse image: nginx ports: - 80:80 - 443:443 volumes: - :/etc/nginx - :/etc/ssl/private

Öncelikle docker-compose dosyanıza yeni bir servis eklemelisiniz. Buna ne istersen diyebilirsin, bu durumda ben tersini seçtim . Burada görüntü olarak az önce nginx'i seçtim , ancak bir üretim ortamında, gelecekteki güncellemelerde herhangi bir değişiklik olması durumunda bir sürüm belirtmek genellikle iyi bir fikirdir.

O zaman iki klasörü ciltlemelisiniz. / etc / nginx , tüm yapılandırma dosyalarınızın depolandığı yerdir ve / etc / ssl / private , SSL sertifikalarınızın depolandığı yerdir. Kapsayıcıyı ilk kez başlattığınızda yapılandırma klasörünüzün ana makinenizde OLMAMASI ÇOK önemlidir. Konteynırınızı docker-compose ile başlattığınızda, klasörü otomatik olarak oluşturur ve onu konteynerin içeriğiyle doldurur. Ana makinenizde boş bir yapılandırma klasörü oluşturduysanız, onu bağlar ve kabın içindeki klasör boş olur.

Neden Çalışır

Bu kısımda pek bir şey yok. Çoğunlukla docker-compose ile başka herhangi bir kapsayıcıyı başlatmak gibidir. Burada dikkat etmeniz gereken şey, 80 ve 443 numaralı bağlantı noktalarını bağladığınızdır. Burası tüm isteklerin geleceği yerdir ve sizin belirleyeceğiniz hizmete iletileceklerdir.

Nginx'i Yapılandırma

Ne yapalım

Artık ana makinenizde bir yapılandırma klasörünüz olmalıdır. Bu dizine geçtiğinizde, bir sürü farklı dosya ve adlı bir klasör görmelisiniz conf.d. İçinde var conf.dtüm yapılandırma dosyaları alınacaktır söyledi. Şu anda tek bir default.confdosya var, devam edip onu silebilirsiniz.

Hala içeride conf.d, iki klasör oluşturun: sites-availableve sites-enabled. İçine gidin sites-availableve ilk yapılandırma dosyanızı oluşturun. Burada Plex için bir giriş ayarlayacağız, ancak isterseniz kurduğunuz başka bir hizmeti kullanmaktan çekinmeyin. Dosyanın adı gerçekten önemli değil, ancak adını vermeyi tercih ederim plex.conf.

Şimdi dosyayı açın ve aşağıdakileri girin:

upstream plex { server plex:32400; } server { listen 80; server_name plex.example.com; location / { proxy_pass //plex; } }

sites-enabledDizine gidin ve aşağıdaki komutu girin:

ln -s ../sites-available/plex.conf .

Bu, diğer klasördeki dosyaya sembolik bir bağlantı oluşturacaktır. Şimdi geriye tek bir şey kaldı ve o nginx.confda yapılandırma klasöründeki dosyayı değiştirmektir . Dosyayı açarsanız, son satır olarak şunu görmelisiniz:

include /etc/nginx/conf.d/*.conf;

Bunu şu şekilde değiştirin:

include /etc/nginx/conf.d/sites-enabled/*.conf;

Ters proxy'nin gerçekten çalışmasını sağlamak için, konteynerin içindeki nginx servisini yeniden yüklememiz gerekir. Ev sahibinden koşun docker exec nginx -t. Bu, yapılandırma dosyalarınız için bir sözdizimi denetleyicisi çalıştıracaktır. Bu, sözdiziminin uygun olduğu sonucunu vermelidir. Şimdi koş docker exec nginx -s reload. Bu, nginx işlemine yeniden yüklenmesi gerektiğine dair bir sinyal gönderecek ve tebrikler! Artık çalışan bir ters proxy'ye sahipsiniz ve sunucunuza plex.example.com adresinden erişebilmelisiniz (yönlendiricinizdeki ana makinenize bağlantı noktası 80'i ilettiğiniz varsayılarak).

Ters proxy'niz çalışıyor olsa bile, hiçbir şifreleme sağlamayan HTTP üzerinde çalışıyorsunuz. Bir sonraki bölüm, proxy'nizi nasıl güvence altına alacağınız ve SSL Laboratuvarlarında mükemmel bir puan alacağınız olacaktır.

Neden Çalışır

Yapılandırma Dosyası

Gördüğünüz gibi plex.confdosya iki bölümden oluşuyor. Bir upstreamparça ve bir serverparça. Bölüm ile başlayalım server. Bu, gelen istekleri alan bağlantı noktasını, bu yapılandırmanın hangi etki alanına uyacağını ve nereye gönderileceğini tanımladığınız yerdir.

Bu sunucunun kurulum şekline göre, isteklerini vekil olarak almak istediğiniz her hizmet için bir dosya oluşturmanız gerekir; bu nedenle, her bir isteği hangi dosyanın alacağını ayırt etmenin bir yolunu bulmanız gerektiği açıktır. Bu nedir server-nameyönerge yok. Bunun altında locationdirektifimiz var.

Bizim durumumuzda sadece bir tanesine ihtiyacımız var location, ancak istediğiniz kadar locationyönergeye sahip olabilirsiniz . Ön ucu ve arka ucu olan bir web siteniz olduğunu hayal edin. Kullandığınız altyapıya bağlı olarak, ön uca bir kapsayıcı olarak ve arka uca başka bir kapsayıcı olarak sahip olacaksınız. Daha sonra hangilerinin location / {}ön uca location /api/ {}istek göndereceğine ve hangilerinin arka uca istek göndereceğine sahip olabilirsiniz. Birdenbire, tek bir akılda kalıcı etki alanında çalışan birden çok hizmetiniz olur.

Parçaya gelince upstream, yük dengeleme için kullanılabilir. Bunun nasıl çalıştığı hakkında daha fazla bilgi edinmekle ilgileniyorsanız, buradaki resmi belgelere bakabilirsiniz. Basit durumumuz için, proxy yapmak istediğiniz hizmetin ana bilgisayar adını veya ip adresini ve hangi bağlantı noktasına proxy uygulanacağını tanımlayın ve ardından locationyönergedeki yukarı akış adına bakın .

Ana Bilgisayar Adı Vs. IP adresi

Bir ana bilgisayar adının ne olduğunu anlamak için bir örnek verelim. Ev ağınızda 192.168.1.0 olduğunuzu varsayalım. Daha sonra 192.168.1.10'da bir sunucu kurarsınız ve üzerinde Plex'i çalıştırırsınız. Artık aynı ağda olduğunuz sürece Plex'e 192.168.1.10:32400 üzerinden erişebilirsiniz . Diğer bir olasılık, sunucuya bir ana bilgisayar adı vermektir. Bu durumda, ona hostname pleksini vereceğiz . Artık tarayıcınıza plex: 32400 yazarak Plex'e erişebilirsiniz!

Aynı kavram, sürüm 3'te docker-compose için tanıtıldı. Bu makalenin önceki bölümlerinde docker-compose dosyasına bakarsanız, ona bir hostname: reverseyönerge verdiğimi fark edeceksiniz . Artık diğer tüm kapsayıcılar, ana bilgisayar adıyla ters proxy'ime erişebilir. Unutulmaması gereken çok önemli bir nokta, hizmet adının ana bilgisayar adıyla aynı olması gerektiğidir. Bu, docker-compose yaratıcılarının empoze etmeyi seçtiği bir şey.

Unutulmaması gereken bir diğer önemli şey de, varsayılan olarak docker konteynerlerinin kendi ağlarına yerleştirilmesidir. Bu, ana bilgisayar ağınızda dizüstü bilgisayarınızda oturuyorsanız, kapsayıcınıza ana bilgisayar adıyla erişemeyeceğiniz anlamına gelir. Yalnızca ana bilgisayar adları aracılığıyla birbirlerine erişebilen konteynerlerdir.

Yani özetlemek ve gerçekten netleştirmek için. Docker-compose dosyanıza, hostnameyönergeyi hizmetlerinize ekleyin . Çoğu zaman kapsayıcılarınız, kapsayıcıyı her yeniden başlattığınızda yeni bir IP alır, bu nedenle ona ana bilgisayar adı aracılığıyla atıfta bulunmak, kapsayıcınızın hangi IP'yi aldığı önemli değildir.

Kullanılabilir Siteler ve Siteler özellikli

sites-availableVe sites-enableddizinlerini neden oluşturuyoruz ? Bu benim yarattığım bir şey değil. Nginx'i bir sunucuya kurarsanız, bu klasörlerle birlikte geldiğini göreceksiniz. Ancak Docker, bir konteynerin yalnızca bir şey yapması gereken mikro hizmetler göz önünde bulundurularak oluşturulduğundan, bu klasörler konteynerde çıkarılır. Konteyneri kullanma şeklimiz nedeniyle onları yeniden yaratıyoruz.

Ve evet, kesinlikle bir sites-enabledklasör oluşturabilir veya yapılandırma dosyalarınızı doğrudan conf.d. Bu şekilde yapmak, etrafta pasif bir konfigürasyona sahip olmanızı sağlar. Bakım yaptığınızı ve hizmetin aktif olmasını istemediğinizi söyleyin; sadece sembolik bağlantıyı kaldırır ve hizmetin tekrar aktif olmasını istediğinizde onu geri koyarsınız.

Sembolik Bağlantılar

Sembolik bağlantılar, işletim sisteminin çok güçlü bir özelliğidir. Kişisel olarak bir Nginx sunucusu kurmadan önce bunları hiç kullanmamıştım, ancak o zamandan beri onları mümkün olan her yerde kullanıyorum. Diyelim ki 5 farklı proje üzerinde çalışıyorsunuz, ancak tüm bu projeler bir şekilde aynı dosyayı kullanıyor. Ya dosyayı her projeye kopyalayıp doğrudan başvurabilir ya da dosyayı tek bir yere yerleştirebilir ve bu 5 projede o dosyaya sembolik bağlantılar oluşturabilirsiniz.

Bu iki avantaj sağlar: normalde sahip olacağınızdan 4 kat daha az yer kaplarsınız ve sonra hepsinden en güçlüsü; dosyayı tek bir yerde değiştirin ve 5 projenin tümünde aynı anda değişir! Bu biraz yan adım oldu ama bence bahsetmeye değer.

Nginx Proxy'nin Güvenliğini Sağlama

Ne yapalım

Yapılandırma klasörünüze gidin ve 3 dosya oluşturun ve aşağıdaki girdiyle doldurun:

common.conf:

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header X-Frame-Options SAMEORIGIN; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block";

common_location.conf:

proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Port $server_port;

ssl.conf:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ecdh_curve secp384r1; ssl_ciphers "ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384 OLD_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 OLD_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"; ssl_prefer_server_ciphers on; ssl_dhparam /etc/nginx/dhparams.pem; ssl_certificate /etc/ssl/private/fullchain.pem; ssl_certificate_key /etc/ssl/private/privkey.pem; ssl_session_timeout 10m; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; ssl_stapling on; ssl_stapling_verify on;

Şimdi plex.confdosyayı açın ve aşağıdaki şekilde değiştirin (6, 9, 10 ve 14 numaralı satırlara dikkat edin):

upstream plex { server plex:32400; } server { listen 443 ssl; server_name plex.example.com; include common.conf; include /etc/nginx/ssl.conf; location / { proxy_pass //plex; include common_location.conf; } }

Şimdi yapılandırma klasörünüzün köküne dönün ve aşağıdaki komutu çalıştırın:

openssl dhparam -out dhparams.pem 4096

Bu işlemin tamamlanması uzun zaman alır, hatta bazı durumlarda bir saate kadar çıkabilir.

LetsEncrypt SSL Sertifikası alma hakkındaki makalemi takip ettiyseniz, sertifikalarınız içinde bulunmalıdır /etc/letsencrypt/live//.

When I helped a friend set this up on his system, we ran into some problems where it couldn’t open the files when they were located in that directory. Most likely the cause of some permissions problems. The easy solution to this is to make an SSL directory, like /certs, and then mount that to the Nginx container’s /etc/ssl/private folder. In the newly created folder, you should then make symbolic links, to the certs in your LetsEncrypt’s config folder.

When the openssl command is done running, you should run the docker exec nginx -t to make sure that all the syntax is correct, and then reload it by running docker exec nginx -s reload. At this point everything should be running, and you now have a working and perfectly secure reverse proxy!

Why it Works

Looking in the plex.conf file, there is only one major change, and that is what port the reverse proxy is listening on, and telling it that it’s an ssl connection. Then there are 3 places where we’re including the 3 other files we made. While SSL is kind of secure by itself, these other files make it even more secure. However if for some reason you don’t want to include these files, you need to move the ssl-certificate and ssl-certificate-keyinside the .conf file. These are required to have, in order for an HTTPS connection to work.

Common.conf

Looking in the common.conf file, we add 4 different headers. Headers are something that the server sends to the browser on every response. These headers tell the browser to act a certain way, and it is then up to the browser to enforce these headers.

Strict-Transport-Security (HSTS)

This header tells the browser that connections should be made over HTTPS. When this header has been added, the browser won’t let you make plain HTTP connection to the server, ensuring that all communication is secure.

X-Frame-Options

When specifying this header, you are specifying whether or not other sites can embed your content into their sites. This can help avoid clickjacking attacks.

X-Content-Type-Options

Say you have a site where users can upload files. There’s not enough validation on the files, so a user successfully uploads a php file to the server, where the server is expecting an image to be uploaded. The attacker may then be able to access the uploaded file. Now the server responds with an image, however the file’s MIME-type is text/plain. The browser will ‘sniff’ the file, and then render the php script, allowing the attacker to do RCE (Remote Code Execution).

With this header set to ‘nosniff’, the browser will not look at the file, and simply render it as whatever the server tells the browser that it is.

X-XSS-Protection

While this header was more necessary in older browsers, it’s so easy to add that you might as well. Some XSS (Cross-site Scripting) attacks can be very intelligent, while some are very rudimentary. This header will tell browsers to scan for the simple vulnerabilities and block them.

Common_location.conf

X-Real-IP

Because your servers are behind a reverse proxy, if you try to look at the requesting IP, you will always see the IP of the reverse proxy. This header is added so you can see which IP is actually requesting your service.

X-Forwarded-For

Sometimes a users request will go through multiple clients before it reaches your server. This header includes an array of all those clients.

X-Forwarded-Proto

This header will show what protocol is being used between client and server.

Host

This ensures that it’s possible to do a reverse DNS lookup on the domain name. It’s used when the server_name directive is different than what you are proxying to.

X-Forwarded-Host

Shows what the real host of the request is instead of the reverse proxy.

X-Forwarded-Port

Helps identify what port the client requested the server on.

Ssl.conf

SSL is a huge topic in and of itself, and too big to start explaining in this article. There are many great tutorials out there on how SSL handshakes work, and so on. If you want to look into this specific file, I suggest looking at the protocols and ciphers being used, and what difference they make.

Redirecting HTTP to HTTPS

The observant ones have maybe noticed that we are only ever listening on port 443 in this secure version. This would mean that anyone trying to access the site via //* would get through, but trying to connect through //* would just get an error. Luckily there’s a really easy fix to this. Make a redirect.conf file with the following contents:

server { listen 80; server_name _; return 301 //$host$request_uri; }

Now just make sure that it appears in your sites-enabled folder, and when you’ve reloaded the Nginx process in the container, all requests to port 80 will be redirected to port 443 (HTTPS).

Final Thoughts

Now that your site is up and running, you can head over to SSL Labs and run a test to see how secure your site is. At the time of writing this, you should get a perfect score. However there is a big thing to notice about that.

There will always be a balance between security and convenience. In this case the weights are heavily on the side of security. If you run the test on SSL Labs and scroll down, you will see there are multiple devices that won’t be able to connect with your site, because they don’t support new standards.

So have this in mind when you are setting this up. Right now I am just running a server at home, where I don’t have to worry about that many people being able to access it. But if you do a scan on Facebook, you’ll see they won’t have as great a score, however their site can be accessed by more devices.