«Node.js» и «HAPROXY. Работаем ssl to ssl с генерацией сертификатов отдельно на каждом сервере»: разница между страницами

Материал из support.qbpro.ru
(Различия между страницами)
imported>Vix
Нет описания правки
 
imported>Vix
(Новая страница: «'''В рамках данного туториала настроим реверс прокси для работы наших сайтов в прозрачно...»)
 
Строка 1: Строка 1:
process.nextTick(callback) - Гарантированно вызовет функцию callback в следующем цикле eventloop
'''В рамках данного туториала настроим реверс прокси для работы наших сайтов в прозрачном режиме за 10 минут. Поехали.'''
==Документация JsDoc==
[http://usejsdoc.org/ jdoc]
==Серверный JavaScript==
[[Руководство NodeJS]]
[[Node.js Virtual Machine (vm) Usage (перевод)]]
===Node.JS Parent Process ID===
Is it possible to get the parent process-id using Node.JS? I would like to detect if the parent is killed or fails in such a way that it cannot notify the child. If this happens, the parent process id of the child should become 1.


This would be preferable to requiring the parent to periodically send a keep-alive signal and also preferable to running the ps command.
@Emmerman: I'm not sure what you mean. The parent runs require('child_process').spawn(process.argv[0], ['path_to_child.js']) in order to start the child. Then if it needs to talk to the child, it uses the stdin and stdout of the child. stderr is piped to a log. I am guessing the answer would be yes?


*You can use pid-file. Something like that
Мною была поставлена задача что бы на моем сервере под руководством Proxmox с пулом сайтов работала без проблем прозрачная маршрутизация между посетителем и конечным сайтом. Т.к. в инете полно мануалов по базовой настройке Haproxy я столкнулся с проблемой что 99% этих статей описывают работ прокси сервера в режиме терминации а дальше информация идет по не защищенному варианту (от прокси до конечной ВМ). Меня это не устроило и я начал искать по крупицам информацию в сети. К сожалению в нашем русскоязычном сегменте ее мало (читай нет) пришлось шерстить буржуйский сегмент. Конечный результат предлагаю вашему вниманию, думаю кому ни будь он точно сгодится.


<nowiki>var util = require('util'),
<syntaxhighlight lang="shell" line='line'>
    fs = require('fs'),
global
    pidfile = '/var/run/nodemaster.pid';
log /dev/log    local0
log /dev/log    local1 notice
stats socket /haproxy-admin.sock mode 660 level admin
stats timeout 30s
daemon
defaults
maxconn 2000
mode http       
log global
option dontlognull # bind *:443 ssl crt .
option http-server-close
timeout http-request 10s
timeout connect        5000
timeout client          50000
timeout server        50000
frontend stats
bind *:5000
stats enable
stats uri /stats
stats refresh 10s
stats auth admin:mysupersecretpassword #поменяйте на свой пароль
</syntaxhighlight>
Блок отвечающий за работу ssl на ssl
<syntaxhighlight lang="shell" line='line'>
frontend env_ssl_frontend
bind *:443
mode tcp
option tcplog
tcp-request inspect-delay 10s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend bk_app1 if { req.ssl_sni -m end site1.ru }
use_backend bk_app2 if { req.ssl_sni -m end counter.site1.ru }
use_backend bk_app3 if { req.ssl_sni -m end site2.com } 
use_backend bk_app4 if { req.ssl_sni -m end site3.msk.ru }
use_backend bk_app5 if { req.ssl_sni -m end site4.ru }
use_backend bk_app6 if { req.ssl_sni -m end site5.msk.ru }


try {
backend bk_app1
    var pid = fs.readFileSync(pidfile);
mode tcp
    //REPLACE with your signal or use another method to check process existence :)
balance leastconn
    process.kill(pid, 'SIGUSR2');
option tcp-check  
    util.puts('Master already running');
server main 192.168.1.26:443 send-proxy check
    process.exit(1);
} catch (e) {
    fs.writeFileSync(pidfile, process.pid.toString(), 'ascii');
}


//run your childs here</nowiki>
backend bk_app2
mode tcp
balance leastconn
option tcp-check
server main 192.168.1.38:443 send-proxy check


==Библиотеки==
backend bk_app3
===Socket.IO===
mode tcp
balance leastconn
option tcp-check
server main 192.168.1.37:443 send-proxy check


Socket.IO is a Node.JS project that makes WebSockets and realtime possible in all browsers. It also enhances WebSockets by providing built-in multiplexing, horizontal scalability, automatic JSON encoding/decoding, and more.
backend bk_app4
mode tcp
balance leastconn
option tcp-check
server main 192.168.1.100:443 check


'''Установка'''
backend bk_app5
mode tcp
balance leastconn
option tcp-check
server main 192.168.1.31:443 send-proxy check


  npm install socket.io
backend bk_app6
balance leastconn
mode tcp
option tcp-check
server main 192.168.1.200:443 check
  </syntaxhighlight>
Блок отвечающий за работу сайтов на 80 порту
<syntaxhighlight lang="shell" line='line'>
frontend public
        bind *:80


'''Использование'''
        # бок сайтов
        acl host_subdomain1 hdr(host) -i site1.ru
        acl host_subdomain2 hdr(host) -i counter.site1.ru
        acl host_subdomain3 hdr(host) -i site2.com
        acl host_subdomain4 hdr(host) -i site3.msk.ru
        acl host_subdomain5 hdr(host) -i site4.ru
        acl host_subdomain6 hdr(host) -i site5.msk.ru
        ## блок acl
        use_backend subdomain1 if host_subdomain1
        use_backend subdomain2 if host_subdomain2
        use_backend subdomain3 if host_subdomain3
        use_backend subdomain4 if host_subdomain4
        use_backend subdomain5 if host_subdomain5
        use_backend subdomain6 if host_subdomain6


First, require socket.io:
backend subdomain1
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-1 192.168.1.26:80 check


var io = require('socket.io');
backend subdomain2
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-2 192.168.1.37:80 check


Next, attach it to a HTTP/HTTPS server. If you're using the fantastic express web framework:
backend subdomain3
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-3 192.168.1.31:80 check


Express 3.x
backend subdomain4
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-4 192.168.1.100:80 check


<nowiki>var app = express()
backend subdomain5
  , server = require('http').createServer(app)
        option httpclose
  , io = io.listen(server);
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-5 192.168.1.200:80 check


server.listen(80);
backend subdomain6
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-6 192.168.1.38:80 check   
</syntaxhighlight>
Что мы получили в итоге:


io.sockets.on('connection', function (socket) {
Генерация ssl сертификатов происходит на каждом сайте отдельно. Терминации на прокси сервере нет, идет прозрачное перенаправление на конечную машину которая и отдает посетителю свой ssl сертификат.
  socket.emit('news', { hello: 'world' });
Проблем с Яндексом и его роботом дятлом (который мониторит сайт на доступность) не имеем.
  socket.on('my other event', function (data) {
Имеем быстрый и корректный отклик конечной машины для посетителей и поисковиков.
    console.log(data);
В качестве небольшого бонуса, имеем страничку с статистикой работы прокси сервера и сайтов которые он обслуживает. Для этого перейдите на ip (например у меня 192.168.1.150:5000) на котором он работает с портом 5000 и наслаждайтесь. Логин admin а пароль который вы сами установили в верхней секции этого конфига.
  });
});</nowiki>


* Отдельно хочу сделать замечание касаемо этого файла конфигурации Haproxy.


Finally, load it from the client side code:
Весьма вероятно, что когда вы добавите в свой пул сайтов на PROXMOKS-e еще N кол-во виртуальных машин и вам понадобится получить сертификат с Letsencrypt, у вас может не получится это, тк Haproxy не сможет корректно отработать запрос и от вашей машины и к вашей машине.
В таком случае (под диванного сервера) сделайте выход c роутера (или что там у вас) проброс портов на новую ВМ, хотя бы 80 порт и после получения сертификата верните обратно. По крайней мере я так вышел из этой ситуации. Подробнее о проблеме описано по ссылке


<nowiki><script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script></nowiki>


For more thorough examples, look at the examples/ directory.
Как всегда, приветствуются конструктивные предложения и замечания.


'''Примеры использования'''
Всем успехов!


Sending and receiving events.


Socket.IO allows you to emit and receive custom events. Besides connect, message and disconnect, you can emit custom events:
PS Сам реверс прокси у меня поднят и прекрасно себя чувствует на Ubuntu 18.04 которая идет в шаблонах Proxmox-a. По началу я его запускал в режиме полноценной виртуалки но это решение себя не оправдало тк потребляло изрядную процессорную и прочие ресурсы хост машины. С переводом прокси сервера на LXC контейнер потребление по ресурсам упало почти до пары единиц процентов ресурсов хост машины и можно сказать что ничего не потребляет.


// note, io.listen(<port>) will create a http server for you
* [https://habr.com/ru/post/540212/ взято тут]
var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  io.sockets.emit('this', { will: 'be received by everyone' });
 
  socket.on('private message', function (from, msg) {
    console.log('I received a private message by ', from, ' saying ', msg);
  });
 
  socket.on('disconnect', function () {
    io.sockets.emit('user disconnected');
  });
});
Storing data associated to a client
 
Sometimes it's necessary to store data associated with a client that's necessary for the duration of the session.
 
Server side
 
var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  socket.on('set nickname', function (name) {
    socket.set('nickname', name, function () { socket.emit('ready'); });
  });
 
  socket.on('msg', function () {
    socket.get('nickname', function (err, name) {
      console.log('Chat message by ', name);
    });
  });
});
Client side
 
<script>
  var socket = io.connect('http://localhost');
 
  socket.on('connect', function () {
    socket.emit('set nickname', prompt('What is your nickname?'));
    socket.on('ready', function () {
      console.log('Connected !');
      socket.emit('msg', prompt('What is your message?'));
    });
  });
</script>
Restricting yourself to a namespace
 
If you have control over all the messages and events emitted for a particular application, using the default / namespace works.
 
If you want to leverage 3rd-party code, or produce code to share with others, socket.io provides a way of namespacing a socket.
 
This has the benefit of multiplexing a single connection. Instead of socket.io using two WebSocket connections, it'll use one.
 
The following example defines a socket that listens on '/chat' and one for '/news':
 
Server side
 
var io = require('socket.io').listen(80);
 
var chat = io
  .of('/chat')
  .on('connection', function (socket) {
    socket.emit('a message', { that: 'only', '/chat': 'will get' });
    chat.emit('a message', { everyone: 'in', '/chat': 'will get' });
  });
 
var news = io
  .of('/news');
  .on('connection', function (socket) {
    socket.emit('item', { news: 'item' });
  });
Client side:
 
<script>
  var chat = io.connect('http://localhost/chat')
    , news = io.connect('http://localhost/news');
 
  chat.on('connect', function () {
    chat.emit('hi!');
  });
 
  news.on('news', function () {
    news.emit('woot');
  });
</script>
Sending volatile messages.
 
Sometimes certain messages can be dropped. Let's say you have an app that shows realtime tweets for the keyword bieber.
 
If a certain client is not ready to receive messages (because of network slowness or other issues, or because he's connected through long polling and is in the middle of a request-response cycle), if he doesn't receive ALL the tweets related to bieber your application won't suffer.
 
In that case, you might want to send those messages as volatile messages.
 
Server side
 
var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  var tweets = setInterval(function () {
    getBieberTweet(function (tweet) {
      socket.volatile.emit('bieber tweet', tweet);
    });
  }, 100);
 
  socket.on('disconnect', function () {
    clearInterval(tweets);
  });
});
Client side
 
In the client side, messages are received the same way whether they're volatile or not.
 
Getting acknowledgements
 
Sometimes, you might want to get a callback when the client confirmed the message reception.
 
To do this, simply pass a function as the last parameter of .send or .emit. What's more, when you use .emit, the acknowledgement is done by you, which means you can also pass data along:
 
Server side
 
var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  socket.on('ferret', function (name, fn) {
    fn('woot');
  });
});
Client side
 
<script>
  var socket = io.connect(); // TIP: .connect with no args does auto-discovery
  socket.on('connect', function () { // TIP: you can avoid listening on `connect` and listen on events directly too!
    socket.emit('ferret', 'tobi', function (data) {
      console.log(data); // data will be 'woot'
    });
  });
</script>
Broadcasting messages
 
To broadcast, simply add a broadcast flag to emit and send method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
 
Server side
 
var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  socket.broadcast.emit('user connected');
  socket.broadcast.json.send({ a: 'message' });
});
Rooms
 
Sometimes you want to put certain sockets in the same room, so that it's easy to broadcast to all of them together.
 
Think of this as built-in channels for sockets. Sockets join and leave rooms in each socket.
 
Server side
 
var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  socket.join('justin bieber fans');
  socket.broadcast.to('justin bieber fans').emit('new fan');
  io.sockets.in('rammstein fans').emit('new non-fan');
});
Using it just as a cross-browser WebSocket
 
If you just want the WebSocket semantics, you can do that too. Simply leverage send and listen on the message event:
 
Server side
 
var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  socket.on('message', function () { });
  socket.on('disconnect', function () { });
});
Client side
 
<script>
  var socket = io.connect('http://localhost/');
  socket.on('connect', function () {
    socket.send('hi');
 
    socket.on('message', function (msg) {
      // my msg
    });
  });
</script>
Changing configuration
 
Configuration in socket.io is TJ-style:
 
Server side
 
var io = require('socket.io').listen(80);
 
io.configure(function () {
  io.set('transports', ['websocket', 'flashsocket', 'xhr-polling']);
});
 
io.configure('development', function () {
  io.set('transports', ['websocket', 'xhr-polling']);
  io.enable('log');
});
====Перевод документации с оф. сайта====
'''Использование Node HTTP server'''
 
Установить npm install socket.io
 
'''''SERVER (APP.JS)'''''
 
<nowiki>var app = require('http').createServer(handler)
  , io = require('socket.io').listen(app)
  , fs = require('fs')
app.listen(80);
function handler (req, res) {
  fs.readFile(__dirname + '/index.html',
  function (err, data) {
    if (err) {
      res.writeHead(500);
      return res.end('Error loading index.html');
    }
    res.writeHead(200);
    res.end(data);
  });
}
io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});</nowiki>
 
'''''CLIENT (INDEX.HTML)'''''
 
<nowiki><script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
 
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script></nowiki>
 
'''Использование совместно с Express 3 web framework'''
 
Express 3 requires that you instantiate a `http.Server` to attach socket.io to first:
 
 
'''''SERVER (APP.JS)'''''
 
var app = require('express')()
  , server = require('http').createServer(app)
  , io = require('socket.io').listen(server);
server.listen(80);
app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});
 
io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});
 
'''''CLIENT (INDEX.HTML)'''''
 
<nowiki><script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
 
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script></nowiki>
 
'''Использование совместно с  Express web framework'''
 
You can serve normal pages and AJAX requests with Express, and attach your socket.io server
 
For this example, simply run `npm install socket.io express`
 
'''''SERVER (APP.JS)'''''
 
var app = require('express').createServer()
  , io = require('socket.io').listen(app);
app.listen(80);
app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function (socket) {
  socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});
 
'''''CLIENT (INDEX.HTML)'''''
 
<nowiki><script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script></nowiki>
 
'''Отправка и прием событий.'''
 
Socket.IO позволяет обрабатывать и отправлять произвольные события. Кроме `connect`, `message` and `disconnect`, можно создавать произвольные события:
 
'''''SERVER'''''
 
// note, io.listen(<port>) will create a http server for you
var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
  io.sockets.emit('this', { will: 'be received by everyone'});
  socket.on('private message', function (from, msg) {
    console.log('I received a private message by ', from, ' saying ', msg);
  });
  socket.on('disconnect', function () {
    io.sockets.emit('user disconnected');
  });
});
 
'''Прикрепление данных, ассоциированных с клиентом'''
 
Иногда необходимо хранить данные, ассоциированные с клиентом, что необходимо для продолжении (duration) сессии.
 
'''''SERVER'''''
<nowiki>var io = require('socket.io').listen(80);
io.sockets.on('connection', function (socket) {
  socket.on('set nickname', function (name) {
    socket.set('nickname', name, function () {
      socket.emit('ready');
    });
  });
  socket.on('msg', function () {
    socket.get('nickname', function (err, name) {
      console.log('Chat message by ', name);
    });
  });
});
</nowiki>
'''''CLIENT'''''
<nowiki><script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script></nowiki>
 
'''Оборачивание себя (своего кода) в namespace.'''
 
Если вы контролируете все сообщения и события в коде, используйте namespace works по умолчанию (default namespace works)
Если вы хотите использовать сторонний код или предоставлять код другим, socket.io предоставляет возможность использования именованных сокетов (namespacing a socket.)
 
Это полезно при мультиплексировании соединений. Вместо использования двух соединений WebSocket, будет использовано одно.
 
''''SERVER'''''
 
<nowiki>var io = require('socket.io').listen(80);
 
var chat = io
  .of('/chat')
  .on('connection', function (socket) {
    socket.emit('a message', {
        that: 'only'
      , '/chat': 'will get'
    });
    chat.emit('a message', {
        everyone: 'in'
      , '/chat': 'will get'
    });
  });
 
var news = io
  .of('/news')
  .on('connection', function (socket) {
    socket.emit('item', { news: 'item' });
  });</nowiki>
'''''CLIENT'''''
 
<nowiki><script>
  var chat = io.connect('http://localhost/chat')
    , news = io.connect('http://localhost/news');
 
  chat.on('connect', function () {
    chat.emit('hi!');
  });
 
  news.on('news', function () {
    news.emit('woot');
  });
</script></nowiki>
 
'''Отправка летучих (volatile) сообщений.'''
 
Иногда некоторые сообщения могут быть удалены (отброшены). Скажем, у вас есть приложение, которое показывает в реальном времени количество твитов по ключевому слову Бибер.
 
Если определенный клиент не готов к приему сообщений (из-за медлительности сети или других вопросов, или потому, что он связан через длинные голосования и находится в середине запрос-ответ цикла), если он не получит всех твитов, связанных с Бибер, то ваша заявка не будет страдать.
 
В этом случае, вы можете отправить эти сообщения, как летучие сообщений.
 
'''''SERVER'''''
 
<nowiki>var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  var tweets = setInterval(function () {
    getBieberTweet(function (tweet) {
      socket.volatile.emit('bieber tweet', tweet);
    });
  }, 100);
 
  socket.on('disconnect', function () {
    clearInterval(tweets);
  });
});</nowiki>
 
'''Отправка и получение данных (подтверждения)'''
 
Иногда, вы можете получить обратный вызов, когда клиент подтвердил прием сообщения.
 
Чтобы сделать это, просто передать функцию в качестве последнего параметра  `.send` или `.emit`. Более того, когда вы используете `.emit`, подтверждение было сделано вами, значит, вы также можете продолжить передавать данные.
 
'''''SERVER'''''
 
<nowiki>var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  socket.on('ferret', function (name, fn) {
    fn('woot');
  });
});</nowiki>
 
'''''CLIENT'''''
 
<nowiki><script>
  var socket = io.connect(); // TIP: .connect with no args does auto-discovery
  socket.on('connect', function () { // TIP: you can avoid listening on `connect` and listen on events directly too!
    socket.emit('ferret', 'tobi', function (data) {
      console.log(data); // data will be 'woot'
    });
  });
</script></nowiki>
 
'''Broadcasting messages.'''
 
To broadcast, simply add a `broadcast` flag to `emit` and `send` method calls. Broadcasting means sending a message to everyone else except for the socket that starts it.
 
'''''SERVER'''''
 
<nowiki>var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  socket.broadcast.emit('user connected');
});</nowiki>
 
'''Using it just as a cross-browser WebSocket.'''
 
If you just want the WebSocket semantics, you can do that too. Simply leverage `send` and listen on the `message` event:
 
'''''SERVER'''''
 
<nowiki>var io = require('socket.io').listen(80);
 
io.sockets.on('connection', function (socket) {
  socket.on('message', function () { });
  socket.on('disconnect', function () { });
});</nowiki>
 
'''''CLIENT'''''
 
<nowiki><script>
  var socket = io.connect('http://localhost/');
  socket.on('connect', function () {
    socket.send('hi');
 
    socket.on('message', function (msg) {
      // my msg
    });
  });
</script></nowiki>
 
====Примеры кода====
 
http://kuroikaze85.wordpress.com/2010/06/15/socket-io-node-js-game-making/
[http://www.ibm.com/developerworks/ru/library/cl-nodejscloud/ Применение Node.js в качестве полной среды разработки для облачных решений]
<hr>
==Официальная документция==
 
 
* [http://nodejs.org/api/modules.html nodejs.org]
 
* [http://nodeguide.ru/doc/  Руководства по Node.js от Felix’а]
 
* [http://nodebeginner.ru/ Руководства по Node.js упрощенное...]
 
* [http://vremenno.net/js/node-js-for-beginners/ примеры начинающим]
 
==АКСИОМЫ NODE.JS==
Callback-driven парадигма
 
Неблокирующая функция принимает callback последним аргументом:
 
<nowiki>function asuncFunction(arg1,arg2,...,argN, callback){
 
}</nowiki>
 
Callback принимает ошибку первым аргументом, остальные результат:
 
<nowiki>function callback(error, result1,result2,...resultN){
 
}</nowiki>
 
==Кластер==
[[Кластер на основе NodeJS]] -
 
==Примеры архитектуры==
[[Tactoom.com изнутри — социальная блог-платформа на NodeJS/NoSQL]]
 
==Обработка форм и визуализации через NodeJs==
 
[http://nodejs.ru/665]http://nodejs.ru/665
 
[http://habrahabr.ru/post/138629/]http://habrahabr.ru/post/138629/
 
[http://nodeguide.ru/doc/dailyjs-nodepad/node-tutorial-7/]http://nodeguide.ru/doc/dailyjs-nodepad/node-tutorial-7/
 
[http://habrahabr.ru/post/147571/]http://habrahabr.ru/post/147571/
 
[http://www.pvsm.ru/node-js/12212]http://www.pvsm.ru/node-js/12212
 
[http://www.pixelcom.crimea.ua/rukovodstvo-po-html5-canvas.html]http://www.pixelcom.crimea.ua/rukovodstvo-po-html5-canvas.html
 
:[[Установка node.js в Debian]]
 
*Express: веб-фреймворк для Node.js. Руководство пользователя
[http://jsman.ru/express/]http://jsman.ru/express/
 
* Руководство для начинающих
[http://vremenno.net/js/node-js-for-beginners/]http://vremenno.net/js/node-js-for-beginners/
 
*Скелет приложения на Node.js с использованием express, mongoose, backbone.js, socket.io
[http://kulakowka.com/tag/express/]http://kulakowka.com/tag/express/
 
*Русскоязычное сообщество Node.js
[http://forum.nodejs.ru/index.php?topic=130.0]http://forum.nodejs.ru/index.php?topic=130.0
 
*[http://www.pvsm.ru/node-js/16286 Установка node.js на VPS]
 
==Технологии спутники==
Перечень модулей  для Node.js https://github.com/joyent/node/wiki/modules
===Node-sync===
[[Node-sync_—_псевдо-синхронное_программирование_на_nodejs_с_использованием_fibers]]
===socket.io===
* [http://socket.io/ socket.io] [[socket.io документация]]
* [http://blog.denivip.ru/index.php/2012/11/разработка-высокопроизводительных-с/ webSocketServer ru]
 
===Express===
*[http://jsman.ru/express/#quickstart Express: веб-фреймворк для Node.js. Руководство пользователя][[Express: веб-фреймворк для Node.js. Руководство пользователя|Сохраненная копия]]
 
==Отладка и сборка==
*[http://nodejs.ru/324 Отладчик ndb]
*[http://jsman.ru/2012/08/24/browserify.html Browserify - cобираем JS-проект]
*[[JavaScript Strict Mode]]
 
==Примеры кода==
===Цепочка вызывающих себя через callback'и функций с передачей данных следующей функции (обработка ошибок в одном месте, массив функций в качестве параметра)===
 
С использованием async это пишется так:
 
<nowiki>var async = require('async');
 
async.waterfall([
    function(callback){
        setTimeout(function() {
            console.log('f1 done');
            callback(null, 'data from f1');
        }, 100);
    },
    function(data, callback){
        // работа с data
        // или расширение цепочки через функцию f3, которая по окончании работы вызовет callback
        // f3(callback);
        console.log('f2 done');
        callback(null, 'done');
    }
], function (err, result) {
    // result now equals 'done'
    if (err) {
        // единое место для отлова ошибок
    }
    console.log(result);
});</nowiki>
 
== Дополнительные возможности nodejs ==
 
* [http://docs.nodejitsu.com/articles/child-processes/how-to-spawn-a-child-process вызов сторонних команд]
* [[Node js & Подключение модулей без явного использования require или аналог namespace]]
 
== Полезные ресурсы ==
* [http://nodejs.org/download/ node.js]
* [http://nodejs.ru/707 коротко о всех командах node.js]
<br>
* [http://www.askdev.ru/blog/nodejs/54/Отличное-руководство-для-начинающих-по-Node-js/ полезное на старте.]
* [http://vremenno.net/js/node-js-for-beginners/ примеры кода]
* [http://habrahabr.ru/post/102717/ примеры с Хабра]
* [http://drumcoder.co.uk/blog/2011/jan/10/nodejs-phone-book/ пример работы с postgresql]
<br>
* [http://jade-lang.com/ .. не все понял но здорово.."шаблнизатор"]
* [https://github.com/visionmedia/jade#readme описание шаблонизатора..]
* [http://www.mongodb.org/ база данных под node.js]
* [http://www.pvsm.ru/web-razrabotka/2198/print/ то что нужно знать!]
* [http://www.slideshare.net/yurabogdanov/nodejs-8223169 профи советы]
* [http://habrahabr.ru/post/130345/ чужой опыт...]
* [http://habrahabr.ru/post/138071/ еще чужой опыт...]
<hr>
''''''Отладка в Node.Js''''''
* [https://github.com/ajaxorg/cloud9 среда разработки для node.js]
* [https://github.com/dannycoates/node-inspector отлачик для node.js]
* [http://habrahabr.ru/post/114825/ использование node-inspector]
* [http://nodejs.ru/doc/v0.4.x/debugger.html встроенный отладчик]
* [http://nodejs.ru/324 Ndb отладка в node]
<hr>
* [[Node.js debian init.script]]
<hr>
'''''@модули для node.js'''''
* [http://thechangelog.com/stylus-expressive-robust-feature-rich-css-language/ stylus - работа со стилями через nod.js]
 
== Запуск приложений node.js в Linux Debian/Ubuntu через /etc/init.d ==
[[Daemon init script for node.js based app/server (DEBIAN/UBUNTU)]]
 
==10 типичных ошибок Node.js разработчиков==
* [https://makeomatic.ru/blog/2015/05/25/10_mistakes_2_node/ 10 типичных ошибок Node.js разработчиков (Часть 2)]
 
==Официальная документация nodejs на русском==
*[https://js-node.ru/site/article?id=20 nodejs - rus]
*[https://medium.com/@evilj0e/%D0%BC%D0%B0%D1%81%D1%88%D1%82%D0%B0%D0%B1%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-node-js-b575bd5e47e#.v28lno7uk Масштабирование - Recluster]
*[http://www.w3ii.com/ru/nodejs/nodejs_domain_module.html w3ii.com]

Текущая версия от 19:27, 30 ноября 2021

В рамках данного туториала настроим реверс прокси для работы наших сайтов в прозрачном режиме за 10 минут. Поехали.


Мною была поставлена задача что бы на моем сервере под руководством Proxmox с пулом сайтов работала без проблем прозрачная маршрутизация между посетителем и конечным сайтом. Т.к. в инете полно мануалов по базовой настройке Haproxy я столкнулся с проблемой что 99% этих статей описывают работ прокси сервера в режиме терминации а дальше информация идет по не защищенному варианту (от прокси до конечной ВМ). Меня это не устроило и я начал искать по крупицам информацию в сети. К сожалению в нашем русскоязычном сегменте ее мало (читай нет) пришлось шерстить буржуйский сегмент. Конечный результат предлагаю вашему вниманию, думаю кому ни будь он точно сгодится.

global
log /dev/log    local0
log /dev/log    local1 notice
stats socket /haproxy-admin.sock mode 660 level admin
stats timeout 30s
daemon
defaults
maxconn 2000
mode http        
log global
option dontlognull # bind *:443 ssl crt .
option http-server-close
timeout http-request 10s
timeout connect         5000
timeout client          50000
timeout server         50000
frontend stats
bind *:5000
stats enable
stats uri /stats
stats refresh 10s
stats auth admin:mysupersecretpassword #поменяйте на свой пароль

Блок отвечающий за работу ssl на ssl

frontend env_ssl_frontend
bind *:443
mode tcp
option tcplog
tcp-request inspect-delay 10s
tcp-request content accept if { req_ssl_hello_type 1 }
use_backend bk_app1 if { req.ssl_sni -m end site1.ru }
use_backend bk_app2 if { req.ssl_sni -m end counter.site1.ru }
use_backend bk_app3 if { req.ssl_sni -m end site2.com }  
use_backend bk_app4 if { req.ssl_sni -m end site3.msk.ru }
use_backend bk_app5 if { req.ssl_sni -m end site4.ru }
use_backend bk_app6 if { req.ssl_sni -m end site5.msk.ru }

backend bk_app1
mode tcp
balance leastconn
option tcp-check 
server main 192.168.1.26:443 send-proxy check

backend bk_app2
mode tcp
balance leastconn
option tcp-check
server main 192.168.1.38:443 send-proxy check

backend bk_app3
mode tcp
balance leastconn
option tcp-check
server main 192.168.1.37:443 send-proxy check

backend bk_app4
mode tcp
balance leastconn
option tcp-check
server main 192.168.1.100:443 check

backend bk_app5
mode tcp
balance leastconn
option tcp-check
server main 192.168.1.31:443 send-proxy check

backend bk_app6
balance leastconn
mode tcp
option tcp-check
server main 192.168.1.200:443 check

Блок отвечающий за работу сайтов на 80 порту

frontend public
        bind *:80

        # бок сайтов
        acl host_subdomain1 hdr(host) -i site1.ru 
        acl host_subdomain2 hdr(host) -i counter.site1.ru
        acl host_subdomain3 hdr(host) -i site2.com
        acl host_subdomain4 hdr(host) -i site3.msk.ru
        acl host_subdomain5 hdr(host) -i site4.ru
        acl host_subdomain6 hdr(host) -i site5.msk.ru
        ## блок acl 
        use_backend subdomain1 if host_subdomain1
        use_backend subdomain2 if host_subdomain2
        use_backend subdomain3 if host_subdomain3
        use_backend subdomain4 if host_subdomain4
        use_backend subdomain5 if host_subdomain5
        use_backend subdomain6 if host_subdomain6

backend subdomain1
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-1 192.168.1.26:80 check

backend subdomain2
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-2 192.168.1.37:80 check

backend subdomain3
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-3 192.168.1.31:80 check

backend subdomain4
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-4 192.168.1.100:80 check

backend subdomain5
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-5 192.168.1.200:80 check

backend subdomain6
        option httpclose
        option forwardfor
        cookie JSESSIONID prefix
        server subdomain-6 192.168.1.38:80 check

Что мы получили в итоге:

Генерация ssl сертификатов происходит на каждом сайте отдельно. Терминации на прокси сервере нет, идет прозрачное перенаправление на конечную машину которая и отдает посетителю свой ssl сертификат. Проблем с Яндексом и его роботом дятлом (который мониторит сайт на доступность) не имеем. Имеем быстрый и корректный отклик конечной машины для посетителей и поисковиков. В качестве небольшого бонуса, имеем страничку с статистикой работы прокси сервера и сайтов которые он обслуживает. Для этого перейдите на ip (например у меня 192.168.1.150:5000) на котором он работает с портом 5000 и наслаждайтесь. Логин admin а пароль который вы сами установили в верхней секции этого конфига.

  • Отдельно хочу сделать замечание касаемо этого файла конфигурации Haproxy.

Весьма вероятно, что когда вы добавите в свой пул сайтов на PROXMOKS-e еще N кол-во виртуальных машин и вам понадобится получить сертификат с Letsencrypt, у вас может не получится это, тк Haproxy не сможет корректно отработать запрос и от вашей машины и к вашей машине. В таком случае (под диванного сервера) сделайте выход c роутера (или что там у вас) проброс портов на новую ВМ, хотя бы 80 порт и после получения сертификата верните обратно. По крайней мере я так вышел из этой ситуации. Подробнее о проблеме описано по ссылке


Как всегда, приветствуются конструктивные предложения и замечания.

Всем успехов!


PS Сам реверс прокси у меня поднят и прекрасно себя чувствует на Ubuntu 18.04 которая идет в шаблонах Proxmox-a. По началу я его запускал в режиме полноценной виртуалки но это решение себя не оправдало тк потребляло изрядную процессорную и прочие ресурсы хост машины. С переводом прокси сервера на LXC контейнер потребление по ресурсам упало почти до пары единиц процентов ресурсов хост машины и можно сказать что ничего не потребляет.