Nodejs: How to reverse proxy + TLS certificates with Caddy (Cloudflare)? - javascript

this is my first time deploying nodejs from localhost to the live server. I am using aapanel for my live server.
Here is the relevant code in node server.js file:
const hostname = 'localhost';
// const hostname = 'www.thespacebar.io';
// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, hostname, () => {
console.log(`Server is running on port ${PORT}.`);
});
Here is my pm2 settings:
I am unable to open my nodejs app with GET https://www.thespacebar.io:8080, but it works for GET http://www.thespacebar.io:8080
GET https://www.thespacebar.io:8080 does not work with error:
This site can’t provide a secure connection
ERR_SSL_PROTOCOL_ERROR
Anyone know what I did wrong?
EDIT: I have installed Caddy and setup the Caddyfile in /etc/caddy like this:
# The Caddyfile is an easy way to configure your Caddy web server.
#
# Unless the file starts with a global options block, the first
# uncommented line is always the address of your site.
#
# To use your own domain name (with automatic HTTPS), first make
# sure your domain's A/AAAA DNS records are properly pointed to
# this machine's public IP, then replace ":80" below with your
# domain name.
import ./thespacebar.io
:80 {
# Set this path to your site's directory.
root * /usr/share/caddy
# Enable the static file server.
file_server
# Another common task is to set up a reverse proxy:
# reverse_proxy localhost:8080
# Or serve a PHP site through php-fpm:
# php_fastcgi localhost:9000
}
# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile
and created the adjacent file thespacebar.io:
thespacebar.io {
reverse_proxy localhost:8080
}
but when I visit https://thespacebar.io/, I end up at index.html instead of the JSON { message: "Welcome to bezkoder application." }
and POST http://www.thespacebar.io/api/verification/callback with body param verify_token:abcde is supposed to show the JSON:
{
"message": "Callback called successfully."
}
instead of 404 Not Found
EDIT 2: I have removed the portion:
# :80 {
# Set this path to your site's directory.
# root * /usr/share/caddy
# Enable the static file server.
# file_server
# Another common task is to set up a reverse proxy:
# reverse_proxy localhost:8080
# Or serve a PHP site through php-fpm:
# php_fastcgi localhost:9000
# }
# Refer to the Caddy docs for more information:
# https://caddyserver.com/docs/caddyfile
from etc/caddy/Caddyfile
but when I run caddy run Caddyfile and caddy reload Caddyfile, I am getting this error:
[root#vultrguest caddy]# caddy run Caddyfile
2022/12/02 08:11:44.132 INFO using adjacent Caddyfile
2022/12/02 08:11:44.132 WARN Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies {"adapter": "caddyfile", "file": "Caddyfile", "line": 12}
2022/12/02 08:11:44.133 INFO admin admin endpoint started {"address": "localhost:2019", "enforce_origin": false, "origins": ["//localhost:2019", "//[::1]:2019", "//127.0.0.1:2019"]}
2022/12/02 08:11:44.133 INFO http server is listening only on the HTTPS port but has no TLS connection policies; adding one to enable TLS {"server_name": "srv0", "https_port": 443}
2022/12/02 08:11:44.133 INFO http enabling automatic HTTP->HTTPS redirects {"server_name": "srv0"}
2022/12/02 08:11:44.133 INFO tls.cache.maintenance started background certificate maintenance {"cache": "0xc000151030"}
2022/12/02 08:11:44.133 INFO tls.cache.maintenance stopped background certificate maintenance {"cache": "0xc000151030"}
Error: loading initial config: loading new config: http app module: start: listening on :80: listen tcp :80: bind: address already in use
[root#vultrguest caddy]# caddy reload Caddyfile
2022/12/02 08:11:49.875 INFO using adjacent Caddyfile
2022/12/02 08:11:49.876 WARN Caddyfile input is not formatted; run the 'caddy fmt' command to fix inconsistencies {"adapter": "caddyfile", "file": "Caddyfile", "line": 12}
Error: sending configuration to instance: performing request: Post "http://localhost:2019/load": dial tcp [::1]:2019: connect: connection refused
[root#vultrguest caddy]#
If I run GET http://www.thespacebar.io:8080 I get:
Web server is down Error code 521
Visit cloudflare.com for more information.
2022-12-02 08:22:13 UTC
You
EDIT3: The site I am trying to setup reverse proxy is using cloudflare, so I have modified my Caddyfile to:
# The Caddyfile is an easy way to configure your Caddy web server.
#
# Unless the file starts with a global options block, the first
# uncommented line is always the address of your site.
#
# To use your own domain name (with automatic HTTPS), first make
# sure your domain's A/AAAA DNS records are properly pointed to
# this machine's public IP, then replace ":80" below with your
# domain name.
# import ./thespacebar.io
# cloudflare
(cf) {
tls {
resolvers 1.1.1.1
dns cloudflare [cf-token-goes-here]
}
}
but when I run `caddy run Caddyfile`, I got this error:
`Error: adapting config using caddyfile: parsing caddyfile tokens for 'tls': Caddyfile:17 - Error during parsing: getting module named 'dns.providers.cloudflare': module not registered: dns.providers.cloudflare`
thespacebar.io {
import cf
reverse_proxy localhost:8080
}
but when I goto cd /etc/caddy and caddy run Caddyfile I get the error:
Error: adapting config using caddyfile: parsing caddyfile tokens for 'tls': Caddyfile:17 - Error during parsing: getting module named 'dns.providers.cloudflare': module not registered: dns.providers.cloudflare
all the tutorials for adding this module (dns.providers.cloudflare) are for xcaddy and not caddy, how do I add this module for caddy?

Caddy is simple to setup as a reverse proxy, and it gets letsencrypt SSL certs for you with minimal fuss
{
email example#email.com
}
thespacebar.io {
reverse_proxy localhost:8080
}
I see you've posted an update - the one thing I would remove is
:80 {
.....
}
If you read the text you posted it does say to replace :80 with your domain (but don't add :80 or caddy won't do the certificate for the domain)
I also see you haven't set up a global section with an email address - I'm fairly sure that needs to be there (don't quote me on that) for letsencrypt to work - at least it used to when I first started using caddy

here is some pseudo code for a generic caddyfile for caddy v2
for the code below replace "\*" with "*" "\" is used below to escape "/*" in the markdown
this code will add basic security headers and cors to the response
it will proxy pass thru to a process on localhost port 9883
if you have a dns record for your server it will set up the letsencrypt certs for you and renew them when required
see caddy snippets https://caddyserver.com/docs/caddyfile/concepts#snippets
# begin common code block snippet to be imported into the server block,
# for example here we set common security headers
# see the markdown escape comment above for "/\*" should be "/*"
(common) {
header /\* {
-Server
-X-Powered-By
+X-Permitted-Cross-Domain-Policies none
+X-Frame-Options DENY
+X-Content-Type-Options nosniff
+Strict-Transport-Security "max-age=63072000 includeSubDomains preload"
+Referrer-Policy no-referrer
}
}
# cors snippet
(cors) {
#cors_preflight method OPTIONS
# "{args.0}" is an input value used when calling the snippet
#cors header Origin "{args.0}"
handle #cors_preflight {
header Access-Control-Allow-Origin "{args.0}"
header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE"
header Access-Control-Allow-Headers "Content-Type"
header Access-Control-Max-Age "3600"
respond "" 204
}
}
# main server block
# dns record for server is myserver.edu
myserver.edu {
# import common sec headers snippet
import common
# import cors snippet passing server name parameter, wildcard cors poor sec
import cors myserver.edu
# proxy redirect see handle_path directive
# https://caddyserver.com/docs/caddyfile/directives/handle_path
# see the markdown escape comment above for "/\*" should be "/*"
handle_path /somepath/\* {
reverse_proxy localhost:9883 {
header_up X-Real-IP {remote_host}
# caddy will add X-Forwarded-For for you so not need this one
#header_up X-Forwarded-For {remote_host}
header_down Content-Security-Policy "media-src blob:"
}
}
}

Related

Apache reverse proxy to Node - Connection refused: AH00957

I am trying to get a brand new cloud based server working with a default version of 20.04 server ubuntu working with apache and node. The node server appears to be running without issues reporting 4006 port is open. However I believe my apache config is not. The request will hang for a very very long time. No errors are displayed in the node terminal. So the fault must lie in my apache config seeing as we are getting the below apache errors and no JS errors.
Request error after some time
502 proxy error
Apache Error Log
[Sun Oct 17 20:58:56.608793 2021] [proxy:error] [pid 1596878] (111)Connection refused: AH00957: HTTP: attempt to connect to [::1]:4006 (localhost) failed
[Sun Oct 17 20:58:56.608909 2021] [proxy_http:error] [pid 1596878] [client 207.46.13.93:27392] AH01114: HTTP: failed to make connection to backend: localhost
vhost
<VirtualHost IP_ADDRESS:80>
ServerName api.aDomain.com
Redirect permanent / https://api.aDomain.com/
</VirtualHost>
<IfModule mod_ssl.c>
<VirtualHost IP_ADDRESS:443>
ServerName api.aDomain.com
ProxyRequests on
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so
ProxyPass / http://localhost:4006/
ProxyPassReverse / http://localhost:4006/
#certificates SSL
SSLEngine on
SSLCACertificateFile /etc/ssl/api.aDomain.com/apimini.ca
SSLCertificateFile /etc/ssl/api.aDomain.com/apimini.crt
SSLCertificateKeyFile /etc/ssl/api.aDomain.com/apimini.key
ErrorLog ${APACHE_LOG_DIR}/error_api.aDomain.com.log
CustomLog ${APACHE_LOG_DIR}/access_api.aDomain.com.log combined
</VirtualHost>
</IfModule>
terminal output
[nodemon] 1.19.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `babel-node -r dotenv/config --inspect=9229 index.js`
Debugger listening on ws://127.0.0.1:9229/c1fcf271-aea8-47ff-910e-fe5a91fce6d2
For help, see: https://nodejs.org/en/docs/inspector
Browserslist: caniuse-lite is outdated. Please run next command `npm update`
πŸš€ Server ready at http://localhost:4006
Node server
import cors from 'cors'
import scrape from './src/api/routes/scrape'
const express = require('express')
const { ApolloServer, gql } = require('apollo-server-express')
const { postgraphile } = require('postgraphile')
const ConnectionFilterPlugin = require('postgraphile-plugin-connection-filter')
const dbHost = process.env.DB_HOST
const dbPort = process.env.DB_PORT
const dbName = process.env.DB_NAME
const dbUser = process.env.DB_USER
const dbPwd = process.env.DB_PWD
const dbUrl = dbPwd
? `postgres://${dbUser}:${dbPwd}#${dbHost}:${dbPort}/${dbName}`
: `postgres://${dbHost}:${dbPort}/${dbName}`
var corsOptions = {
origin: '*',
optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204
}
async function main() {
// Construct a schema, using GraphQL schema language
const typeDefs = gql`
type Query {
hello: String
}
`
// Provide resolver functions for your schema fields
const resolvers = {
Query: {
hello: () => 'Hello world!',
},
}
const server = new ApolloServer({ typeDefs, resolvers })
const app = express()
app.use(cors(corsOptions))
app.use(
postgraphile(process.env.DATABASE_URL || dbUrl, 'public', {
appendPlugins: [ConnectionFilterPlugin],
watchPg: true,
graphiql: true,
enhanceGraphiql: true,
})
)
server.applyMiddleware({ app })
//Scraping Tools
scrape(app)
const port = 4006
await app.listen({ port })
console.log(`πŸš€ Server ready at http://localhost:${port}`)
}
main().catch(e => {
console.error(e)
process.exit(1)
})
Apache Mods Enabled
/etc/apache2/mods-enabled/proxy.conf
/etc/apache2/mods-enabled/proxy.load
/etc/apache2/mods-enabled/proxy_http.load
Updated Error Logs
[Thu Oct 21 10:59:22.560608 2021] [proxy_http:error] [pid 10273] (70007)The timeout specified has expired: [client 93.115.195.232:8963] AH01102: error reading status line from remote server 127.0.0.1:4006, referer: https://miniatureawards.com/
[Thu Oct 21 10:59:22.560691 2021] [proxy:error] [pid 10273] [client 93.115.195.232:8963] AH00898: Error reading from remote server returned by /graphql, referer: https://miniatureawards.com/
In major situations this is caused by selinux (when you have RHEL or CentOS):
# setsebool -P httpd_can_network_connect 1
link: https://unix.stackexchange.com/questions/8854/how-do-i-configure-selinux-to-allow-outbound-connections-from-a-cgi-script
Also check:
connectivity between the machines
back-end port is open
Use static IP-address (IPv4) or use host-name that are in you /etc/hosts file
I cannot exactly predict what exactly happen it could be NodeJS app crushed and no longer running or there are misconfiguration Apache files. But I strongly believe this scenario will be solved from doing things back from the top.
This step would go through updating unbuntu packages, installing needed application, configuring Apache files and setting up reverse proxy with NodeJS and Apache.
Just don't touch your NodeJS files and other code related application and they will be safe. You may also backup just to make sure. Other running application on that ubuntu server example database application like MySQL as will be just fine and still be running.
1. First we need to update ubuntu packages and install Apache, and NodeJS
$ sudo apt update
$ sudo apt install apache2 npm
2. Run this command to enable us to use Apache as a reverse proxy server
sudo a2enmod proxy proxy_http rewrite headers expires
3. Create an Apache virtual host file.
This command would will let you use ubuntu terminal as your text editor follow the guide and prompt from the terminal to write.
NOTE:
Change the "yourSite.com" with the domain of your site. It isn't really important should be the name of the file. But I think its better to name it after your site domain so you can recognize it.
$ sudo nano /etc/apache2/sites-available/yourSite.com.conf
4. Use the nano editor is to write your Apache config file for your site.
Notice: This part is critical so please pay attention
Change your ServerName and ServerAlias with your site domain name.
The ProxyPass and the ProxyPassReverse this has two parameters.
The first one is a back-slash "/" This an absolute path where your NodeJS should be located and since its single back-slash that means its your home directory.
The second one is the url "http://127.0.0.1:3000/" of your NodeJS application. Pay attentions to its PORT "3000" you may need to replaced it with the PORT you use in your NodeJS app.
<VirtualHost *:80>
ServerName example.com // replace this with site domain name without www at the beginning
ServerAlias www.example.com // replace this with site domain name beginning with www. + yourdomainname + .com
ProxyRequests Off
ProxyPreserveHost On
ProxyVia Full
<Proxy *>
Require all granted
</Proxy>
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:30000/
</VirtualHost>
5. disable the default Apache site and enable the new one.
$ sudo a2dissite 000-default
$ sudo a2ensite example.com.conf
6. Restart your Apache Server to apply the changes
sudo systemctl restart apache2
We could be ready at this point as we done setting up Apache as a reverse proxy, But we also need to install the npm package of your project and then run your NodeJS application.
7. The rest of the step is all related to NodeJS deployment. You may be already know this steps.
// install npm packages
npm install
// for a better experience using NodeJS in production install pm2 globally
npm install -g pm2
// Then run your NodeJS application using pm2 command
pm2 start // you should be at root of your NodeJS project folder when running this command
// run this another pm2 command to make sure your NodeJS app will re-run when it encounter downtime.
$ pm2 save
$ pm2 startup
Your Apache and NodeJS server is up and running now
Try to access your site by typing entering your site domain name in the browsers address bar
e.g http://yourSite.com
If you use a docker for your node server, then it might be set up incorrectly
I'm not an expert on this topic, but I have a similar setup; I use socket.io to serve WebSockets...
From your posts it seems you don't need to proxy WebSockets as well, the one shown in your logs seems to be only for debugging purposes (please correct me if I'm wrong).
Following the core of my Apache configuration:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/socket.io [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule /(.*) ws://127.0.0.1:4006/$1 [P,L]
<Location />
ProxyPass http://127.0.0.1:4006/ retry=2
ProxyPassReverse http://127.0.0.1:4006/
</Location>
Another couple of suggestions.
Warning
Do not enable proxying with ProxyRequests until you have secured your server. Open proxy servers are dangerous both to your network and to the Internet at large.
Source: https://httpd.apache.org/docs/2.4/mod/mod_proxy.html#proxyrequests
I don't know which is the IPV6 setup on your host, you could try to use 127.0.0.1 rather than localhost in you Apache configuration to try forcing Apache to use IPV4.

Using Kubernetes with Skaffold and running Next JS produces "Your connection is not private" under HTTPS in Chrome

I'm running Skaffold with a few apps in Development :
Skaffold.yaml
apiVersion: skaffold/v2alpha3
kind: Config
deploy:
kubectl:
manifests:
- ./infra/k8s/*
build:
local:
push: false
artifacts:
- image: MYDOCKERID/client
context: client
docker:
dockerfile: Dockerfile
sync:
manual:
- src: '**/*.js'
dest: .
Dockerfile of client :
FROM node:alpine
WORKDIR /app
COPY package.json .
RUN npm install
COPY . .
CMD ["npm", "run", "dev"]
client-depl.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: client-depl
spec:
replicas: 1
selector:
matchLabels:
app: client
template:
metadata:
labels:
app: client
spec:
containers:
- name: client
image: MYDOCKERID/client
---
apiVersion: v1
kind: Service
metadata:
name: client-srv
spec:
selector:
app: client
ports:
- name: client
protocol: TCP
port: 3000
targetPort: 3000
When executing skaffold dev from command line everything is compiled perfectly :
[92m[client-depl-5bdc8cffcd-s9z9r client] [0mevent - compiled successfully
[92m[client-depl-5bdc8cffcd-s9z9r client] [0mwait - compiling...
[92m[client-depl-5bdc8cffcd-s9z9r client] [0mAttention: Next.js now collects completely anonymous telemetry regarding usage.
[92m[client-depl-5bdc8cffcd-s9z9r client] [0mThis information is used to shape Next.js' roadmap and prioritize features.
[92m[client-depl-5bdc8cffcd-s9z9r client] [0mYou can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
[92m[client-depl-5bdc8cffcd-s9z9r client] [0mhttps://nextjs.org/telemetry
[92m[client-depl-5bdc8cffcd-s9z9r client] [0m
[92m[client-depl-5bdc8cffcd-s9z9r client] [0mevent - compiled successfully
I've added the domain in Hosts file in Windows etc folder :
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
# 102.54.94.97 rhino.acme.com # source server
# 38.25.63.10 x.acme.com # x client host
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost
127.0.0.1 ticketing.dev
However when typing in Chrome ticketing.dev I get :
How can I run the app in Chrome and overcome this message ?
You are missing a certificate to have your connection secure. You will also need to configure the ingress to use the cert that you create.
You should read Manage TLS Certificates in a Cluster.
Kubernetes provides a certificates.k8s.io API, which lets you provision TLS certificates signed by a Certificate Authority (CA) that you control. These CA and certificates can be used by your workloads to establish trust.
You can have a look into a nice guide on how to Adding SSL/TLS support to applications in Kubernetes-native way.
You can create a self-signed certificate, this medium article shows how to do that on Windows.
On Linux you can do following:
[root]# mkdir certs
[root]# openssl req -nodes -newkey rsa:2048 -keyout certs/ticketing.key -out certs/ticketing.csr -subj "/C=/ST=/L=/O=/OU=/CN=default"
[root]# openssl x509 -req -sha256 -days 365 -in certs/ticketing.csr -signkey certs/ticketing.key -out certs/ticketing.crt
This will create a cert that is valid for 365 days.
Then create a secret which will hold your cert:
kubectl create secret generic ticketing-certs --from-file=certs -n default
Once the cert and secret is ready you should create an ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example1-ingress
spec:
tls:
- hosts:
- www.ticketing.dev
secretName: ticketing-cert
rules:
- host: www.ticketing.dev
http:
paths:
- path: /
backend:
serviceName: client-srv
servicePort: 3000
Let me know if you need anything more.
I assume you are using the project for development purposes. If you want to run the app on chrome. To bypass this security warning, just right this on the webpage showing warning blindly :
thisisunsafe

Angular + Node(Express) + SSL integration

This is my first time deploying ssl. I have express node js module running at localhost:4000. I have generated the self-signed certificate and installed in the server and it is working. Now, I have my angularjs frontend running at localhost:3000(I am using http-server to run the angular code).
To make my point more clearer, here's is the code on the server side:-
// Import node js modules
var https = require('https')
var fs = require('fs')
var express = require('express')
// Load App configuration
var config = require('./config/config')
// Database Integration Here(mongodb)
// Initialize the express app
var app = express()
// App express Configuration
// parse application/json
app.use(bodyParser.json())
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: true}))
app.use(cors())
app.set('serverHost', config.server.host)
app.set('serverPort', config.server.port)
app.set('serverUrl', config.server.url)
// Initializing various app modules
// Initialize the components
//Initialize the route(controller)
// Start the app with a given port no and mode
var env = process.env.NODE_ENV || 'development'
var httpsOptions = {
key: fs.readFileSync(__dirname + '/cert/server.key'),
cert: fs.readFileSync(__dirname + '/cert/server.crt')
}
https.createServer(httpsOptions, app).listen(app.get('serverPort'), function () {
// Server and mode info
console.log('The homerungurus backend running on server: '
+ app.get('serverHost')
+ ' and the port is: '
+ app.get('serverPort'))
console.log("The mode is: " + env)
})
As you can see I have installed the certs in the server.
I don't need a http-proxy because i will deploy the angular webserver on the standard port 443.
I am not able to understand few things:-
How to enable and set ssl certificate in my angular module so that
express and angular can communicate over ssl.
How will I display the cert of my backend express node to the browser?
I hope I have made my point more clearer.
Any help is appreciated?
Ok, where do we start...
You have a backend (express node js) running on port 4000, and a frontend (angularjs with http-server) running on port 3000, so you basically have two independent webservers running. When you say you "installed" the ssl certificate on the server, I assume you have it sitting in some directory but not actually installed on one of your servers.
You have several options to deploy your code, together with your SSL certificate. The best approach would be to seperate frontend from backend by urls.
That would mean that your frontend gets served from: https://frontend.example.com
and your backend gets served from https://backend.example.com (you can change the urls to whatever you want, so something like https://example.com or https://www.example.com is fine as well)
As far as I recall, if you have https:// on your frontend, you also need https:// on your backend, otherwise you will have problems with browsers security policies. You might also have to look for same origin policy, and allow on your server that https://frontend.example.com can access https://backend.example.com, but for that open a new ticket if you need it :D
The user would see the green symbol from https://frontend.example.com
I assume you know how you would change the backend url so your angular code would use https://backend.example.com instead of http://localhost:4000
To serve now your existing servers on port 443 (that is the default port for https and is always used if you say https://... but do not specify a port) you need an http proxy.
As http proxy (you can google for reverse proxy) you can take either apache or nginx, both are very common.
There are a couple of tutorials out there, how to setup nginx / apache which are OS specific, but Im sure you will manage. Dont forget to install mod_ssl and mod_http_proxy mod for apache (I dont remember if nginx needs something specifc as well)
A typical config for an apache reverse proxy would look like this:
<VirtualHost *:80>
# this part redirects all traffic from normal http to https
ServerName frontend.example.com
ServerSignature Off
RewriteEngine on
RewriteCond %{HTTPS} !=on
RewriteRule .* https://%{SERVER_NAME}%{REQUEST_URI} [NE,R,L]
</VirtualHost>
<virtualhost *:443>
# this is the actual part with some security enhancements
ServerName frontend.example.com
ServerAdmin webmaster#localhost
# be carefull with HSTS, it might break your setup if you
# do not know what you do. If you are not sure, do not
# comment the next line in
# Header always add Strict-Transport-Security "max-age=15768000"
# Enable SSL
SSLEngine on
# only strong encryption ciphers
# for reference https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy
# and no RC4 according to https://community.qualys.com/blogs/securitylabs/2013/03/19/rc4-in-tls-is-broken-now-what
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS !RC4"
SSLCompression Off
SSLCertificateFile /path/to/cert.pem
SSLCertificateKeyFile /path/to/privkey.pem
# this next line is not needed if you have a self signed cert
SSLCertificateChainFile /path/to/chain.pem
ServerSignature Off
RequestHeader set X-FORWARDED-PROTOCOL https
RequestHeader set X-Forwarded-Ssl on
ProxyPreserveHost On
# Ensure that encoded slashes are not decoded but left in their encoded state.
# http://doc.gitlab.com/ce/api/projects.html#get-single-project
AllowEncodedSlashes NoDecode
<Location />
# New authorization commands for apache 2.4 and up
# http://httpd.apache.org/docs/2.4/upgrading.html#access
Require all granted
ProxyPassReverse http://127.0.0.1:3000
ProxyPassReverse http://frontend.example.com/
</Location>
#apache equivalent of nginx try files
# http://serverfault.com/questions/290784/what-is-apaches-equivalent-of-nginxs-try-files
# http://stackoverflow.com/questions/10954516/apache2-proxypass-for-rails-app-gitlab
RewriteEngine on
RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
RewriteRule .* http://127.0.0.1:3000%{REQUEST_URI} [P,QSA]
RequestHeader set X_FORWARDED_PROTO 'https'
You will need the exact same twice, for the frontend like shown above and for the backend, where you replace port 3000 with 4000 and frontend.example.com with backend.example.com.
I hope this helps you a bit. Its not as complete as it could, but it should give you a hint how to setup your two http servers behind a http proxy to server your ssl certificate.
The above comment made by #chickahoona is more than enough. My solution is as follows:-
I removed http-server and used nginx for my frontend because i wanted to have html5 mode and for that I needed to have url rewriting.
I have used nginx as a proxy server rather than apache.
That's it and everything else is same as #chickahoona has pointed out.

grunt-contrib-connect - Fatal error: getaddrinfo ENOTFOUND my.website - How to set up custom URL?

I want to use grunt-contrib-connect to create a server under a specific URL, let's say http://my.website/. According to the documentation, all I need to do is just to change the hostname option, but I keep getting an error saying: Fatal error: getaddrinfo ENOTFOUND my.website.
Here's my Gruntfile.js:
connect: {
dev: {
options: {
keepalive: true,
port: 80,
hostname: 'my.website',
base: 'public'
}
}
},
Thanks.
Hosts are merely "aliases" that other computers in the network (or your own!) can use to find IPs. Your machine may even control more than one IP (by having many network interfaces). However, you can only listen to requests in IPs you control!
When you start a server, it binds itself to a specific network interface (which has a specific IP address), in a specific port, and starts listening.
In your case the server failed to resolve my.website (because it really doesn't exist) and refused to listen on this address. It isn't one of your IPs!
TL;DR: You must add your desired host to /etc/hosts (Mac, Linux) and map it to 127.0.0.1, your localhost. Now, when the server starts up, it will be able to resolve this host and grab the port.
I'm sorry I can't go into lot's of detail (I already forgot all the details!), but this is roughly it :)

Hosting multiple Node.JS applications recognizing subdomains with a proxy server

I am trying to redirect certain subdomains to a specific port on my ubuntu AWS EC2 virtual server. Already tried it with DNS and that wouldn't work so based on the following topics, Default route using node-http-proxy? and How do I use node.js http-proxy for logging HTTP traffic in a computer?, I was trying to create a Node.JS proxy server with logging. That said I mixed it a bit up together (I'm new to Node.JS, still learning) and made the following script:
var httpProxy = require('http-proxy');
var PORT = 80;
logger = function() {
return function (request, response, next) {
// This will run on each request.
console.log(JSON.stringify(request.headers, true, 2));
next();
}
}
var options = {
// this list is processed from top to bottom, so '.*' will go to
// 'http://localhost:3000' if the Host header hasn't previously matched
router : {
'dev.domain.com': 'http://localhost:8080',
'beta.domain.com': 'http://localhost:8080',
'status.domain.com': 'http://localhost:9000',
'health.domain.com': 'http://localhost:9000',
'log.domain.com': 'http://localhost:9615',
'^.*\.domain\.com': 'http://localhost:8080',
'.*': 'http://localhost:3000'
}
};
// Listen to port 80
httpProxy.createServer(logger(), options).listen(PORT);
console.log("Proxy server started, listening to port" + PORT);
Well what happens is that I keep getting the following error and can't figure out how to put this to work:
$node proxyServer.js
Proxy server started, listening to port80
events.js:72
throw er; // Unhandled 'error' event
^
Error: listen EACCES
at errnoException (net.js:904:11)
at Server._listen2 (net.js:1023:19)
at listen (net.js:1064:10)
at Server.listen (net.js:1138:5)
at ProxyServer.listen (/home/ubuntu/QuantBull-Project/node_modules/http-proxy/lib/http-proxy/index.js:130:16)
at Object.<anonymous> (/home/ubuntu/QuantBull-Project/proxyServer.js:28:43)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
In short I'm trying to receive http request on port 80 and if it came from sub1.domain.com it will be redirected to portA and if it came frome sub2.domain.com it'll be redirected to portB from the same IP adress and both ports are open to the public.
Can someone explain how to fix this and explain why it happens?
Port Access:
As mentioned by the previous answer and comments the port below 1024 can't be opened by a regular user. This can be overcome by following these instruction:
If cat /proc/sys/net/ipv4/ip_forward returns 0 uncomment net.ipv4.ip_forward at the file /etc/sysctl.conf and enable these changes: sudo sysctl -p /etc/sysctl.conf, if it returns 1, skip this step;
Set up forwarding from port 80 to one desired above 1024 (i.e. port 8080): sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080;
Open up the Linux firewall to allow connections on port 80: sudo iptables -A INPUT -p tcp -m tcp --sport 80 -j ACCEPT and sudo iptables -A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
Note: To make these changes stick even when restarting the server you may check the this out.
http-proxy's routefeature is removed:
After taking care of the port access the proxy server continued without working, so after opening an issue it seemed that the routing feature was removed because, according to Nodejitsu Inc.:
The feature was removed due to simplicity. It belongs in a separate module and not in http-proxy itself as http-proxy is just responsible for the proxying bit.
So they recommended to use http-master.
Using http-master:
As described in http-master's README section, node.js is required and we need to run npm install -g http-master (may be needed to run as root depending on your setup). Then we create the config file, i.e. http-master.conf, were we add our routing details and for this specific question, the config file is as followed:
{
# To detect changes made to the config file:
watchConfig: true,
# Enable logging to stdout:
logging: true,
# Here is where the magic happens, definition of our proxies:
ports: {
# because we defined that Port 80 would be redirected to port 8080 before,
# we listen here to that port, could be added more, i.e. for the case of a
# secure connections trough port 443:
8080 : {
proxy: {
# Proxy all traffic for monitor subdomains to port 9000
'status.domain.com' : 9000,
'health.domain.com' : 9000,
# Proxy all traffic for logger subdomains to port 9615
'log.domain.com' : 9615,
# Proxy all traffic from remaining subdomains to port 8000
'*.domain.com' : 8000
},
redirect: {
# redirect .net and .org requests to .com
'domain.net': 'http://domain.com/[path]',
'domain.org': 'http://domain.com/[path]'
}
}
}
}
And we are almost done, now we just run it with: http-master --config http-master.conf and our subdomain routing should be working just fine.
Note: If you want to run the proxy server on the background I recommend using a tool like forever or pm2, and in the case of using pm2 I recommend reading this issue.
If you are running your proxy as a regular user (not root), you can't open ports below 1024. There may be a way to do this as a normal user but usually I just run such things as root.

Categories