Jak hostować wiele witryn Node.js na tym samym adresie IP / serwerze z różnymi domenami?


95

Mam serwer linux z przypisanym pojedynczym adresem IP. Chcę hostować wiele witryn Node.js na tym serwerze pod tym adresem IP, z których każda (oczywiście) ma unikalną domenę lub subdomenę. Chcę je wszystkie w porcie 80.

Jakie mam możliwości, aby to zrobić?

Oczywistym rozwiązaniem wydaje się być obsługa wszystkich domen przez aplikację sieciową node.js, która działa jako serwer proxy i przechodzi do innych aplikacji node.js działających na unikalnych portach.


4
Robię to i korzystam z nginx, wirtualnego hostingu opartego na nazwach. Jako bonus nginx można skonfigurować do obsługi plików statycznych, przekierowań perm itp.
— Numery1311407

Odpowiedzi:


85

Wybierz jedną z:


3
to bardzo dobra i krótka lista opcji, które przeczytałem gdzie indziej. Czy wiesz, dla każdego z tych rozwiązań, które procesy będą wymagały ponownego uruchomienia po dodaniu nowej domeny? Dla 1) brak. 2) tylko węzeł-http-proxy. W przypadku 3) cały wątek wszystkich witryn musiałby zostać zrestartowany. Czy to jest poprawne?
— Flion,

1
@Flion: Możesz napisać serwery proxy oparte na węzłach w taki sposób, aby można było ponownie załadować konfigurację domeny bez konieczności ponownego uruchamiania procesu. To naprawdę zależy od dokładnych wymagań aplikacji.
— josh3736,

Nie to, o co pytano.
— Patrick Sturm

52

Diet.js oferuje bardzo przyjemny i prosty sposób na hostowanie wielu domen na tej samej instancji serwera. Możesz po prostu nazwać nowyserver()dla każdej ze swoich domen.

Prosty przykład

// 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')
})

Oddzielanie aplikacji

Jeśli chcesz mieć różne foldery dla swoich aplikacji, możesz mieć taką strukturę folderów:

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

W /server/index.jswymagałbyś każdej aplikacji według jej folderu:

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

W /server/yourApp/index.jsbyś Konfiguracja swoją pierwszą domenę , takich jak:

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

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

A w /server/yourOtherApp/index.jstym skonfigurowałbyś swoją drugą domenę, taką jak:

// 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 ')
});

Czytaj więcej:


Ten komentarz uratował wszystkie moje problemy :) ... nawet w 2016 roku
— myTerminal

Czy to załaduje się automatycznie? Zacząłem używać PM2, ale nie pozwala mi to hostować wielu domen i zwrotnego proxy
— Pini Cheyni

Czy to zastępuje ekspres, czy działa razem z nim? Zgaduję, że też. Ale chcę mieć pewność, zanim utworzę frankenstein.
— Mardok,

1
Do Twojej wiadomości Od lipca 2019 - dietjs.com już nie działa i od około 2 lat nie było aktualizacji bazy kodów na githubie.
— sirclesam

21

Hm ... dlaczego uważasz, że nodejs powinien działać jako proxy. Zasugeruję uruchomienie kilku aplikacji węzłów nasłuchujących na różnych portach. Następnie użyj nginx, aby przekazać żądanie do odpowiedniego portu. Jeśli użyjesz jednego nodejs, będziesz miał również pojedynczy punkt awarii. Jeśli ta aplikacja ulegnie awarii, wszystkie witryny przestaną działać.



13

Mam interfejs API, którego używam w witrynie, a poniżej znajduje się moja konfiguracja. Ja też mam to z SSL i GZIP, jak ktoś tego potrzebuje to po prostu skomentuj.

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);

7

Jeśli używasz serwera connect / express, możesz zobaczyć vhostoprogramowanie pośredniczące. Pozwoli to na użycie wielu domen (subdomen) dla adresu serwera.

Możesz postępować zgodnie z podanym tutaj przykładem , który wygląda dokładnie tak, jak potrzebujesz.


5

Oto jak to zrobić za pomocą waniliowego 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}`)
})

Całkiem proste, co?


4

Najpierw zainstaluj na zawsze i sprężysty .

Następnie napisz skrypt startowy. W tym skrypcie dodaj regułę do narzędzia zapory ogniowej iptables, aby przekazać mu ruch na porcie 80 do portu 8000 (lub cokolwiek innego, co wybierzesz). W moim przykładzie 8000 to miejsce, w którym biegnę bouncy

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

Używając forever, powiedzmy skryptowi, aby uruchomił bouncy na porcie 8000

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

Routes.json coś podobnego

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

NodeJS aplikacja1, aplikacja2 i aplikacja3 działają odpowiednio na portach 5000, 5001 i 5002.

Skrypt, którego używam w moim przypadku, można znaleźć tutaj i być może będziesz musiał trochę zmienić, aby dopasować się do swojego środowiska.

O tym też pisałem bardziej szczegółowo i możesz go znaleźć tutaj .


Powinieneś sprawdzić PM2
— Pini Cheyni

ok to jest super, ale jak mogę wymusić http-> https w bouncy ??

3

To jest mój najprostszy projekt demonstracyjny bez żadnego oprogramowania pośredniego ani serwera proxy.
Wymaga to tylko kilku kodów i to wystarczy.

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

Dzięki tej strukturze możesz łatwo konfigurować i utrzymywać każdą aplikację niezależnie.
Mam nadzieję, że to byłoby dla ciebie pomocne.


2

Dosłownie, gdy otrzymasz obiekt żądania i odpowiedzi, możesz uzyskać domenę za pośrednictwem „request.headers.host”… (nie adresu IP, a właściwie domeny).


1

Oparty na @Michaaatje i @papiro, bardzo łatwy sposób:

Załóżmy, że masz typowe strony, takie jak ...

var app = express()
app.use(sess)
app.use(passport.initialize())
app.use(passport.session())
app.use('/static', express.static('static'))

app.get('/', ensureLoggedIn("/loginpage"), function(req, res, next) {
    ...
})

app.get('/sales', ensureLoggedIn("/loginpage"), function(req, res, next) {
    ...
})

app.get('/about', ensureLoggedIn("/loginpage"), function(req, res, next) {
    ...
})

app.post('/order', ensureLoggedIn("/loginpage"), urlencodedParser, (req, res) => {
    ...
})

.. i tak dalej.

Powiedzmy, że domena główna to „abc.test.com”

Ale masz „alternatywną” domenę (być może dla klientów), którą jest „customers.test.com”.

Po prostu dodaj to ...

var app = express()
app.use(sess)
app.use(passport.initialize())
app.use(passport.session())
app.use('/static', express.static('static'))

app.use((req, res, next) => {
    req.isCustomer = false
    if (req.headers.host == "customers.test.com") {
        req.isCustomer = true
    }
    next();
})

a potem to jest takie proste ...

app.get('/', ensureLoggedIn("/loginpage"), function(req, res, next) {
    if (req.isCustomer) {
        .. special page or whatever ..
        return
    }
    ...
})

app.get('/sales', ensureLoggedIn("/loginpage"), function(req, res, next) {
    if (req.isCustomer) {
        res.redirect('/') .. for example
        return
    }
    ...
})

app.get('/about', ensureLoggedIn("/loginpage"), function(req, res, next) {
    if (req.isCustomer) { ... }
    ...
})

app.post('/order', ensureLoggedIn("/loginpage"), urlencodedParser, (req, res) => {
    if (req.isCustomer) { ... }
    ...
})

Dzięki @Michaaatje i @papiro.


0

Ten przewodnik po cyfrowym oceanie to doskonały sposób. Używa modułu pm2, który demonizuje twoją aplikację (uruchamia je jako usługę). Nie ma potrzeby stosowania dodatkowych modułów, takich jak Forever, ponieważ w przypadku awarii automatycznie uruchomi ponownie aplikację. Posiada wiele funkcji, które pomagają monitorować różne aplikacje działające na serwerze. To niesamowite!


1
Czy PM2 nasłuchuje na porcie 80?
— Guy

@Guy Na dole przewodnika znajduje się sekcja dotycząca konfigurowania zwrotnego serwera proxy z nginx, który wystawi pm2 na port 80
— Isaac Pak

Używam PM2 w wielu projektach. To świetny produkt. Po prostu źle zrozumiałem twoją odpowiedź, ponieważ oryginalne pytanie było nieco inne i myślałem, że sugerujesz, że zaspokoiło tę potrzebę. dzięki.
— Guy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.