NGINX: invalid number of arguments in "proxy_set_header" - docker

Setting up a reverse proxy for a couple sites, one of which requires the users IP for login purposes. The reverse proxy is configured with NGINX and hosted in a docker container, docker is running Linux 10 (Buster) and is on a windows machine.
This code works, but doesn't pass the users IP:
server {
listen 80;listen [::]:80;
server_name your.domain.com;
location / {
proxy_pass http://Host IP:Port/;
proxy_buffering off;
}
}
When i add the headers it suddenly stops working, which doesn't really make much sense to me as i got the code snippets straight from NGINX's docs, this is how the code looks with the headers:
server {
listen 80;listen [::]:80;
server_name your.domain.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://Host IP:Port/;
proxy_buffering off;
}
}
When i restart the container, it instantly shuts down and i get this error message:
2020/11/13 20:17:58 [emerg] 1#1: invalid number of arguments in "proxy_set_header" directive in /etc/nginx/conf.d/admin.conf:6
nginx: [emerg] invalid number of arguments in "proxy_set_header" directive in /etc/nginx/conf.d/admin.conf:6
I've tried removing one of the headers but the result is still the same, when i remove both everything works as intended, been trying to find a fix for a couple hours to no avail so i hope that someone here can help me out.

Related

How to call GRPC Server in NGINX config

How to call GRPC Server which is located in docker container on Swarm cluster from NGINX reverse proxy?
GRPC Server in container/service called webui with kestrel development certificate installed
NGINX Proxy which is located outside the stack and routes access to Swarm stacks
GRPC Client is located on a separate virtual machine on another network, the browser page at https://demo.myorg.com is available
part nginx.conf
server {
listen 443 ssl;
server_name demo.myorg.com;
...
location / {
proxy_pass https://namestack_webui;
}
GRPC Client appsetting.json
{
"ConnectionStrings": {
"Database": "Data Source=Server_name;Initial Catalog=DB;User Id=user;Password=pass;MultipleActiveResultSets=True;"
}
...
"GRPCServerUri": "https://demo.myorg.com/",
...
}
}
Problem when connecting GRPC Client to Server, i get error
END] GetOpcDaServerSettingsQuery. Time spent: 7,7166ms
fail: Grpc.Net.Client.Internal.GrpcCall[6]
Error starting gRPC call.
System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception.
---> System.ComponentModel.Win32Exception (0x80090367): No common application protocol exists between the client and the server. Application protocol negotiation failed..
--- End of inner exception stack trace ---
Tried to write and specify a kestrel development certificate (for GRPC Client) that is loaded into the Swarm stack (namestack) through which the other containers in the stack are authenticated, the error is the same.
I understand that it is necessary to specify in appsetting.json the GRPC Server container address (https://namestack_webui), but it is behind NGINX, and I can only specify the GRPC host address (https://demo.myorg.com), tell me what is wrong?
The perfect solution for such a case was not found online.
I finally figured out and found a solution to my question, and I publish it for discussion.
If there are no comments against, then mark it as correct, at least it works for me and will work for YOU.
to proxy grpc connections through NGINX in the configuration, the location section must specify something similar to the url /PackageName.ServiceName/MethodName (This is indicated here by https://learn.microsoft.com/en-aspnetus/aspnet/core/grpc/troubleshoot?view=aspnetcor7.0#unable-to-start-aspnet-core-grpc-app-on-macos )
This URL can be checked with the developer or in the logs when grpc client connects
Should be used to proxy directive grpc_pass grpcs://namecontainer;
Should use http2 protocol.
So the correct configuration file for nginx in my case should look like this
server {
listen 443 ssl **http2**;
server_name demo.myorg.com;
ssl_certificate ...;
ssl_certificate_key ...;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers RC4:HIGH:!aNULL:!MD5:!kEDH;
add_header Strict-Transport-Security 'max-age=604800';
underscores_in_headers on;
large_client_header_buffers 4 16k;
location / {
proxy_pass https://name_container;
# Configuration for WebSockets
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_cache off;
# WebSockets were implemented after http/1.0
proxy_http_version 1.1;
# Configuration for ServerSentEvents
proxy_buffering off;
# Configuration for LongPolling or if your KeepAliveInterval is longer than 60 seconds
proxy_read_timeout 100s;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-URL-SCHEME https;
}
location /App.Name.Api.Contract.ApiService/UpdateOpcDaTags {
grpc_pass grpcs://name_container;
}
}

.Net core POST API in NGINX reverse proxy throws error 404

This is my first time posting a question. Kindly let me know if I am missing something that needs to be shared.
I am trying to POST some data into database through my C# APP and API (separately build), but it throws error 404 only for the POST API. All other pages work fine and so does the GET request. The app and API have been deployed on a LINUX machine through NGINX reverse proxy server. Both of them work on HTTP protocol. The feature works for localhost, but not for IP dependent URL.
Here is the content of service file for the app, I do not know what is missing in it. Please take care of the "/" as well where ever it is needed. While performing RnD, I found that the POST request in NGINX gets redirected to GET, I don't know if this will be helpful or not, but felt like sharing.
server {
listen myIP:6002;
server_name attendancepp;
root /home/user/net-core/Publish/AttendanceModule/AttendanceApp;
location /AttendanceApp/{
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://myIP:6002/;
proxy_set_header Accept-Encoding "";
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_redirect off;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
The app works on the URL http://myIP:6002/attendance/allPages . All the pages are accessible without any issue. Just the POST part is not working.
Thank you, in advance.
working fine after commenting
try_files $uri $uri/ =404
cd /etc/nginx/sites-available/
sudo nano default << nginx
edit file then CTR+X and 'y' for yes
sudo systemctl restart nginx

Map http requests from nginx to docker

I have different versions of my web application running in Docker containers. And nginx is running on my host machine.
Is it possible to access the desired deployed version of my web application with the help of sub-domain such as v1.myapp.io, v2.myapp.io without reconfiguring and restarting the nginx?
I also want to access future versions in the same way?
Could anyone tell me if there is any way to achieve it?
Please consider me a newbie to Docker/nginx world.
Thanks in Advance.
Yes, although it can be done but its very difficult to achieve with docker only. kubernetes will make this very easy and everything like dns, service mapping is provided out of the box. I will include both docker and kubernetes approach:
Docker approach:
A first draft will look like this, use regex in nginx server_name and set the docker container names with a pattern. Create a /etc/hosts entry for different containers like:
172.16.0.1 v1.docker.container
172.16.0.2 v2.docker.container
And nginx server conf look like:
server {
listen 80;
server_name "~^(?<ns>[a-z]+.+)\.myapp\.io";
resolver 127.0.0.1:53 valid=30s;
# make sure $ns.docker.container is resolved to container IP
set $proxyserver "$ns.docker.container";
location / {
try_files $uri #clusterproxy;
}
location #clusterproxy {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-IP $clientip;
proxy_set_header X-Forwarded-For $clientip;
proxy_set_header X-Real-IP $clientip;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-FORWARDED-PROTO 80;
proxy_pass http://$proxyserver:80;
}
}
Kubernetes approach:
Create different service and deployment for different versions in a namespace. Lets say namespace is 'app-namespace'. Service names are self explanatory:
APP version v1: v1-app-service
APP version v2: v2-app-service
To make nginx more flexible you can add the service name as namespace to $proxyserver
Nginx rule:
server {
listen 80;
server_name "~^(?<version>[a-z]+.+)\.myapp\.io";
# you can replace this with kubernetes dns server IP
resolver 127.0.0.1:53 valid=30s;
# make sure $ns.docker.container is resolved to container IP
set $proxyserver "$version.app-namespace.svc.kubernetes";
location / {
try_files $uri #clusterproxy;
}
location #clusterproxy {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-IP $clientip;
proxy_set_header X-Forwarded-For $clientip;
proxy_set_header X-Real-IP $clientip;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-FORWARDED-PROTO 80;
proxy_pass http://$proxyserver:80;
}
}
I found another solution to this problem after digging a lot. It can be easily be done with Automated Nginx Reverse Proxy for Docker.
Once docker container for ngninx was up and running on my system.
I spun two docker containers of my webapp(diff versions) with the following command:
docker run -e VIRTUAL_HOST=v1.myapp.io --name versionOne -d myapp.io:v1
docker run -e VIRTUAL_HOST=v2.myapp.io --name versionTwo -d myapp.io:v2
and it worked out for me.
Additional notes:
1. I am using dnsmasq for handling all dns queries

Rails5 Action Cable Nginx 404 and 502 errors

Everyone :).
I know people have already faced alot of problems related to mine. I have tried all but my issue has not been resolved. I have been working from past 3 days to fix this but I am unable to do it.
I am using ActionCable for the first time and on development server it is working fine. But in production where I am using Puma and Nginx I am facing terrible issues.
Initially when I had not (location /cable) settings in nginx configuration, server gives me 404 handshake error
i.e Error during WebSocket handshake: Unexpected response code: 404
Then after I add following location /cable configuration in nginx configuration I start getting 502 bad gateway error.
Note: I have not opened any port specifically for ActionCable. I assume it is not required. only port 80 is open on my server.
I need some expert to help me with this. I need quick help to get it fixed. Thanks in advance :)
I have these two lines present in my environment/production.rb
config.action_cable.url = "ws://my_linode_domain/cable"
config.action_cable.allowed_request_origins = [/http:\/\/*/, /https:\/\/*/]
This is my nginx config file
upstream app {
# Path to Puma SOCK file, as defined previously
server unix:/home/deploy/artcrate/shared/tmp/sockets/puma.sock fail_timeout=0;
}
server {
listen 80;
#server_name localhost;
server_name my_linode_domain
# prevents 502 bad gateway error
large_client_header_buffers 8 32k;
root /home/deploy/artcrate/current/public;
try_files $uri/index.html $uri #app;
location / {
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_pass http://app;
}
location ~ ^/(assets|fonts|system)/|favicon.ico|robots.txt {
gzip_static on;
expires max;
add_header Cache-Control public;
}
location /cable{
proxy_pass http://app;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
error_page 500 502 503 504 /500.html;
client_max_body_size 4G;
keepalive_timeout 10;
}
I have tried various proxy_pass options in location /cable settings but none worked.
Everyone. :)
After a week of struggle, hardwork and constantly playing around with nginx and puma configuration files and keenly reading blogs again and again, I was able to figure out the issue.
My nginx configurations were correct. I had to add two more lines to puma.rb configuration which don't come with default configurations. Those two lines are:
workers 2
daemonize true
daemonize true: this tells puma to run in the background by spawning a subprocess and detaching it from the executing shell. If you don't use daemonize, you need to run the puma process via nohup and put it in the background explicitly.
I am not sure if I required workers 2 but I had added them while resolving my issue. So I let it there. But after adding above two lines my ActionCable started to work normally.
RAILS and RUBY version I am using for this project is
Rails 5.0.7
ruby 2.3.1p112
ok. So today I wanted to integrate Action Cable again in my project but faced the same issue again. I applied my above solution but it didn't work. Last time although it worked but I wasn't satisfied with the solution thinking that why would ActionCable work in single thread/worker on local machine.
But this time I focussed and figured out the culprit.
Culprit is NGINX configuration
Configuration when I was facing 404 handshake errors
location /cable {
proxy_pass http://example.com;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection Upgrade;
}
Configuration when all started working fine.
location /cable {
proxy_pass http://puma;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
proxy_set_header Connection Upgrade;
}
so the culprit line was:
proxy_pass http://example.com;
Here we are pointing it to NGINX which is wrong, it should point to our puma server path which in my configuration is represented by 'puma'.
Here is the Summary of my implementation of ActionCable and its working copy on Production Server
So to integrate Action Cable with Rails 5 you need to follow following steps:
Setup Redis on default port.
Add these lines in environments/staging.rb or environments/production.rb, depending on your application environment.
config.action_cable.url = [/ws://*/, /wss://*/]
config.action_cable.allowed_request_origins = [/http://*/, /https://*/]
Finally setup you NGINX file as explained above. Here is my complete NGINX configuration in gist nginx.conf. I had replaced my site name with 'example.com' and project name with 'example'. So if you are copying anything, just make sure you replace those with yours otherwise nothing will work as paths will be broken.
I hope this will really release the pain while pushing ActionCable to live application and resolve this handshake error for anyone as this is very very tricky and technical thing and a lot of docs just mention to point action cable to your main site url and not puma server running behind your nginx.
Thanks.

How to point many paths to proxy server in nginx

I'm trying to set nginx location that will handle various paths and proxy them to my webapp.
Here is my conf:
server {
listen 80;
server_name www.example.org;
#this works fine
location / {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://localhost:8081/myApp/;
}
#not working
location ~ ^/(.+)$ {
proxy_pass http://localhost:8081/myApp/$1;
}
}
I would like to access myApp with various paths like: /myApp/ABC, /myApp/DEF, myApp/GEH or /myApp/ZZZ.
Of course these paths are not available in myApp. I want them to point to root of myApp and keep url.
Is that possible to archive with nginx ?
Nginx locations match in order of definition. location / is basically a wildcard location, so it will match everything, and nothing will reach the second location. Reverse the order of the two definitions, and it should work. But actually, now that I look at it more closely, I think both locations are essentially doing the same thing:
/whatever/path/ ->>proxies-to->> http://localhost:8081/myApp/whatever/path/
A very late reply. this might help someone
try proxy_pass /myApp/ /location1 /location2;
Each location separated with space.
You will probably have to do a rewrite followed by a proxy pass, I had the same issue. Check here: How to make a conditional proxy_pass within NGINX

Resources