如何使用Nginx在Ubuntu14.04上部署Meteor.js应用程序

来自菜鸟教程
跳转至:导航、​搜索

关于 Meteor.js

Meteor.js 是一个 JavaScript 框架,它允许 Web 开发人员编写一次 JavaScript 代码并在客户端和服务器端重用它。 这要归功于 Meteor 独特的构建过程(阅读有关 构建应用程序代码和代码共享 的更多信息)。 这也解决了在开发模式(开发人员编码和调试)和生产模式之间需要复杂部署过程的问题,这对于面向公众的应用程序版本来说足够安全. Meteor 框架为客户端代码和服务器代码以及开发和生产提供了一种密切相关的方式。 这可能是客户端开发人员开始处理服务器端代码的最简单方法!

要查看实际情况,您可能需要查看 Meteor 网站上的介绍性 视频

Meteor.js 允许您开发项目,如网站(Web 应用程序)、基于 HTML5 的 Web 浏览器应用程序(使用 AppCache)或移动应用程序(通过与 PhoneGap 集成)。 您所需要的只是 Javascript 和 HTML 知识。 Meteor 包括对 MongoDB(一种 NoSQL 数据库)的支持。 Atmosphere 托管的软件包可以为您的应用程序提供完整的构建块,从而进一步加快开发速度。

在本教程结束时,我们将拥有:

  • 安装 Meteor.js
  • 创建了一个部署包,其中包含生产就绪格式的整个 Meteor 应用程序(减去 Web 服务器和数据库后端)
  • 安装 Nginx 作为我们的 Web 服务器,将 HTTP 请求传递给 Meteor
  • 安装 MongoDB 作为我们的数据库引擎
  • 使用 Upstart 管理我们的应用程序
  • 为 Meteor 数据库配置每日数据库备份

在本教程中,如果您还没有自己的 Meteor 应用程序,您可以使用 Meteor 网站 中的“Todo List”示例应用程序。

在你开始之前

你应该有:

  • 单独开发计算机上的现有 Meteor 应用程序(您可以查看示例“Todo List”应用程序 here;教程稍后提供说明)

  • 全新的 Ubuntu 14.04 服务器; 现有的 Meteor 安装在大多数情况下应该可以工作

  • root 访问服务器执行命令

  • 更新了软件包列表。 执行:

     apt-get update
  • todos.net 替换为您实际使用的域名(如果您没有域并且将使用 IP 地址,则将其保留)

  • todos(不带 .net)替换为您的应用程序的名称

第 1 步 — 设置 Nginx Web 服务器

我们将安装和设置 Nginx,因为它允许我们使用 SSL 加密 Web 流量,这是 Meteor 的内置 Web 服务器不提供的功能。 Nginx 还将让我们在同一台服务器上为其他网站提供服务,并过滤和记录流量。

在我们的配置中,我们将使用 SSL 证书保护我们的站点,并将所有流量从 HTTP 重定向到 HTTPS。 我们还将利用一些新的安全实践来增强 SSL 连接的安全性。

为了安装 Nginx,我们执行:

apt-get install nginx

/etc/nginx/sites-available中创建一个虚拟主机配置文件。

下面是一个带注释的配置文件,我们可以将其创建为 /etc/nginx/sites-available/todos,其内容如下。 所有配置设置的说明都包含在文件的注释中:

server_tokens off; # for security-by-obscurity: stop displaying nginx version

# this section is needed to proxy web-socket connections
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

# HTTP
server {
    listen 80 default_server; # if this is not a default server, remove "default_server"
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html; # root is irrelevant
    index index.html index.htm; # this is also irrelevant

    server_name todos.net; # the domain on which we want to host the application. Since we set "default_server" previously, nginx will answer all hosts anyway.

    # redirect non-SSL to SSL
    location / {
        rewrite     ^ https://$server_name$request_uri? permanent;
    }
}

# HTTPS server
server {
    listen 443 ssl spdy; # we enable SPDY here
    server_name todos.net; # this domain must match Common Name (CN) in the SSL certificate

    root html; # irrelevant
    index index.html; # irrelevant

    ssl_certificate /etc/nginx/ssl/todos.pem; # full path to SSL certificate and CA certificate concatenated together
    ssl_certificate_key /etc/nginx/ssl/todos.key; # full path to SSL key

    # performance enhancement for SSL
    ssl_stapling on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 5m;

    # safety enhancement to SSL: make sure we actually use a safe cipher
    ssl_prefer_server_ciphers on;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK';

    # config to enable HSTS(HTTP Strict Transport Security) https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security
    # to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping
    add_header Strict-Transport-Security "max-age=31536000;";

    # If your application is not compatible with IE <= 10, this will redirect visitors to a page advising a browser update
    # This works because IE 11 does not present itself as MSIE anymore
    if ($http_user_agent ~ "MSIE" ) {
        return 303 https://browser-update.org/update.html;
    }

    # pass all requests to Meteor
    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade; # allow websockets
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header X-Forwarded-For $remote_addr; # preserve client IP

        # this setting allows the browser to cache the application in a way compatible with Meteor
        # on every applicaiton update the name of CSS and JS file is different, so they can be cache infinitely (here: 30 days)
        # the root path (/) MUST NOT be cached
        if ($uri != '/') {
            expires 30d;
        }
    }
}

如果您想根据需要调整配置文件并获得更多说明,请查看 Nginx 虚拟主机 上的本教程。

从虚拟主机配置文件中可以看出,Nginx 将需要有效的 SSL 证书和 /etc/nginx/ssl 中的密钥。 我们需要创建这个目录并保护它:

mkdir /etc/nginx/ssl
chmod 0700 /etc/nginx/ssl

然后我们可以在上面配置中定义的位置创建包含证书(和链证书,如果需要)和密钥的文件:

  • 证书:/etc/nginx/ssl/todos.pem
  • 键:/etc/nginx/ssl/todos.key

如果您还没有 SSL 证书和密钥,您现在应该使用此 为 Nginx 创建自签名 SSL 证书的教程创建自签名证书。 请记住,您需要使用配置文件中的相同名称,例如 todos.key 作为密钥名称,todos.pem 作为证书名称。 虽然自签名证书适用于测试,但建议使用商业签名证书进行生产使用。 自签名证书将引发连接到 ssl_stapling 的 Nginx 警告,并在 Web 浏览器中发出安全警告。

完成创建或获取证书后,请确保您拥有上述 todos.pemtodos.key 文件。

接下来,我们应该禁用默认虚拟主机:

rm /etc/nginx/sites-enabled/default

并启用我们的 Meteor 虚拟主机:

ln -s /etc/nginx/sites-available/todos /etc/nginx/sites-enabled/todos

测试 vhost 配置是否无错误(如果您有自签名证书,您将看到与 ssl_stapling 相关的错误;这没关系):

nginx -t

如果一切看起来都不错,我们可以将更改应用到 Nginx:

nginx -s reload

此时,您可以使用网络浏览器访问 https://todos.net(或您的 IP 地址)。 它将向我们显示 502 Bad Gateway。 没关系,因为我们还没有运行 Meteor!

第二步——建立一个 MongoDB 数据库

我们将从常规的 Ubuntu 存储库安装 MongoDB。 标准配置应该没问题。 连接到数据库不需要身份验证,但只能从 localhost 进行连接。 这意味着没有外部连接是可能的,因此数据库是安全的,只要我们没有不受信任的用户通过 SSH 访问系统。

安装 MongoDB 服务器包:

apt-get install mongodb-server

这是我们运行 MongoDB 所需要做的一切。 为了确保无法从外部主机访问,我们执行以下操作以确保 MongoDB 绑定到 127.0.0.1。 用这个命令检查:

netstat -ln | grep -E '27017|28017'

预期输出:

tcp        0      0 127.0.0.1:27017         0.0.0.0:*               LISTEN
tcp        0      0 127.0.0.1:28017         0.0.0.0:*               LISTEN
unix  2      [ ACC ]     STREAM     LISTENING     6091441  /tmp/mongodb-27017.sock

为了在出现问题时提供每日备份,我们可以 可选地 安装一个简单的命令作为每日 cron 作业。 创建文件/etc/cron.d/mongodb-backup

@daily root mkdir -p /var/backups/mongodb; mongodump --db todos --out /var/backups/mongodb/$(date +'\%Y-\%m-\%d')

第 3 步 — 安装 Meteor 应用程序

首先,我们需要安装 Node.js。 由于 Meteor 通常需要比标准存储库中的版本更新的 Node.js 版本,我们将使用自定义 PPA (在撰写本文时,Ubuntu 14.04 提供 nodejs=0.10.25~dfsg2-2ubuntu1 而 Meteor 0.8 .3 需要 Node.js 0.10.29 或更高版本)

执行以下命令以使用 Node.js 添加 PPA,并按 Enter 确认:

add-apt-repository ppa:chris-lea/node.js

输出:

 Evented I/O for V8 javascript. Node's goal is to provide an easy way to build scalable network programs
 More info: https://launchpad.net/~chris-lea/+archive/ubuntu/node.js
Press [ENTER] to continue or ctrl-c to cancel adding it

gpg: keyring `/tmp/tmphsbizg3u/secring.gpg' created
gpg: keyring `/tmp/tmphsbizg3u/pubring.gpg' created
gpg: requesting key C7917B12 from hkp server keyserver.ubuntu.com
gpg: /tmp/tmphsbizg3u/trustdb.gpg: trustdb created
gpg: key C7917B12: public key "Launchpad chrislea" imported
gpg: Total number processed: 1
gpg:               imported: 1  (RSA: 1)
OK

现在我们必须刷新存储库缓存,然后我们可以安装 Node.js 和 npm(Node.js 包管理器):

apt-get update
apt-get install nodejs

以普通用户身份运行我们的 Meteor 应用程序是一个好习惯。 因此,我们将专门为此目的创建一个新的系统用户:

adduser --disabled-login todos

输出:

Adding user `todos' ...
Adding new group `todos' (1001) ...
Adding new user `todos' (1001) with group `todos' ...
Creating home directory `/home/todos' ...
Copying files from `/etc/skel' ...
Changing the user information for todos
Enter the new value, or press ENTER for the default
        Full Name []: 
        Room Number []: 
        Work Phone []: 
        Home Phone []: 
        Other []: 
Is the information correct? [Y/n]

第四步——配置新贵

现在我们准备创建 Upstart 服务来管理我们的 Meteor 应用程序。 Upstart 将在启动时自动启动应用程序,并在 Meteor 死机时重新启动它。 您可以在 本教程 中阅读有关创建 Upstart 服务文件的更多信息。

创建文件 /etc/init/todos.conf。 再一次,它被在线注释:

# upstart service file at /etc/init/todos.conf
description "Meteor.js (NodeJS) application"
author "Daniel Speichert <daniel@speichert.pro>"

# When to start the service
start on started mongodb and runlevel [2345]

# When to stop the service
stop on shutdown

# Automatically restart process if crashed
respawn
respawn limit 10 5

# we don't use buil-in log because we use a script below
# console log

# drop root proviliges and switch to mymetorapp user
setuid todos
setgid todos

script
    export PATH=/opt/local/bin:/opt/local/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    export NODE_PATH=/usr/lib/nodejs:/usr/lib/node_modules:/usr/share/javascript
    # set to home directory of the user Meteor will be running as
    export PWD=/home/todos
    export HOME=/home/todos
    # leave as 127.0.0.1 for security
    export BIND_IP=127.0.0.1
    # the port nginx is proxying requests to
    export PORT=8080
    # this allows Meteor to figure out correct IP address of visitors
    export HTTP_FORWARDED_COUNT=1
    # MongoDB connection string using todos as database name
    export MONGO_URL=mongodb://localhost:27017/todos
    # The domain name as configured previously as server_name in nginx
    export ROOT_URL=https://todos.net
    # optional JSON config - the contents of file specified by passing "--settings" parameter to meteor command in development mode
    export METEOR_SETTINGS='{ "somesetting": "someval", "public": { "othersetting": "anothervalue" } }'
    # this is optional: http://docs.meteor.com/#email
    # commented out will default to no email being sent
    # you must register with MailGun to have a username and password there
    # export MAIL_URL=smtp://postmaster@mymetorapp.net:password123@smtp.mailgun.org
    # alternatively install "apt-get install default-mta" and uncomment:
    # export MAIL_URL=smtp://localhost
    exec node /home/todos/bundle/main.js >> /home/todos/todos.log
end script

在此配置文件中需要注意的一件事是 METEOR_SETTINGS 参数。 如果在启动 Meteor 的开发模式时使用 meteor --settings config.json,则应将 config.json 的内容作为变量粘贴到 METEOR_SETTINGS 中。

如果您计划使用 Meteor 的电子邮件包,MAIL_URL 必须是有效的 SMTP URL only。 您可以使用 MailGun(Meteor 推荐的)、本地邮件服务器等。

正如我们在文件中看到的,日志将被保存到 /home/todos/todos.log. 这个文件不会随着时间的推移而旋转并且 WILL GROW。 密切关注它是个好主意。 理想情况下,其中不应该有很多内容(错误)。 或者,您可以在 Upstart 脚本的末尾设置 日志轮换 或将 >> 替换为 > 以覆盖整个文件而不是附加到它的末尾.

不要启动此服务,因为我们还没有实际的 Meteor 应用程序文件!

第五步——部署 Meteor 应用程序

可选:如果您还没有 Meteor 项目

如果您还没有 Meteor 项目并且想使用演示应用程序,那不是问题!

在您的家用计算机或开发 Linux 服务器上执行此下一步。 命令可能因您的操作系统而异。 移动到您的主文件夹:

cd ~

首先,安装 Meteor 的开发版:

curl https://install.meteor.com | /bin/sh

然后从一个名为 Todo List 的示例创建一个应用程序:

meteor create --example todos

现在进入您的应用程序的目录,您可以继续:

cd todos

所有 Meteor 项目

是时候从我们的 Meteor 应用程序创建一个生产版本包了。 以下命令应在您的 家用计算机或开发 Linux 服务器 上执行,无论您的 Meteor 应用程序在哪里。 转到您的项目目录:

cd /app/dir

并执行:

meteor build .

这将在目录 /app/dir 中创建一个类似 todos.tar.gz 的存档文件。 将此文件复制到 Droplet 上的 ~ 目录中。

scp todos.tar.gz root@todos.net:~

现在回到你的Droplet。创建一个项目目录并将归档项目文件移动到其中。 请注意,这是我们之前创建的项目用户的主文件夹, 不是 您的根主文件夹:

mkdir /home/todos
mv todos.tar.gz /home/todos

进入项目目录并解压:

cd /home/todos
tar -zxf todos.tar.gz

看一下项目自述文件:

cat /home/todos/bundle/README

该捆绑包包含一个 README 文件,其内容为:

This is a Meteor application bundle. It has only one external dependency:
Node.js 0.10.29 or newer. To run the application:

  $ (cd programs/server && npm install)
  $ export MONGO_URL='mongodb://user:password@host:port/databasename'
  $ export ROOT_URL='http://example.com'
  $ export MAIL_URL='smtp://user:password@mailhost:port/'
  $ node main.js

Use the PORT environment variable to set the port where the
application will listen. The default is 80, but that will require
root on most systems.

Find out more about Meteor at meteor.com.

这个配方反映在我们的 /etc/init/todos.conf 文件中。 README 中还提到了我们需要做的另一件事。

现在我们需要安装一些必需的 npm 模块。 为了能够构建其中的一些,我们还需要安装 g++ 并制作:

apt-get install g++ make
cd /home/todos/bundle/programs/server
npm install

你应该看到这样的输出:

npm WARN package.json meteor-dev-bundle@0.0.0 No description
npm WARN package.json meteor-dev-bundle@0.0.0 No repository field.
npm WARN package.json meteor-dev-bundle@0.0.0 No README data
 
> fibers@1.0.1 install /home/todos/bundle/programs/server/node_modules/fibers
> node ./build.js

`linux-x64-v8-3.14` exists; testing
Binary is fine; exiting
underscore@1.5.2 node_modules/underscore

semver@2.2.1 node_modules/semver

source-map-support@0.2.5 node_modules/source-map-support
└── source-map@0.1.29 (amdefine@0.1.0)

fibers@1.0.1 node_modules/fibers

我们需要这样做的原因是因为我们的应用程序包不包含依赖于平台的模块和库。

我们几乎准备好运行应用程序,但是由于我们以 root 身份操作文件,并且它们应该由 todos 用户拥有,我们需要更新项目目录的所有权:

chown todos:todos /home/todos -R

第六步——表演时间

至此,我们拥有了运行 Meteor 应用程序所需的一切:

  • 已安装 Node.js 环境
  • 应用程序安装在其项目目录中
  • 配置为运行应用程序的 Upstart 服务
  • MongoDB数据库
  • 我们的 Meteor 应用程序前面的 Nginx 代理服务器提供 SSL 加密

要启动我们的应用程序,让我们从项目目录执行以下命令:

start todos

现在您应该可以在浏览器中的 https://todos.net 中查看您的应用程序。

重新部署应用程序

当您在开发模式中进行更改时(您将;我们毕竟是开发人员!),您可以简单地重复第五步(从 meteor build 开始)并完成大部分步骤,直到 [ X197X] 命令,它将通过 Upstart 重新加载您的应用程序。

这样您就可以在不停机的情况下推送新版本。 客户(您网站的访问者)会自动拉取新版本的代码并刷新他们的页面——这就是 Meteor 的魔力!

如果您想对此进行测试,您可以在家用计算机或开发服务器上的应用程序开发副本中对 todos/client/todos.html 页面中的文本进行简单更改。

开发服务器:

建造:

meteor build /app/dir

上传:

scp todos.tar.gz root@todos.net:/home/todos

生产服务器:

扩张:

tar -zxf /home/todos/todos.tar.gz

进入项目文件夹:

cd /home/todos/bundle/programs/server

更新 npm 模块(您可能会看到一些警告):

npm install

重新启动应用程序:

restart todos

故障排除

如果出现问题,这里有一些关于在哪里寻找问题的提示:

  • 如果您的应用程序启动和终止,请检查 /home/todos/todos.log; 它应该抛出适当的错误消息(例如 在编程错误的情况下)。
  • 如果您看到的是 HTTP 错误而不是您的应用程序,请检查 /var/log/nginx/error.log
  • 如果您认为数据库可能有问题,请检查 /var/log/mongodb/mongodb.log

最后,检查是否所有服务都在运行:

status todos
service nginx status
status mongodb