20200810のHTMLに関する記事は10件です。

ストップウォッチ作ってみた(HTML,CSS,JavaScript)

ストップウォッチ作ってみた

HTML,CSS(SCSS),JavaScript(not jQuery)でストップウォッチ作ってみました。ストップウォッチ作成は初心者が通り道らしいので私も通ってみました。どこか変なところやアドバイスがあればコメントお願いしますー!

ちなみにSCSSは特に解説してません。

完成形

こんな感じのができました。0.5 倍で見ると見やすいです。CodePen の埋め込み機能を使ってみましたがデフォルトで 0.5 倍にできたらいいんですけどやり方わかりませんでした(笑)

See the Pen zYqGmJz by mkt-engr (@mkt-engr) on CodePen.

特長

  • 時間、分、秒、ミリ秒まで表示する(時間までは使われなそうやけど一応実装した)
  • START,STOP,RESET の 3 つのボタンがある
  • 最初は START ボタンのみ活性化されている
  • STOP ボタンを押すと START という文字が RESTART に変わる
  • STOP ボタンを押すと STOP ボタンが非活性化し RESTART ボタンと RESET ボタンが活性化される
  • RESET ボタンを押すと RESTART ボタンの文字が START に変わる

実装方針

new Date().getTime()がストップウォッチの主役です。MDN の getTime のページによると

1970 年 1 月 1 日 00:00:00 UTC から指定した日時までの経過時間をミリ秒で表した数値。

とあるので

console.log(new Date().getTime());

とすると 1970 年 1 月 1 日 0 時 0 分からの経過時間をミリ秒で表示してくれます。これを利用して START ボタンや STOP ボタンを押した時刻を取得してストップウォッチを実装します。

ストップウォッチには START(RESTART),STOP,RESET の 3 つのボタンがありますがそれに対応して 3 つのイベントリスナーを実装します。

実装の詳細

一番 STOP ボタンの実装に苦労しました。

HTML と JavaScript のイベントリスナー以外の記述

HTML はシンプルです。時刻を表示する部分(<div class="display">)とボタンを表示する部分(<div class="buttons">)に分かれているだけです。

index.html
  <div class="stopwatch_wrapper">
    <div class="display">
      <span id="minutes" class="time">00</span>
      <span id="seconds" class="time">00</span>
      <span id="milli_seconds" class="time">000</span>
    </div>
    <div class="buttons">
      <button class="button" id="start">start</button>
      <button class="button" id="stop" disabled>stop</button>
      <button class="button" id="reset" disabled>reset</button>
    </div>
  </div>

ひとまずこれらのボタンや数値を操作するために以下の記述をします。

script.js
//上から分、秒、ミリ秒
const minutes = document.getElementById('minutes');
const seconds = document.getElementById('seconds');
const milli_seconds = document.getElementById('milli_seconds');

//ボタンたち
const start = document.getElementById('start');
const stop = document.getElementById('stop');
const reset = document.getElementById('reset');

3 つのボタンでそれぞれにイベントリスナーがついています。それらのイベントリスナーが共通でアクセスする変数を定義します。1 番下のpast_moving_timeがストップウォッチの実装の肝かなと思ってます。

script.js
// ストップウォッチを動かすときに用いるsetIntervalの返り値
let timer_id;

// ストップウォッチを動かし始めてからの時間
let stopwatch_time = 0;

// STARTボタンを押した時間
let press_start_time = 0;

// STOPボタンを押した時間
let press_stop_time = 0;

//ストップウォッチが動いていた時間の合計(STARTボタンを押してからSTOPボタンを押すまでの時間の合計)
let past_moving_time = 0;

3 つのイベントリスナー

START ボタン

START ボタンのイベントリスナーのコードは以下の通りです。3 つ特長があるのでそれはコードの後で書きます。

script.js
start.addEventListener('click', () => {
  press_start_time = new Date().getTime();
  timer_id = setInterval(() => {
    stopwatch_time = new Date().getTime() - press_start_time + past_moving_time;

    const time_milli_seconds = `00${Math.floor(stopwatch_time % 1000)}`.slice(
      -3
    );
    const time_seconds = `0${Math.floor((stopwatch_time / 1000) % 60)}`.slice(
      -2
    );
    const time_minutes = `0${
      Math.floor(stopwatch_time / 1000 / 60) % 60
    }`.slice(-2);
    const time_hours = `00${Math.floor(stopwatch_time / 1000 / 60 / 60)}`.slice(
      -3
    );

    //ブラウザに時間を描画する
    minutes.innerHTML = time_minutes;
    seconds.innerHTML = time_seconds;
    milli_seconds.innerHTML = time_milli_seconds;
  }, 1);

  1. START(RESTART)ボタンを押しからの経過時間の取得

まずボタンを押した時間を以下のようにして取得します。

   press_start_time = new Date().getTime();

現在の時間(new Date().getTime())から START ボタンを押した時間を引けば現在の時間が得られます。

   stopwatch_time = new Date().getTime() - press_start_time + past_moving_time;

ストップウォッチを最初にもしくは RESET ボタンを押した後はpast_moving_timeは 0 なので一旦無視してください。これについては STOP ボタンで解説します。

2) slice に関して
.slice(-2)とか.slice(-3)とかは0をパディングしてます。例えば秒を取得するとき 1 秒なら 01 を 23 秒なら 23 に変換しています。どんな秒数でも0を前にパディングしておいて後ろから 2 つ分を slice することでどんな秒数が来ても共通の処理ができます。具体的には以下の通りです。

  • 1→01→01 を取得
  • 23→023→23 を取得

3) ミリ秒、秒、分、時間の取得

stopwatch_timeはあくまでミリ秒です。こいつから秒、分、時間を取り出します。ここではstopwatch_time=123467123とします。

  • ミリ秒

stopwatch_timeは 123467.123 秒を表しています。なので下 3 桁を取得するために以下のように 1000 で割った余りを計算します。

  const time_milli_seconds = `00${stopwatch_time % 1000}`.slice(-3);

stopwatch_timeの 4,5 桁目を取得することを考えます。なのでまずは 1000 で割りMath.floorすることで123467を取得します。ストップウォッチに表示される秒数は 2 桁なので下 2 桁を取得します。60 以上になったら分に繰り上げる必要があるので123467を 60 で割ったあまりを以下のようにして取得します。

  const time_seconds = `0${Math.floor((stopwatch_time / 1000) % 60)}`.slice(-2);

こうすることで 60 秒未満の場合でも 60 秒以上 99 秒以下の場合でも同じ処理で対応できます。例えば 123467 % 60 なら 7 となり123456 % 60 なら 56みたいな感じです。

  • 分,時間

上と同様のロジックで分と時間を以下のようにして取得します。

  const time_minutes = `0${Math.floor(stopwatch_time / 1000 / 60) % 60}`.slice(
    -2
  );
  const time_hours = `0${Math.floor(stopwatch_time / 1000 / 60 / 60)}`.slice(
    -2
  );

STOP ボタン

実装方針ストップウォッチ実装の肝と言っていたpast_moving_timeについて解説します。シンプルに STOP ボタンが押されてclearIntervalをするだけだと RESTART ボタンを押したときに再び 0 秒から始まってしまいます。なぜかというと START(RESTART)ボタンを押すたびにイベントリスナーが走って以下のようにpress_start_timeが更新されるからです。

START ボタンのイベントリスナーには以下のような記述がありました。

script.js
start.addEventListener('click', () => {
  press_start_time = new Date().getTime();
  timer_id = setInterval(() => {
  stopwatch_time = new Date().getTime() - press_start_time + past_moving_time;

RESTART を押すとストップウォッチが再び 0 から始まってしまうことを避けるために定義した変数がpast_moving_timeです。

STOP ボタンのイベントリスナーのコードは以下の通りです。

script.js
stop.addEventListener('click', () => {
  clearInterval(timer_id);
  start.innerHTML = 'restart';

  press_stop_time = new Date().getTime();
  past_moving_time += press_stop_time - press_start_time;

  //STOPボタンを1度押すと非活性され、STARTボタンとRESETボタンは活性化される
  stop.disabled = true;
  start.disabled = false;
  reset.disabled = false;
});

ストップウォッチを動かしている時間の取得

past_moving_time に関してやってることはめっちゃシンプルです。STOP ボタンを押した時間から START ボタンを押した時間を引けばストップウォッチが動いていた時間を以下のように導出できます。

 past_moving_time += press_stop_time - press_start_time;

ここで+=をしているのは何度も STOP,RESTART が押されることを想定してのことです。

START ボタンのイベントリスナーの記述を見ると以下のようにpast_moving_time(ストップウォッチが動いていた時間の合計)がstopwatch_timeに加算されています。

script.js
start.addEventListener('click', () => {
  press_start_time = new Date().getTime();
  timer_id = setInterval(() => {
    stopwatch_time = new Date().getTime() - press_start_time + past_moving_time;

RESET ボタン

RESET ボタンの実装が一番簡単です。やることは以下の 2 つです。

  • ストップウォッチの停止(clearInterval)
  • 初期化(ブラウザの表示,ストップウォッチの表示をするために用いた変数)

RESET ボタンのイベントリスナーのコードは以下の通りです。

script.js
reset.addEventListener('click', () => {
  clearInterval(timer_id);

  start.innerHTML = 'start';

  //ブラウザの表示を初期化
  minutes.innerHTML = '00';
  seconds.innerHTML = '00';
  milli_seconds.innerHTML = '000';

  //変数を初期化
  stopwatch_time = 0;
  press_start_time = 0;
  press_stop_time = 0;
  past_moving_time = 0;

  //RESETボタンを押したらSTARTボタンしか押せない状態にする
  start.disabled = false;
  stop.disabled = true;
  reset.disabled = true;
});

CSS ファイル

SCSS を使っていない方もいると思うのでコンパイルした CSS をここに書いておきます。ちなみに VS Code のプラグインを使うと Webpack とかの準備をすることなく簡単に SCSS が使えるのでおすすめです。ここにプラグインに関して分かりやすく書いてありました。

style.css
style.css
body {
  margin: 0;
  padding: 0;
  -webkit-box-sizing: border-box;
          box-sizing: border-box;
}

html {
  font-size: 20px;
}

.buttons {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  margin-bottom: 1rem;
  margin-top: 1rem;
}

.buttons .button {
  text-transform: uppercase;
  padding: 1rem 2rem;
  margin-right: 1rem;
  color: white;
  border: none;
  cursor: pointer;
  -webkit-transition: all 0.1s ease-out;
  transition: all 0.1s ease-out;
  background: #4676d7;
  border-radius: 5px;
  font-size: 1.5rem;
  border: 2px solid transparent;
  -webkit-box-shadow: 0 0 8px gray;
          box-shadow: 0 0 8px gray;
  min-width: 225px;
}

.buttons .button:hover {
  background-color: transparent;
  color: #252020;
  border-color: #4676d7;
}

.buttons .button:disabled {
  background-color: #ccc;
}

.buttons .button:disabled:hover {
  color: white;
  border-color: transparent;
  cursor: default;
}

.display {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  padding: 2rem;
  background-color: #d3b3ab;
}

.display .time {
  font-size: 5rem;
}

.display .time:nth-child(1)::after {
  content: ':';
}

.display .time:nth-child(2)::after {
  content: ':';
}

.display .time:nth-child(3)::after {
  content: '.';
}
/*# sourceMappingURL=style.css.map */

展望

  • START ボタンを STOP ボタンは 1 つにするべきかな?
  • React や Vue でも作りたい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Google HTML / CSSスタイルガイド】を初めて読んだので、一言で分かるようにまとめてみた -基本・HTML編-

どうも7noteです。フロントエンジニア4年目です。

何万行とHTML・CSSを書いてきたので綺麗なソースにはそこそこ自信がありました。
ですが、Google HTML / CSSスタイルガイドを読んで唖然・・・
できてない事多いなぁ。。。と。

あくまで参考程度でいいとは思うのですが、プロとしてはやっぱり推奨されている綺麗な書き方で書きたい!!
きっとこの記事を読んでくださっている方も、ソースは綺麗に書きたいと思っているはず!

class名の命名則やインデントについての書き方のルールを見直すきっかけになるかも!
またSEO対策には直接影響はないかもしれないが、クローラーの最適化にはなるようなので、知っていて損はない!!!

というわけで、早速google翻訳に頼りながらガイドラインを読んでみた。↓

1.背景

このドキュメントでは、HTMLとCSSのフォーマットとスタイルのルールを定義します。コラボレーション、コード品質の向上、サポートインフラストラクチャの有効化を目的としています。これは、GSSファイルを含む、HTMLおよびCSSを使用する未加工の作業ファイルに適用されます。ツールは、一般的なコード品質が維持されている限り、自由に難読化、縮小、およびコンパイルできます。

ふむふむなるほど。

2.一般

2.1一般的なスタイル規則

2.1.1プロトコル

他ドメインからファイルを読み込むとき(特にjQueryやapi等)はhttpsを使いなさい』とのこと。

<!-- 非推奨 -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<!-- 推奨 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>

また関連する話として、sslについてはgoogleが2018年の7月から常時SSL化を推奨しているので、新しく制作するサイトに関しても常時SSLにするのは一般常識になっているのかなと思います。
参考:https://www.idcf.jp/rentalserver/aossl/browser/required-chrome68/

2.2一般的なフォーマット規則

2.2.1インデント

インデントはスペース2個にしなさい』だって。(タブで書いてた・・・)

<!-- 非推奨 -->
<ul>
    <li>Fantastic
    <li>Great
</ul>

<!-- 推奨 -->
<ul>
  <li>Fantastic
  <li>Great
</ul>

タブとスペースが混同するのはダブ-ですよ、ともかいてます。(・・・はいすみません。面白くないです。次行きます。)

2.2.2大文字

HTML・CSSに大文字は使うな』とのこと。ただし文字列は除く。

<!-- 非推奨 -->
<A HREF="/">Home</A></script>
<!-- 推奨 -->
<img src="google.png" alt="Google">

BEMの書き方なんかを見ても基本小文字しか書かれてないので大文字で書いている人は少なそう。でもたまに「class="areaBlock"」みたいなclassを見かけることがあるので使わないように注意が必要。

2.2.3末尾の空白

不要な空白文字は入れるな』とのことです。

<!-- 非推奨 -->
<p>What?_
<!-- 推奨 -->
<p>Yes please.

誤って入ってしまわないように気を付けましょう。
エディタによっては不要な空白を警告してくれたり、不可視文字を見えるようにできたり、あとで一括削除してくれるものもあるようなのでツールに頼ってもいいかもしれませんね!
改行・空白・タブ削除ツール

2.3一般的なメタルール

2.3.1エンコーディング

エンコーディングはUTF-8(BOMなし)を使いましょう』

<!-- 推奨 -->
<meta charset="utf-8">

はーい、わかりました!
(エンコーディングって何?という方はこちら→https://wa3.i-3-i.info/word135.html)

cssでは指定しないように。』とも書いてます。

2.3.2コメント

必要に応じてコードを説明するために使っていいよ』とのこと。

<!-- 推奨 -->
↑こんなかんじでコメントを書いて良い

ありがたい。さすがgoogle先生。

2.3.3アクションアイテム

コメントの書き方でTODO:~~~って書き方をしてもいいよ
な、、なんだこれ、見たことないぞ・・・。

<!-- 推奨 -->
<!-- TODO: remove optional tags -->
<ul>
  <li>Apples</li>
  <li>Oranges</li>
</ul>

・・・調べた情報によると、「TODO(ユーザー名など):内容」という様に書くらしい。
まぁコメントなのであまり使う場面は少ないのかな。。。

3.HTML

3.1 HTMLスタイルのルール

3.1.1ドキュメントタイプ

HTML5を使いましょう。
DOCTYPEは<!DOCTYPE html>このように書く

<!-- 推奨 -->
<!DOCTYPE html>

void要素は閉じるな。

<!-- 非推奨 -->
<br />
<!-- 推奨 -->
<br>

HTML5の基本的な書き方ですね。

3.1.2 HTMLの妥当性

<!DOCTYPE html>の宣言や、閉じタグなどは忘れず正しく書きましょう

<!-- 非推奨 -->
<title>Test</title>
<article>This is only a test.

<!-- 推奨 -->
<!DOCTYPE html>
<meta charset="utf-8">
<title>Test</title>
<article>This is only a test.</article>

3.1.3セマンティクス

目的に応じた要素を正しく使ってください

<!-- 非推奨 -->
<div onclick="goToRecommendations();">All recommendations</div>
<!-- 推奨 -->
<a href="recommendations/">All recommendations</a>

なんでもかんでもdivやspanで書かず、段落にはp、アンカーリンクにはaを使いましょうって話。

3.1.4マルチメディアのフォールバック

映像や画像が表示できなかった時の代替情報を用意しなさい

<!-- 非推奨 -->
<img src="spreadsheet.png">
<!-- 推奨 -->
<img src="spreadsheet.png" alt="Spreadsheet screenshot.">

img要素には必ずaltを書きなさい的な話ですね。

altについては過去に記事を書いたので参考にしてください。
【初心者でもわかる】imgタグのaltの付け方

3.1.5懸念の分離

HTMLとCSSとjavascriptは分けて書きましょう』的なことが書いてます。

<!-- 非推奨 -->
<link rel="stylesheet" href="base.css" media="screen">
<link rel="stylesheet" href="grid.css" media="screen">
<link rel="stylesheet" href="print.css" media="print">
<h1 style="font-size: 1em;">HTML sucks</h1>
<center>I can’t believe there’s no way to control the styling of
  my website without doing everything all over again!</center>

<!-- 推奨 -->
<link rel="stylesheet" href="default.css">

要素(タグ)の構造はHTMLファイルに。見た目のスタイルはCSSファイルに。などそれぞれ役割をはっきりさせ、住み分けさせることでメンテナンス性を上げてくださいねという話のようです。
htmlのタグに直書きでcssは書けますができるだけ書かないように注意しましょう!

3.1.6エンティティ参照

実体参照する必要のない文字は実体参照で書かないで!』と。

<!-- 非推奨 -->
ユーロはこう書きます。&ldquo;&eur;&rdquo;<!-- 推奨 -->
ユーロはこう書きます。"€"。

たとえばユーロ(€)などは実体参照が不要な文字なので、€と検索してそのまま使いましょう。

3.1.7オプションのタグ

<html>,<head>,<body>等は省略可能です。省略しましょう。

<!-- 非推奨 -->
<!DOCTYPE html>
<html>
  <head>
    <title>Spending money, spending bytes</title>
  </head>
  <body>
    <p>Sic.</p>
  </body>
</html>

<!-- 推奨 -->
<!DOCTYPE html>
<title>Saving money, saving bytes</title>
<p>Qed.

え、省略していいんですね。いや、省略できるのは知っていたけど、毎回律儀に書いてた。。。。
明日から省略して書こうっと。

省略できるタグをまとめているQiitaの記事がありました。
https://qiita.com/labocho/items/54fd70c73ced35c8ba49

3.1.8 type属性

外部ファイルを読み込むとき、type属性は省略する

<!-- 非推奨 -->
<link rel="stylesheet" href="https://www.google.com/css/maia.css" type="text/css">
<!-- 推奨 -->
<link rel="stylesheet" href="https://www.google.com/css/maia.css">

link要素やscript要素のtype="text/css"type="text/script"は省略しましょうとのこと。いつもコピペしてたから付けてしまってそう・・・

3.2 HTMLのフォーマットルール

3.2.1一般的なフォーマット

ulやtableの子要素はちゃんとインデントを取りなさい

<!-- 非推奨 -->
<ul>
<li>Moe
<li>Larry
<li>Curly
</ul>

<!-- 推奨 -->
<table>
  <thead>
    <tr>
      <th scope="col">Income
      <th scope="col">Taxes
  <tbody>
    <tr>
      <td>$ 5.00
      <td>$ 4.50
</table>

かしこまりました。

3.2.2 HTMLの行折り返し

htmlのタグが属性が増えてしまい異常に長い時は、途中で改行してもいいよ

<!-- 推奨 -->
<md-progress-circular
    md-mode="indeterminate"
    class="md-accent"
    ng-show="ctrl.loading"
    md-diameter="35">
</md-progress-circular>

見やすさ重視でタグの途中でも改行していいよってgoogle先生が言ってくれている、ありがとうgoogle先生!!!

3.2.3 HTML引用符

属性を書く時はダブルクォーテーション(")でくくりなさい。

<!-- 非推奨 -->
<a class='maia-button maia-button-secondary'>Sign in</a>
<!-- 推奨 -->
<a class="maia-button maia-button-secondary">Sign in</a>

class=""やalt=""などの属性はシングルクォーテーション(')ではなくダブルクォーテーション(")を使いましょう。


基礎・HTML編はここまで!
CSS編はこちらから!

おそまつ!

(コメント・質問・ソースの指摘等なんでもウェルカムです!初心者の方でも気軽に質問ください!)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

シンプルな申し込みフォームを作った

HTMLやCSSを勉強として、シンプルな申し込みフォームを作りました。
どんなフォームをどのように作ったかを簡潔にまとめました。

成果物

スクリーンショット 2020-08-10 21.37.42.png

作ったものはこんな感じ。
会員制サイトにありそうなシンプルな申し込みフォームを作りました。

HTML

<div class="content">
   <h1>入会申し込み</h1>
   <p>入会するには、次のフォームに必要事項をご記入ください。</p>
   <div class="controll">
      <label for="myemail">メールアドレス <span class="required">必須</span></label>
      <input id="myemail" type="email" name="email">
   </div>
   <div class="controll">
      <label for="mypassword">パスワード <span class="required">必須</span></label>
      <input id="mypassword" type="password" name="password">
   </div>
   <div class="controll">
      <button type="submit">登録する</button>
   </div>
</div>

フォームのタイトルはh1タグで、タイトル直下の注釈をpタグで出力。
フォームの送信項目であるメールアドレスとパスワードはinputで出力して、
buttonタグがクリックされた時に、inputタグの入力値が送信される想定。

でもフォームって言うからにはformタグを使った方が良かったなぁ・・・
formタグで書き換えたやつがこんな感じ↓↓

<form class="content">
   <h1>入会申し込み</h1>
   <p>入会するには、次のフォームに必要事項をご記入ください。</p>
   <div class="controll">
      <label for="myemail">メールアドレス <span class="required">必須</span></label>
      <input id="myemail" type="email" name="email">
   </div>
   <div class="controll">
      <label for="mypassword">パスワード <span class="required">必須</span></label>
      <input id="mypassword" type="password" name="password">
   </div>
   <div class="controll">
      <input class="submit" type="submit" value="登録する">
   </div>
</form>

全体を囲っていたdivタグがformタグになって、「登録する」ボタンのタグがinputタグになる感じですね。
本来であればformタグには送信先等を定義してあげます。

CSS

個人的にcssは苦手です。
まだお洒落なアニメーションを作るなんてことはできませんが、とにかくシンプルな見た目にすること意識しました。

.submit {
    width:100%;
    background-color: #2096f3;
    color:#fff;
    padding:15px;
    border: 0;
    border-radius:5px;
    box-shadow: 0 0 8px rgba(0,0,0,.4);

}

.required {
    color:#f33;
    font-size: .9em;
    padding: 3px;
    background-color: #fee;
    font-weight: bold;
}

要点だけ。

「.submit」では「登録する」ボタンのデザインを当てています。
色とか枠はいいとして、box-shadowの各設定値は注意です。
x軸、y軸、影の濃さ、影の色(r,g,b,不透明度)をそれぞれ設定します。

まとめ

今回は簡単な申し込みフォームを作りました。
cssの色付けで原色は使わない方が良さそうですね。
色使いなんかはこれから色々と作っていく中で学んでいきます。

応用としてフォームの送信先を作成して、DBに送信内容を登録して、、、なんてところまで作れるようになると良さそう。

参考

[HTML/CSS/JavaScript] フロントエンドエンジニアになりたい人の Webプログラミング入門

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Qiitaを始める。

今日から学習したことはQiitaで書いていこうと思う。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WebRTCで快適な画面共有を 基本編

友人にゲーム画面を共有することが多いのですが、SkypeでもDiscordでもZoomでもSteamのブロードキャストでも、低解像度だったり、解像度は取れていてもビットレートの関係で文字すら読めなかったり(画質が悪い)、遅延がそこそこ長かったりします。
配信知識ゼロから、この一週間で勉強したので、諸々まとめです。
この記事はやり方を説明するものではないのであしからず。

高画質、低遅延配信がしたい!

まあ普通にYoutubeに限定配信してURLを友人に教えれば見る側で手軽に画質変えられるし便利なんですけれど.... なんか自分でやりたくなってしまいました。
ポートの開放ができるなら、RTMPをグローバルIPで外からアクセスさせたり、HLS,MPEG-DASHでCMAF chunkを活用したりと選択肢はあります。
しかし自分の環境下ではポートの開放ができないので、動的に空いてるところを使ってもらうためにブラウザ上でWebRTCを試してみました。
WebRTCのページ共有にngrokを使いましたが、友人側にhtmlを渡してローカルサーバを立ててもらえば不要です。ローカルかhttpsであればいいので、当然Github Pagesとかでもいいです。
ひとまずXSplit Broadcasterを入力として使います。ロゴ入りますが無料でも十分です。
OBS Virtual cameraでもいいですが、XsplitはCPU使用率OBS比で3割くらいで済みます。
今回はSkyway SDKを使わせていただきました。(TURN月500GBまでなら無償で使える)
自分は一対一の共有を想定していたため、TURNサーバの使用のみでSFUはオフにしました。
※テストしたら、自分と友人の場合はTURNサーバオフでも通信できました。
この場合シグナリングサーバとSTUNサーバしか使っていないので、シグナリング月5万回までは制限なしで使えます。最終的にはここも自分で実装予定ですが。

いきなり問題発生

やけに画質が悪い。
配信ソフトのプレビューは綺麗だし、仮想カメラを他の配信ソフトに入力して見ても綺麗だったので、ブラウザ側の問題と認定。

どうも、デフォルトの帯域がそこまで広くなく、それを超えるものはブラウザ側で自動的に圧縮され、画質が悪くなるようで....恐らく1.5Mbps程度で調整されていました。環境次第?
ブラウザのデフォルトにも、おそらくSkyway SDKのデフォルトにも制限はあるんじゃないかな。
FPS維持優先で、画質が先に悪くなる印象。

1. 入力ソースの解像度はちゃんと指定しないと圧縮される

getUserMediaでは幅、高さ、フレームレートを指定可能で、理想値を指定したり、最低値最大値の指定ができます。
何も書かず指定だけすると、理想値(ideal)と見なされます。
正直、理想値を下回る分には問題なさそうなので自分の環境で出力し得る最大を入れればいいです。
ソースではとりあえずHD 60fpsで指定してます。
とりあえずこれでプレビューする分には高画質で見れるはずです。
(chrome://media-internals/ で見た感じ、OBS cameraやXsplitの仮想カメラ機能は30fpsまでらしいですが、メディアソースのFPSは60ですし見た目で明らかに60fps対応です。
chromeの画面キャプチャも60fpsは対応してます)

2. 送るデータの最大ビットレートも指定しないと圧縮される

プレビューは綺麗だけどいざ通信を開始して受信した映像を見ると相変わらずの画質でした。
今度は送信する際になにか制限が掛かっているはずです。
SDPで帯域を指定するには、今回はSkywayのコードを書き換える必要があったり....?
幸いオープンソースなので覗いたところ、javascriptのコードに直に書き込まず、htmlでオプションを追加するだけでした。コードでは14000kbpsにしてあります。まぁ14Mbpsですね。
一応最大ビットレートの指定らしいですが、挙動としては制限というよりもリクエストに過ぎないような気がします。
また、通信途中に帯域変える場合はSDPを弄るのかな? これはまた別の機会に。

コード

ありふれてますが一応、htmlのコード github
プレビューしやすくするためにオート再生、コントロールは初めからオン。
htmlやjavascriptにはまだ詳しくありませんが、Skywayのリファレンスを見ればほとんどの人が作れるかと。

こいつの問題は、通信しだしてからのメディア変更に対応できないのを無理やり再接続で対応させているということ。
SFU通信の場合などはreplaceStream()が使えるみたいなんですがP2Pだとよくわからず力業です。いろいろ試してみます。
また、共有停止にlocalStream.getVideoTracks()[0].enabled = false; を使うとあくまでミュートでしかなく、元々HD60fpsで送信していた場合、HD60fpsの黒い画面を引き続き送るためビットレート的にはほぼ停止できますが、開封負荷により負荷は下がらない。
ちゃんと停止させる場合はlocalStream.getVideoTracks()[0].stop(); でOK。
今後変わる可能性は大いにあり。
画面共有のほうは共有停止ボタンが出るのでそれ押しても停止できます。

感想

現在欧州にいますが、東京の友人にTime isを共有して遅延を確認したところ、2秒未満でした
だいぶすごい。しかも電話が同じくらい遅延しているので会話している時は遅延0の感覚です(笑)
加えて、分かりやすく画質方向での改善が大きい。
まあ世の中の画面共有全部これにしたら輻輳の危険性が高まりますがね....
自分も友人もマシンパワーやネットワーク速度を考慮しないで済む環境なのでそこは楽でした。
CMAF chunkによる低遅延HLSでもなんでもそうですが、基本的に低遅延と負荷はトレードオフなのでそれなりにCPU負荷使いますね。特に双方向共有を一つのPCで横に並べて行うと顕著です。
次回はSkyway SDKなしでやってみる感じです。
その後はWebRTCというかP2Pでの画面共有についてもう少し詰めていきます。敢えて遅延があるほうが話しやすい場合もあるので、接続時に遅延を選択できたりすると面白いかも?(受信側でバッファする感じでしょうか)
API周りの理解が皆無で根拠が薄いので、仕様と異なる場合はぜひコメントしてください!

参考

便利な機能 chrome://webrtc-internals (ローカルリソースなのでリンクは組み込めません)送信ビットレートとかTURNサーバを経由しているどうかなど見れます
Skyway https://webrtc.ecl.ntt.com/
Skyway リファレンス https://webrtc.ecl.ntt.com/api-reference/javascript.html

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Flexbox入門

Flexboxを使うとfloatで実現していたような縦並びや横並びのレイアウト、または折り返しのレイアウトを簡単に組むことができます。

横並びにする display: flex

display: flexは指定した要素の子要素を横並びにします。

使い方

横並びにしたい要素の親要素にdisplay: flexを指定します。

index.html
<ul class="flex-list">
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
</ul>
style.css
.flex-list {
  display: flex;
}

子要素の幅を親要素に合わせて伸縮させる flex: auto

flex: autoは指定した要素の幅を親要素に合わせて伸縮させることができます。

index.html
<ul class="flex-list">
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
</ul>
style.css
.flex-list {
  display: flex;
}

.flex-list li {
  flex: auto; /* 調整したい要素に適用する */
}

子要素のサイズに応じて折り返す flex-wrap: wrap

flex-wrap: wrapを指定すると、子要素のサイズに応じて折り返すことができます。
PC、タブレット、スマホで一列の表示個数を変えたいというのがよくあるユースケースだと思うので、
メディアクエリと合わせて使いましょう。

使い方

折り返したい要素の親要素にflex-wrap: wrapを指定します。
折り返したい要素自身には列数に応じたwidthを指定します。

index.html
<ul class="flex-list">
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
</ul>
style.css
.flex-list {
  display: flex;
  flex-wrap: wrap;
}

.flex-list li {
  flex: auto;
  width: 50%; /* 一列に2つ表示する */
}

子要素を上から下に並べる flex-direction: column

flex-direction: columnは子要素を上から下へ並べます。

使い方

縦に並べたい要素の親要素にflex-direction: columnを指定します。

index.html
<ul class="flex-list">
  <li>item1</li>
  <li>item2</li>
  <li>item3</li>
</ul>
style.css
.flex-list {
  flex-direction: column;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

子要素が全てfloatでも、親要素が子要素を含む高さを持つように設定する

親要素の高さは子要素を包む高さとなりますが、
子要素が全てfloatの時、親要素の高さは0となってしまいます。
これは、floatが「浮いている」という意味で、親要素から見るとfloatの子要素は存在しないように見えるためです。

floatの解除

子要素が全てfloatでも、親要素が高さを持つように設定してみます。
floatclear: left;で「浮いている」状態を解除できます。
clear: left;を適用するためだけの空のタグを用意します。
空タグとclearfloatを解除するのはよく使うテクニックらしいです。

index.html
<div>
  <div class="float">
    ...
  </div>
  <div class="float">
    ...
  </div>
  <div class="clear"></div> <!-- `clear: left;`を設定するための空タグ -->
</div>
style.css
.float {
  float: left;
}

.clear {
    clear: left;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python初心者によるDjango超入門!その1「Hello World」とだけ書かれたHTMLページを表示させてみた

背景・目的

Udemyというオンライン講座でDjangoを学習しました。本記事は備忘録を兼ねたアウトプット目的のページです。初心者目線で分かりやすく書いてみようと思います。
参考にさせていただきました講座は以下の2つです。両方とも甲乙付けがたいとてもいい講座でした。

プログラミング初心者でも安心、Python/Django入門講座
【Python 3 x Django 2.0】作りながら覚えるDjango

Djangoってなに?なぜDjangoなの?

ものすごく簡単に言いますと、Pythonの天才プログラマー達が自分のような初心者プログラマーでも簡単にWebサイトを構築できるように、必要なものを集めてくれた道具箱みたいなものです。カッコよく言うとWebフレームワークと言います。

Djangoの他にもJavaScriptやRubyなどで作られたWebフレームワークがあり、シェア率で見ると、そちらの方が2020年現在で上らしいです。ただ、自分の場合はPythonを趣味で使っているといことがあり、基礎知識を学習するコストが低いのでDjangoを選択することにしました。

仮想環境を作ってみる(Windows10機での場合)

まず、仮想環境というものを作ります。これを作っておくと独立した環境になるので、後でライブラリを追加したことで、「さっきまで動いていたのに動かくなったー」というマヌケな事態が発生しなくなります。機械学習系のライブラリだとしょっちゅうこういう事態に陥るので、ちゃんとやっておきましょう。切り戻しも簡単に出来ます。

PowerShellまたはコマンドプロンプトを起動します。
仮想環境は「virtualenv」で作成します。
インストールされていない場合は、以下のコマンドでインストールします。

> py -m pip install virtualenv

インストール出来たら、さっそく仮想環境を構築しましょう。
venvという名前の環境名で構築します。
※環境名は自由です。

> py -m virtualenv venv

作った仮想環境にログインしてみましょう。
venvフォルダに移動してから、以下のコマンドを打つと仮想環境に入ります。

> \Scripts\activate

Djangoのインストールと初期設定

仮想環境に入った後、Djangoをインストールします。

> pip install django

Djangoがインストール出来たら、プロジェクトを作成します。

プロジェクトというのは、これが先に述べた天才Pythonプログラマー達が作ってくれた道具箱です。これにはWebサーバーを構築する上で必要な物がつまっています。

大変有難いのですが、このフォルダ構造が慣れないうちはかなり難解で混乱します。出来るだけ丁寧にどこのファイルを編集しているのか詳しく書いていきます。

「first」という名前のプロジェクトを作成してみます。
※プロジェクト名は自由ですが、仮想環境名と同じにすると混乱するので止めましょう。

> django-admin startproject first

firstというフォルダが作成されるので、firstファルダに移動します。移動した後はWebアプリケーションの作成をします。
※以下はmyappという名前のアプリケーションを作成

> py manage.py startapp myapp

これで新規にmyappというフォルダが作成されました。
以下のようなツリー構造になっているかと思います。
firstプロジェクトフォルダの下に、またfirstフォルダがあって、
「はぁ?」と思うかもしれませんが、こうなっていれば成功です。
image.png
続いて、first\firstの直下にsettings.pyがあります。それを開きましょう。
※↓の赤線で囲った部分です。
image.png
その中に、「INSTALLED_APPS」と記載された箇所があります。
それを以下のように追記しましょう。

first\fisrt\settings.py
INSTALLED_APPS = [
    "...",
    "first", # <-追記
]

これで「firstというアプリがあるんだよ」ということをDjangoに教えることができました。
更に下のほうにスクロールして、LANGUAGE_CODEとTIME_ZONEを以下のように修正します。

first\fisrt\settings.py
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'

LANGUAGE_CODEは日本語、TIME_ZONEは日本の時刻にするという意味です。
これでsettings.pyの設定は完了です。上書き保存して閉じましょう。

urls.pyの編集

続いて、urls.pyを編集します。
名前の通り、ブラウザから入力されたURLの名前解決をするためのファイルです。
first\first\urls.pyを開きます↓
image.png

ファイルを開いたら、以下のように記載します。

first\first\urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('myapp/', include('myapp.urls')) # <- 追記
]

これは、URLにmyappがあったら、myappの直下にあるurls.pyを見に行くようにという指示になります。
こうすることで、今後同じプロジェクト内にアプリが増えても、urlpatternsにURLが乱立しなくて済むのため分かりやすくなります。

続いて、myappフォルダを開いて、urls.pyを新規に作成します。
※デフォルトでは、アプリフォルダの直下にurls.pyはありません。
image.png
ファイルを作成したら開いて、以下のように記述します。

first\myapp\urls.py
from django.urls import path
from . import views

app_name = 'myapp'

urlpatterns = [
    path('', views.index, name='index'),
    path('test/', views.test_index, name='testindex')
]

from . import viewsでviews.pyをimportします。
app_name = 'myapp'はmyappのURLについて名前解決をするという意味です。
urlpatternsにはmyappの後に続くURLについての処理を記載します。
path('', views.index, name='index')myapp/というURLが来た場合の処理、
path('test/', views.test_index, name='testindex')myapp/testというURLが来た場合の処理になります。

まだviews.pyを編集していないのでイメージがわきづらいかと思いますが、
myapp/というURLが来た場合、views.pyにあるindexという関数が実行されます。
myapp/testというURLが来た場合はtest_indexの関数が実行されます。

この関数名は任意です。
これでurls.pyの編集は終わりです。
続いてviews.pyを編集しましょう。

views.pyの編集

さきほどurls.pyで指定したindexとtest_indexという関数を作成しましょう。
views.pyは以下に保存されています。
image.png
views.pyを開き、以下のように記述します。

first\myapp\views.py
from django.http import HttpResponse

def index(request):
    return HttpResponse("hello world")

def test_index(request):
    return HttpResponse("test")

def indexはviews.indexがrequestを受け取ったら、"hello world"と返すだけの関数です。def test_indexはviews.test_indexがrequestを受け取ったら、"test"と返すだけの関数です。

これでviews.pyの編集は終わりです。
いよいよ開発用サーバーを起動してみます。

開発用サーバーの起動

開発用サーバーは、PowerShellで起動します。
一番最初に作ったプロジェクトフォルダの直下に移動してください。
その直下にmanage.pyがあることを確認します。
image.png
そして、以下のコマンドを実行してください。

py manage.py runserber

起動すると以下のような結果が表示されます。
エラーが出た場合は今までの手順で何かミスがあると思われます。
image.png

インターネットブラウザでhttp://127.0.0.1:8000/myapphttp://127.0.0.1:8000/myapp/testとに正常にアクセスできることを確認してください。

無事にhello worldが表示されているかと思います。
image.png

次の記事

次の記事は以下になります。
https://qiita.com/sw1394/items/903397960d7164ff31ac

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RaspberryPiで簡易的な練習用webサーバを作り公開する手順

RaspberryPiで簡易的な練習用webサーバを作り公開する手順

DSC_0148.JPG

はじめに

HTML, CSS, Javascriptを学ぶために、普通はローカルでHTMLファイルを作成し、それをChromeなどに読み込ませる。
しかし、この方法だとwebページを公開している感じがしない。
このページでは、学習中のテストページをWANに公開しながら作成する方法を簡単に解説する。
これで、学習のモチベーションが保てたらいいんじゃないですかね。
ファイルのアップロードは、難しいことを考えずに、windowsのエクスプローラからできるようにします。

目次

  • RaspberryPiを購入
  • RaspberryPiにOSをインストール
  • 初期設定
    • Wifi接続
    • IP固定
    • アップグレード
    • ファイアウォール設定
  • SSHインストール
    • windowsクライアントの設定
  • Webサーバソフトインストール (Nginx)
  • ファイル共有ソフトインストール (samba)
    • 設定ファイル変更
  • ルータのポート開放

RaspberryPiを購入

テスト用のwebサーバなので性能は必要ないです。
おすすめはRaspberryPi 3 model A+ (3300円)
フルサイズのHDMIがささります。
どの機種を選ぶにしても、必ず64bit対応モデルを選ぶこと。

OSをインストール

UbuntuServer20.04をインストールします。

以下のサイトからRaspberryPi専用のOSインストールツールRaspberry Pi imagerをダウンロードし、インストール
https://www.raspberrypi.org/downloads/
Desktop Screenshot 2020.08.10 - 08.11.12.69 (2).png

インストールしたソフトを起動
s-pi imager 1.jpg

書き込むSDカードを指定
s-pi imager 1 - コピー.jpg

OSを選択
s-pi imager 1 - コピー - コピー - コピー.jpg

OSとSDカードが正しく選択されていることを確認し、WRITEを押下
s-pi imager 1 - コピー - コピー - コピー - コピー - コピー.jpg

起動

ラズパイに書き込んだSDカードを差し込み、HDMIと電源をつなげば起動する。

OSの初期設定

①初回ログイン

User : ubuntu
Pass : ubuntu

注意 起動後数分間はこのユーザとパスワードでログインしようとしてもできません。謎の文字列が表示されるまで待ちましょう。

初回ログインが通るとパスワード変更が促されるので変更します。

②日本語キーボードに変更

sudo dpkg-reconfigure keyboard-configuration

Generic 105-key PC (intl.)JapaneseJapaneseThe default for the keyboard layoutNo compose keyYes
の順に選択

③wifiの接続

ネットワークアダプタの名前を調べる

ip a

DSC_0149.JPG

設定ファイルを開く

nano /etc/netplan/50-cloud-init.yaml

設定ファイルを編集

編集前

# This file is generated from information provided by
# the datasource.  Changes to it will not persist across an instance.
# To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        enp5s0:
            addresses: []
            dhcp4: true
            optional: true
    version: 2

編集後

network:
    ethernets:
        enp5s0:
            addresses: []
            dhcp4: true
            optional: true
    wifis:
        "ネットワークアダプタ名":
            addresses: []
            dhcp4: true
            optional: true
            access-points:
                "SSID":
                    password: "password"
    version: 2

④IP固定も同じファイルで設定するので同時にやってしまう

今回は192.168.1.101に固定

編集後

network:
    ethernets:
        enp5s0:
            addresses: []
            dhcp4: true
            optional: true
    wifis:
        "ネットワークアダプタ名":
            addresses: [192.168.1.101/24]
            dhcp4: false
            dhcp6: false
            optional: true
            gateway4: 192.168.1.1
            nameservers:
                addresses: [192.168.1.1, 8.8.8.8, 8.8.4.4]
            access-points:
                "SSID":
                    password: "password"
    version: 2

いったん再起動

sudo reboot

⑤アップデート

sudo apt update
sudo apt upgrade

E: Could no get lock /var/lib/apt/lists/lock. It is held by process 1847 (apt-get)というエラーが出る場合は以下のコマンドを実行する

sudo rm /var/lib/apt/lists/lock
sudo rm /var/cache/apt/archives/lock

とりあえずこれで治る

⑥ファイアウォール設定

ファイアウォール有効化

sudo ufw enable

デフォルトで禁止設定にする

sudo ufw default deny

HTTP用に80番, 443番
SSH用に22番

sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 22

設定リロード

sudo ufw reload

OpenSSHインストール

①Ubuntu側でインストール

sudo apt install ssh

②windows側でSSHクライアントインストール

Puttyダウンロード
https://www.chiark.greenend.org.uk/~sgtatham/putty/

RaspberryPiのipを入力する
s-putty.jpg

うまく接続できていれば一度警告画面が表示され、以下のようなログイン画面に移ります
s-putty - コピー.jpg

webサーバソフトインストール

今回は性能の低いRaspberryPiで実行しているので軽量なNginxを利用する

sudo apt install nginx

ブラウザに http://192.168.1.101 と入力するとデフォルトページが表示される
s-nginx.jpg

ファイル共有ソフトインストール

データベース接続などは少しハードルが高いので、今回はnginxのデフォルト公開ディレクトリをファイル共有し、windowsのエクスプローラから簡単に操作できるようにする。
デフォルトの公開フォルダは/var/www/htmlに設定されている。

①Sambaインストール

sudo apt install samba

②Samba共有設定

Ubuntu上にSamba接続用のユーザを作成。今回のユーザ名は"WebServer"

sudo useradd WebServer

上で設定したユーザをSambaユーザに設定する

sudo pdbedit -a WebServer

ここで作成したユーザとパスワードが、windowsのエクスプローラからアクセスするときのユーザとパスワードになる。

③Samba設定ファイルの変更

設定ファイルを開く

sudo nano /etc/samba/smb.conf

設定ファイルの最後に以下の記述を追加する

/etc/samba/smb.conf
[WebServer]
path = /var/www/html
browseable = yes
writable = yes
valid users = WebServer

共有フォルダの権限を変更

sudo chmod -R 777 /var/www/html

Samba設定反映

sudo service smbd restart

ファイアウォールでSambaのポートを開ける

sudo ufw allow samba

④windowsエクスプローラから共有フォルダにアクセス

エクスプローラ上部のPath入力枠に直接"\\192.168.1.101"と入力する。(\はwindows上では¥と表示されます)
s-エクスプローラ.jpg
ユーザ名とパスワードはSambaユーザを登録したときに設定したもの
s-エクスプローラ - コピー - コピー.jpg
いま、デフォルトの公開ディレクトリ内にはデフォルトページのHTMLファイルがあることがわかる。
ここにHTMLファイルをコピーすれば公開される。

ルータのポート開放

ポート開放設定

WANから来たパケットをRaspberryPiに渡すためにルータ側で設定をする
HTTPとHTTPsのポートである80と443を開放する
s-ポート開放.jpg

ポート開放テスト

グローバルIPから目的のポートにアクセスできるか確認する

グローバルIP確認
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3637373132392f32356437313639372d343134382d386665312d633436652d3962626461646634313637362e6a706567.jpg

確認したグローバルIPを入力して先ほどと同じページが表示されたらweb公開成功
s-ポート開放 - コピー.jpg

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RaspberryPiでwindowsファイル共有を使ったお手軽練習用webサーバを作り公開する手順

RaspberryPiで簡易的な練習用webサーバを作り公開する手順

DSC_0148.JPG

はじめに

HTML, CSS, Javascriptを学ぶために、普通はローカルでHTMLファイルを作成し、それをChromeなどに読み込ませる。
しかし、この方法だとwebページを公開している感じがしない。
このページでは、学習中のテストページをWANに公開しながら作成する方法を簡単に解説する。
これで、学習のモチベーションが保てたらいいんじゃないですかね。
ファイルのアップロードは、難しいことを考えずに、windowsのエクスプローラからできるようにします。

目次

  • RaspberryPiを購入
  • RaspberryPiにOSをインストール
  • 初期設定
    • Wifi接続
    • IP固定
    • アップグレード
    • ファイアウォール設定
  • SSHインストール
    • windowsクライアントの設定
  • Webサーバソフトインストール (Nginx)
  • ファイル共有ソフトインストール (samba)
    • 設定ファイル変更
  • ルータのポート開放

RaspberryPiを購入

テスト用のwebサーバなので性能は必要ないです。
おすすめはRaspberryPi 3 model A+ (3300円)
フルサイズのHDMIがささります。
どの機種を選ぶにしても、必ず64bit対応モデルを選ぶこと。

OSをインストール

UbuntuServer20.04をインストールします。

以下のサイトからRaspberryPi専用のOSインストールツールRaspberry Pi imagerをダウンロードし、インストール
https://www.raspberrypi.org/downloads/
Desktop Screenshot 2020.08.10 - 08.11.12.69 (2).png

インストールしたソフトを起動
s-pi imager 1.jpg

書き込むSDカードを指定
s-pi imager 1 - コピー.jpg

OSを選択
s-pi imager 1 - コピー - コピー - コピー.jpg

OSとSDカードが正しく選択されていることを確認し、WRITEを押下
s-pi imager 1 - コピー - コピー - コピー - コピー - コピー.jpg

起動

ラズパイに書き込んだSDカードを差し込み、HDMIと電源をつなげば起動する。

OSの初期設定

①初回ログイン

User : ubuntu
Pass : ubuntu

注意 起動後数分間はこのユーザとパスワードでログインしようとしてもできません。謎の文字列が表示されるまで待ちましょう。

初回ログインが通るとパスワード変更が促されるので変更します。

②日本語キーボードに変更

sudo dpkg-reconfigure keyboard-configuration

Generic 105-key PC (intl.)JapaneseJapaneseThe default for the keyboard layoutNo compose keyYes
の順に選択

③wifiの接続

ネットワークアダプタの名前を調べる

ip a

DSC_0149.JPG

設定ファイルを開く

nano /etc/netplan/50-cloud-init.yaml

設定ファイルを編集

編集前

# This file is generated from information provided by
# the datasource.  Changes to it will not persist across an instance.
# To disable cloud-init's network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
    ethernets:
        enp5s0:
            addresses: []
            dhcp4: true
            optional: true
    version: 2

編集後

network:
    ethernets:
        enp5s0:
            addresses: []
            dhcp4: true
            optional: true
    wifis:
        "ネットワークアダプタ名":
            addresses: []
            dhcp4: true
            optional: true
            access-points:
                "SSID":
                    password: "password"
    version: 2

④IP固定も同じファイルで設定するので同時にやってしまう

今回は192.168.1.101に固定

編集後

network:
    ethernets:
        enp5s0:
            addresses: []
            dhcp4: true
            optional: true
    wifis:
        "ネットワークアダプタ名":
            addresses: [192.168.1.101/24]
            dhcp4: false
            dhcp6: false
            optional: true
            gateway4: 192.168.1.1
            nameservers:
                addresses: [192.168.1.1, 8.8.8.8, 8.8.4.4]
            access-points:
                "SSID":
                    password: "password"
    version: 2

いったん再起動

sudo reboot

⑤アップデート

sudo apt update
sudo apt upgrade

E: Could no get lock /var/lib/apt/lists/lock. It is held by process 1847 (apt-get)というエラーが出る場合は以下のコマンドを実行する

sudo rm /var/lib/apt/lists/lock
sudo rm /var/cache/apt/archives/lock

とりあえずこれで治る

⑥ファイアウォール設定

ファイアウォール有効化

sudo ufw enable

デフォルトで禁止設定にする

sudo ufw default deny

HTTP用に80番, 443番
SSH用に22番

sudo ufw allow 80
sudo ufw allow 443
sudo ufw allow 22

設定リロード

sudo ufw reload

OpenSSHインストール

①Ubuntu側でインストール

sudo apt install ssh

②windows側でSSHクライアントインストール

Puttyダウンロード
https://www.chiark.greenend.org.uk/~sgtatham/putty/

RaspberryPiのipを入力する
s-putty.jpg

うまく接続できていれば一度警告画面が表示され、以下のようなログイン画面に移ります
s-putty - コピー.jpg

webサーバソフトインストール

今回は性能の低いRaspberryPiで実行しているので軽量なNginxを利用する

sudo apt install nginx

ブラウザに http://192.168.1.101 と入力するとデフォルトページが表示される
s-nginx.jpg

ファイル共有ソフトインストール

データベース接続などは少しハードルが高いので、今回はnginxのデフォルト公開ディレクトリをファイル共有し、windowsのエクスプローラから簡単に操作できるようにする。
デフォルトの公開フォルダは/var/www/htmlに設定されている。

①Sambaインストール

sudo apt install samba

②Samba共有設定

Ubuntu上にSamba接続用のユーザを作成。今回のユーザ名は"WebServer"

sudo useradd WebServer

上で設定したユーザをSambaユーザに設定する

sudo pdbedit -a WebServer

ここで作成したユーザとパスワードが、windowsのエクスプローラからアクセスするときのユーザとパスワードになる。

③Samba設定ファイルの変更

設定ファイルを開く

sudo nano /etc/samba/smb.conf

設定ファイルの最後に以下の記述を追加する

/etc/samba/smb.conf
[WebServer]
path = /var/www/html
browseable = yes
writable = yes
valid users = WebServer

共有フォルダの権限を変更

sudo chmod -R 777 /var/www/html

Samba設定反映

sudo service smbd restart

ファイアウォールでSambaのポートを開ける

sudo ufw allow samba

④windowsエクスプローラから共有フォルダにアクセス

エクスプローラ上部のPath入力枠に直接"\\192.168.1.101"と入力する。(\はwindows上では¥と表示されます)
s-エクスプローラ.jpg
ユーザ名とパスワードはSambaユーザを登録したときに設定したもの
s-エクスプローラ - コピー - コピー.jpg
いま、デフォルトの公開ディレクトリ内にはデフォルトページのHTMLファイルがあることがわかる。
ここにHTMLファイルをコピーすれば公開される。

ルータのポート開放

ポート開放設定

WANから来たパケットをRaspberryPiに渡すためにルータ側で設定をする
HTTPとHTTPsのポートである80と443を開放する
s-ポート開放.jpg

ポート開放テスト

グローバルIPから目的のポートにアクセスできるか確認する

グローバルIP確認
68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3637373132392f32356437313639372d343134382d386665312d633436652d3962626461646634313637362e6a706567.jpg

確認したグローバルIPを入力して先ほどと同じページが表示されたらweb公開成功
s-ポート開放 - コピー.jpg

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む