Caddy reverse proxy, prioritize files, then reverse_proxy - caddy

I got trouble using Caddy v2, while in v1 I never have such trouble
I want to prioritize:
file_server if started with /upload/*
reverse_proxy to 127.0.0.1:9090 if started with /api/*
else reverse_proxy to 127.0.0.1:3000
But seems I cannot get it properly work using v2, I've tried a lot (with matchers, changing port because 127.0.0.1 always 404 but localhost didn't, etc) but seems the 127.0.0.1:3000 always prioritized instead of file_server even when file exists, because it have wildcard?
{
debug
auto_https off
log {
output stdout
level DEBUG
}
local_certs
}
127.0.0.1:80, localhost:80 {
root ./svelte/dist
file_server /upload/* browse
reverse_proxy /api/* 127.0.0.1:9090
reverse_proxy * 127.0.0.1:3000
}

Nevermind, got the answer
https://caddy.community/t/v2-hard-to-make-it-right/13394/2
127.0.0.1, 127.0.0.1:80, localhost, localhost:80 {
handle /upload/* {
root ./svelte/dist
file_server browse
}
handle /api/* {
reverse_proxy 127.0.0.1:9090
}
handle {
reverse_proxy 127.0.0.1:3000
}
}

Related

caddy: one server, 2 secure reverse proxies

I'd like to set up two secure reverse proxies on the same server with a single Caddyfile. The web server listens on port 8081, and the following successfully accepts outside connections on normal port 443 and directs them internally to 8081.
# this works, accepting requests at https://api.mysite.com
api.mysite.com {
tls webmaster#mysite.com # lets encrypt
reverse_proxy localhost:8081
log
}
Now I want to also be able to connect to a database server that listens on port 7777, but I'd like to keep that port shut to the outside and accept incoming connections at port 9999 (over SSL/TLS). So far my attempts at building a Caddyfile have not just been unsuccessful, they also prevent the initial secure web connection from working.
(Caddy 2.4.3)
api.mysite.com {
tls webmaster#mysite.com # lets encrypt
reverse_proxy localhost:8081
log
}
api.mysite.com:9999 {
reverse_proxy localhost:7777
log
}
Nope
api.mysite.com {
tls webmaster#mysite.com # lets encrypt
reverse_proxy localhost:8081
log
}
localhost:9999 {
reverse_proxy localhost:7777
log
}
Nope
api.mysite.com {
tls webmaster#mysite.com # lets encrypt
reverse_proxy localhost:8081
localhost:9999 {
reverse_proxy localhost:7777
}
log
}
Still nope
I'm having a very difficult time getting much useful information from the Caddyfile docs. Any ideas? Thanks in advance.

Caddy V2 IP whitelist

I am trying to implement IP whitelist on my Caddy v2 configuration. Something equivalent to NGINX configuration like:
allow 1.1.1.1;
allow 8.8.8.8;
deny all;
My current Caddy configuration pretty straight forward:
my.website.com {
reverse_proxy http://127.0.0.1:3000 {
}
}
Thanks
You can try something like this in caddy v2:
my.domain.com {
#teammember {
remote_ip forwarded 183.77.5.126 113.73.5.126
}
handle #teammember {
reverse_proxy /* localhost:8081
}
respond "<h1>You are attempting to access protected resources!</h1>" 403
}
I'm not saying qed's answer is wrong, however I couldn't get it to work in my case (possibly due to using import templates inside a handle?)...
My solution was... Old config:
private.example.com {
import my_template argument_1 /path/to/example/argument2
}
This changed to:
private.example.com {
#blocked not remote_ip 1.2.3.4
respond #blocked "<h1>Access Denied</h1>" 403
import my_template argument_1 /path/to/example/argument2
}
Simply adding those two lines allows my site to be accessed on that IP. A test curl from a different IP returned the 403 error.
This is done on Caddy 2.4.6
I am not sure it is possible directly in Caddy, but you can add a middleware/plugin to do this.
Here is the link you can get it : https://github.com/pyed/ipfilter
According to the doc of this middleware, to you want to allow only the 2 IPs you wrote, you should probably do something like this :
my.website.com {
reverse_proxy http://127.0.0.1:3000
ipfilter / {
rule allow
ip 1.1.1.1 8.8.8.8
blockpage notauthorized.html
}
}
I also think if want to block every requests, not just the /, you have to write ipfilter /* instead of ipfilter /.

Nginx reverse proxy in docker for express.js server

In docker, I have a client facing server container, an api server container and a nginx container that is exposed outside at port 8000. After running api and client server container, I am running nginx container with has nginx.conf replaced with the following:
events {
}
http {
server {
listen 80;
location /api {
proxy_pass http://server:9002;
}
location / {
proxy_pass http://client:9001;
}
}
}
I can verify client server working properly through nginx by making request to http://localhost:8000 or http://localhost:8000/blah. But if I go to the URL http://localhost:8000/api, it redirects to http://localhost/api and fails to connect.
I verified that the server container is actually running by running it with a separate exposed port and it returns result on request as expected. How would I fix this ?
It might have been an environmental variable issue. I had PORT env var set on docker-compose.yml but not in Docekrfile, adding it solved the issue. Removing PORT env var from docker-compose.yml still works.

Nginx Proxy On Custom Port

I have a node process listening on port 11180, and would like to redirect all request from https:example.com:11179 to it. How can I accomplish this with nginx ?
I cannot use port 443, because it is forwarding to a different process. However I do have a certificate for the domain example.com
I have tried using this configuration
server {
listen 11179 ssl
location / {
proxy_pass http://127.0.0.1:11180
...
}
}
but the site just keeps loading, however the same configuration works if i listen on port 443
server {
listen 443 ssl
location / {
proxy_pass http://127.0.0.1:11180
...
}
}
Thanks a bunch for your help
Turns out it was a firewall problem :P

Cannot run multiple NodeJs server on one subdomain

I am trying to run multiple NodeJs server for (official) Kik Chatbots with different webhooks from one Subdomain on my webserver.
However, I am not able to do that. For one bot it works just fine. This is my setup for one working NodeJs server only:
Lets assume all webhooks are located at https://bots.mydomain.com
app.js:
'use strict';
let util = require('util');
let http = require('http');
let request = require('request');
let Bot = require('#kikinteractive/kik');
let bot = new Bot({
username: "foo",
apiKey: "bar",
baseUrl: "https://bots.mydomain.com"
});
bot.updateBotConfiguration();
// ... code ...
let server = http.createServer(bot.incoming()).listen(process.env.PORT || 8080);
So this Nodejs server is basically listening on port 8080. Therefore, my nginx config for the site https://bots.mydomain.com looks like this:
server {
root /var/www/bots.mydomain.com/public_html;
index index.php index.html index.htm;
server_name bots.mydomain.com;
location / { proxy_pass http://localhost:8080/; } # Port 8080
}
So far so good. This works perfectly fine! But here comes the issue:
If I try to run multiple NodeJs server, by making directories in the public_html folder, lets say /bot1 and /bot2 and adapt my nginx config like that:
server {
root /var/www/bots.mydomain.com/public_html;
index index.php index.html index.htm;
server_name bots.mydomain.com;
location /bot1 { proxy_pass http://localhost:8080/; } # Port 8080
location /bot2 { proxy_pass http://localhost:8090/; } # Port 8090
}
and finally setting the second server to listen on port 8090 instead of 8080 and of course setting the base URL to https://bots.mydomain.com/bot1 or https://bots.mydomain.com/bot2, nothing works anymore. And by that I mean the webhooks do no pass any data to the NodeJs server. They are, however running! I know this because if I navigate to (for example) https://bots.mydomain.com while the bot is offline, I obviously receive the error 502 Bad Gateway but if the bot is online I get a timeout (which means the server is indeed listening).
Am I missing something or does Nginx just not allow multiple webhooks or proxy_passes for directories?
A workaround would be to make a subdomain for each bot, which would work (I tried). But I'd like to use sub directories rather than subdomains for the bots.
EDIT:
I noticed a strange behavior: If I set a proxy_pass for /
like: location / { proxy_pass http://localhost:8080; }
to port 8080 and set the baseurl in the bot1 script to bots.mydomain.com/bot1, Bot-1 works.
But I obviously still can't get other bots to work aswell because I'm using the root (/).
Does that mean it's a problem with Kik-API's way of listening?
EDIT 2:
I checked the Nginx Log now and it seems like the Kik Wrapper tries to listen on a directory which doesn't exists. I did the following: Start the bot on port 8080 & message it. This is the log output:
https://pastebin.com/7G6TViHM
2017/04/13 09:07:05 [error] 15614#15614: *1 open() "/var/www/bots.mydomain.com/public_html/incoming" failed (2: No such file or directory), client: 107.XXX.XXX.XXX, server: bots.mydomain.com, request: "POST /incoming HTTP/1.1", host: "bots.mydomain.com"
2017/04/13 09:07:13 [error] 15614#15614: *1 open() "/var/www/bots.mydomain.com/public_html/incoming" failed (2: No such file or directory), client: 107.XXX.XXX.XXX, server: bots.mydomain.com, request: "POST /incoming HTTP/1.1", host: "bots.mydomain.com"
But I still don't know how to fix this. As a test I created the directory incoming in public_html. This returned the following in the log:
2017/04/13 09:32:41 [error] 15614#15614: *10 directory index of "/var/www/bots.mydomain.com/public_html/incoming/" is forbidden, client: 107.XXX.XXX.XXX, server: bots.mydomain.com, request: "GET /incoming/ HTTP/1.1", host: "bots.mydomain.com"
Does anyone have an idea on how to fix it?
I think your issue lies with a trailing slash in proxy_pass, which removes the /bot1 and /bot2 prefixes once passed to upstream (replacing both with mere /), so, each bot in your nodejs code has a mismatched baseUrl setting as a result (as you mention that you did change those settings appropriately to match the external URL).
-location /bot1 { proxy_pass http://localhost:8080/; } # Port 8080
-location /bot2 { proxy_pass http://localhost:8090/; } # Port 8090
+location /bot1 { proxy_pass http://localhost:8080; } # Port 8080
+location /bot2 { proxy_pass http://localhost:8090; } # Port 8090
It probably doesn't wok because your target servers get the path that includes the /bot1 and /bot2 prefix, which they may not expect.
Maybe try:
location /bot1 {
rewrite ^/bot1/(.*)$ /$1 break;
proxy_pass http://localhost:8080/;
}
location /bot2 {
rewrite ^/bot2/(.*)$ /$1 break;
proxy_pass http://localhost:8090/;
}
In case anyone comes across this question:
It's just not possible by Kik's API design.
When you initialize your bot with
let bot = new Bot({
username: "foo",
apiKey: "bar",
baseUrl: "https://bots.mydomain.com"
});
this baseUrl is essentially a webhook and cannot be re-used. It has to be somewhat unique.
A possible work-around would be specifying a port directly in the base-url.

Resources