AWSのDBはRDSにありますので、そこからインスタンスを起動します。
Multi-AZ Deploymentの設定は通常「はい」にして、セキュリティを高めます。
DBインスタンスを作成したら、エンドポイントを確認します。
そして、mysqlに接続します。
[ec2-user@ip-172-31-21-202 ~]$ mysql -h mydbinstance.c7fqvxerxxxx.ap-northeast-1.rds.amazonaws.com -u name -p
ソフトウェアエンジニアの技術ブログ:Software engineer tech blog
随机应变 ABCD: Always Be Coding and … : хороший
AWSのDBはRDSにありますので、そこからインスタンスを起動します。
Multi-AZ Deploymentの設定は通常「はい」にして、セキュリティを高めます。
DBインスタンスを作成したら、エンドポイントを確認します。
そして、mysqlに接続します。
[ec2-user@ip-172-31-21-202 ~]$ mysql -h mydbinstance.c7fqvxerxxxx.ap-northeast-1.rds.amazonaws.com -u name -p
IMAGESはインスタンスのテンプレートのようなものです。
イメージは、サーバーがシャットダウンされて、snapshots、AMIsが作られます。
インスタンスがシャットダウンされると、パブリックDNSが使用できなくなるので、Elastic IPsでIPアドレスを作成します。
そして、作成済みのインスタンスと関連付けを行います。
すると、インスタンスに割り当てられていることがわかります。
バックアップはElastic block storeのvolumesでクリップスナップショットをつくれば、その時点のバックアップをとります。
インスタンスのスペック変更は、一旦インスタンスを停止し、インスタンスタイプの変更で簡単に変更することができます。
AWSに接続したら、サーバーにhttpd、php、mysqlをインストールします。
[ec2-user@ip-172-31-21-202 ~]$ sudo yum -y install httpd php mysql
インストールが完了したら、httpdの立ち上げを行います。
[ec2-user@ip-172-31-21-202 ~]$ sudo service httpd start Starting httpd: [ OK ] [ec2-user@ip-172-31-21-202 ~]$ sudo chkconfig httpd on
そうしたら、index.htmlファイルを作成し、ウェブサーバーが稼働しているか確認してみます。
[ec2-user@ip-172-31-21-202 ~]$ sudo vim /var/www/html/index.html
すると、反映されていることが確認できます。
AWSの設定ですが、アプリケーションの規模やアクセス数に応じてスペックを決めるのが通常ですが、昨今では最小構成から始めて、必要に応じてスペックを上げていくのがトレンドのようです。
AWSの費用は、さくらインターネット・GMOクラウド社等の他のクラウドサーバに比べて高いですが、オートスケール(Amazon EC2)・インターネットストレージ(Amazon S3)・メール配信(Amazon SES)・データベース(Amazon RDS)等のサービスが充実してます。
t2.nanoですと、東京リージョンで$0.01/1時間あたりくらいです。
インスタンスをつくっていきましょう。
セキュリティグループ(ファイヤーウォール)はデフォルトでSSHの設定がありますが、web用のHTTP、ポート80を追加しましょう。
インスタンスのDescriptionでパブリックDNSがアクセスする際のアドレスになります。
なお、インスタンスを立ち上げると、ELASTIC BLOCK STOREのVolumuesが自動的に作成されます。
インスタンスへの接続は、ターミナルから行います。
秘密鍵のパーミッションを設定して、ssh接続すると、t2.nanoへの接続が確認できます。
[vagrant@localhost aws]$ chmod 600 test.pem [vagrant@localhost aws]$ ssh -i "test.pem" ec2-user@ec2-54-199-174-180.ap-northeast-1.compute.amazonaws.com The authenticity of host 'ec2-54-199-174-180.ap-northeast-1.compute.amazonaws.com (54.199.174.180)' can't be established. RSA key fingerprint is 62:7f:e2:a3:17:ed:52:6b:c7:65:65:fc:05:38:e1:d3. Are you sure you want to continue connecting (yes/no)? y Please type 'yes' or 'no': yes Warning: Permanently added 'ec2-54-199-174-180.ap-northeast-1.compute.amazonaws.com,54.199.174.180' (RSA) to the list of known hosts. __| __|_ ) _| ( / Amazon Linux AMI ___|\___|___| https://aws.amazon.com/amazon-linux-ami/2016.09-release-notes/
code-bird phpはtwitter APIにphpでアクセスする際のライブラリです。
git hubのページに解説があるように、以下のように記載していきます。
require_once ('codebird.php'); \Codebird\Codebird::setConsumerKey('YOURKEY', 'YOURSECRET'); // static, see README $cb = \Codebird\Codebird::getInstance(); You may either set the OAuth token and secret, if you already have them: $cb->setToken('YOURTOKEN', 'YOURTOKENSECRET');
twitter-devでmyappを作成し、アクセスキー、トークンを取得してphpに実装していきましょう。
<?php require_once('codebird.php'); require_once('config.php'); Codebird::setConsumerKey(CONSUMER_KEY, CONSUMER_SECRET); $cb = Codebird::getInstance(); $cb->setToken(ACCESS_TOKEN, ACCESS_TOKEN_SECRET); $params = array( 'screen_name' => 'name', 'include_rts' => true ); $tweets = (array) $cb->statuses_userTimeline($params); var_dump($tweets);
<!DOCTYPE html> <html lang="ja" ng-app> <head> <meta charset="UTF-8"> <title>Angular js</title> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script> <script src="myscript.js"></script> <body> <h1>YouTube Search</h1> <div ng-controller="mainCtrl"> <form ng-submit="doSearch()" name="myForm"> <input type="text" ng-model="query" required> <input type="submit" value="search" ng-disabled="myForm.$invalid"> </form> <h2>Results</h2> <ul ng-show="results.length" style="list-style:none;padding:0"> <li ng-repeat="result in results"> <img ng-src="{{result.media$group.media$thumbnail[0].url}}"> {{result.title.$t}} </li> </ul> <p ng-hide="results.length">↑から検索してください。</p> </div> </body> </html>
var mainCtrl = function($scope, $http){ $scope.doSearch = function(){ var url = 'https://gdata.youtube.com/feeds/api/videos?' + [ 'q=' + encodeURIComponent($scope.query), 'alt=json', 'max-results=10', 'v=2', 'callback=JSON_CALLBACK' ].join('&'); $http.jsonp(url).success(function(data){ // console.dir(data); $scope.results = data.feed.entry; }); } }
投稿内容はdatファイルに格納します。
<?php $dataFile = 'bbs.dat'; // csrf session_start(); function setToken(){ $token = sha1(uniqid(mt_rand(), true)); $_SESSION['token'] = $token; } function checkToken(){ if (empty($_SESSION['token']) || ($_SESSION['token'] !=$_POST['token'])){ echo "不正なpostが行われました!"; exit; } } function h($s){ return htmlspecialchars($s, ENT_QUOTES, 'utf-8'); } if($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['message']) && isset($_POST['user'])){ checkToken(); $message =trim($_POST['message']); $user = trim($_POST['user']); if($message !== ''){ $user = ($user === '') ? 'ななしさん' : $user; $message = str_replace("\t", '', $message); $user = str_replace("\t", '', $user); $postedAt = date('Y-m-d H:i:s'); $newData = $message . "\t" . $user . "\t" . $postedAt. "\n"; $fp = fopen($dataFile, 'a'); fwrite($fp, $newData); fclose($fp); } } else { setToken(); } $posts = file($dataFile, FILE_IGNORE_NEW_LINES); $posts = array_reverse($posts); ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>簡易掲示板</title> </head> <body> <h1>簡易掲示板</h1> <form action="" method="post"> message: <input type="text" name="message"> user: <input type="text" name="user"> <input type="submit" value="投稿"> <input type="hidden" name="token" value="<?php echo h($_SESSION['token']); ?>"> </form> <h2>投稿一覧(<?php echo count($posts); ?>件)</h2> <ul> <?php if (count($posts)) : ?> <?php foreach ($posts as $post) : ?> <?php list($message, $user, $postedAt) = explode("\t", $post); ?> <li><?php echo h($message); ?>(<?php echo h($user); ?>)-<?php echo h($postedAt); ?></li> <?php endforeach; ?> <li></li> <?php else : ?> <li>まだ投稿はありません。</li> <?php endif; ?> </ul> </body> </html>
mac os10では標準でunixコマンドラインにインストールされているので確認してみましょう。
mac-no-MacBook-Air:~ mac$ emacs --version GNU Emacs 22.1.1 Copyright (C) 2007 Free Software Foundation, Inc. GNU Emacs comes with ABSOLUTELY NO WARRANTY. You may redistribute copies of Emacs under the terms of the GNU General Public License. For more information about these matters, see the file named COPYING.
emacsの起動は、emacs、終了はcommand+cです。
画面:
-window:画面
-buffer:タブ
-mode line:今開いているbufferの情報
-mini buffer:コマンドの情報
ファイルは、コマンドキーで、ctr-x, ctr-fで、ディレクトリが表示されるので、編集したいファイルを開きます。
移動は以下のコマンドでも動けます。
c-f
c-b
c-p
c-n
c-a
c-e
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[i].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は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
ブラウザです。