Apache và Node.js trên cùng một máy chủ


352

Tôi muốn sử dụng Node vì nó nhanh, sử dụng cùng ngôn ngữ tôi đang sử dụng ở phía máy khách và nó không bị chặn theo định nghĩa. Nhưng anh chàng mà tôi thuê để viết chương trình xử lý tệp (lưu, chỉnh sửa, đổi tên, tải xuống, tải lên tệp, v.v.), anh ta muốn sử dụng apache. Vì vậy, tôi phải:

  1. Thuyết phục anh ta sử dụng Node (anh ta đang từ bỏ chút ít về điều đó)

  2. Tìm hiểu làm thế nào để tải lên, tải xuống, đổi tên, lưu, vv các tập tin trong nút hoặc

  3. Tôi phải cài đặt apache và nút trên cùng một máy chủ.

Đó là tình huống thuận lợi nhất, và làm thế nào để tôi thực hiện điều đó?

Câu trả lời:


704

Câu hỏi tuyệt vời!

Có rất nhiều trang web và ứng dụng web miễn phí được triển khai bằng PHP chạy trên Apache, rất nhiều người sử dụng nó để bạn có thể kết hợp một thứ gì đó khá dễ dàng và bên cạnh đó, đó là cách phục vụ nội dung tĩnh không có trí tuệ. Node là nhanh, mạnh mẽ, thanh lịch và là một công cụ gợi cảm với sức mạnh thô của V8 và một ngăn xếp phẳng không có phụ thuộc được xây dựng.

Tôi cũng muốn sự dễ dàng / linh hoạt của Apache và sự cộc cằn và tao nhã của Node.JS, tại sao tôi không thể có cả hai ?

May mắn thay với chỉ thị ProxyPass trong Apache, httpd.confkhông quá khó để chuyển tất cả các yêu cầu trên một URL cụ thể sang ứng dụng Node.JS của bạn.

ProxyPass /node http://localhost:8000

Ngoài ra, hãy đảm bảo các dòng sau KHÔNG được nhận xét để bạn có được proxy và mô hình con phù hợp để định tuyến lại các yêu cầu http:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Sau đó chạy ứng dụng Node của bạn trên cổng 8000!

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello Apache!\n');
}).listen(8000, '127.0.0.1');

Sau đó, bạn có thể truy cập tất cả logic Node.JS bằng cách sử dụng /node/đường dẫn trên url của mình, phần còn lại của trang web có thể được để lại cho Apache để lưu trữ các trang PHP hiện có của bạn:

nhập mô tả hình ảnh ở đây

Bây giờ điều duy nhất còn lại là thuyết phục công ty lưu trữ của bạn cho phép bạn chạy với cấu hình này !!!


6
Đây là một câu trả lời tuyệt vời, chỉ muốn thêm một liên kết với một ít thông tin hơn về proxy proxy mà tôi đã sử dụng để thực hiện công việc này. Kiểm tra các ý kiến ​​là tốt. boriskuzmanovic.wordpress.com/2006/10/20/ khăn
Alex Muro

11
Tôi đã thử nghiệm đặt "ProxyPass / 127.0.0.1:8000 " bên trong một thùng chứa máy chủ ảo và có thể chuyển hướng thành công toàn bộ một nhóm miền sang một thể hiện nút. Tôi cũng đã thử nghiệm với "time wget ..." để so sánh tốc độ truy cập nút trực tiếp với việc truy cập nó qua Apache. Trong 30 cặp thử nghiệm, sự khác biệt trung bình là khoảng 0,56ms. Thời gian tải thấp nhất là 120ms cho cả trực tiếp và qua Apache. Thời gian tải cao nhất là 154ms cho trực tiếp và 164 qua Apache. Không phải là một sự khác biệt đáng kể. Nếu tôi có hai IP sang trọng, tôi sẽ không định tuyến qua Apache, nhưng bây giờ tôi sẽ gắn bó với Proxypass
kaan_a

5
Không phải proxy này yêu cầu từ Apache đến Node, trong khi nó sẽ lấy đi những lợi ích của bản chất không chặn của Node?
Truy tìm

2
Xin chào @Basj, tôi không có kinh nghiệm cài đặt hỗ trợ cho websockets. Phải nói rằng, Apache 2.4.6 dường như có hỗ trợ cho lưu lượng truy cập websockets bằng cách sử dụng mod_proxy_wstunnel. Tôi thấy bạn đã tìm thấy câu trả lời của mình, đối với những người khác có cùng vấn đề, vui lòng tham khảo: serverfault.com/questions/616370/ Kẻ
Steven de Salas

4
Tôi phải thêm cái này vào đâu trên các bản phân phối dựa trên debian? Không có tệp httpd.conf.
santi

63

Câu hỏi này thuộc về Server Fault nhiều hơn nhưng FWIW tôi muốn nói rằng chạy Apache trước Node.js không phải là một cách tiếp cận tốt trong hầu hết các trường hợp.

ProxyPass của Apache rất tuyệt vời đối với nhiều thứ (như phơi bày các dịch vụ dựa trên Tomcat như một phần của trang web) và nếu ứng dụng Node.js của bạn chỉ thực hiện một vai trò nhỏ, cụ thể hoặc là một công cụ nội bộ chỉ có số lượng người dùng hạn chế sau đó có thể dễ dàng hơn chỉ sử dụng nó để bạn có thể làm cho nó hoạt động và tiếp tục, nhưng điều đó không giống như trường hợp ở đây.

Nếu bạn muốn tận dụng hiệu suất và quy mô, bạn sẽ nhận được từ việc sử dụng Node.js - và đặc biệt nếu bạn muốn sử dụng thứ gì đó liên quan đến việc duy trì kết nối liên tục như ổ cắm web - tốt hơn hết bạn nên chạy cả Apache và Node của bạn. js trên các cổng khác (ví dụ: Apache trên localhost: 8080, Node.js trên localhost: 3000) và sau đó chạy một cái gì đó như nginx, Varnish hoặc HA proxy ở phía trước - và định tuyến lưu lượng theo cách đó.

Với một cái gì đó như véc ni hoặc nginx, bạn có thể định tuyến lưu lượng dựa trên đường dẫn và / hoặc máy chủ lưu trữ. Cả hai đều sử dụng ít tài nguyên hệ thống hơn và có khả năng mở rộng hơn nhiều khi sử dụng Apache để làm điều tương tự.


13
Câu trả lời này nên có nhiều upvote. Cách sử dụng nginx proxy chắc chắn tốt hơn nhiều so với phương pháp apache.
đọc lại

Nhưng nó rất tốn tài nguyên
The Oracle

1
Bạn có một số con số để sao lưu tuyên bố của mình rằng nginx sẽ ít tốn tài nguyên hơn httpd không?
RedShift

Tôi không mặc dù nó khá ấn tượng. Trong khi tôi cố gắng không để liên kết ra trong trả lời là các liên kết là mong manh nhưng bạn có thể tìm thấy một số cuộc thảo luận và các ví dụ thông qua Google - ví dụ help.dreamhost.com/hc/en-us/articles/... ... Apache là phần mềm tuyệt vời nhưng thông thường nó không phải là một cách tiếp cận tuyệt vời trong một bối cảnh như thế này.
Iain Collins

Câu trả lời này nghe có vẻ hay, nhưng sau đó làm thế nào để truy cập Node.js thông qua httpS vì nó đã được Apache sử dụng?
Pierre

34


Hướng dẫn chạy node servercùng apache2(v2.4.xx) server:

Để chuyển tất cả các yêu cầu trên một URL cụ thể sang ứng dụng Node.JS của bạn, hãy tạo CUSTOM.conftệp trong /etc/apache2/conf-availablethư mục và thêm dòng sau vào tệp đã tạo:

ProxyPass /node http://localhost:8000/

Thay đổi 8000 thành số cổng ưa thích cho node server.
Cho phép cấu hình tùy chỉnh với lệnh sau:

$> sudo a2enconf CUSTOM

TÙY CHỈNH là tên tệp mới được tạo của bạn mà không có phần mở rộng, sau đó kích hoạt proxy_httpbằng lệnh:

$> sudo a2enmod proxy_http

cần kích hoạt cả hai proxyproxy_httpmô-đun. Bạn có thể kiểm tra xem mô-đun có được bật hay không bằng:

$> sudo a2query -m MODULE_NAME

Sau khi cấu hình và mô-đun được bật, bạn sẽ cần khởi động lại máy chủ apache:

$> sudo service apache2 restart

Bây giờ bạn có thể thực thi máy chủ nút. Tất cả các yêu cầu đến URL/nodesẽ được xử lý bởi máy chủ nút.


Hoạt động như một lá bùa! :)
Kees Koenen

15

Chạy Node và Apache trên một máy chủ là chuyện nhỏ vì chúng không xung đột. NodeJS chỉ là một cách để thực thi phía máy chủ JavaScript. Vấn đề nan giải thực sự đến từ việc truy cập cả Node và Apache từ bên ngoài. Theo tôi thấy, bạn có hai lựa chọn:

  1. Thiết lập Apache để ủy quyền tất cả các yêu cầu phù hợp với NodeJS, sẽ thực hiện tải lên tệp và bất cứ thứ gì khác trong nút.

  2. Có Apache và Node trên các kết hợp IP: cổng khác nhau (nếu máy chủ của bạn có hai IP, thì một cái có thể được liên kết với trình nghe nút của bạn, cái kia với Apache).

Tôi cũng bắt đầu nghi ngờ rằng đây có thể không phải là thứ bạn đang thực sự tìm kiếm. Nếu mục tiêu cuối cùng của bạn là để bạn viết logic ứng dụng của mình trong Nodejs và một phần "xử lý tệp" mà bạn không tải cho nhà thầu, thì đó thực sự là một lựa chọn ngôn ngữ, không phải máy chủ web.


9

Bạn có thể sử dụng một cách tiếp cận khác nhau, chẳng hạn như viết một máy chủ proxy ngược với nodejs để proxy cả apache và tất cả các ứng dụng nodejs khác.

Trước tiên, bạn cần làm cho apache chạy trên một cổng khác ngoài cổng 80. ví dụ: cổng 8080

Sau đó, bạn có thể viết một tập lệnh proxy ngược với nodejs là:

var proxy = require('redbird')({port: 80, xfwd: false);

proxy.register("mydomain.me/blog", "http://mydomain.me:8080/blog");
proxy.register("mydomain.me", "http://mydomain.me:3000");

Bài viết sau đây mô tả toàn bộ quá trình thực hiện điều này.

CHẠY APACHE VỚI NODE JS REVERSE PROXY - SỬ DỤNG REDBIRD


2
ProxyPass /node http://localhost:8000/     
  • điều này làm việc cho tôi khi tôi thực hiện mục nhập trên trong httpd-vhosts.conf thay vì httpd.conf
  • Tôi đã cài đặt XAMPP trên môi trường của mình và đang tìm cách đạt tất cả lưu lượng truy cập tại apache trên cổng 80 với ứng dụng NodeJS chạy trên cổng 8080, tức là http: // localhost / [name_of_the_node_application]

1

Tôi đã kết hợp câu trả lời ở trên với chứng chỉ SSL certbot và các tiêu đề cho phép kiểm soát truy cập CORS và làm cho nó hoạt động nên tôi nghĩ tôi sẽ chia sẻ kết quả.

Apache httpd.conf được thêm vào dưới cùng của tệp:

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so

Cài đặt Virtualhost của Apache (doc root cho PHP nằm dưới Apache và SSL với Certbot, trong khi trang web node.js / socket.io chạy trên cổng 3000 - và sử dụng chứng chỉ SSL từ Apache) Cũng lưu ý rằng trang web node.js sử dụng proxy cho thư mục / nodejs, socket.io và ws (websockets):

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName www.example.com
    ServerAlias www.example.com
    DocumentRoot /var/html/www.example.com
    ErrorLog /var/html/log/error.log
    CustomLog /var/html/log/requests.log combined
    SSLCertificateFile /etc/letsencrypt/live/www.example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

    RewriteEngine On
    RewriteCond %{REQUEST_URI}  ^socket.io          [NC]
    RewriteCond %{QUERY_STRING} transport=websocket [NC]
    RewriteRule /{.*}       ws://localhost:3000/$1  [P,L]

    RewriteCond %{HTTP:Connection} Upgrade [NC]
    RewriteRule /(.*) ws://localhost:3000/$1 [P,L]

    ProxyPass /nodejs http://localhost:3000/
    ProxyPassReverse /nodejs http://localhost:3000/

    ProxyPass /socket.io http://localhost:3000/socket.io
    ProxyPassReverse /socket.io http://localhost:3000/socket.io

    ProxyPass /socket.io ws://localhost:3000/socket.io
    ProxyPassReverse /socket.io ws://localhost:3000/socket.io

</VirtualHost>
</IfModule>

Sau đó, ứng dụng node.js của tôi (app.js):

var express = require('express');
var app = express();
    app.use(function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Headers", "X-Requested-With");
        res.header("Access-Control-Allow-Headers", "Content-Type");
        res.header("Access-Control-Allow-Methods", "PUT, GET, POST, DELETE, OPTIONS");
        next();
    });
var http = require('http').Server(app);
var io = require('socket.io')(http);

http.listen({host:'0.0.0.0',port:3000});

Tôi buộc người nghe ip4, nhưng đó là tùy chọn - bạn có thể thay thế:

http.listen(3000);

Mã ứng dụng node.js (app.js) tiếp tục với:

io.of('/nodejs').on('connection', function(socket) {
    //optional settings:
    io.set('heartbeat timeout', 3000); 
    io.set('heartbeat interval', 1000);

    //listener for when a user is added
    socket.on('add user', function(data) {
         socket.join('AnyRoomName');
         socket.broadcast.emit('user joined', data);
    });

    //listener for when a user leaves
    socket.on('remove user', function(data) {
         socket.leave('AnyRoomName');
         socket.broadcast.emit('user left', data);
    });

    //sample listener for any other function
    socket.on('named-event', function(data) {
         //code....
         socket.broadcast.emit('named-event-broadcast', data);
    });

    // add more listeners as needed... use different named-events...
});

cuối cùng, về phía máy khách (được tạo dưới dạng nodejs.js):

//notice the /nodejs path
var socket = io.connect('https://www.example.com/nodejs');

//listener for user joined
socket.on('user joined', function(data) {
    // code... data shows who joined...
});

//listener for user left
socket.on('user left', function(data) {
    // code... data shows who left...
});

// sample listener for any function:
socket.on('named-event-broadcast', function(data) {
    // this receives the broadcast data (I use json then parse and execute code)
    console.log('data1=' + data.data1);
    console.log('data2=' + data.data2);
});

// sample send broadcast json data for user joined:
socket.emit('user joined', {
    'userid': 'userid-value',
    'username':'username-value'
});

// sample send broadcast json data for user left 
//(I added the following with an event listener for 'beforeunload'):
// socket.emit('user joined', {
//     'userid': 'userid-value',
//     'username':'username-value'
// });

// sample send broadcast json data for any named-event:
socket.emit('named-event', {
    'data1': 'value1',
    'data2':'value2'
});

Trong ví dụ này khi tải JS, nó sẽ phát ra cho socket một "sự kiện có tên" gửi dữ liệu trong JSON đến máy chủ node.js / socket.io.

Sử dụng io và socket trên máy chủ theo path / nodejs (được kết nối bởi máy khách), nhận dữ liệu và sau đó gửi lại dưới dạng quảng bá. Bất kỳ người dùng nào khác trong ổ cắm sẽ nhận được dữ liệu với trình phát "có tên sự kiện" của người nghe. Lưu ý rằng người gửi không nhận được phát sóng riêng của họ.


0

Gần đây tôi đã gặp phải vấn đề này, nơi tôi cần liên lạc giữa máy khách và máy chủ bằng cách sử dụng websocket trong một dự án codeigniter dựa trên PHP.

Tôi đã giải quyết vấn đề này bằng cách thêm cổng (ứng dụng nút đang chạy) vào Allow incoming TCP ports& Allow outgoing TCP portslist.

Bạn có thể tìm thấy các cấu hình này trong Firewall Configurationsbảng WHM của máy chủ của bạn.


-1

Tôi đã tìm kiếm thông tin tương tự. Cuối cùng đã tìm thấy câu trả lời từ liên kết trên câu trả lời ở trên bởi @Straseus

http://argument.callee.info/2010/04/20/rucky-apache-and-node-js-together/

Đây là giải pháp cuối cùng để chạy trang web apache trên cổng 80, dịch vụ nút js trên cổng 8080 và sử dụng .htaccess RewriteRule

Trong DocumentRoot của trang web apache, hãy thêm vào như sau:

Options +FollowSymLinks -MultiViews

<IfModule mod_rewrite.c>

RewriteEngine on

# Simple URL redirect:
RewriteRule ^test.html$ http://arguments.callee.info:8000/test/ [P]

# More complicated (the user sees only "benchmark.html" in their address bar)
RewriteRule ^benchmark.html$ http://arguments.callee.info:8000/node?action=benchmark [P]

# Redirect a whole subdirectory:
RewriteRule ^node/(.*) http://arguments.callee.info:8000/$1 [P]

Đối với chuyển hướng cấp thư mục, liên kết ở trên đã đề xuất quy tắc (. +), Yêu cầu một hoặc nhiều ký tự sau 'nút /'. Tôi đã phải chuyển đổi nó thành (. *) Không có hoặc nhiều hơn để công cụ của tôi hoạt động.

Cảm ơn rất nhiều về liên kết @Straseus


3
Chỉ cần lưu ý rằng cờ [P] yêu cầu phải bật Apache mod_proxy.
Simon East

Điều này là không hiệu quả. Tại sao gọi công cụ Rewrite đơn giản ProxyPass?
Michael Irigoyen

-2

Tôi giả sử rằng bạn đang tạo một ứng dụng web vì bạn tham khảo Apache và Node. Trả lời nhanh - Có thể - CÓ. Được khuyến nghị - KHÔNG. Node gói máy chủ web của riêng nó và hầu hết các trang web chạy trên cổng 80. Tôi cũng giả sử rằng hiện tại không có plugin Apache nào được Nodejs hỗ trợ và tôi không chắc chắn việc tạo máy chủ ảo có phải là cách tốt nhất để thực hiện việc này không. Đây là những câu hỏi nên được trả lời bởi các nhà phát triển, những người duy trì Nodej như những người tốt ở Joyent.

Thay vì các cổng, sẽ tốt hơn nếu đánh giá ngăn xếp công nghệ của Node hoàn toàn khác với hầu hết các cổng khác và đó là lý do tại sao tôi thích nó nhưng nó cũng liên quan đến một vài thỏa hiệp mà bạn nên biết trước.

Ví dụ của bạn trông tương tự như một CMS hoặc một ứng dụng web chia sẻ và có hàng trăm ứng dụng trong số các ứng dụng có sẵn sẽ chạy tốt trên Apache. Ngay cả khi bạn không thích bất kỳ giải pháp readymade nào, bạn có thể viết một ứng dụng web bằng PHP / Java / Python hoặc trộn n nó với một vài ứng dụng đã sẵn sàng và tất cả chúng đều được thiết kế và hỗ trợ để chạy phía sau một phiên bản Apache duy nhất.

Đã đến lúc tạm dừng và suy nghĩ về những gì tôi vừa nói.

Bây giờ bạn đã sẵn sàng để quyết định xem bạn sẽ sử dụng techstack nào. Nếu trang web của bạn sẽ không bao giờ sử dụng bất kỳ ứng dụng nào trong số hàng ngàn ứng dụng được tạo sẵn yêu cầu Apache, thì hãy truy cập Node nếu không trước tiên bạn phải loại bỏ các giả định mà tôi đã nêu trước đó.

Cuối cùng, sự lựa chọn của bạn về techstack quan trọng hơn bất kỳ thành phần riêng lẻ nào.

Tôi hoàn toàn đồng ý với @Straseus rằng việc sử dụng api hệ thống tệp node.js tương đối tầm thường để xử lý tải lên và tải xuống nhưng hãy suy nghĩ thêm về những gì bạn muốn từ trang web của bạn trong thời gian dài và sau đó chọn techstack của bạn.

Học khung của Node dễ hơn học các khung khác nhưng nó không phải là thuốc chữa bách bệnh. Với một nỗ lực hơn một chút (có thể là một nỗ lực đáng giá trong chính nó), bạn cũng có thể tìm hiểu bất kỳ khuôn khổ nào khác. Tất cả chúng ta đều học hỏi lẫn nhau và bạn sẽ làm việc hiệu quả hơn nếu bạn làm việc như một nhóm nhỏ hơn là khi bạn làm việc một mình và các kỹ năng kỹ thuật phụ trợ của bạn cũng sẽ phát triển nhanh hơn. Do đó, đừng giảm giá các kỹ năng của các thành viên khác trong nhóm của bạn quá rẻ.

Bài đăng này khoảng một năm tuổi và rất có thể bạn đã quyết định nhưng tôi hy vọng rằng lời nói của tôi sẽ giúp người tiếp theo trải qua một quyết định tương tự.

Cảm ơn vì đã đọc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.