¿Cómo puedo alojar varios sitios Node.js en la misma IP / servidor con diferentes dominios?

92

Tengo un servidor Linux con una única IP vinculada. Quiero alojar varios sitios Node.js en este servidor en esta IP, cada uno (obviamente) con un dominio o subdominio único. Los quiero a todos en el puerto 80.

¿Cuáles son mis opciones para hacer esto?

Una solución obvia parece ser que todos los dominios sean atendidos por una aplicación web node.js que actúe como un proxy y pase a las otras aplicaciones node.js que se ejecutan en puertos únicos.

Chico
fuente
4
Hago esto y upstream con nginx, alojamiento virtual basado en nombres. Como beneficio adicional, nginx se puede configurar para servir archivos estáticos, realizar redireccionamientos permanentes, etc.
números1311407

Respuestas:

83

Elija uno de:

  • Utilice algún otro servidor ( como nginx ) como proxy inverso.
  • Utilice node-http-proxy como proxy inverso.
  • Use el middleware vhost si cada dominio puede ser servido desde la misma base de código Connect / Express y la instancia de node.js.
josh3736
fuente
3
esa es una lista muy buena y breve de las opciones que he leído en otros lugares. ¿Conoce usted para cada una de estas soluciones qué procesos deberían reiniciarse cuando se agrega un nuevo dominio? Para 1) ninguno. Para 2) solo el nodo-http-proxy. Para 3) sería necesario reiniciar todo el hilo de todos los sitios. ¿Es esto correcto?
Flion
1
@Flion: podría escribir los proxies basados ​​en nodos de tal manera que pudiera volver a cargar la configuración del dominio sin necesidad de reiniciar el proceso. Realmente depende de los requisitos exactos de su aplicación.
josh3736
No lo que se preguntó.
Patrick Sturm
52

Diet.js tiene una forma muy agradable y sencilla de alojar varios dominios con la misma instancia de servidor. Simplemente puede llamar a uno nuevoserver()para cada uno de sus dominios.

Un ejemplo simple

// Require diet
var server = require('diet');

// Main domain
var app = server()
app.listen('http://example.com/')
app.get('/', function($){
    $.end('hello world ')
})

// Sub domain
var sub = server()
sub.listen('http://subdomain.example.com/')
sub.get('/', function($){
    $.end('hello world at sub domain!')
})

// Other domain
var other = server()
other.listen('http://other.com/')
other.get('/', function($){
    $.end('hello world at other domain')
})

Separando sus aplicaciones

Si desea tener diferentes carpetas para sus aplicaciones, entonces podría tener una estructura de carpetas como esta:

/server
   /yourApp
       /node_modules
       index.js
   /yourOtherApp
       /node_modules
       index.js
   /node_modules
   index.js

En /server/index.jsnecesitaría cada aplicación por su carpeta:

require('./yourApp')
require('./yourOtherApp')

En /server/yourApp/index.js, configuraría su primer dominio como:

// Require diet
var server = require('diet')

// Create app
var app = server()
app.listen('http://example.com/')
app.get('/', function($){
    $.end('hello world ')
})

Y en /server/yourOtherApp/index.js, configuraría su segundo dominio como:

// Require diet
var server = require('diet')

// Create app
var app = server()
app.listen('http://other.com/')
app.get('/', function($){
    $.end('hello world at other.com ')
});

Lee mas:

Adam Halasz
fuente
Este comentario salvó todos mis problemas :) ... incluso en 2016
myTerminal
¿Se recargará automáticamente? Comencé a usar PM2 pero no me permite alojar múltiples dominios y proxy inverso
Pini Cheyni
¿Esto reemplaza al expreso o funciona junto con él? Mi conjetura es cualquiera. Pero quiero estar seguro antes de crear un frankenstein.
Mardok
1
Para su información, a partir de julio de 2019, dietjs.com ya no está activo y no ha habido una actualización del código base de github en ~ 2 años.
sirclesam
20

Hm ... por qué piensas que nodejs debería actuar como un proxy. Sugeriré ejecutar varias aplicaciones de nodo escuchando en diferentes puertos. Luego use nginx para reenviar la solicitud al puerto correcto. Si usa un solo nodejs, también tendrá un solo punto de falla. Si esa aplicación falla, todos los sitios caen.

Krasimir
fuente
12

Tengo una API que uso en un sitio y a continuación se muestra mi configuración. También lo tengo con SSL y GZIP, si alguien lo necesita, solo coméntamelo.

var http = require('http'),
    httpProxy = require('http-proxy');

var proxy_web = new httpProxy.createProxyServer({
        target: {
            host: 'localhost',
            port: 8080
        }
    });

    var proxy_api = new httpProxy.createProxyServer({
        target: {
            host: 'localhost',
            port: 8081
        }
    });

    http.createServer(function(req, res) {
        if (req.headers.host === 'http://www.domain.com') {
            proxy_web.proxyRequest(req, res);
            proxy_web.on('error', function(err, req, res) {
                if (err) console.log(err);
                res.writeHead(500);
                res.end('Oops, something went very wrong...');
            });
        } else if (req.headers.host === 'http://api.domain.com') {
            proxy_api.proxyRequest(req, res);
            proxy_api.on('error', function(err, req, res) {
                if (err) console.log(err);
                res.writeHead(500);
                res.end('Oops, something went very wrong...');
            });
        }
    }).listen(80);
fuelusumar
fuente
7

Si está utilizando el servidor Connect / Express, puede ver el vhost middleware. Permitirá que se utilicen varios dominios (subdominios) para la dirección del servidor.

Puede seguir el ejemplo dado aquí , que se ve exactamente como lo que necesita.

usuario568109
fuente
3

Este es mi proyecto de demostración más simple sin ningún middleware o proxy.
Esto requiere solo unos pocos códigos y es suficiente.

https://github.com/hitokun-s/node-express-multiapp-demo

Con esta estructura, puede configurar y mantener fácilmente cada aplicación de forma independiente.
Espero que esto sea de ayuda para ti.

toshi
fuente
3

Primero instale para siempre y rebotando .

Luego escribe un script de inicio. En este script, agregue una regla a la utilidad de firewall de iptables para indicarle que reenvíe el tráfico en el puerto 80 al puerto 8000 (o cualquier otra cosa que elija). En mi ejemplo, 8000 es donde corro bouncy

sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8000

Usando para siempre, digamos al script que se ejecute bouncy en el puerto 8000

forever start --spinSleepTime 10000 /path/to/bouncy /path/to/bouncy/routes.json 8000

El route.json sería algo como

{
    subdomain1.domain.com" : 5000,
    subdomain2.domain.com" : 5001,
    subdomain3.domain.com" : 5002
}

NodeJS application1, application2 y application3 se ejecutan en los puertos 5000, 5001 y 5002 respectivamente.

El script que utilizo en mi caso se puede encontrar aquí y es posible que deba cambiar un poco para adaptarse a su entorno.

También escribí sobre esto con más detalles y lo puedes encontrar aquí .

Kevin Le - Khnle
fuente
Debe verificar PM2
Pini Cheyni
ok, esto es genial, pero ¿cómo puedo forzar http-> https en bouncy?
2

A continuación, le indicamos cómo hacerlo con Vanilla Node.js:

const http = require('http')
const url = require('url')
const port = 5555
const sites = {
  exampleSite1: 544,
  exampleSite2: 543
}

const proxy = http.createServer( (req, res) => {
  const { pathname:path } = url.parse(req.url)
  const { method, headers } = req
  const hostname = headers.host.split(':')[0].replace('www.', '')
  if (!sites.hasOwnProperty(hostname)) throw new Error(`invalid hostname ${hostname}`)

  const proxiedRequest = http.request({
    hostname,
    path,
    port: sites[hostname],
    method,
    headers 
  })

  proxiedRequest.on('response', remoteRes => {
    res.writeHead(remoteRes.statusCode, remoteRes.headers)  
    remoteRes.pipe(res)
  })
  proxiedRequest.on('error', () => {
    res.writeHead(500)
    res.end()
  })

  req.pipe(proxiedRequest)
})

proxy.listen(port, () => {
  console.log(`reverse proxy listening on port ${port}`)
})

Bastante simple, ¿eh?

papiro
fuente
1

literalmente, cuando obtiene el objeto de solicitud y respuesta, puede obtener el dominio a través de "request.headers.host" ... (no la ip, en realidad el dominio)

Michaaatje
fuente
0

Esta guía del océano digital es una excelente manera. Utiliza el módulo pm2 que demoniza su aplicación (los ejecuta como un servicio). No se necesitan módulos adicionales como Forever, ya que reiniciará su aplicación automáticamente si falla. Tiene muchas características que lo ayudan a monitorear las diversas aplicaciones que se ejecutan en su servidor. ¡Es bastante impresionante!

Isaac Pak
fuente