警告:数据库的SSL Key没有做定期的更新,因此每3个月可能会因为Key过期导致服务因数据库无法访问而异常。
虽然有不少教程,但找来找去没有一个能顺利的在Ubuntu上顺利部署的。因此在这里把自己部署的过程记录下来。
前提条件:
Ubuntu Server 16.04.1 LTS 64 服务器
一个域名
- 登陆Ubuntu 服务器,除了root或者安装的用户之外,创建一个管理员用户:
1
2
3
4
5//创建用户
sudo adduser xxxxxx
//授权管理员权限
sudo usermod -aG sudo xxxxxx
- 安装Node和npm
1
2
3
4
5
6
7curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
sudo apt-get install -y nodejs
//安装完毕后可以用下面的命令查看node和npm的版本
node --version
npm --version
- 安装mongo db
1
2
3
4
5
6sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2930ADAE8CAF5059EE73BB4B58712A2291FA4AD5
echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.6 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.6.list
sudo apt-get update
sudo apt-get install -y mongodb-org
参考连接:Install MongoDB Community Edition on Ubuntu
系统重启时,自动启动mongodb1
sudo systemctl enable mongod
- 安装Nginx
1
2
3
4
5
6
7sudo apt-get update
sudo apt-get install nginx
//安装完毕之后,Nginx会自动启动
//可以在浏览器查看ip,得到的应该如下:
//不知道ip的话,可以用下面的命令得到
ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'
参考连接:How To Install Nginx on Ubuntu 14.04 LTS
- 设置Let’s Encrypt支持https
5.1 添加云解析:
在购买的云服务器的控制台,找到云解析,找到购买的域名,添加两条解析:
– 添加一条A record,将域名”example.com”指向Ubuntu服务器的公网IP
– 添加一条A record,将域名”www.example.com”指向Ubuntu服务器的公网IP
5.2 安装Certbot1
2
3
4
5sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx
配置Nginx1
2
3
4
5
6
7
8
9
10
11sudo nano /etc/nginx/sites-available/default
将server_name _;这一行的内容修改为对应的域名,例如:
server_name example.com www.example.com;
//检查修改内容是否正确
sudo nginx -t
//重启nginx
sudo service nginx reload
获取SSL证书1
2//记得修改对应的域名
sudo certbot --nginx -d example.com -d www.example.com
自动续约SSL证书1
sudo certbot renew --dry-run
参考连接:How To Secure Nginx with Let’s Encrypt on Ubuntu 14.04
配置Mongo DB支持SSL连接1
2
3
4
5sudo cat /etc/letsencrypt/archive/domain_name/{fullchain1.pem,privkey1.pem} | sudo tee /etc/ssl/mongo.pem
//确保mongo.pem 只可以被 mongodb 访问
sudo chown mongodb:mongodb /etc/ssl/mongo.pem
sudo chmod 600 /etc/ssl/mongo.pem
修改mongo配置文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17sudo nano /etc/mongod.conf
//修改内容如下:
# network interfaces
net:
port: 27017
bindIp: 0.0.0.0
ssl:
mode: requireSSL
PEMKeyFile: /etc/ssl/mongo.pem
# security
security:
authorization: enabled
setParameter:
failIndexKeyTooLong: false
保存配置文件
添加一个新的DB管理员用户1
2
3
4
5
6
7
8
9
10
11//连接mongo db
mongo --port 27017
//创建一个管理员用户(请修改为自己的用户名和密码)
use admin
db.createUser({
user: "sammy",
pwd: "password",
roles: [ { role: "userAdminAnyDatabase", db: "admin" } ]
})
exit
重启mongo db1
sudo service mongod restart
以后可以这样连接mongo db1
2//然后需要输入密码
mongo --port 27017 --ssl --sslAllowInvalidCertificates --authenticationDatabase admin --username sammy --password
创建一个database和对应的db用户1
2use database_name
db.createUser({ user: "database_user", pwd: "password", roles: [ "readWrite", "dbAdmin" ] })
//注意,上面的”sammy”是DB登陆用户,而这个”database_user”才可以对这个database可以操作。我们后面连接数据库时,需要用到这个”database_user”和对应的密码以及数据库。
例如:1
mongodb://database_user:password@your_domain_name:27017/database_name?ssl=true
安装Parse Server App Sample1
2
3
4
5git clone https://github.com/ParsePlatform/parse-server-example.git
cd ~/parse-server-example
npm install
测试Sample Application1
2
3
4
5
6
7
8npm start
结果如下:
> parse-server-example@1.0.0 start /home/sammy/parse-server-example
> node index.js
DATABASE_URI not specified, falling back to localhost.
parse-server-example running on port 1337.
另外开启一个session连接服务器,用如下测试1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22curl -X POST \
-H "X-Parse-Application-Id: myAppId" \
-H "Content-Type: application/json" \
-d '{"score":1337,"playerName":"Sammy","cheatMode":false}' \
http://localhost:1337/parse/classes/GameScore
Output
{"objectId":"fu7t4oWLuW","createdAt":"2016-02-02T18:43:00.659Z"}
curl -H "X-Parse-Application-Id: myAppId" http://localhost:1337/parse/classes/GameScore
Output
{"results":[{"objectId":"GWuEydYCcd","score":1337,"playerName":"Sammy","cheatMode":false,"updatedAt":"2016-02-02T04:04:29.497Z","createdAt":"2016-02-02T04:04:29.497Z"}]}
curl -X POST \
-H "X-Parse-Application-Id: myAppId" \
-H "Content-Type: application/json" \
-d '{}' \
http://localhost:1337/parse/functions/hello
Output
{"result":"Hi"}
回到原来的Session,Ctrl-C终止Parse Application的运行。
安装dashboard1
2
3
4
5
6
7
8
9
//将dashboard加入package中
cd ~/parse-server-example
nano package.json
"dependencies"中添加一行
parse-dashboard": "1.1.2"
npm install
配置新的Application,包括dashboard1
nano my_app.js
内容如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75// Packtor Server
var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var ParseDashboard = require('parse-dashboard');
var path = require('path');
var databaseUri = process.env.DATABASE_URI || 'mongodb://database_user:password@your_domain_name:27017/database_name?ssl=tru';
if (!databaseUri) {
console.log('DATABASE_URI not specified, falling back to localhost.');
}
// Set up parse server
var api = new ParseServer({
databaseURI: databaseUri || 'mongodb://database_user:password@your_domain_name:27017/database_name?ssl=tru',
cloud: process.env.CLOUD_CODE_MAIN || __dirname + '/cloud/main.js',
appId: process.env.APP_ID || 'appId',
masterKey: process.env.MASTER_KEY || 'masterKey',
serverURL: process.env.SERVER_URL || 'http://localhost:1337/parse',
publicServerURL: 'https://your_domain_name/parse'
});
var app = express();
// Serve static assets from the /public folder
app.use('/public', express.static(path.join(__dirname, '/public')));
// Serve the Parse API on the /parse URL prefix
var mountPath = process.env.PARSE_MOUNT || '/parse';
app.use(mountPath, api);
// Parse Server plays nicely with the rest of your web routes
app.get('/', function(req, res) {
res.status(200).send('Parse Server App');
});
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
console.log('Parse-server running on port ' + port + '.');
});
// Set up parse dashboard
var dashboard = new ParseDashboard({
"apps": [{
"serverURL": 'https://your_domain_name/parse', // Not localhost
"appId": 'appId',
"masterKey": 'masterKey',
"appName": "appName",
"production": false,
"iconName": "app-icon.png",
}],
"users": [
{
"user":"user",
"pass":"password"
}
],
"iconsFolder": "icons"
});
var dashApp = express();
// make the Parse Dashboard available at /dashboard
dashApp.use('/dashboard', dashboard);
// Parse Server plays nicely with the rest of your web routes
dashApp.get('/', function(req, res) {
res.status(200).send('Parse Dashboard App');
});
var httpServerDash = require('http').createServer(dashApp);
httpServerDash.listen(4040, function() {
console.log('dashboard-server running on port 4040.');
});
运行这个Application,可以用如下命令:1
2
3
4
5
6node my_app.js
结果应该如下:
Iconsfolder at path: icons not found!
Parse-server running on port 1337.
dashboard-server running on port 4040.
配置Nignx1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30Ctrl+C终止Application运行
sudo nano /etc/nginx/sites-available/default
在location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
}
之后, 添加如下内容
location /parse/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:1337/parse/;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_redirect off;
}
# Pass requests for /dashboard/ to Parse Server instance at localhost:4040
location /dashboard/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
proxy_pass http://localhost:4040/dashboard/;
proxy_ssl_session_reuse off;
proxy_set_header Host $http_host;
proxy_redirect off;
}
保存,退出,并重启Nginx1
2
3sudo nginx -t
sudo service nginx reload
再次运行Application1
node my_app.js
此时,访问https://www.iosreader.com/dashboard/将会跳转到dashboard的login界面,可以用定义在配置文件里的用户名(user)和密码(password)进行登陆
安装PM21
2
3
4
5Ctrl+c退出Application
//返回用户目录
cd ~
sudo npm install -g pm2
/*
配置ecosystem.json1
nano ecosystem.json
1 | { |
*/
运行PM21
2
3
4
5
6
7
8
9
10
11
12
13
14
15//pm2 start ecosystem.json
修改为pm2 start my_app.js
不知道为何,配置ecosystem.json并且通过该文件启动my_app.js,在服务器重启之后,parse server的连接会出错,暂时不清楚问题的原因,以及如何修改。但是可以通过直接启动my_app.js,此方法在服务器重启之后,一切服务正常。
Sample Output
...
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Process launched
┌───────────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├───────────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ parse-wrapper │ 0 │ fork │ 3499 │ online │ 0 │ 0s │ 13.680 MB │ enabled │
└───────────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
保存1
2
3
4pm2 save
Sample Output
[PM2] Dumping processes
1 | sudo pm2 startup ubuntu -u xxxxxx --hp /home/xxxxxx/ |