Bagaimana cara saya menghosting beberapa situs Node.js di IP / server yang sama dengan domain berbeda?

95

Saya memiliki server linux dengan satu IP terikat padanya. Saya ingin meng-host beberapa situs Node.js di server ini pada IP ini, masing-masing (jelas) dengan domain atau subdomain yang unik. Saya ingin semuanya di port 80.

Apa pilihan saya untuk melakukan ini?

Solusi yang jelas tampaknya memiliki semua domain yang dilayani oleh aplikasi web node.js yang bertindak sebagai proxy dan melakukan penerusan ke aplikasi node.js lain yang berjalan pada port unik.

Orang
sumber
4
Saya melakukan ini dan upstream dengan nginx, hosting virtual berbasis nama. Sebagai bonus, nginx dapat dikonfigurasi untuk melayani file statis, melakukan pengalihan perm, dll.
numbers1311407

Jawaban:

85

Pilih salah satu dari:

  • Gunakan beberapa server lain ( seperti nginx ) sebagai proxy terbalik.
  • Gunakan node-http-proxy sebagai proxy balik.
  • Gunakan middleware vhost jika setiap domain dapat disajikan dari basis kode Connect / Express dan instance node.js yang sama.
josh3736
sumber
3
itu adalah daftar pilihan yang sangat bagus dan singkat yang pernah saya baca di tempat lain. Apakah Anda kebetulan mengetahui untuk masing-masing solusi ini, proses mana yang perlu dimulai ulang saat domain baru ditambahkan? Untuk 1) tidak ada. Untuk 2) hanya node-http-proxy. Untuk 3) seluruh utas semua situs perlu direstart. Apakah ini benar?
Flion
1
@Flion: Anda dapat menulis proxy berbasis node sedemikian rupa sehingga Anda dapat memuat ulang konfigurasi domain tanpa memerlukan proses restart. Itu benar-benar tergantung pada persyaratan pasti aplikasi Anda.
josh3736
Bukan apa yang diminta.
Patrick Sturm
52

Diet.js memiliki cara yang sangat bagus dan sederhana untuk menghosting beberapa domain dengan server yang sama. Anda cukup memanggil yang baruserver()untuk setiap domain Anda.

Contoh Sederhana

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

Memisahkan Aplikasi Anda

Jika Anda ingin memiliki folder berbeda untuk aplikasi Anda, Anda dapat memiliki struktur folder seperti ini:

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

Di /server/index.jsAnda akan membutuhkan setiap aplikasi dengan foldernya:

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

Di /server/yourApp/index.jsAnda akan mengatur domain pertama Anda seperti:

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

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

Dan /server/yourOtherApp/index.jsAnda akan mengatur domain kedua Anda seperti:

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

Baca lebih banyak:

Adam Halasz
sumber
Komentar ini menyelamatkan semua masalah saya :) ... bahkan pada 2016
myTerminal
Apakah ini akan dimuat ulang secara otomatis? Saya mulai menggunakan PM2 tetapi PM2 tidak memungkinkan saya untuk meng-host beberapa domain dan membalikkan proxy
Pini Cheyni
Apakah ini menggantikan express, atau bekerja di sampingnya? Tebakan saya juga. Tapi saya ingin memastikan sebelum saya membuat frankenstein.
Mardok
1
FYI Mulai Juli 2019 - dietjs.com tidak aktif lagi dan belum ada pembaruan untuk basis kode github dalam ~ 2 tahun.
sirclesam
21

Hm ... mengapa Anda berpikir bahwa nodejs harus bertindak sebagai proxy. Saya akan menyarankan untuk menjalankan beberapa aplikasi node yang mendengarkan di port yang berbeda. Kemudian gunakan nginx untuk meneruskan permintaan ke port yang benar. Jika menggunakan satu nodejs Anda juga akan memiliki satu titik kegagalan. Jika aplikasi itu mogok maka semua situs akan mati.

Krasimir
sumber
13

Saya memiliki API yang saya gunakan di situs dan di bawah ini adalah konfigurasi saya. Saya juga memilikinya dengan SSL dan GZIP, jika seseorang membutuhkannya, beri komentar saja.

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.dll
sumber
7

Jika Anda menggunakan koneksi / server ekspres, Anda dapat melihat vhostmiddleware. Ini akan memungkinkan beberapa domain (sub-domain) untuk digunakan sebagai alamat server.

Anda dapat mengikuti contoh yang diberikan di sini , yang terlihat persis seperti yang Anda butuhkan.

pengguna568109
sumber
5

Berikut cara melakukannya menggunakan 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}`)
})

Cukup sederhana, ya?

papiro
sumber
4

Instal pertama selamanya dan goyang .

Kemudian tulis skrip startup. Dalam skrip ini, tambahkan aturan ke utilitas firewall iptables untuk memintanya meneruskan lalu lintas pada port 80 ke port 8000 (atau apa pun yang Anda pilih). Dalam contoh saya, 8000 adalah tempat saya menjalankan goyang

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

Menggunakan selamanya, beri tahu skrip untuk menjalankan bouncy pada port 8000

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

Routes.json akan menyukai

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

NodeJS application1, application2 dan application3 masing-masing dijalankan pada port 5000, 5001, dan 5002.

Skrip yang saya gunakan dalam kasus saya dapat ditemukan di sini dan Anda mungkin harus sedikit mengubah agar sesuai dengan lingkungan Anda.

Saya juga menulis tentang ini lebih detail dan Anda dapat menemukannya di sini .

Kevin Le - Khnle
sumber
Anda harus memeriksa PM2
Pini Cheyni
ok ini bagus, tapi bagaimana cara memaksa http-> https dalam keadaan goyang ??
3

Ini adalah proyek demo paling sederhana saya tanpa middleware atau proxy.
Ini hanya membutuhkan sedikit kode, dan itu sudah cukup.

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

Dengan struktur ini, Anda dapat dengan mudah menyiapkan dan mengelola setiap aplikasi secara mandiri.
Saya harap ini bisa membantu Anda.

toshi
sumber
2

Secara harfiah, ketika Anda mendapatkan objek permintaan dan respons, Anda bisa mendapatkan domain melalui "request.headers.host" ... (bukan alamat IP, sebenarnya domain).

Michaaatje
sumber
1

Berdasarkan @Michaaatje dan @papiro, caranya sangat mudah:

Katakanlah Anda memiliki beberapa halaman biasa seperti ...

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

.. dan seterusnya.

Katakanlah domain utamanya adalah "abc.test.com"

Tetapi Anda memiliki domain "alternatif" (mungkin untuk pelanggan) yaitu "customers.test.com".

Cukup tambahkan ini ...

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

dan semudah ini ...

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

Terima kasih kepada @Michaaatje dan @papiro.

Gendut
sumber
0

Ini panduan dari laut digital adalah cara terbaik. Ia menggunakan modul pm2 yang membuat aplikasi Anda menjadi daemonisasi (menjalankannya sebagai layanan). Tidak perlu modul tambahan seperti Forever, karena itu akan memulai ulang aplikasi Anda secara otomatis jika macet. Ini memiliki banyak fitur yang membantu Anda memantau berbagai aplikasi yang berjalan di server Anda. Ini sangat luar biasa!

Isaac Pak
sumber
1
Apakah PM2 mendengarkan pada port 80?
Guy
@Guy Di bagian bawah panduan ini adalah bagian tentang menyiapkan proxy terbalik dengan nginx yang akan mengekspos pm2 ke port 80
Isaac Pak
Saya menggunakan PM2 di banyak proyek. Ini produk hebat. Saya hanya salah memahami jawaban Anda karena pertanyaan asli di sini agak berbeda dan saya pikir Anda menyiratkan bahwa itu memenuhi kebutuhan itu. Terima kasih.
Guy