Reverse proxy of multiple container - docker

I have 2 API containers (docker) running on port 10000 and 10003. I want to reverse proxy both of them so the API can be called from a single port which is port 80. I am trying to use NGINX to do that and this is my nginx configuration file:
worker_processes 1;
events { worker_connections 1024; }
http {
server {
listen 80;
server_name container1;
location / {
proxy_pass http://10.10.10.50:10003;
}
}
server {
listen 80;
server_name container2;
location / {
proxy_pass http://10.10.10.50:10000;
}
}
}
I found that it is only working on the container 1 and if there is a request for container 2, it will generate 404 not found warning because the request go to the container 1 instead of container 2.

Finally, I found a solution using NGINX. All I need to do is to create a new NGINX container then reconfigure the url of my 2 API container. The configuration file that I wrote looks like this:
worker_processes auto;
events { worker_connections 1024; }
http {
upstream container1 {
server 10.10.10.50:10003;
}
upstream container2 {
server 10.10.10.50:10000;
}
server {
listen 80;
location /container1/ {
proxy_pass http://container1/;
}
location /container2/ {
proxy_pass http://container2/;
}
}
}
Now, I can make requests for both API containers by using port 80 as it will be re-routed from the port into the designated port (reverse-proxy).

Related

How to Reverse Proxy using Nginx to Dockerized Swagger UI's along with web apis?

I have 2 servers, one with dockerized nginx and one with 3 dockerized web apis allowing traffic through different ports (say 441, 442, 443) which has swagger UI along with it respectively.
with limited knowledge on nginx, I am trying to reverse proxy to all the swagger UI endpoints using the nginx container. This is how my nginx conf looks like, but it doesnt work as expected, it would be great if someone can advice where I am going wrong.
I am able to hit the service with the exact match location context /FileService which return index.html. But index.html has the script call where nginx fails to serve these static contents.
index.html
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
nginx.conf
server {
listen 443 ssl http2;
server_name www.webby.com;
access_log /var/log/nginx/access.log;
ssl_certificate /etc/ssl/yyyy.crt;
ssl_certificate_key /etc/ssl/xxxx.key;
ssl_protocols TLSv1.2;
if ($http_referer = 'https://$host/FileService') {
rewrite ^/(\w+) /swagger/fileservice/$1;
}
if ($http_referer = 'https://$host/PreProcess') {
rewrite ^/(\w+) /swagger/preprocess/$1;
}
location = /FileService {
proxy_pass 'http://appy.com:441/swagger/index.html';
}
location = /PreProcess {
proxy_pass 'http://appy.com:442/swagger/index.html';
}
# curl http://appy.com:441/swagger/swagger-ui-bundle.js is giving the js on this container
location ~* /swagger/fileservice(.*) {
proxy_pass 'http://appy.com:441/swagger/$1';
}
location ~* /swagger/preprocess(.*) {
proxy_pass 'http://appy.com:442/swagger/$1';
}
}
accesslog on the nginx looks like
anyways I struggled my way to implement this. Not sure if its the right approach (because I read on the internet that if block inside location context is evil), but works for my case. Feel free to correct my answer
server {
listen 443 ssl http2;
server_name www.webby.com;
access_log /var/log/nginx/access.log;
ssl_certificate /etc/ssl/yyyy.crt;
ssl_certificate_key /etc/ssl/xxxx.key;
ssl_protocols TLSv1.2;
location = /FileService {
proxy_pass 'http://appy.com:441/swagger/index.html';
}
location = /PreProcess {
proxy_pass 'http://appy.com:442/swagger/index.html';
}
location ~ ^/swagger/(.*)$ {
if ($http_referer = 'https://$host/FileService') {
proxy_pass 'http://appy.com:441/swagger/$1';
}
if ($http_referer = 'https://$host/PreProcess') {
proxy_pass 'http://appy.com:442/swagger/$1';
}
}
location ~ ^/swagger(.*)$ {
if ($http_referer = 'https://$host/FileService') {
proxy_pass 'http://appy.com:441/swagger/swagger$1';
}
if ($http_referer = 'https://$host/PreProcess') {
proxy_pass 'hhttp://appy.com:442/swagger/swagger$1';
}
}
}

Configure redirect Uris of Identity server in docker environment

Okay, this quite big so just skip to the last section for a brief.
I have a demo application (netcore 6.0) built on micro-service architect, suppose we have 3 services:
identity (Auth service - IdentityServer4)
frontend (mvc - aspnet)
nginx (reverse proxy server)
and all three are running on docker environment here is the docker-compose file
services:
demo-identity:
image: ${DOCKER_REGISTRY-}demoidentity:lastest
build:
context: .
dockerfile: Identity/Demo.Identity/Dockerfile
ports:
- 5000:80 //only export port 80,
volumes:
- ./Identity/Demo.Identity/Certificate:/app/Certificate:ro
networks:
- internal
demo-frontend:
image: ${DOCKER_REGISTRY-}demofrontend:lastest
build:
context: .
dockerfile: Frontend/Demo.Frontend/Dockerfile
ports:
- 5004:80 //only export port 80,
networks:
- internal
proxy:
build:
context: ./nginx-reverse-proxy
dockerfile: Dockerfile
ports:
- 80:80
- 443:443
volumes:
- ./nginx-reverse-proxy/cert/:/etc/cert/
links:
- demo-identity
depends_on:
- demo-identity
- demo-frontend
networks:
- internal
They all design to run internal, but nginx, it will be the proxy server, and here is the nginx.config file
worker_processes 4;
events { worker_connections 1024; }
http {
upstream app_servers_identity {
server demo-identity:80;
}
upstream app_servers_frontend {
server demo-frontend:80;
}
server {
listen 80;
listen [::]:80;
server_name demo-identity;
return 301 https://identity.demo.local$request_uri;
}
server {
listen 80;
listen [::]:80;
server_name identity.demo.local;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name identity.demo.local;
ssl_certificate /etc/cert/demo.crt;
ssl_certificate_key /etc/cert/demo.key;
location / {
proxy_pass http://app_servers_identity;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
server {
listen 80;
listen [::]:80;
server_name frontend.demo.local;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name frontend.demo.local;
ssl_certificate /etc/cert/demo.crt;
ssl_certificate_key /etc/cert/demo.key;
location / {
proxy_pass http://app_servers_frontend;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
}
}
}
also I update the host file to configure two virtual hosts identity.demo.local and frontend.demo.local (the term "localhost" sometimes confusing me when using docker.)
Then I setup the identity server like this
...
builder.Services.Configure<IdentityOptions>(options => {
// Default Password settings.
});
services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.Ids)
.AddInMemoryApiResources(Config.Apis)
.AddInMemoryClients(Config.Clients)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddAspNetIdentity<ApplicationUser>()
.AddSigningCredential(new X509Certificate2("./Certificate/demo_dev.pfx", "******"));
...
and here is the client static config
...
new Client
{
ClientName = "MVC Client",
ClientId = "mvc-client",
AllowedGrantTypes = GrantTypes.Hybrid,
RedirectUris = new List<string>{ "http://gateway.demo.local/signin-oidc"},
RequirePkce = false,
AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile },
ClientSecrets = { new Secret("MVCSecret".Sha512()) }
}
...
In the Frontend service, I also configure Oidc as below
...
services.AddAuthentication(opt =>
{
opt.DefaultScheme = "Cookies";
opt.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies", opt => {
opt.CookieManager = new ChunkingCookieManager();
opt.Cookie.HttpOnly = true;
opt.Cookie.SameSite = SameSiteMode.None;
opt.Cookie.SecurePolicy = CookieSecurePolicy.Always;
})
.AddOpenIdConnect("oidc", opt => {
opt.SignInScheme = "Cookies";
opt.Authority = "http://demo-identity";
opt.ClientId = "mvc-client";
opt.ResponseType = "code id_token";
opt.SaveTokens = true;
opt.ClientSecret = "MVCSecret";
opt.ClaimsIssuer = "https://identity.demo.local";
opt.RequireHttpsMetadata = false;
});
...
TL,DR: A micro-service application host on docker, which included IdentityServer, MVC, Nginx. They all run internal and only can be access via nginx proxy. The host name also configure to virtual host names - which make more sense.
Okay here is the problem, when I access to a protected api of MVC, it redirect me to identity server (identity.demo.local) to login, but after I login success, it should redirect me to the mvc, but it did not. After research, I figure out the reason that after login, the identity redirect me to the origin site with the cookies contain authentication info, but the redirect uri is not secured, it's http://frontend.demo.local instead of https. I'm not sure how this property is configured ( I try to update the nginx.conf but nothing change). And it still work correctly when I run by visual studio, without docker.
Any help is appreciated.

docker-compose + nginx proxy_pass

app.somename.local is not working, but localhost is proxies to app:3000. I want to access to app via typing server_name into browser
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream app {
server app:3000;
}
server {
server_name app.somename.local;
location / {
proxy_pass http://app/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
}
}
}
app.somename.local
Your shooting at wrong target. You need to get that server name resolved.
Do this.
127.0.0.1 app.somename.local >> /etc/hosts
And it should work.

Map docker containers ports with nginx

When a location is with root and another is with proxy_pass nginx does not work in the url /laravel. The response of this url is "404 Not Found".If I remove url location / and /moda, the url /laravel works. I do this, because I want map docker containers.
nginx.conf file :
server {
listen 80;
server_name local.monllar.com;
location /laravel {
root /var/www/local.monllar.com/public_html;
index index.html index.htm;
}
location / {
proxy_pass http://localhost:32768;
}
location /moda {
proxy_pass http://localhost:2222/moda;
}
}
I found the solution. This maps the ips of the docker containers to my local server names
nginx.conf file :
server
{
listen 80;
server_name local.monllar.com;
location / {
root /var/www/local.monllar.com/public_html;
index index.html index.htm;
}
}
server
{
listen 80;
server_name local.moda.com;
location / {
proxy_pass http://localhost:2222/moda/;
}
}
server
{
listen 80;
server_name local.laravel.com;
location / {
proxy_pass http://localhost:32768;
}
}
/private/etc/hosts file in Mac
127.0.0.1 local.monllar.com
127.0.0.1 local.moda.com
127.0.0.1 local.laravel.com

Rails app on two domain + nginx + passenger

How can I have one app on two domains using nginx + passenger? I add second domain in nginx but this redirect to domain1.net
server {
listen 80;
server_name domain2.net *.domain2.net;
rewrite ^/(.*)$ http://www.domain2.net/$1 permanent;
}
server {
listen 80;
server_name www.domain2.net;
root /var/www/domain1/public/; # <--- be sure to point to 'public'!
}
server {
listen 80;
server_name domain1.net *.domain1.net;
rewrite ^/(.*)$ http://www.domain1.net/$1 permanent;
}
server {
listen 80;
server_name www.domain1.net;
root /var/www/domain1/public/; # <--- be sure to point to 'public'!
passenger_enabled on;
client_max_body_size 20M;
location / {
passenger_enabled on;
root /var/www/domain1/public/;
}
}
What I want is to have one app on two domains because I want to translate app for users from second domain.
server {
listen 80;
server_name domain2.net *.domain2.net;
rewrite ^/(.*)$ http://www.domain2.net/$1 permanent;
}
server {
listen 80;
server_name www.domain2.net;
root /var/www/domain1/public/;
passenger_enabled on;
location / {
passenger_enabled on;
root /var/www/domain1/public/;
}
}
server {
listen 80;
server_name domain1.net *.domain1.net;
rewrite ^/(.*)$ http://www.domain1.net/$1 permanent;
}
server {
listen 80;
server_name www.domain1.net;
root /var/www/domain1/public/; # <--- be sure to point to 'public'!
passenger_enabled on;
client_max_body_size 20M;
location / {
passenger_enabled on;
root /var/www/domain1/public/;
}
}
you should add passenger stream also to the second domain then it should work.
One tip move each domain into site.conf file then include then in nginx.conf this will be easier to maintenance.
make sure you restart Nginx after the change.

Resources