Farklı etki alanlarıyla aynı IP / sunucuda birden çok Node.js sitesini nasıl barındırırım?


95

Tek bir IP'ye bağlı bir linux sunucum var. Bu IP üzerinde bu sunucuda, her biri (açıkça) benzersiz bir etki alanına veya alt etki alanına sahip birden çok Node.js sitesini barındırmak istiyorum. Hepsini 80 numaralı bağlantı noktasında istiyorum.

Bunu yapmak için seçeneklerim nelerdir?

Bariz bir çözüm, tüm etki alanlarının bir proxy görevi gören ve benzersiz bağlantı noktalarında çalışan diğer node.js uygulamalarına geçiş yapan bir node.js web uygulaması tarafından hizmet verilmiş olması gibi görünüyor.


4
Bunu ve upstream'i nginx, isme dayalı sanal barındırma ile yapıyorum. Bonus olarak nginx, statik dosyalar sunmak, yönlendirmelere izin vermek vb. İçin yapılandırılabilir
numbers1311407

Yanıtlar:


85

Aşağıdakilerden birini seçin:


3
bu, başka bir yerde okuduğum seçeneklerin çok iyi ve kısa bir listesi. Bu çözümlerin her biri için, yeni bir alan eklendiğinde hangi işlemlerin yeniden başlatılması gerektiğini biliyor musunuz? 1 için) yok. 2 için) yalnızca düğüm-http-proxy. 3) için, tüm sitelerin tüm iş parçacığı yeniden başlatılmalıdır. Bu doğru mu?
Flion

1
@Flion: Düğüm tabanlı proxy'leri, işlemin yeniden başlatılmasına gerek kalmadan etki alanı yapılandırmasını yeniden yükleyebileceğiniz şekilde yazabilirsiniz. Gerçekten uygulamanızın tam gereksinimlerine bağlıdır.
josh3736

Sorulan değil.
Patrick Sturm

52

Diet.js , aynı sunucu örneğiyle birden çok etki alanını barındırmanın çok güzel ve basit bir yolunu sunar. server()Her alanınız içinyeni bir çağrı yapabilirsiniz.

Basit Bir Örnek

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

Uygulamalarınızı Ayırma

Uygulamalarınız için farklı klasörlere sahip olmak istiyorsanız, aşağıdaki gibi bir klasör yapısına sahip olabilirsiniz:

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

İçinde /server/index.jsher uygulamayı kendi klasörüne göre isteyeceksiniz:

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

In /server/yourApp/index.jssize olur kurulum ilk alan gibi:

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

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

Ve /server/yourOtherApp/index.jssizde aşağıdaki gibi ikinci alanınızı kurarsınız:

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

Daha fazla oku:


Bu yorum tüm sorunlarımı kurtardı :) ... 2016'da bile
myTerminal

Bu otomatik olarak yeniden yüklenecek mi? PM2 kullanmaya başladım ancak birden fazla alan adı barındırmama ve proxy'yi ters
çevirmeme

Bu ifade yerine mi yoksa onunla birlikte mi çalışıyor? Benim tahminim de öyle. Ama bir frankenstein yaratmadan önce emin olmak istiyorum.
Mardok

1
Bilginize Temmuz 2019 itibariyle - dietjs.com artık yok ve yaklaşık 2 yıldır github kod tabanında bir güncelleme yapılmadı.
sirclesam

21

Hm ... neden nodej'lerin bir proxy gibi davranması gerektiğini düşünüyorsun. Farklı bağlantı noktalarında dinleyen birkaç düğüm uygulaması çalıştırmanızı önereceğim. Ardından isteği doğru bağlantı noktasına iletmek için nginx'i kullanın. Tek bir düğüm kullanırsanız, ayrıca tek bir hata noktasına sahip olacaksınız. Bu uygulama çökerse, tüm siteler kapanır.



13

Bir sitede kullandığım bir API var ve aşağıda benim yapılandırmam var. Ayrıca SSL ve GZIP ile de sahibim, birinin ihtiyacı olursa bana yorum yapın.

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

Connect / express server kullanıyorsanız, vhostara yazılımı görebilirsiniz . Sunucu adresi için birden fazla alanın (alt alanların) kullanılmasına izin verecektir.

Tam olarak ihtiyacınız olana benzeyen burada verilen örneği takip edebilirsiniz .


5

Vanilla Node.js kullanarak bunu nasıl yapacağınız aşağıda açıklanmıştır:

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}`)
})

Oldukça basit, ha?


4

İlk önce sonsuza kadar yükleyin ve zıplayın .

Ardından bir başlangıç ​​komut dosyası yazın. Bu komut dosyasında, iptables güvenlik duvarı yardımcı programına 80 numaralı bağlantı noktasındaki trafiği 8000 numaralı bağlantı noktasına (veya seçtiğiniz herhangi bir şeye) iletmesini söyleyen bir kural ekleyin. Örneğimde 8000, sıçrayan koştuğum yer

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

Sonsuza kadar kullanarak, betiğe 8000 numaralı bağlantı noktasında hemen çıkarak çalışmasını söyleyelim

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

Route.json bir şey ister

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

NodeJS application1, application2 ve application3 sırasıyla 5000, 5001 ve 5002 numaralı bağlantı noktalarında çalışır.

Benim durumumda kullandığım komut dosyası burada bulunabilir ve ortamınıza uyması için biraz değişiklik yapmanız gerekebilir.

Bunu daha ayrıntılı olarak da yazdım ve burada bulabilirsiniz .



tamam bu harika, ancak http-> https'yi bouncy'e nasıl zorlayabilirim?


2

Kelimenin tam anlamıyla, istek ve yanıt nesnesini aldığınızda, etki alanını "request.headers.host" ... aracılığıyla alabilirsiniz (IP adresi değil, aslında etki alanı).


1

@Michaaatje ve @papiro'ya göre çok kolay bir yol:

Diyelim ki bazı tipik sayfalarınız var ...

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) => {
    ...
})

.. ve bunun gibi.

Ana etki alanının "abc.test.com" olduğunu varsayalım

Ancak, "müşteriler.test.com" olan bir "alternatif" etki alanınız (belki müşteriler için) vardır.

Bunu ekleyin ...

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

ve sonra bu kadar kolay ...

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) { ... }
    ...
})

@Michaaatje ve @papiro'ya teşekkürler.


0

Dijital okyanustan alınan bu rehber mükemmel bir yoldur. Uygulamanızı arka plana atan (bir hizmet olarak çalıştıran) pm2 modülünü kullanır. Forever gibi ek modüllere gerek yok çünkü çökerse uygulamanızı otomatik olarak yeniden başlatacaktır. Sunucunuzda çalışan çeşitli uygulamaları izlemenize yardımcı olan birçok özelliğe sahiptir. Oldukça harika!


1
PM2 80 numaralı bağlantı noktasını dinliyor mu?
Guy

@Guy Kılavuzun altında, pm2'yi 80 numaralı bağlantı noktasına maruz bırakacak nginx ile ters bir proxy kurma hakkında bir bölüm var
Isaac Pak

PM2'yi birçok projede kullanıyorum. Harika bir ürün. Buradaki asıl soru biraz farklı olduğu için cevabınızı yanlış anladım ve bu ihtiyacı karşıladığını ima ettiğinizi düşündüm. Teşekkürler.
Guy
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.