ProxyPass、ProxyPassReverseを設定し、商用環境でexpressサーバに接続

## virtualhostで、ProxyPass、ProxyPassReverseを設定し、node appとすると、商用のドメインからでもexpressさーばに接続できるようになる。

vi /etc/httpd/conf.d/hoge.conf

<VirtualHost *:80>
DocumentRoot /var/www/html/hoge/express
ServerName www.target.com
ServerAlias target.com
CustomLog logs/target.com-access.log common
ErrorLog  logs/target.com-error.log
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
AddDefaultCharset UTF-8
<Directory "/var/www/html/hoge/express/">
AllowOverride All
</Directory>
</VirtualHost>

ProxyPassは転送
ProxyPassReverseはリダイレクト情報の書き換え

なるほど、expressサーバについて大分理解が深まった。expressサーバはapacheとは別ですね。
しかし、expressを使うところだけ、Jsonで取得するように、ユーザからのアクセスはProxyPassを使って転送させるって、アーキテクチャとしてどうなんだろうか。。。express単体のアプリケーションならいいが、フレームワークの中でexpressを使うってのは、仕組み的には可能だが、他の方法を探した方が建設的か。。。

商用環境でexpressを実行しようとすると…

まずサーバーにてnodeが入っていることを確認
$ node -v
$ npm -v

express install
$ sudo npm install express -g
$ sudo npm install -g express-generator
$ express -h
$ sudo npm install nodemon -g

続いて、ディレクトリにexpress install
$ git clone https://github.com/***/***.git
$ cd dir

### nodemon, node起動
$ nodemon app
Forbidden
You don’t have permission to access /express/ on this server.

$ node app
Forbidden
You don’t have permission to access /express/ on this server.

app.listen(3000);
console.log("server starting ... ")

コマンドラインでは、server starting …と表示されているので、Expressサーバーは起動するが、アクセスしようとすると403(Forbidden)

### IPの3000ポート
$ ifconfig
160.***.***.**:3000でアクセス
-> このサイトにアクセスできません

80番ポート経由でアクセスした場合に、内部の3000番ポートにアクセスできないからか。

expressのincludeでSyntaxError: Unexpected identifier in /*/index.ejs while compiling ejs

GET / 500 1.492 ms – 1426
SyntaxError: Unexpected identifier in /*/index.ejs while compiling ejs

If the above error is not helpful, you may want to try EJS-Lint:
https://github.com/RyanZim/EJS-Lint
Or, if you meant to create an async function, pass `async: true` as an option.

includeの有無でエラーが生じるので色々試したところ、エラーが消えました。
## before

<% include header.ejs %>
	<h1>Posts</h1>
	<ul>
		<% for (var i=0; i<posts.length; i++) { %>
			<li>
				<a href="/posts/<%= i %>"><%= posts&#91;i&#93;.title %></a>
			</li>
		<% } %>
	</ul>
<% include footer.ejs %>

## after

<% include('header.ejs') %>
	<h1>Posts</h1>
	<ul>
		<% for (var i=0; i<posts.length; i++) { %>
			<li>
				<a href="/posts/<%= i %>"><%= posts&#91;i&#93;.title %></a>
			</li>
		<% } %>
	</ul>
<% include('footer.ejs') %>

ページ数が増えれば増えるほど、includeを使わない手はないので、includeでエラーがあるとドキッとします。

express 2

Regular Expression

app.get('/items/:id([0-9]+)', function(req, res){
	res.send('item no: ' + req.params.id);
});

file

app.get('/hello.txt', function(req, res){
	res.sendfile(__dirname + '/public/hello.txt');
});

public folder読み込み

app.use(express.static(__dirname + '/public'));

– app.useで読み込む処理をmiddlewareと言う

var logger = require('morgan');
app.use(logger('dev'));
app.use(function(req, res, next){
	console.log('my custom middleware');
	next();
})

$ sudo npm install nodemon -g
$ nodemon app

$ npm install ejs

app.get('/', function(req, res){
	res.render('index');
});

app.get('/', function(req, res){
	res.render('index', {title: 'title'});
});
<body>
	<h1><%= title %></h1>
	hello from index ejs!
</body>
app.param('id', function(req, res, next, id){
	var users = ['yamda', 'nakamura', 'kobayashi'];
	req.params.name = users[id];
	next();
});
app.get('/hello/:id', function(req, res){
	res.send('hello ' + req.params.name);
})

app.get('/bye/:id', function(req, res){
	res.send('hello ' + req.params.name);
})

### Post

var bodyParser = require('body-parser');

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// ディレクトリ
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
// middleware
// app.use(app.router);
var logger = require('morgan');
app.use(logger('dev'));
app.use(express.static(__dirname + '/public'));

app.get('/new', function(req, res){
	res.render('new');
});

app.post('/create', function(req, res){
  //
  	res.send(req.body.name);
})

view, routingの設計をServerサイドの言語ではなく、JavaScriptで書いていける。

express

what is ‘express’ ?
-> Fast, unopinionated, minimalist web framework for Node.js

$ sudo npm install express -g
$ sudo npm install -g express-generator
$ express -h

$ express sample
$ cd sample
$ npm install
$ DEBUG=sample:* npm start
http://192.168.33.10:3000/

app.js

var express = require('express'),
	app = express();

// app.use(app.router);

app.get('/', function(req, res){
	res.send('hello world');
});

app.get('/wine', function(req, res){
	res.send('JACOB\'S CREEK');
});

app.listen(3000);
console.log("server starting ... ")
app.get('/users/:name', function(req, res){
	res.send('hello' + req.params.name);
});
app.get('/users/:name?', function(req, res){
	if (req.params.name){
		res.send('hello ' + req.params.name);
	} else {
		res.send('hello nobady!');
	}
});

リクエストに対してルーティングをやっていることはわかるが、サーバーの記述がよくわからない。apacheのように、サーバーを立てているのか? 既存のサーバー環境(nginx, apache等)で動かす場合は、どういう記述になるのか?
-> Node.jsをサービス化(デーモン化)して、nginxまたはApacheからリバースプロキシで接続

リバースプロキシとは?
->特定のサーバへのリクエストが必ず通過するように設置されたプロキシサーバ

ん? いまいちよくわかりません。

Vagrant環境(amazon linux2)で、Expressを使ってhttpsサーバーを立てる

まず、sslモジュールをinstall
$ sudo yum install mod_ssl

続いてkeyとcertを作成して読み込む
# 手順
## certificate file作成
openssl req -newkey rsa:2048 -new -nodes -keyout key.pem -out csr.pem
openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out server.crt

## package.json

{
	"name": "test-webrtc",
	"version": "0.0.1",
	"private": true,
	"dependencies": {
		"express": "4.x",
		"ejs": "3.0.1"
	}
}

$ npm install

## server.js

var express = require('express');
var app = express();

var fs = require("fs");
var https = require("https");
var options = {
	key: fs.readFileSync('key.pem'),
	cert: fs.readFileSync('server.crt')
}
var server = https.createServer(options, app);

console.log('server started');

app.get('/', function(req, res){
	res.render('index.ejs');
});

server.listen(3000);

$ node server.js

# 駄目な方法
## certificate file作成
$ openssl genrsa > server.key
$ openssl req -new -key server.key > server.csr
$ openssl x509 -req -signkey server.key < server.csr > server.crt

var express = require('express');
var app = express();

var fs = require("fs");
var https = require("https");
var options = {
	key: fs.readFileSync('server.key'),
	cert: fs.readFileSync('server.crt')
}
var server = https.createServer(options, app);

console.log('server started');

app.get('/', function(req, res){
	res.writeHead(200);
	res.render('index.ejs');
});

server.listen(3000);

## server.js
keyがpemファイルでないので、エラーが出ます
$ node server.js
_tls_common.js:88
c.context.setCert(options.cert);
^

Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
at Object.createSecureContext (_tls_common.js:88:17)
at Server (_tls_wrap.js:819:25)
at new Server (https.js:60:14)
at Object.createServer (https.js:82:10)
at Object. (/home/vagrant/webrtc/server.js:10:20)
at Module._compile (module.js:653:30)
at Object.Module._extensions..js (module.js:664:10)
at Module.load (module.js:566:32)
at tryModuleLoad (module.js:506:12)
at Function.Module._load (module.js:498:3)

vagrantでhttpsの環境を作ろうとした時、opensslとphpのビルトインサーバーでhttps環境を作っていましたが、フロントエンドだけならexpressで十分だということがわかりました。
expressはhttpのみかと勘違いしていたが、よくよく考えたら、できないわけない😂😂😂

express blog system

expressで簡易ブログをつくります。

var bodyParser = require('body-parser');
var logger = require('morgan');
var express = require('express'),
 app = express()
 post = require('./routes/post');

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

// middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.methodOverride());

app.use(logger('dev'));
app.use(function(err, req, ers, next){
  res.send(err.message);
});

// csrf対策
app.use(express.cookieParser());
app.use(express.session({secret: '386424ggrsr'}));
app.use(express.csrf());
app.use(function(req, res, next){
  res.locals.csrftoken = req.csrfToken();
  next();
});

// routing
app.get('/', post.index);
app.get('/posts/:id([0-9]+)', post.show);
app.get('/posts/new', post.new);
app.post('/posts/create', post.create);
app.get('/posts/:id/edit', post.edit);
app.put('/posts/:id', post.update);
app.delete('/posts/:id', post.destroy);
/*


app.get('/new', function(req, res){
  res.render('new');
});
*/
 app.listen(3000);
 console.log("server starting...");

post.js

var bodyParser = require('body-parser');
var logger = require('morgan');
var express = require('express'),
 app = express()
 post = require('./routes/post');

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');

// middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.methodOverride());

app.use(logger('dev'));
app.use(function(err, req, ers, next){
  res.send(err.message);
});

// csrf対策
app.use(express.cookieParser());
app.use(express.session({secret: '386424ggrsr'}));
app.use(express.csrf());
app.use(function(req, res, next){
  res.locals.csrftoken = req.csrfToken();
  next();
});

// routing
app.get('/', post.index);
app.get('/posts/:id([0-9]+)', post.show);
app.get('/posts/new', post.new);
app.post('/posts/create', post.create);
app.get('/posts/:id/edit', post.edit);
app.put('/posts/:id', post.update);
app.delete('/posts/:id', post.destroy);
/*


app.get('/new', function(req, res){
  res.render('new');
});
*/
 app.listen(3000);
 console.log("server starting...");

index.html

<% include ../header %>
<body>
 <h1>Posts</h1>
 <ul>
   <% for (var i = 0; i < posts.length; i++){%>

   <li><a href="/posts/<%= i %>"><%= posts&#91;i&#93;.title %></a></li>
   <li><a href="/posts/<%= i %>/edit">[Edit]</a></li>
   <form method="post" action="/posts/<%= i %>">
     <input type="submit" value="del">
     <input type="hidden" name="_csrf" value="<%= csrftoken %>">
       <input type="hidden" name="_method" value="delete">
       <input type="hidden" name="id" value="<%= i %>">
   </form>
 </li>
   <% } %>
 </ul>
 <p><a href="/posts/">Add new</a></p>
<% include ../footer %>

post

var posts = [
  {title: 'title0', body: 'body0'},
  {title: 'title1', body: 'body1'},
  {title: 'title2', body: 'body2'},
];

exports.index = function(req, res){
  res.render('posts/index', {posts: posts});
};
exports.show = function(req, res){
  res.render('posts/show', {post: posts[req.params.id]});
};
exports.update = function(req, res, next){
  if (req.body.id !== req.params.id){
    next(new Error('ID not valid'));
  }else {
  posts[req.body.id] = {
    title: req.body.title,
    body: req.body.body
  };
  res.redirect('/');
};
exports.destroy = function(req, res, next){
  if (req.body.id !== req.params.id){
    next(new Error('ID not valid'));
  }else {
  posts.splice(req.body.id, 1);
  res.redirect('/');
}
};
exports.show = function(req, res){
  res.render('posts/new');
};
exports.create = function(req, res){
  var post = {
    title: req.body.title,
    body: req.body.body
  };
  posts.push(post);
  res.redirect('/');
};
exports.edit = function(req, res){
  res.render('posts/edit', {post: posts[req.params.id], id: req.params.id});
};

edit

<% include ../header %>
<body>
 <h1>Edit</h1>
<form method="post" action="/posts/<%= id %>">
  <input type="text" name="title" value="<%= post.title %>">
  <input type="text" name="body" value="<%= post.body %>">
  <input type="hidden" name="_csrf" value="<%= csrftoken %>">
  <input type="hidden" name="_method" value="Update">
  <input type="hidden" name="id" value="<%= id %>">
  <input type="submit" value="Update">
</form>

<p><a href="/">go back</a></p>
<% include ../footer %>

new

<% include ../header %>
<body>
 <h1>Add nnew</h1>
<form method="post" action="/posts/create">
  <input type="text" name="body">
  <input type="hidden" name="_csrf" value="<%= csrftoken %>">
  <input type="submit" value="add!">
</form>

<p><a href="/">go back</a></p>
<% include ../footer %>

show

<% include ../header %>
<body>
 <h1><%= post.title %></h1>
<p><%= post.body%></p>
<p><a href="/">go back</a></p>
<% include ../footer %>

header

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>

footer

</body>
</html>

expressのgetとpost

expressはnode.jsのフレームワークです。npmでサーバー側にインストールして動かします。ここでは、getとpostの挙動をみましょう。

var bodyParser = require('body-parser');
var logger = require('morgan');
var express = require('express'),
 app = express();

app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');


// middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

app.use(logger('dev'));
app.use(express.static(__dirname + '/public'));

app.get('/new', function(req, res){
  res.render('new');
});
app.post('/create', function(req, res){
  res.send(req.body.name);
});

 app.listen(3000);
 console.log("server starting...");

new.ejs


[nodemon] restarting due to changes...
[nodemon] starting `node app.js`
server starting...
GET /new 200 22.101 ms - 141
POST /create 200 1.023 ms - 5
GET /new 304 4.233 ms - -
POST /create 200 0.560 ms - 6

ブラウザです。
%e7%84%a1%e9%a1%8c