在 Ubuntu 部署基于 Meteor 的 Web 应用程序

本篇教程帮助大家完成 Meteor 的安装和部署一个简单的 Todo List DEMO 程序。教程参考自 Digital Ocean 的一篇外文教程

会涉及到下面的一些知识:

  • 安装 Meteor.js
  • 搭建轻量级的 WebServer(Nginx) 和后端数据库( MongoDB )
  • 配置 Web 应用程序
  • 配置日常的数据库备份方案

这是 Meteor 的一个介绍:

介绍来自于 IBM 论坛这篇不错的中文教程:http://www.ibm.com/developerworks/cn/web/w...

Meteor 是一种新的 JavaScript 框架,用于自动化和简化实时运行的 Web 应用程序的开发。它使用一个名为分布式数据协议 (Distributed Data Protocol, DDP) 的协议来处理实时通信,使用 WebSockets 的新浏览器以及使用 Asynchronous JavaScript + XML (Ajax) 长轮询的旧浏览器来支持这种协议。在这两种情况下,浏览器到服务器的通信是透明的。

DDP 协议旨在处理 JavaScript Serialized Object Notation (JSON) 文档集合,使 JSON 文档容易创建、更新、删除、查询和访问。因为 DDP 是一种开源协议,所以您可将它连接到任何客户端或数据存储。它为 MongoDB 提供了开箱即使用支持。
事实上,Meteor 提供了两个 MongoDB 数据库:一个客户端缓存数据库和服务器上的一个 MongoDB 数据库。当一个用户更改一些数据时(例如通过单击 Save),在浏览器中运行的 JavaScript 代码会更新本地 MongoDB 中的相应的数据库项,然后向服务器发出一个 DDP 请求。该代码立即像操作已获得成功那样继续运行,因为它不需要等待服务器回复。与此同时,服务器在后台更新。如果服务器操作失败或返回一个意外结果,那么客户端 JavaScript 代码会依据从服务器新返回的数据立即进行调整。这种调整称为延迟补偿,向用户提供了更高的认知速度。

显然,甚至连 Meteor 的模板系统也是为简化实时通信而设计的。在大多数 Web 框架中,您可以轻松地混合使用超文本标记语言 (HTML) 和代码,或者与 HTML 等效的标记,比如 HTML 抽象标记语言 (Haml)。这使您能够轻松地将来自数据库的动态值插入发送给用户的页面中。在这之后,您应该负责准备提供一个系统来观察对数据的更改,然后更新您的标记。但是,Meteor 中的模板系统用于记录访问了模板中的哪些数据,并自动回调,以便在底层数据更改时调用此 HTML,使实时模板变得更加简单快捷。

Meteor 的目录结构: http://docs.meteor.com/#/full/structuringy...

Github : https://github.com/meteor/meteor

官方网站https://github.com/meteor/meteor

完整文档: http://docs.meteor.com/

在开始之前需要你做些准备:

  • VPS 的 SSH 账号,拥有 sudo 权限;
  • 公网可以访问的域名,没有的话就直接拿 IP 访问;
  • 一个本地开发好的 Meteor 测试项目(本文中拿 Meteor 官网上面的 Todo List 示例程序做演示)

如果你创建了一台 VPS,可以参考这篇教程进行初始化

Ubuntu 14.04 CheckList : 分享:[Server Hacks] New Ubuntu 14.04 Server Checklist

配置 Nginx Web 服务器

下载安装 Nginx

sudo apt-get install nginx

/etc/nginx/sites-available 目录下面创建一个虚拟主机配置 todo

sudo touch /etc/nginx/sites-available/todo

文件内容:

server_tokens off; # 安全考虑:不显示 nginx 的版本

# Websocket 代理连接配置
upstream meteor_server {
    # additional health checks for each instance
    # do not send requests to a backend server if they failed to respond 3 times in a row
    # define fail as no request for 30s
    server 127.0.0.1:3000 max_fails=3 fail_timeout=30s; #locally running Meteor on port 3000
    server 127.0.0.1:8080 max_fails=3 fail_timeout=30s weight=2; # second backend server receives twice the requests as the first server
    ip_hash; # send the same IP always to the same backend server
}

## redirect all non-www requests to the www subdomain
## Also redirect non-ssl to ssl, remove the server block if you do not use SSL
server {
    listen 80;
    server_name DOMAIN;
    if ($host = 'DOMAIN') {
        return 301 https://$host$request_uri;
    }
}

## actual site configuration
server {
    server_name DOMAIN
    #listen 80 spdy; #uncomment this line if you do not use SSL

    # delete the following SSL block if you do not need https
    listen 443 ssl spdy;
    ssl_certificate /etc/nginx/ssl/todo.crt;
    ssl_certificate_key /etc/nginx/ssl/todo.key;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_ciphers ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:DES-CBC3-SHA:!ADH:!AECDH:!MD5;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/nginx/ssl/todo.crt;
    resolver 8.8.8.8 8.8.4.4;
    # end of SSL block

    ## performance boost using gzip
    gzip on;
    gzip_disable "msie6";
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
    # end of GZIP block

    ## this is the actual load balancing to the meteor backend servers
    location / {
        proxy_pass http://meteor_server; # the name used in upstreams, substituted for any of the defined instances
        proxy_redirect off;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        # Make sure to use WebSockets
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    ## if nginx has access to the js and css files created by meteor, you can proxy these as well
    #location ~* "^/[a-z0-9]{40}\.(css|js)$" {
    #    root /home/meteor/app/programs/web.browser; # where to find the meteor created files
    #    access_log off;
    #    expires 30d;
    #    add_header Pragma public;
    #    add_header Cache-Control "public";
    #}

    ## serve static files by nginx instead of Meteor (the public/ folder)
    location ~ \.(jpg|jpeg|png|gif|mp3|ico|pdf) {
        root /home/meteor/app/programs/web.browser/app; # this should point at the content from the public folder
        access_log off;
        expires 30d;
        add_header Pragma public;
    }
}

关于 SSL 的配置,可以看这篇文章 https://www.digitalocean.com/community/tut...

更多关于 Nginx 的虚拟主机配置,可以看这里:https://www.digitalocean.com/community/tut...

如果没有域名,你可以暂时把 server_name 配置为 IP 地址;

我们需要移除掉默认的虚拟主机配置:

sudo rm /etc/nginx/sites-enabled/default

启用新的虚拟主机配置:

sudo ln -s /etc/nginx/sites-available/todo /etc/nginx/sites-enabled/todo

快速查看一下配置语法是否有问题:

sudo nginx -t

立刻应用最新的配置:

sudo nginx -s reload

现在访问配置的域名或者 IP,你应该看到 ·502 Bad Gateway· , 这是正确的,应为我们还没有把 Meteor 部署上去;

设置 MongoDB 数据库
sudo apt-get install mongodb-server

因为我们目前只通过本地连接 MongoDB 数据库,所以没有加任何权限认证,需要保证系统没有非法的 SSH 用户登录。

查看一下 MongoDB 是否正常运行:

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     207113   /tmp/mongodb-27017.sock

创建一个 bash 脚本来完成日常的数据库备份工作:

sudo touch /etc/cron.d/mongodb-backup

文件内容:

@daily root mkdir -p /var/backups/mongodb; mongodump --db todos --out /var/backups/mongodb/$(date +'\%Y-\%m-\%d')
安装 Meteor 应用程序

首先,需要安装一下 nodejs,因为 Meteor 需要较新版本的 nodejs,需要添加一下 nodejs 的仓库源:

sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodejs

最佳实践是为运行 Meteor 创建一个用户:

sudo adduser --disabled-login todo

写一点开机启动脚本帮我们完成启动一些服务的重复性工作:

sudo touch /etc/init/todo.conf

文件内容:

# 启动脚本文件 at /etc/init/todo.conf
description "Meteor.js (NodeJS) application"
author "Jobs Long <jobslong@ideas.top>"

# 启动服务
start on started mongodb and runlevel [2345]

# 停止服务
stop on shutdown

# 崩溃的时候自动重启
respawn
respawn limit 10 5

# 禁用系统内置的日志记录
# console log

# 切换到 todo 用户来执行 
setuid todo
setgid todo

# 这个脚本语言大家如果看不懂,可以先略过
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/todo
    export HOME=/home/todo
    # 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://todo.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/todo/bundle/main.js >> /home/todo/todos.log
end script

部署 Meteor 应用程序

我们在自己本地机器上面安装 Meteor 程序来创建示例程序:

Mac OS or Linux

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

Window 环境请下载官网的二进制包进行安装

创建示例程序 Todo List :

meteor create --example todos

切换到项目目录里面构建项目:

meteor build . --server http://172.21.4.58

通过 scp 或者 ftp 把构建好的二进制包上传到服务器:

scp todos.tar.gz root@ServerIP:/home/todo

解压

tar -zxvf todos.tar.gz

进入程序服务端目录更新 npm 依赖:

cd /home/todo/bundle/programs/server && npm install

授予运行用户合适的权限:

chown todo:todo /home/todo -R
大功告成

启动一下应用程序:

start todo

当你之后本地修改做了一些程序更改之后,需要按照部署的流程重新上传部署一下,你也可以写个脚本完成自动化部署;

在安装过程中你肯定会遇到各种麻烦,但不希望你去问别人我安装不上去,程序运行不了这种问题。日志文件和 Google 是你首要而且很重要的解决途径。

  • /home/todo/todo.log Meteor 应用程序的日志文件
  • /var/log/nginx/error.log Nginx 日志文件
  • /var/log/mongodb/mongodb.log MongoDB 数据库日志文件

示例程序界面:

demo

Enjoy !

Remote. Open. Engineer.
本帖已被设为精华帖!
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 3
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!