Intercept request and then forward to another Server - php

Problem
I am facing a unique problem here. I have a nginx server with an admin panel (admin.example.com). Now I want to allow only specific IP addresses to access that server and I know that we can do that through nginx allow and deny tag. But that approach is quite difficult for non-technical users and would require access to the server itself to make the change and then reload nginx. The purpose is to make it easy for anyone to whitelist IP addresses.
Solution
We came up with a UI app.example.com (hosted on a different server) to allow manage the IP addresses. Now I want to route all (admin.example.com) requests through this new server which will check if the IP is allowed then proxy the request to admin.example.com otherwise deny the access.
Question
My question is how do we route all the requests through app.example.com and once the IP has been verified only then forward the request to the origin which is admin.example.com here?
If it is possible through the nginx reverse proxy then do I need to process the request through a local upstream such as PHP or python and then forward the request after the verification?
Anyone example with pseudo code for nginx configuration will be highly appreciated.
I know services like Cloudflare does it but I need only a basic setup.

This is what I wanted How do I make web service calls within nginx? . Another approach is to use the Openresty lua JIT to preprocess the request and then forward it to the reverse proxy.
https://openresty.org/en/

Related

Build a simple PHP proxy server for a shared host

I've searched a lot but I couldn't find a PHP proxy server which can be run on a shared host, so I decided to build a very simple one from scratch but I'm still on the first step. I've created a subdomain httpp.alvandsoft.com and also redirected all its subdirectories (REQUEST_URI) to the main index.php to be logged and to know what whould a proxy server exactly receive and send
(The log is accessible through https://httpp.alvandsoft.com/?log=1&log_filename=log.txt)
But whenever I set it as a proxy for Telegram or other apps, it doesn't receive ANY requests at all, even when I use 443 or 80 ports, neither in different proxies such as HTTP, SOCKS or MTPROTO.
Is proxy something that depends on the server's settings and works in a way other than regular HTTP requests and responses or I'm missing something?
I found it out myself. HTTP(s) proxies send their requested URL as Host request header and many hosts and websites, check this request header and if it's not a member of their valid IPs, redirect it immediately.

HTTP and nodeJS on separate servers

I have two websites:
1)httpwebsite.com where I run my web application which uses APACHE, PHP and MYSQL;
2)wss.com where I run a nodeJS websocket server, used for a multiplayer game;
I want to host the javascript client-side files that communicate with the websocket server, on httpwebsite.com, so I dont have to configure a http server on nodeJS, for many reasons, like security and lack of experience with using nodeJS as HTTP server.
I want to use nodeJS only for the websocket server, for performance and flexibility reasons, among many others.
I've heard that Same-origin policy restricts communication from httpwebsite.com with wss.com , but can this be reconfigured to actually allow communication between two different domains that want to communicate with each other on purpose?
Do I have other options than actually running a HTTP server on the nodeJS server?
You can use CORS for secure requests from one domain to another domain.
http://www.html5rocks.com/en/tutorials/cors/
2 options:
You can add CORS headers to wss.com to allow access to website.com to load it's resources. The link Matt gave should explain how this works and you just need to add this HTTP Header to each Node server you need to access.
You can proxy your requests through your Apache server to the node server. So the web browser thinks it's talking to a service on the same origin. This is often used to only have your web server publically available and your app server (running node) not directly available and protected behind a firewall - though obviously Apache needs to be able to access it.
You can use this config in Apache to achieve option 2 to forward http://website.com/api calls to a service running in wss.com on port 3000.
#send all /api requests to node
ProxyPass /api http://wss.com:3000
#Optionally change all references to wss.com to this domain on return:
ProxyPassReverse /api http://wss.com:3000

Redirect with DNS

I need to make a transparent redirect (without the user seeing the address change in the address bar). When the user types example.com he/she should be redirected to 123.123.123.123:9090 (IP:PORT). I cannot use CNAME or A cause it does not accept the PORT. How can I do that? I know that using SRV I can do that but my webserver does not allow it.
I also tried using THE mod_proxy on Apache to rewrite the request from domain example.com -> 123.123.123.123:9090 however it is absurd cause the user requests the content, the apache requests the content to my IP and after that the response has to go up all way back. I need the user request to reach the webserver directly without proxy.
Well, DNS doesn't care about ports, only about hostnames. Thats why you can access every server like example.com:8080 (will probably fail for 99% of all servers though ;)). So what should happen when I try to request your site via example.com:8080? Does port 8080, or 9090 takes precedence?
Long story short: There is no way around a proxy. But easier would be to let it listen on port 80 directly.

How to enable user custom domains in PHP

I'm having a system where users can input their purchased domain into their profile, so when accessing their domain, it should replace their custom domain, e.g.
http://domain.com/custom-name to http://purchaseddomain.com.
So when they access their purchase domain, it should take them to their profile including their navigation links, such as links on their page will be replaced with their purchased domain, for example viewing their records would be:
http://domain.com/custom-name/records to http://purchaseddomain.com/records.
Tumblr enables this feature, however I have no idea how this all works:
This is exactly how I like to have a feature like this, I've searched on SO, but it didn't seem to help.
Now this is a problem, I'm not sure how I can validate, confirm and merge their purchased domain into my server without a problem using PHP - I'm using Codeigniter for this.
Is there a solid, stable plugin/library or detailed tutorial that can have the ability to enable custom domains masking a internal domain?
My server is running Ubuntu 11.10 on nginx 1.0.6.
The templating will be just fine for me, which I can do - all I need help on is how to safely accept and merge their domain to my server.
EDIT: Just looked into nginx VirtualHostExample, this looks good overall but how will I be able to dynamically add/remove those domain entries while the domain has an A record pointing to my server?
You won't merge their domain to your server.
In fact, when they will register their domains, they will make it point to your server.
On your server configuration, you'll have to dynamically create rules that implicitly redirect the page to the one they created on your server.
So, users will see http://purchaseddomain.com/on-uri but you serve the page http://domain.com/custom-name/one-uri
I.E:
it's like if you added on an .htaccess - even if you don't use apache, it's just to explain what the "system" must be:
RewriteCond %{HTTP_HOST} purchaseddomain\.com$ [NC]
RewriteRule (.*) /custom-name/$1
The accepted answer mentions customers pointing their DNS to your web server. But, that's not enough to make it work in this day and age.
If your customers just CNAME to your domain or create the A record to your IP and you don't handle TLS termination for these custom domains, your app will not support HTTPS, and without it, your app won't work in modern browsers on these custom domains.
You need to set up a TLS termination reverse proxy in front of your webserver. This proxy can be run on a separate machine but you can run it on the same machine as the webserver.
CNAME vs A record
If your customers want to have your app on their subdomain, e.g. app.customer.com they can create a CNAME app.customer.com pointing to your proxy.
If they want to have your app on their root domain, e.g. customer.com then they'll have to create an A record on customer.com pointing to your proxy's IP. Make sure this IP doesn't change, ever!
How to handle TLS termination?
To make TLS termination work, you'll have to issue TLS certificates for these custom domains. You can use Let's Encrypt for that. Your proxy will see the Host header of the incoming request, e.g. app.customer1.com or customer2.com etc., and then it will decide which TLS certificate to use by checking the SNI.
The proxy can be set up to automatically issue and renew certificates for these custom domains. On the first request from a new custom domain, the proxy will see it doesn't have the appropriate certificate. It will ask Let's Encrypt for a new certificate. Let's Encrypt will first issue a challenge to see if you manage the domain, and since the customer already created a CNAME or A record pointing to your proxy, that tells Let's Encrypt you indeed manage the domain, and it will let you issue a certificate for it.
To issue and renew certificates automatically, I'd recommend using Caddyserver, greenlock.js, OpenResty (Nginx).
tl;dr on what happens here;
Caddyserver listens on 443 and 80, it receives requests, issues, and renews certificates automatically, proxies traffic to your backend.
How to handle it on my backend
Your proxy is terminating TLS and proxying requests to your backend. However, your backend doesn't know who is the original customer behind the request. This is why you need to tell your proxy to include additional headers in proxied requests to identify the customer. Just add X-Serve-For: app.customer.com or X-Serve-For: customer2.com or whatever the Host header is of the original request.
Now when you receive the proxied request on the backend, you can read this custom header and you know who is the customer behind the request. You can implement your logic based on that, show data belonging to this customer, etc.
More
Put a load balancer in front of your fleet of proxies for higher availability. You'll also have to use distributed storage for certificates and Let's Encrypt challenges. Use AWS ECS or EBS for automated recovery if something fails, otherwise, you may be waking up in the middle of the night restarting machines, or your proxy manually.
If you need more detail you can DM me on Twitter #dragocrnjac
This is what is working for me:
server {
server_name *.mydomain.com
root /var/www/$host;
...
}
Then you need to make directories like: /var/www/user1.mydomain.com/, /var/www/user2.mydomain.com/, ...
I couldn't figure out how to leave the '.mydomain.com' out of the directory name. If anyone has any idea, pls let me know :)

Does a cURL post to the same site leave the local network?

I'm doing a PHP cURL post, using a complete URL (http://www.mysite.com), from one page to another on the same site. (I know this isn't the best way to do it; but for my purpose this is what I need)
My question is:
Will the cURL post still go out across the internet, do a name lookup and travel a route as though it were a post coming from a different site. Or will the post stay on the servers local network?
There are multiple parts to the request, the dns lookup and the get or post to the site.
DNS Records are usually cached on most OSes, so it's rather unlikely that the server would have to do a dns lookup for it's own external ip, but it's possible.
As for the post, let's assume a basic layout:
Firewall => DMZ Apache PHP Server (www.mysite.com)
222.xxx.xxx.123 => 192.168.0.2
And mysite.com resolves to 222.xxx.xxx.123, then your request will go to your firewall's external interface and bounce back in. That's not terribly public traffic, but it goes out none-the less.
However, if you wanted to bypass that, you could put an entry in the host file of the server to say
127.0.0.1 mysite.com
(assuming you control the server, ie not shared hosting)
No. The post itself (unless you have multiple interfaces and your routing is totally screwed up) will not traverse the internet. Your local host ought to be able to resolve its own name as well, but there is a possibility that a DNS request will be made to determine the IP address corresponding to the name. I would hope that the network stack implementation on your system would prevent the post's packets from even hitting the wire (similar to localhost), but I wouldn't count on it.
It depends on your network setup. Many sites have a domain name pointing to the IP address of a front facing router or load balancer which forward the request to the web server.
If that's the case a request to your own site can make a round-trip to the router. Though it's unlikely that the request will go through the internet unless you have a very unusual setup (such as round robin DNS with multiple datacenters).
You can avoid the round-trip by associating the site FQDN to the loopback interface in your webserver /etc/hosts which will also save you a DNS request.

Categories