[{"data":1,"prerenderedAt":5768},["ShallowReactive",2],{"tag-infrastructure":3},{"count":4,"content":5},12,[6,610,2324,3215,3530,3758,4114,4531,5036,5202],{"id":7,"title":8,"body":9,"category":596,"createdAt":598,"description":8,"extension":599,"index":600,"meta":601,"navigation":602,"path":603,"publish":602,"seo":604,"series":600,"seriesTitle":600,"stem":605,"tag":606,"thumbnail":600,"updatedAt":598,"__hash__":609},"articles\u002Farticles\u002Fconnect-with-scp-ssh.md","FTPクライアントでなくターミナルでsshやscpによる通信を行う方法",{"type":10,"value":11,"toc":556},"minimark",[12,16,19,22,25,29,32,38,48,53,64,67,70,75,85,94,98,101,104,107,110,113,116,120,123,126,134,137,140,143,146,148,151,154,157,160,163,166,169,174,177,180,183,186,197,203,206,212,219,222,225,231,234,237,243,246,249,255,258,261,264,276,279,282,285,288,294,297,303,306,312,315,319,322,325,328,331,337,340,343,349,356,362,365,369,372,378,381,384,387,390,396,399,403,406,409,415,418,424,427,433,436,439,442,445,448,454,457,463,466,470,476,480,486,490,493,499,505,508,511,517,520,523,529,535,538,541,547,550,553],[13,14,15],"p",{},"こんにちはjunです。あなたはサーバー上にファイルをアップロードする際にどうやっていますか？大体がFTPクライアント（windowsだとwinscp、MacだとFileZillaなど）を使用していると思います。",[13,17,18],{},"GUIで操作できるソフトは扱いやすく、簡単にアップロード・ダウンロードを行ったり、複数ファイルを移動する際などは便利です。しかしある程度エンジニアレベルが上がると、サーバー構築やサーバー上での操作、例えば権限のいるファイルの編集とか機械的なファイル操作が必要になってくるので、FTPクライアントでの操作では限界が生じます。",[13,20,21],{},"特に大量のファイルを扱う際にはGUIクライアントソフトを用いると時間がかかったりすることも多かったり、権限によってファイルの操作ができない場合はsudoを打てる環境を用意しないといけません。",[13,23,24],{},"今回の記事ではSSHでサーバーとのやりとりをするための設定、そしてローカルとリモート間のscpを用いたファイル転送などGUIからCLI操作へのステップアップできるように解説していきたいと思います",[26,27,28],"h2",{"id":28},"前提条件",[13,30,31],{},"細かい説明に入る前に以下の条件での説明とします。",[13,33,34],{},[35,36,37],"strong",{},"クライアント",[39,40,41,45],"ul",{},[42,43,44],"li",{},"macOS Catalina 10.15.5",[42,46,47],{},"ターミナルを使用",[13,49,50],{},[35,51,52],{},"サーバー（GMO VPSとします）",[39,54,55,58,61],{},[42,56,57],{},"centOS7",[42,59,60],{},"22番ポート開放済み",[42,62,63],{},"sshdインストール済み",[26,65,66],{"id":66},"用語や基礎知識の確認",[13,68,69],{},"まず以降の説明を行う前に基礎的な用語と知識の解説を行います。知っている人はフンフンと頷きながら飛ばしてください。",[71,72,74],"h3",{"id":73},"ssh","SSH",[13,76,77,80,81,84],{},[35,78,79],{},"S","ecure ",[35,82,83],{},"Sh","ellのこと。直訳すると「安全なシェル」。シェルというのはターミナルとかコマンドプロンプトのことだと思ってください。そのシェルとネットワークを用いて遠隔にあるサーバーを操作します。昔はTelnetというものを用いてシェルで遠隔操作していましたが、Telnetで送受信するデータが平文という脆弱性がありました。",[13,86,87,88,90,91,93],{},"それに対する形で通信内容が暗号化される様になっているのがSSH。だから",[35,89,79],{},"ecure な ",[35,92,83],{},"ellと言われる。HttpにHttpsがついた様なニュアンス。",[71,95,97],{"id":96},"ipアドレス","IPアドレス",[13,99,100],{},"ネットワーク通信を行うえで必要な、各ネットワーク機器を一意に区別する数字のこと。マイナンバーとか車のナンバーみたいなものです。IPを用いることで接続するサーバーを指定することができます。SSHでは接続先のIPを知る必要があります。",[71,102,103],{"id":103},"ユーザー",[13,105,106],{},"サーバー上で操作するための名前というか、操作者の名前です。ユーザーを複数作り権限を割り振ることでサーバー上の操作を制限することができます。個々の名前にしておけば、誰が何を実行したのかも分かります。SSHでは「どのユーザー（権限を持った人）で実行するか？」が大切になります。",[13,108,109],{},"linuxでは「root」という名前のユーザーが最初にいます。このrootは他人のパスワードも変えられるし、サーバー上全てのファイルを消すことなんて可能な、なんでもできる「スーパーユーザー」です。",[71,111,112],{"id":112},"グループ",[13,114,115],{},"ユーザーをくくる為の「組」のこと。そのままの意味です。同じグループ内であれば所有者が異なるファイルであっても操作ができます。（そのような権限が付与されている場合）",[71,117,119],{"id":118},"ssh認証方式","SSH認証方式",[13,121,122],{},"SSHはリモートでサーバーに接続しますが、サーバーからしてみれば「どこのよく分からないIP（あなたのPC）から自分をいじってもいいか？」と聞かれているので必ず認証をします。つまりこのサーバーをいじっても良い正規の人間かをチェックします。",[13,124,125],{},"その認証方式としてSSHでは主に",[39,127,128,131],{},[42,129,130],{},"パスワード認証方式",[42,132,133],{},"鍵交換方式",[13,135,136],{},"の２つがあります。",[138,139,130],"h4",{"id":130},[13,141,142],{},"接続する際のユーザー名と、そのユーザーに紐づいたパスワードで接続することができます。Webサービスでログインがあるものと同じですね。分かりやすいですが、接続の度にパスワードを求められてちょっと面倒です。",[13,144,145],{},"また総当たり攻撃で突破される可能性もあるので、運用とセキュリティ面では次の鍵交換がおすすめです。",[138,147,133],{"id":133},[13,149,150],{},"秘密鍵と公開鍵というものを用いて認証を行います。鍵交換による認証原理の説明は今回は省きます。秘密鍵をクライアント（ローカル）において、公開鍵をサーバーにおいておきます。",[13,152,153],{},"ユーザーに紐づいた秘密鍵・公開鍵で認証を行います。秘密鍵は後述する通りにコマンドのオプションで指定できるので自動化やSSHの簡略化の際に便利になります。また秘密鍵のファイルが外部に漏れなければパスワード方式より安全です。",[13,155,156],{},"今回の解説では鍵交換方式でのSSH実行方法の設定も行います。",[26,158,159],{"id":159},"接続準備",[13,161,162],{},"今回は自分でVPSを借りて接続をするという状況として操作をします。ConohaやGMOではブラウザから最初にサーバーの設定を行います。",[13,164,165],{},"OSやrootユーザーのパスワードを設定してまず、サーバーが作られます。IPアドレスなども管理画面などに表示されていると思いますので控えておきます。",[13,167,168],{},"IPアドレスは「123.456.789.012」の様なピリオド４つで分けられた数字列のことです。",[170,171],"image-render",{":src":172,":width":173},"'_mix\u002Fconoha-768x714.png'","'100%'",[170,175],{":src":176,":width":173},"'_mix\u002Fxserver-768x432.png'",[71,178,179],{"id":179},"接続自体は簡単",[13,181,182],{},"IPアドレスとSSHユーザー名とパスワードがわかればあとは簡単です。とりあえず今回はVPSを借りているという想定なので、そのVPSのIPとrootユーザーパスワードがわかっているとします。",[13,184,185],{},"macならばターミナルを開きます。macにはsshを行うsshdが入っているので以下のコマンドを唱えます。",[187,188,193],"pre",{"className":189,"code":191,"language":192},[190],"language-text","~ % ssh root@IP_ADRESS\n","text",[194,195,191],"code",{"__ignoreMap":196},"",[13,198,199,202],{},[194,200,201],{},"ssh ユーザー名＠IPアドレス","を入力します。これは「指定したIPアドレスにrootというユーザー名でssh接続します！」という意味です。特にオプションを指定せず、パスワード認証方式が許可されている場合はパスワードを聞いてくるので入力します。",[13,204,205],{},"正しくパスワードを入力すると次の様な文章が出てきます。",[187,207,210],{"className":208,"code":209,"language":192},[190],"The authenticity of host '*****************' can't be established.\nRSA key fingerprint is *****************.\nAre you sure you want to continue connecting (yes\u002Fno)? \n>yes #問題なければ\n",[194,211,209],{"__ignoreMap":196},[13,213,214,215,218],{},"これはSSHキーフィンガースプリントと言われ日本語では「鍵指紋」と言われています。簡単に説明すると指定したIPで接続しても「本当に自分が繋ごうとしてるサーバーであっていますか？」と尋ねてくる。基本的にVPSなどは信頼できるので",[194,216,217],{},"yes","を選択。",[13,220,221],{},"この時yesを押すとクライアント側にサーバーから送られた公開鍵のハッシュ が保存されます。次回以降の接続ではこの公開鍵のハッシュが一緒に認証に使用されます。なぜ一緒に使われるのかというと、サーバーのなりすまし防止です。",[13,223,224],{},"IPなどの情報に加えてさらにsshdサーバーを区別するためにこの情報を保存して、接続先を担保します。もし次回に保存した公開鍵とサーバーから提示された公開鍵ハッシュ が異なると以下の様な警告が出ます。",[187,226,229],{"className":227,"code":228,"language":192},[190],"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\nIT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!\n",[194,230,228],{"__ignoreMap":196},[26,232,233],{"id":233},"接続の確認",[13,235,236],{},"認証が終えるとこれでssh完了です。意外と簡単ですよね。変わったかどうかを確かめるには、とりあえずターミナルの表示を確認してみてください。",[187,238,241],{"className":239,"code":240,"language":192},[190],"Last login: Wed Jul 15 18:11:06 2020 from xxxxxxxxxxxxx\n[root@HOST_NAME ~]$\n",[194,242,240],{"__ignoreMap":196},[13,244,245],{},"この様にログイン時間、そして左側の表記が「ユーザー名＠IPなどのホスト名　カレントディレクトリ名」になっています。この状態であればログインできています。",[13,247,248],{},"sshを止める場合には",[187,250,253],{"className":251,"code":252,"language":192},[190],"[root@HOST_NAME ~]$ exit\n",[194,254,252],{"__ignoreMap":196},[13,256,257],{},"と入力するとsshを終了(ログアウト)できます。",[26,259,260],{"id":260},"鍵交換の実装",[13,262,263],{},"前述した通りパスワード認証はわかりやすいですが、逐一パスワードを入力したりするのは面倒ですし、自動化ができません。流出や総当たりの危険性があるので出来たら鍵交換方式に変えた方がスムーズです。",[265,266,267,270,273],"ol",{},[42,268,269],{},"ここではrootでパスワード認証して初めてssh接続をした。",[42,271,272],{},"このサーバーにはsshの公開鍵も秘密鍵もねえ！",[42,274,275],{},"root用の鍵交換認証を実装",[13,277,278],{},"という状況で鍵交換を実装したいと思います。",[71,280,281],{"id":281},"秘密鍵と公開鍵を作成する",[13,283,284],{},"サーバーにログインした状態で秘密鍵と公開鍵を作成します。ユーザーのホーム ディレクトリには「.ssh」という隠しフォルダがあり、その中にssh用の鍵を格納します。",[13,286,287],{},"もしホームディレクトリに.sshディレクトリがない場合は作成します。今回は無かったとしましょう。",[187,289,292],{"className":290,"code":291,"language":192},[190],"[root@HOST_NAME ~]$ mkdir .ssh\n[root@HOST_NAME ~]$ chmod 700 ~\u002F.ssh \n",[194,293,291],{"__ignoreMap":196},[13,295,296],{},".sshディレクトリは権限を700にします。でないと鍵による接続ができません。その.sshに移動して以下のコマンドを唱えて両鍵を作成します。今回はパスフレーズ（追加のパスワード）はなしとします。パスフレーズを入れるとパスワード認証の様に逐一入力を求められてしまいます。",[187,298,301],{"className":299,"code":300,"language":192},[190],"[root@HOST_NAME .ssh]$ ssh-keygen -t rsa -f id_rsa #-fはファイル名を指定できる。\nEnter passphrase (empty for no passphrase): #←パスフレーズを入力。基本なしでもOK、その際はEnterをおす\nEnter same passphrase again: #←パスフレーズを再入力。基本なしの時はEnterをおす\nYour identification has been saved in \u002Froot\u002F.ssh\u002Fid_rsa.\nYour public key has been saved in \u002Froot\u002F.ssh\u002Fid_rsa.pub.\nThe key fingerprint is:\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx root@xxxxx\nThe key's randomart image is:\n+--[ RSA 2048]----+\n|                 |\n|       .         |\n|        o        |\n|oo     . .       |\n|*.. .   S .      |\n|+E o       .     |\n|=.o . .   .      |\n|.+ . o ...       |\n|*+.   ..+o       |\n+-----------------+\n[root@HOST_NAME .ssh]$ ls\n[root@HOST_NAME .ssh]$ id_rsa id_rsa.pub\n",[194,302,300],{"__ignoreMap":196},[13,304,305],{},"鍵を作成してディレクトリ内をみると２つのファイルが見つかります。pubがついている方が公開鍵で、もう片方が秘密鍵です。次に公開鍵をサーバーに登録し、600権限を割り振ります。以下のコマンドを唱えます。",[187,307,310],{"className":308,"code":309,"language":192},[190],"[root@HOST_NAME .ssh]$ cat id_rsa.pub >> authorized_keys\n[root@HOST_NAME .ssh]$ chmod 600 authorized_keys\n[root@HOST_NAME .ssh]$ rm -fv id_rsa.pub #id_rsa.pubは捨てる\n",[194,311,309],{"__ignoreMap":196},[13,313,314],{},"権限の設定を忘れて接続ができないミスが多いので注意。",[26,316,318],{"id":317},"秘密鍵をクライアント自分のpcへ送信","秘密鍵をクライアント（自分のPC）へ送信",[13,320,321],{},"では次に接続元となる自分のPCへサーバーで作成した秘密鍵id_rsaを送信します。.sshフォルダ以外の場所に移動して、クラアントツールでひっぱてもいいですが、せっかくなのでscpコマンドを用いてやってみましょう。",[138,323,324],{"id":324},"scpコマンドでリモートからコピーする",[13,326,327],{},"scpはGUIのソフトでの送受信の正体です。リモートからローカルへのファイルのコピーをします。ファイルをコピーするコマンドにcpがありますが、あれがネットワークを通じている物だと思ってください。",[13,329,330],{},"リモートからローカルへコピーする時はローカル側で以下のような入力をします。",[187,332,335],{"className":333,"code":334,"language":192},[190],"jun@MacBook-Pro% scp \u003Cユーザー名>@\u003CIPアドレス>:\u003Cファイルまでのパス> \u003Cファイルを置くローカルのパス>\n",[194,336,334],{"__ignoreMap":196},[13,338,339],{},"scpの後に１つ目に「コピー元のファイルまでのパス」、２つ目に「コピーしたファイルの置き場所」を入力します。注意して欲しいのはscpコマンドはサーバーにログインして唱えるのではないということです。",[13,341,342],{},"よくわからないと思うので、同じようにリモートからあるファイルを取得する操作をFileZillaで行うと以下のようにメッセージが表示されます。やっていることはscpと変わりません。",[187,344,347],{"className":345,"code":346,"language":192},[190],"状態:     \"\u002Fvar\u002Fwww\u002Fhtml\" のディレクトリ リストの表示成功\n状態:     xxx.xx.xxx.xxx に接続中...\n状態:     Using username \"sample\". \n状態:     Connected to    xxx.xx.xxx.xxx\n状態:     \u002Fvar\u002Fwww\u002Fhtml\u002Findex.php のダウンロードを開始しています\n状態:     42 バイト (1 秒) のファイル転送に成功しました\n",[194,348,346],{"__ignoreMap":196},[13,350,351,352,355],{},"ローカルからリモートへ接続してファイルを取得しているのがわかります。scpによるファイルの送受信は ",[35,353,354],{},"サーバーにログインして行うのではなくて"," 、ローカル側から接続先を指定してファイルの送受信を行います。今回の秘密鍵を持ってくる場合は以下のように打ちます。",[187,357,360],{"className":358,"code":359,"language":192},[190],"jun@MacBook-Pro% scp root@IP_ADRESS:~\u002F.ssh\u002Fid_rsa ~\u002F\n",[194,361,359],{"__ignoreMap":196},[13,363,364],{},"「~\u002F」というのは「ホームディレクトリ」配下という意味です。「rootの ~\u002F.ssh\u002Fid_rsaにあるファイル」を「ローカルのホームディレクトリ 」にコピーしろ！という命令です。",[71,366,368],{"id":367},"秘密鍵を適当な箇所に置いて権限を付与","秘密鍵を適当な箇所に置いて、権限を付与",[13,370,371],{},"秘密鍵は接続の際にパスで参照できればどこに置いてもいいのですが、わかりやすいようにローカルの.sshディレクトリ配下に入れることにします。Macにはホームディレクトリに.sshというssh用の隠しフォルダがあります。以下はローカルでの作業です。",[187,373,376],{"className":374,"code":375,"language":192},[190],"jun@MacBook-Pro % cd ~ #ホームディレクトリに移動\njun@MacBook-Pro ~ % mv id_rsa .ssh\u002F && cd .ssh\njun@MacBook-Pro .ssh % ls -a\nconfig  id_rsa  known_hosts\n\njun@MacBook-Pro .ssh % chmod 600 id_rsa\n",[194,377,375],{"__ignoreMap":196},[13,379,380],{},"ここでも秘密鍵は600権限を付与しておきます。ここも忘れてハマりやすいので注意。ssh接続先が多くなり、鍵が増えたら「keys」などの適当な鍵収納用のフォルダを作るといいです。",[26,382,383],{"id":383},"鍵交換で接続する",[13,385,386],{},"以上で鍵交換の実装は完了です。実務的な運用の場合はサーバーでパスワードログインを禁止するなどが必要ですが今回は省略します。ではローカルから鍵を使ってログインしましょう。",[13,388,389],{},".ssh配下に鍵があるので、鍵のパスを指定しする様に以下の様に唱えます。",[187,391,394],{"className":392,"code":393,"language":192},[190],"jun@MacBook-Pro ~ % ssh -i ~\u002F.ssh\u002Fid_rsa root@IP_ADRESS\n",[194,395,393],{"__ignoreMap":196},[13,397,398],{},"パスワード式の接続に「-i」オプションを指定すると、「鍵交換で接続」という意味になります。-iの後にはローカルに保存した秘密鍵までのパスを指定します。あとはユーザー名とIPアドレスを入力すれば完了です。",[26,400,402],{"id":401},"パス指定が面倒","パス指定が面倒〜〜",[13,404,405],{},"鍵交換で実装を行うとパスワードを入力しなくていいので、メモをみたり自動化の際には便利です。しかしパスの指定が面倒という欠点がありますが、簡単に解決できます。エイリアスを設定してとても簡単に接続できる様になります。",[13,407,408],{},"早速設定してみましょう。.sshディレクトリに移動して「config」というファイルを編集します。なければ作成してください。",[187,410,413],{"className":411,"code":412,"language":192},[190],"jun@MacBook-Pro ~ % cd ~\u002F.ssh\njun@MacBook-Pro .ssh % vi config\n",[194,414,412],{"__ignoreMap":196},[13,416,417],{},"このconfigファイルに以下の情報を登録します。",[187,419,422],{"className":420,"code":421,"language":192},[190],"Host sshconnect #好きな名前\n HostName IP_ADRESS\n User root\n Port 22\n IdentityFile ~\u002F.ssh\u002Fid_rsa\n",[194,423,421],{"__ignoreMap":196},[13,425,426],{},"configファイルに上記の様に記述すると以下のコマンドを唱えるだけで、HostNameで指定したサーバーへsshができます。",[187,428,431],{"className":429,"code":430,"language":192},[190],"jun@MacBook-Pro ~ % ssh sshconnect\n",[194,432,430],{"__ignoreMap":196},[13,434,435],{},"とっても短くになりました。「sshconnect」と入力しただけです。さらに鍵交換式なのでパスワードの入力も入りません。ちなみにユーザー名だけだと、パスワードが求められ入力しないといけません。セキュリティの関係上configファイルにはパスワードを記録できません。（FileZillaなどのソフトはソフト自身が記憶している）",[13,437,438],{},"完全にストレスフリーにHostのエイリアスを打つだけで接続するには鍵交換式しかできません。",[26,440,441],{"id":441},"scpでファイルを送ってみよう",[13,443,444],{},"scpファイルの送受信をまとめておきます。",[71,446,447],{"id":447},"エイリアスを用いた送受信",[187,449,452],{"className":450,"code":451,"language":192},[190],"jun@MacBook-Pro ~ %　scp ~\u002Ftest.txt sshconnect:~\u002F\n",[194,453,451],{"__ignoreMap":196},[13,455,456],{},"sshの接続先は上記の様にエイリアス化するとリモート先をこんなに簡単に接続できます。エイリアスを使わない場合は以下の様に唱えます。",[187,458,461],{"className":459,"code":460,"language":192},[190],"jun@MacBook-Pro ~ %　scp -i ~\u002F.ssh\u002Fid_rsa ~\u002Ftest.txt root@IP_ADRESS:~\u002F\n",[194,462,460],{"__ignoreMap":196},[13,464,465],{},"以下はエイリアスを用いた鍵交換となっています。",[26,467,469],{"id":468},"ローカルリモート","ローカル→リモート",[187,471,474],{"className":472,"code":473,"language":192},[190],"jun@MacBook-Pro ~ %　scp ~\u002Ftest.txt sshconnect:~\u002F\n\n# scp \u003Cローカルのファイルまでのパス>　\u003Cエイリアス>:\u003Cリモートのコピー先のパス>\n",[194,475,473],{"__ignoreMap":196},[26,477,479],{"id":478},"リモートローカル","リモート→ローカル",[187,481,484],{"className":482,"code":483,"language":192},[190],"jun@MacBook-Pro ~ %　scp sshconnect:~\u002Ftest.txt　~\u002F \n\n# scp \u003Cエイリアス>:\u003Cリモートのファイルまでのパス>　\u003Cローカルのコピー先のパス>\n",[194,485,483],{"__ignoreMap":196},[26,487,489],{"id":488},"ディレクトリ-ごと移動ローカルから","ディレクトリ ごと移動（ローカルから）",[13,491,492],{},"膨大なファイルを輸送する時に早くて便利です。",[187,494,497],{"className":495,"code":496,"language":192},[190],"jun@MacBook-Pro ~ %　scp -r ~\u002Fheavy\u002F sshconnect:~\u002F\n",[194,498,496],{"__ignoreMap":196},[13,500,501,504],{},[194,502,503],{},"-r","を指定しないと「送信するものが普通のファイルじゃないよ！（not a regular file）」と怒られます。再起的にコピーされるので、ディレクトリ配下全てがコピーされます。",[26,506,507],{"id":507},"リモートからリモート",[13,509,510],{},"リモートサーバーその１をsshconnect01、その２をsshconnect02として01から02へ移動する場合です。ローカルを経由する方法と01で02に対するscpを行う方法があります。図示すると以下の様な感じです。",[187,512,515],{"className":513,"code":514,"language":192},[190],"ローカル経由\n\n  |-------sshconnect01\n  |↓   ←\nlocal\n  |↓　　→\n  |------sshconnect02\n\nリモートから直接\n  |-------sshconnect01\n  |↑   →       |↓\nlocal          |↓\n               |↓\n          sshconnect02\n",[194,516,514],{"__ignoreMap":196},[138,518,519],{"id":519},"リモートで直接",[13,521,522],{},"リモート01から02に直接送る場合はローカルで以下の様に打ちます",[187,524,527],{"className":525,"code":526,"language":192},[190],"リモート01から02に直接送る場合はローカルで以下の様に打ちます\n",[194,528,526],{"__ignoreMap":196},[13,530,531,532,534],{},"ディレクトリを写す場合は ",[194,533,503],{}," オプションを付けます。ただし、この方法は01は02への接続情報を持っていなければなりません。エリアスの場合も01の.ssh\u002Fconfigに sshconnect02についての記述を書く必要があります。02が鍵認証を行っている場合は01に02の鍵をおいておく必要があります。",[138,536,537],{"id":537},"ローカル経由",[13,539,540],{},"01から02に接続できない場合はローカルを経由する様にします。以下の様に打ちます。",[187,542,545],{"className":543,"code":544,"language":192},[190],"jun@MacBook-Pro ~ %　scp -3 sshconnect01:~\u002Ftest.txt　sshconnect02:~\u002F \n",[194,546,544],{"__ignoreMap":196},[13,548,549],{},"-3 オプションを使用します。ディレクトリコピーならばさらに -r を付けましょう。01からローカルに引っ張ってきてから、02へ送信します。自身の転送量は多くなりますが手軽にできます。",[26,551,552],{"id":552},"あとがき",[13,554,555],{},"以上がsshによるリモートログインとscpによるファイル送受信方法です。いつもはGUIソフトで操作しつつ、大量のファイル移動や権限が伴う移動などはコマンドを用いた方が便利です。まずはtest.txtなど影響のないファイルを作って、練習するといいでしょう。",{"title":196,"searchDepth":557,"depth":557,"links":558},3,[559,561,572,575,576,579,583,584,585,588,589,590,591,595],{"id":28,"depth":560,"text":28},2,{"id":66,"depth":560,"text":66,"children":562},[563,564,565,566,567],{"id":73,"depth":557,"text":74},{"id":96,"depth":557,"text":97},{"id":103,"depth":557,"text":103},{"id":112,"depth":557,"text":112},{"id":118,"depth":557,"text":119,"children":568},[569,571],{"id":130,"depth":570,"text":130},4,{"id":133,"depth":570,"text":133},{"id":159,"depth":560,"text":159,"children":573},[574],{"id":179,"depth":557,"text":179},{"id":233,"depth":560,"text":233},{"id":260,"depth":560,"text":260,"children":577},[578],{"id":281,"depth":557,"text":281},{"id":317,"depth":560,"text":318,"children":580},[581,582],{"id":324,"depth":570,"text":324},{"id":367,"depth":557,"text":368},{"id":383,"depth":560,"text":383},{"id":401,"depth":560,"text":402},{"id":441,"depth":560,"text":441,"children":586},[587],{"id":447,"depth":557,"text":447},{"id":468,"depth":560,"text":469},{"id":478,"depth":560,"text":479},{"id":488,"depth":560,"text":489},{"id":507,"depth":560,"text":507,"children":592},[593,594],{"id":519,"depth":570,"text":519},{"id":537,"depth":570,"text":537},{"id":552,"depth":560,"text":552},[597],"devstack","2026-03-25","md",null,{},true,"\u002Farticles\u002Fconnect-with-scp-ssh",{"title":8,"description":8},"articles\u002Fconnect-with-scp-ssh",[607,608],"infrastructure","network","vb0ciWoDxv7wsXMgPxZsPl_2qDz-iNYzIyU8cFy07oc",{"id":611,"title":612,"body":613,"category":2314,"createdAt":2315,"description":2316,"extension":599,"index":600,"meta":2317,"navigation":602,"path":2318,"publish":602,"seo":2319,"series":600,"seriesTitle":600,"stem":2320,"tag":2321,"thumbnail":600,"updatedAt":2315,"__hash__":2323},"articles\u002Farticles\u002Fgithub-actions-node-js.md","Github Actionsを用いてVueファイルをビルド・rsyncで本番環境にデプロイする。",{"type":10,"value":614,"toc":2293},[615,618,621,624,627,636,640,652,655,661,664,667,930,933,936,939,942,945,951,954,957,960,980,986,1001,1017,1020,1023,1030,1039,1042,1045,1059,1065,1071,1077,1083,1089,1095,1098,1104,1110,1113,1374,1380,1382,1390,1393,1396,1425,1439,1542,1556,1585,1588,1634,1641,1644,1651,1658,1693,1696,1735,1739,1742,1873,1884,1891,1921,1938,1983,1997,2008,2012,2015,2085,2088,2095,2099,2105,2172,2176,2186,2237,2247,2254,2257,2264,2268,2271,2274,2277,2280,2283,2286,2289],[13,616,617],{},"こんにちはjunです。皆さんはVueやReact、Nuxtなどなどフロントエンドフレームワークやライブラリを使っていますでしょうか？これらのライブラリはフロントの構築が楽になりますが、一度Node.jsを用いてビルドする必要があります。そしてビルドしたファイルを読み込ませることで動作します。",[13,619,620],{},"ローカルの環境ではNode.jsがあるので問題ないですが、デプロイする本番環境になくて困ったということはありませんでしょうか？サーバー要件などで本番環境にNode.jsを入れられない、無い場合は予めどこかでビルドして転送する必要があります。",[13,622,623],{},"一番手っ取り早いのはローカルでビルドしてFTPなりrsyncすることです。しかし何人もプロジェクトに関わっていたり、属人化したり、環境が統一されていないなど色々とデメリットがあります。",[13,625,626],{},"私はLaravel+Nuxt.jsなプロジェクトを開発し、Xserver（レンタルサーバー）に配置したことがあります。Laravelのアセットファイルと、Nuxt.jsはNode.jsでビルドする必要がありますが、レンタルサーバー にはNode.jsがありません。（Xserverには気合で入れらるらしいですが、、パフォーマンスなどの都合でやめました。）",[13,628,629,630,635],{},"そこで前から気になっていたGithub Actionsを用いてGithub上でビルドを行い、本番環境でrsyncすることでなんとかアセットファイル系がデプロイできました。今回はこの方法について解説します。前提やGithub Actionsの説明から行いますで、さっさと内部コードを知りたい方は「",[631,632,634],"a",{"href":633},"#%E3%83%AF%E3%83%BC%E3%82%AF%E3%83%95%E3%83%AD%E3%83%BC%E3%82%92%E6%9B%B8%E3%81%84%E3%81%A6%E3%81%84%E3%81%8F","ワークフローを書いていく","」へ移動してください。",[26,637,639],{"id":638},"github-actionsとは","Github Actionsとは",[641,642,643],"blockquote",{},[13,644,645,646,651],{},"GitHub Actionsを使用すると、ワールドクラスのCI \u002F CDですべてのソフトウェアワークフローを簡単に自動化できます。 GitHubから直接コードをビルド、テスト、デプロイでき、コードレビュー、ブランチ管理、問題のトリアージを希望どおりに機能させます。(",[631,647,648],{"href":648,"rel":649},"https:\u002F\u002Fgithub.co.jp\u002Ffeatures\u002Factions",[650],"nofollow",")",[13,653,654],{},"Github ActionsはGithubでビルド、テスト、デプロイ作業ができる環境です。Github上のコードを用いてすぐにビルドなどができます。例えばLaravelのVueファイルをビルドする際にはLaravelのプロジェクトルートで",[187,656,659],{"className":657,"code":658,"language":192},[190],"npm run prod\n",[194,660,658],{"__ignoreMap":196},[13,662,663],{},"とnode.jsのコマンドを打って、node.jsを動かしてビルドファイルを作成します。そしてビルド後にはcss,jsディレクトリが作成されます。このビルド操作をGithubの環境でも行えるようにします。",[13,665,666],{},"以下のようなymlファイルをGithub上で作成して、ビルド・やりたいコマンドを記述します。",[187,668,672],{"className":669,"code":670,"language":671,"meta":196,"style":196},"language-yml shiki shiki-themes material-theme-ocean","name: Deploy\n\non: [ workflow_dispatch ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n    \n    steps:\n    - uses: actions\u002Fcheckout@v2\n      with:\n        ref: release\n    - uses: actions\u002Fsetup-node@v2\n      with:\n        node-version: '14'\n        cache: 'npm'\n     - name: public build\n      run: |\n        npm install\n        npm run prod\n        rsync -av --delete \\\n        .\u002Fpublic\u002Fcss .\u002Fpublic\u002Fjs .\u002Fpublic\u002Fimages \\\n        deploy:$LARAVEL_PATH\u002Fpublic\u002F\n        scp .\u002Fpublic\u002Fmix-manifest.json deploy:$LARAVEL_PATH\u002Fpublic\u002Fmix-manifest.json\n      env:\n        LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}\n","yml",[194,673,674,691,696,713,717,726,734,739,750,757,765,779,786,797,809,816,833,848,862,874,880,886,892,898,904,910,918],{"__ignoreMap":196},[675,676,679,683,687],"span",{"class":677,"line":678},"line",1,[675,680,682],{"class":681},"s-wAU","name",[675,684,686],{"class":685},"sAklC",":",[675,688,690],{"class":689},"sfyAc"," Deploy\n",[675,692,693],{"class":677,"line":560},[675,694,695],{"emptyLinePlaceholder":602},"\n",[675,697,698,702,704,707,710],{"class":677,"line":557},[675,699,701],{"class":700},"sbqyR","on",[675,703,686],{"class":685},[675,705,706],{"class":685}," [",[675,708,709],{"class":689}," workflow_dispatch",[675,711,712],{"class":685}," ]\n",[675,714,715],{"class":677,"line":570},[675,716,695],{"emptyLinePlaceholder":602},[675,718,720,723],{"class":677,"line":719},5,[675,721,722],{"class":681},"jobs",[675,724,725],{"class":685},":\n",[675,727,729,732],{"class":677,"line":728},6,[675,730,731],{"class":681},"  build",[675,733,725],{"class":685},[675,735,737],{"class":677,"line":736},7,[675,738,695],{"emptyLinePlaceholder":602},[675,740,742,745,747],{"class":677,"line":741},8,[675,743,744],{"class":681},"    runs-on",[675,746,686],{"class":685},[675,748,749],{"class":689}," ubuntu-latest\n",[675,751,753],{"class":677,"line":752},9,[675,754,756],{"class":755},"s0W1g","    \n",[675,758,760,763],{"class":677,"line":759},10,[675,761,762],{"class":681},"    steps",[675,764,725],{"class":685},[675,766,768,771,774,776],{"class":677,"line":767},11,[675,769,770],{"class":685},"    -",[675,772,773],{"class":681}," uses",[675,775,686],{"class":685},[675,777,778],{"class":689}," actions\u002Fcheckout@v2\n",[675,780,781,784],{"class":677,"line":4},[675,782,783],{"class":681},"      with",[675,785,725],{"class":685},[675,787,789,792,794],{"class":677,"line":788},13,[675,790,791],{"class":681},"        ref",[675,793,686],{"class":685},[675,795,796],{"class":689}," release\n",[675,798,800,802,804,806],{"class":677,"line":799},14,[675,801,770],{"class":685},[675,803,773],{"class":681},[675,805,686],{"class":685},[675,807,808],{"class":689}," actions\u002Fsetup-node@v2\n",[675,810,812,814],{"class":677,"line":811},15,[675,813,783],{"class":681},[675,815,725],{"class":685},[675,817,819,822,824,827,830],{"class":677,"line":818},16,[675,820,821],{"class":681},"        node-version",[675,823,686],{"class":685},[675,825,826],{"class":685}," '",[675,828,829],{"class":689},"14",[675,831,832],{"class":685},"'\n",[675,834,836,839,841,843,846],{"class":677,"line":835},17,[675,837,838],{"class":681},"        cache",[675,840,686],{"class":685},[675,842,826],{"class":685},[675,844,845],{"class":689},"npm",[675,847,832],{"class":685},[675,849,851,854,857,859],{"class":677,"line":850},18,[675,852,853],{"class":685},"     -",[675,855,856],{"class":681}," name",[675,858,686],{"class":685},[675,860,861],{"class":689}," public build\n",[675,863,865,868,870],{"class":677,"line":864},19,[675,866,867],{"class":681},"      run",[675,869,686],{"class":685},[675,871,873],{"class":872},"s6cf3"," |\n",[675,875,877],{"class":677,"line":876},20,[675,878,879],{"class":689},"        npm install\n",[675,881,883],{"class":677,"line":882},21,[675,884,885],{"class":689},"        npm run prod\n",[675,887,889],{"class":677,"line":888},22,[675,890,891],{"class":689},"        rsync -av --delete \\\n",[675,893,895],{"class":677,"line":894},23,[675,896,897],{"class":689},"        .\u002Fpublic\u002Fcss .\u002Fpublic\u002Fjs .\u002Fpublic\u002Fimages \\\n",[675,899,901],{"class":677,"line":900},24,[675,902,903],{"class":689},"        deploy:$LARAVEL_PATH\u002Fpublic\u002F\n",[675,905,907],{"class":677,"line":906},25,[675,908,909],{"class":689},"        scp .\u002Fpublic\u002Fmix-manifest.json deploy:$LARAVEL_PATH\u002Fpublic\u002Fmix-manifest.json\n",[675,911,913,916],{"class":677,"line":912},26,[675,914,915],{"class":681},"      env",[675,917,725],{"class":685},[675,919,921,924,927],{"class":677,"line":920},27,[675,922,923],{"class":681},"        LARAVEL_PATH",[675,925,926],{"class":685}," :",[675,928,929],{"class":689}," ${{ secrets.LARAVEL_PATH }}\n",[13,931,932],{},"Dokcerファイルやバッチファイルと似た感じです。Node.jsの環境などはGithubが用意してくれます。",[71,934,935],{"id":935},"使える言語など",[13,937,938],{},"結構なんでもいけます。Node.jsはしかり、PHP\u002FPython\u002FRuby\u002FJava\u002FPower Shellなど色々あります。",[71,940,941],{"id":941},"料金",[13,943,944],{},"パブリックリポジトリの場合は何分使おうが無料です。しかしプライベートの場合は無料枠があり、フリーは毎月2000分までとなっています。(2022年1月時点)",[13,946,947,948],{},"参照：",[631,949,648],{"href":648,"rel":950},[650],[13,952,953],{},"私のプロジェクトの場合、大体3分ぐらいで終わりますし、頻繁にビルドしないので基本無料で使えそうです。",[26,955,956],{"id":956},"全体処理の概要とビルド対象",[13,958,959],{},"今回ビルドするプロジェクトはLaravelとNuxtが連携されたプロジェクトです。",[39,961,962,973],{},[42,963,964,965,968,969,972],{},"Laravelのresources配下に作ったsassとVueファイル。公開ディレクトリの",[194,966,967],{},"css\u002F",",",[194,970,971],{},"js\u002F","に吐き出される",[42,974,975,976,979],{},"Nuxtの静的書き出しファイル。",[194,977,978],{},"dist\u002F","というディレクトリが生成される。",[187,981,984],{"className":982,"code":983,"language":192},[190],".\n├── README.md\n├── app\n├── artisan\n├── bootstrap\n├── composer.json\n├── composer.lock\n├── config\n├── database\n├── nuxt # nuxtはここ\n├── package-lock.json\n├── package.json\n├── phpunit.xml\n├── public # ここにLaravelのcss,jsが吐き出される\n├── resources\n├── routes\n├── server.php\n├── storage\n├── tests\n├── tinker_test.php\n└── webpack.mix.js\n",[194,985,983],{"__ignoreMap":196},[13,987,988,989,992,993,996,997,1000],{},"まあとりあえず、Laravelルートで",[194,990,991],{},"npm run prod","そして、",[194,994,995],{},"nuxt\u002F","にて",[194,998,999],{},"npm run generate","してnode.jsを動かす必要があります。",[13,1002,1003,1004,968,1006,968,1008,968,1011,968,1014,1016],{},"そして生成されてた",[194,1005,967],{},[194,1007,971],{},[194,1009,1010],{},"images\u002F",[194,1012,1013],{},"mix-manifest.json",[194,1015,978],{},"ディレクトリ・ファイルを本番サーバーに転送します。",[13,1018,1019],{},"転送の際にはrsyncを使用し、SSHの鍵認証で接続します。またこのアクションは手動で行うようにします。一応、masterブランチにプッシュされた時に自動で実行なんてこともできます。ただし今回はビルドする環境が欲しいだけなので、処理の実行は手動で行います。以上がActionの概要です。",[26,1021,1022],{"id":1022},"環境変数を定義しておく",[13,1024,1025,1026,1029],{},"まずSSHやビルドで使用する",[194,1027,1028],{},".env","など環境変数を定義しておきます。Github Actionsでも環境変数を定義できます。",[13,1031,1032,1033,1038],{},"リポジトリのSettingsから",[631,1034,1037],{"href":1035,"rel":1036},"https:\u002F\u002Fgithub.com\u002Fmedia-ch\u002Fsetagaya_foodshare\u002Fsettings\u002Fsecrets\u002Factions",[650],"Secrets","の画面で定義できます。",[170,1040],{":src":1041,":width":173},"'github-actions-node-js\u002Fsecrets-setting.png'",[13,1043,1044],{},"「New repository secret」をクリックしてキー名と値を入力します。",[13,1046,1047,1050,1051,1054,1055,1058],{},[35,1048,1049],{},"SSH_KEY","：SSHに使用する鍵ファイルの中身です。",[194,1052,1053],{},".pem","、",[194,1056,1057],{},".key","などを開いて記述された文字をすべてコピペしてください。",[13,1060,1061,1064],{},[35,1062,1063],{},"SSH_HOST","：接続先のホスト名です。",[13,1066,1067,1070],{},[35,1068,1069],{},"SSH_PORT","：接続先のポートです。",[13,1072,1073,1076],{},[35,1074,1075],{},"SSH_USER","：接続先のユーザーです。",[13,1078,1079,1082],{},[35,1080,1081],{},"LARAEL_PATH","：本番サーバーでのLaravelが置かれている絶対パスです。",[13,1084,1085,1088],{},[35,1086,1087],{},"GOOGLE_MAP_API_KEY","：NuxtでGoogleMapのAPI（フロントに出してもOKなやつ）を使っているので定義。あとで使います。",[13,1090,1091,1092,1094],{},"以上のSSHに関連する値と、",[194,1093,1028],{},"の記述で必要であれば書いておきます。それではアクションの内容を書いていきましょう。",[26,1096,1097],{"id":1097},"ワークフローを作成しテンプレートを選択する",[13,1099,1100,1101],{},"メニューの「Actions」をクリックしたのち、「New Workflow」をクリックします。\n",[170,1102],{":src":1103},"'github-actions-node-js\u002Fmenu.png'",[13,1105,1106,1107],{},"するとworkflowを選択する画面にて、テンプレートをいくつか用意してくれています。\n",[170,1108],{":src":1109},"'github-actions-node-js\u002Fworkflows.png'",[13,1111,1112],{},"今回はNode.jsのビルドしかないので「Node.js」を選択します。するとある程度の記述が書かれた状態で、yamlが表示されます。",[187,1114,1118],{"className":1115,"code":1116,"language":1117,"meta":196,"style":196},"language-yaml shiki shiki-themes material-theme-ocean","# This workflow will do a clean installation of node dependencies, cache\u002Frestore them, build the source code and run tests across different versions of node\n# For more information see: https:\u002F\u002Fhelp.github.com\u002Factions\u002Flanguage-and-framework-guides\u002Fusing-nodejs-with-github-actions\n\nname: Node.js CI\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        node-version: [12.x, 14.x, 16.x]\n        # See supported Node.js release schedule at https:\u002F\u002Fnodejs.org\u002Fen\u002Fabout\u002Freleases\u002F\n\n    steps:\n    - uses: actions\u002Fcheckout@v2\n    - name: Use Node.js ${{ matrix.node-version }}\n      uses: actions\u002Fsetup-node@v2\n      with:\n        node-version: ${{ matrix.node-version }}\n        cache: 'npm'\n    - run: npm ci\n    - run: npm run build --if-present\n    - run: npm test\n","yaml",[194,1119,1120,1126,1131,1135,1144,1148,1154,1161,1175,1182,1194,1198,1204,1210,1214,1222,1226,1233,1240,1264,1269,1273,1279,1289,1300,1309,1315,1324,1337,1350,1362],{"__ignoreMap":196},[675,1121,1122],{"class":677,"line":678},[675,1123,1125],{"class":1124},"sC9rS","# This workflow will do a clean installation of node dependencies, cache\u002Frestore them, build the source code and run tests across different versions of node\n",[675,1127,1128],{"class":677,"line":560},[675,1129,1130],{"class":1124},"# For more information see: https:\u002F\u002Fhelp.github.com\u002Factions\u002Flanguage-and-framework-guides\u002Fusing-nodejs-with-github-actions\n",[675,1132,1133],{"class":677,"line":557},[675,1134,695],{"emptyLinePlaceholder":602},[675,1136,1137,1139,1141],{"class":677,"line":570},[675,1138,682],{"class":681},[675,1140,686],{"class":685},[675,1142,1143],{"class":689}," Node.js CI\n",[675,1145,1146],{"class":677,"line":719},[675,1147,695],{"emptyLinePlaceholder":602},[675,1149,1150,1152],{"class":677,"line":728},[675,1151,701],{"class":700},[675,1153,725],{"class":685},[675,1155,1156,1159],{"class":677,"line":736},[675,1157,1158],{"class":681},"  push",[675,1160,725],{"class":685},[675,1162,1163,1166,1168,1170,1173],{"class":677,"line":741},[675,1164,1165],{"class":681},"    branches",[675,1167,686],{"class":685},[675,1169,706],{"class":685},[675,1171,1172],{"class":689}," master",[675,1174,712],{"class":685},[675,1176,1177,1180],{"class":677,"line":752},[675,1178,1179],{"class":681},"  pull_request",[675,1181,725],{"class":685},[675,1183,1184,1186,1188,1190,1192],{"class":677,"line":759},[675,1185,1165],{"class":681},[675,1187,686],{"class":685},[675,1189,706],{"class":685},[675,1191,1172],{"class":689},[675,1193,712],{"class":685},[675,1195,1196],{"class":677,"line":767},[675,1197,695],{"emptyLinePlaceholder":602},[675,1199,1200,1202],{"class":677,"line":4},[675,1201,722],{"class":681},[675,1203,725],{"class":685},[675,1205,1206,1208],{"class":677,"line":788},[675,1207,731],{"class":681},[675,1209,725],{"class":685},[675,1211,1212],{"class":677,"line":799},[675,1213,695],{"emptyLinePlaceholder":602},[675,1215,1216,1218,1220],{"class":677,"line":811},[675,1217,744],{"class":681},[675,1219,686],{"class":685},[675,1221,749],{"class":689},[675,1223,1224],{"class":677,"line":818},[675,1225,695],{"emptyLinePlaceholder":602},[675,1227,1228,1231],{"class":677,"line":835},[675,1229,1230],{"class":681},"    strategy",[675,1232,725],{"class":685},[675,1234,1235,1238],{"class":677,"line":850},[675,1236,1237],{"class":681},"      matrix",[675,1239,725],{"class":685},[675,1241,1242,1244,1246,1248,1251,1253,1256,1258,1261],{"class":677,"line":864},[675,1243,821],{"class":681},[675,1245,686],{"class":685},[675,1247,706],{"class":685},[675,1249,1250],{"class":689},"12.x",[675,1252,968],{"class":685},[675,1254,1255],{"class":689}," 14.x",[675,1257,968],{"class":685},[675,1259,1260],{"class":689}," 16.x",[675,1262,1263],{"class":685},"]\n",[675,1265,1266],{"class":677,"line":876},[675,1267,1268],{"class":1124},"        # See supported Node.js release schedule at https:\u002F\u002Fnodejs.org\u002Fen\u002Fabout\u002Freleases\u002F\n",[675,1270,1271],{"class":677,"line":882},[675,1272,695],{"emptyLinePlaceholder":602},[675,1274,1275,1277],{"class":677,"line":888},[675,1276,762],{"class":681},[675,1278,725],{"class":685},[675,1280,1281,1283,1285,1287],{"class":677,"line":894},[675,1282,770],{"class":685},[675,1284,773],{"class":681},[675,1286,686],{"class":685},[675,1288,778],{"class":689},[675,1290,1291,1293,1295,1297],{"class":677,"line":900},[675,1292,770],{"class":685},[675,1294,856],{"class":681},[675,1296,686],{"class":685},[675,1298,1299],{"class":689}," Use Node.js ${{ matrix.node-version }}\n",[675,1301,1302,1305,1307],{"class":677,"line":906},[675,1303,1304],{"class":681},"      uses",[675,1306,686],{"class":685},[675,1308,808],{"class":689},[675,1310,1311,1313],{"class":677,"line":912},[675,1312,783],{"class":681},[675,1314,725],{"class":685},[675,1316,1317,1319,1321],{"class":677,"line":920},[675,1318,821],{"class":681},[675,1320,686],{"class":685},[675,1322,1323],{"class":689}," ${{ matrix.node-version }}\n",[675,1325,1327,1329,1331,1333,1335],{"class":677,"line":1326},28,[675,1328,838],{"class":681},[675,1330,686],{"class":685},[675,1332,826],{"class":685},[675,1334,845],{"class":689},[675,1336,832],{"class":685},[675,1338,1340,1342,1345,1347],{"class":677,"line":1339},29,[675,1341,770],{"class":685},[675,1343,1344],{"class":681}," run",[675,1346,686],{"class":685},[675,1348,1349],{"class":689}," npm ci\n",[675,1351,1353,1355,1357,1359],{"class":677,"line":1352},30,[675,1354,770],{"class":685},[675,1356,1344],{"class":681},[675,1358,686],{"class":685},[675,1360,1361],{"class":689}," npm run build --if-present\n",[675,1363,1365,1367,1369,1371],{"class":677,"line":1364},31,[675,1366,770],{"class":685},[675,1368,1344],{"class":681},[675,1370,686],{"class":685},[675,1372,1373],{"class":689}," npm test\n",[13,1375,1376,1377,1379],{},"最初は上記の構成となっています。",[194,1378,682],{},"はワークフローの名前になります。わかりやすいものに変えておきましょう。",[26,1381,634],{"id":634},[13,1383,1384,1385],{},"まず最初にLaravelのアセットファイルを作成してrsyncするとこまで記述します。なお登場する記述に関してはこちらの公式ドキュメントを参考にしてください。",[631,1386,1389],{"href":1387,"rel":1388},"https:\u002F\u002Fdocs.github.com\u002Fja\u002Factions\u002Fusing-workflows\u002Fworkflow-syntax-for-github-actions",[650],"ワークフロー構文",[71,1391,1392],{"id":1392},"実行条件などの変更",[13,1394,1395],{},"最初は実行条件などを変更します。",[187,1397,1399],{"className":1115,"code":1398,"language":1117,"meta":196,"style":196},"name: Deploy\n\non: [ workflow_dispatch ]\n",[194,1400,1401,1409,1413],{"__ignoreMap":196},[675,1402,1403,1405,1407],{"class":677,"line":678},[675,1404,682],{"class":681},[675,1406,686],{"class":685},[675,1408,690],{"class":689},[675,1410,1411],{"class":677,"line":560},[675,1412,695],{"emptyLinePlaceholder":602},[675,1414,1415,1417,1419,1421,1423],{"class":677,"line":557},[675,1416,701],{"class":700},[675,1418,686],{"class":685},[675,1420,706],{"class":685},[675,1422,709],{"class":689},[675,1424,712],{"class":685},[13,1426,1427,1430,1431,1434,1435,1438],{},[194,1428,1429],{},"on:","はこのワークフローの実行条件です。デフォルトでは",[194,1432,1433],{},"master","ブランチにpushされることが条件ですが、ここでは",[194,1436,1437],{},"workflow_dispatch","として、手動で実行できるようにします。",[187,1440,1442],{"className":1115,"code":1441,"language":1117,"meta":196,"style":196},"jobs:\n  build:\n\n    runs-on: ubuntu-latest\n    \n    steps:\n    - uses: actions\u002Fcheckout@v2\n      with:\n        ref: release\n    - uses: actions\u002Fsetup-node@v2\n      with:\n        node-version: '14'\n        cache: 'npm'\n",[194,1443,1444,1450,1456,1460,1468,1472,1478,1488,1494,1502,1512,1518,1530],{"__ignoreMap":196},[675,1445,1446,1448],{"class":677,"line":678},[675,1447,722],{"class":681},[675,1449,725],{"class":685},[675,1451,1452,1454],{"class":677,"line":560},[675,1453,731],{"class":681},[675,1455,725],{"class":685},[675,1457,1458],{"class":677,"line":557},[675,1459,695],{"emptyLinePlaceholder":602},[675,1461,1462,1464,1466],{"class":677,"line":570},[675,1463,744],{"class":681},[675,1465,686],{"class":685},[675,1467,749],{"class":689},[675,1469,1470],{"class":677,"line":719},[675,1471,756],{"class":755},[675,1473,1474,1476],{"class":677,"line":728},[675,1475,762],{"class":681},[675,1477,725],{"class":685},[675,1479,1480,1482,1484,1486],{"class":677,"line":736},[675,1481,770],{"class":685},[675,1483,773],{"class":681},[675,1485,686],{"class":685},[675,1487,778],{"class":689},[675,1489,1490,1492],{"class":677,"line":741},[675,1491,783],{"class":681},[675,1493,725],{"class":685},[675,1495,1496,1498,1500],{"class":677,"line":752},[675,1497,791],{"class":681},[675,1499,686],{"class":685},[675,1501,796],{"class":689},[675,1503,1504,1506,1508,1510],{"class":677,"line":759},[675,1505,770],{"class":685},[675,1507,773],{"class":681},[675,1509,686],{"class":685},[675,1511,808],{"class":689},[675,1513,1514,1516],{"class":677,"line":767},[675,1515,783],{"class":681},[675,1517,725],{"class":685},[675,1519,1520,1522,1524,1526,1528],{"class":677,"line":4},[675,1521,821],{"class":681},[675,1523,686],{"class":685},[675,1525,826],{"class":685},[675,1527,829],{"class":689},[675,1529,832],{"class":685},[675,1531,1532,1534,1536,1538,1540],{"class":677,"line":788},[675,1533,838],{"class":681},[675,1535,686],{"class":685},[675,1537,826],{"class":685},[675,1539,845],{"class":689},[675,1541,832],{"class":685},[13,1543,1544,1545,1548,1549,1551,1552,1555],{},"このリポジトリの場合、本番環境は常に",[194,1546,1547],{},"release","ブランチをプルするのでビルド対象ファイルも",[194,1550,1547],{},"のものを使用します。そのため",[194,1553,1554],{},"- uses: actions\u002Fcheckout@v2","というブランチのチェックアウトが処理を行う記述をします。",[187,1557,1559],{"className":1115,"code":1558,"language":1117,"meta":196,"style":196},"    - uses: actions\u002Fcheckout@v2\n      with:\n        ref: release\n",[194,1560,1561,1571,1577],{"__ignoreMap":196},[675,1562,1563,1565,1567,1569],{"class":677,"line":678},[675,1564,770],{"class":685},[675,1566,773],{"class":681},[675,1568,686],{"class":685},[675,1570,778],{"class":689},[675,1572,1573,1575],{"class":677,"line":560},[675,1574,783],{"class":681},[675,1576,725],{"class":685},[675,1578,1579,1581,1583],{"class":677,"line":557},[675,1580,791],{"class":681},[675,1582,686],{"class":685},[675,1584,796],{"class":689},[13,1586,1587],{},"これでリリースブランチにチェックアウトしてビルドできるようになります。",[187,1589,1591],{"className":1115,"code":1590,"language":1117,"meta":196,"style":196},"- uses: actions\u002Fsetup-node@v2\n      with:\n        node-version: '14'\n        cache: 'npm'\n",[194,1592,1593,1604,1610,1622],{"__ignoreMap":196},[675,1594,1595,1598,1600,1602],{"class":677,"line":678},[675,1596,1597],{"class":685},"-",[675,1599,773],{"class":681},[675,1601,686],{"class":685},[675,1603,808],{"class":689},[675,1605,1606,1608],{"class":677,"line":560},[675,1607,783],{"class":681},[675,1609,725],{"class":685},[675,1611,1612,1614,1616,1618,1620],{"class":677,"line":557},[675,1613,821],{"class":681},[675,1615,686],{"class":685},[675,1617,826],{"class":685},[675,1619,829],{"class":689},[675,1621,832],{"class":685},[675,1623,1624,1626,1628,1630,1632],{"class":677,"line":570},[675,1625,838],{"class":681},[675,1627,686],{"class":685},[675,1629,826],{"class":685},[675,1631,845],{"class":689},[675,1633,832],{"class":685},[13,1635,1636,1637,1640],{},"これでNode.js14の環境を使用できるようになり、npmコマンドも使用できるようになります。それでは",[194,1638,1639],{},"step:","配下に実行するコマンドを書いていきましょう。",[71,1642,1643],{"id":1643},"実行コードの書き方",[13,1645,1646,1647,1650],{},"実行コードは",[194,1648,1649],{},"name:","を用いて区分けできます。長いと何がなんだか分からなくなるので、書いておくといいです。",[13,1652,1653,1654,1657],{},"そして実行内容は",[194,1655,1656],{},"run:","に記述します。",[187,1659,1661],{"className":1115,"code":1660,"language":1117,"meta":196,"style":196},"    - run: npm ci\n    - run: npm run build --if-present\n    - run: npm test\n",[194,1662,1663,1673,1683],{"__ignoreMap":196},[675,1664,1665,1667,1669,1671],{"class":677,"line":678},[675,1666,770],{"class":685},[675,1668,1344],{"class":681},[675,1670,686],{"class":685},[675,1672,1349],{"class":689},[675,1674,1675,1677,1679,1681],{"class":677,"line":560},[675,1676,770],{"class":685},[675,1678,1344],{"class":681},[675,1680,686],{"class":685},[675,1682,1361],{"class":689},[675,1684,1685,1687,1689,1691],{"class":677,"line":557},[675,1686,770],{"class":685},[675,1688,1344],{"class":681},[675,1690,686],{"class":685},[675,1692,1373],{"class":689},[13,1694,1695],{},"のように１つづつ書いてもいいですが、ここでは以下のようにまとめて書くことにします。",[187,1697,1699],{"className":1115,"code":1698,"language":1117,"meta":196,"style":196},"    - name: ssh key generate\n      run: |\n        echo \"$SSH_KEY\" > id_rsa\n        mkdir ~\u002F.ssh\n        chmod 700 ~\u002F.ssh\n",[194,1700,1701,1712,1720,1725,1730],{"__ignoreMap":196},[675,1702,1703,1705,1707,1709],{"class":677,"line":678},[675,1704,770],{"class":685},[675,1706,856],{"class":681},[675,1708,686],{"class":685},[675,1710,1711],{"class":689}," ssh key generate\n",[675,1713,1714,1716,1718],{"class":677,"line":560},[675,1715,867],{"class":681},[675,1717,686],{"class":685},[675,1719,873],{"class":872},[675,1721,1722],{"class":677,"line":557},[675,1723,1724],{"class":689},"        echo \"$SSH_KEY\" > id_rsa\n",[675,1726,1727],{"class":677,"line":570},[675,1728,1729],{"class":689},"        mkdir ~\u002F.ssh\n",[675,1731,1732],{"class":677,"line":719},[675,1733,1734],{"class":689},"        chmod 700 ~\u002F.ssh\n",[71,1736,1738],{"id":1737},"sshの設定","SSHの設定",[13,1740,1741],{},"そんでは最初にSSHの設定を行います。毎回、鍵のパスとかを記述するのは面倒なのでSSHのconfigファイルを作ってエイリアスで呼べるようにしましょう。",[187,1743,1745],{"className":1115,"code":1744,"language":1117,"meta":196,"style":196},"    - name: ssh key generate\n      run: |\n        echo \"$SSH_KEY\" > id_rsa\n        mkdir ~\u002F.ssh\n        chmod 700 ~\u002F.ssh\n        mv id_rsa ~\u002F.ssh\u002F\n        chmod 600 ~\u002F.ssh\u002Fid_rsa\n        echo \"HOST deploy\" >> ~\u002F.ssh\u002Fconfig\n        echo \"HostName $SSH_HOST\" >> ~\u002F.ssh\u002Fconfig\n        echo \"user $SSH_USER\" >> ~\u002F.ssh\u002Fconfig\n        echo \"Port $SSH_PORT\" >> ~\u002F.ssh\u002Fconfig\n        echo \"IdentityFile $HOME\u002F.ssh\u002Fid_rsa\" >> ~\u002F.ssh\u002Fconfig\n        echo \"StrictHostKeyChecking no\" >> ~\u002F.ssh\u002Fconfig\n        echo \"UserKnownHostsFile=\u002Fdev\u002Fnull\" >> ~\u002F.ssh\u002Fconfig\n        chmod 644 ~\u002F.ssh\u002Fconfig\n      env:\n        SSH_KEY: ${{ secrets.SSH_KEY }}\n        SSH_HOST: ${{ secrets.SSH_HOST }}\n        SSH_USER: ${{ secrets.SSH_USER }}\n        SSH_PORT: ${{ secrets.SSH_PORT }}\n",[194,1746,1747,1757,1765,1769,1773,1777,1782,1787,1792,1797,1802,1807,1812,1817,1822,1827,1833,1843,1853,1863],{"__ignoreMap":196},[675,1748,1749,1751,1753,1755],{"class":677,"line":678},[675,1750,770],{"class":685},[675,1752,856],{"class":681},[675,1754,686],{"class":685},[675,1756,1711],{"class":689},[675,1758,1759,1761,1763],{"class":677,"line":560},[675,1760,867],{"class":681},[675,1762,686],{"class":685},[675,1764,873],{"class":872},[675,1766,1767],{"class":677,"line":557},[675,1768,1724],{"class":689},[675,1770,1771],{"class":677,"line":570},[675,1772,1729],{"class":689},[675,1774,1775],{"class":677,"line":719},[675,1776,1734],{"class":689},[675,1778,1779],{"class":677,"line":728},[675,1780,1781],{"class":689},"        mv id_rsa ~\u002F.ssh\u002F\n",[675,1783,1784],{"class":677,"line":736},[675,1785,1786],{"class":689},"        chmod 600 ~\u002F.ssh\u002Fid_rsa\n",[675,1788,1789],{"class":677,"line":741},[675,1790,1791],{"class":689},"        echo \"HOST deploy\" >> ~\u002F.ssh\u002Fconfig\n",[675,1793,1794],{"class":677,"line":752},[675,1795,1796],{"class":689},"        echo \"HostName $SSH_HOST\" >> ~\u002F.ssh\u002Fconfig\n",[675,1798,1799],{"class":677,"line":759},[675,1800,1801],{"class":689},"        echo \"user $SSH_USER\" >> ~\u002F.ssh\u002Fconfig\n",[675,1803,1804],{"class":677,"line":767},[675,1805,1806],{"class":689},"        echo \"Port $SSH_PORT\" >> ~\u002F.ssh\u002Fconfig\n",[675,1808,1809],{"class":677,"line":4},[675,1810,1811],{"class":689},"        echo \"IdentityFile $HOME\u002F.ssh\u002Fid_rsa\" >> ~\u002F.ssh\u002Fconfig\n",[675,1813,1814],{"class":677,"line":788},[675,1815,1816],{"class":689},"        echo \"StrictHostKeyChecking no\" >> ~\u002F.ssh\u002Fconfig\n",[675,1818,1819],{"class":677,"line":799},[675,1820,1821],{"class":689},"        echo \"UserKnownHostsFile=\u002Fdev\u002Fnull\" >> ~\u002F.ssh\u002Fconfig\n",[675,1823,1824],{"class":677,"line":811},[675,1825,1826],{"class":689},"        chmod 644 ~\u002F.ssh\u002Fconfig\n",[675,1828,1829,1831],{"class":677,"line":818},[675,1830,915],{"class":681},[675,1832,725],{"class":685},[675,1834,1835,1838,1840],{"class":677,"line":835},[675,1836,1837],{"class":681},"        SSH_KEY",[675,1839,686],{"class":685},[675,1841,1842],{"class":689}," ${{ secrets.SSH_KEY }}\n",[675,1844,1845,1848,1850],{"class":677,"line":850},[675,1846,1847],{"class":681},"        SSH_HOST",[675,1849,686],{"class":685},[675,1851,1852],{"class":689}," ${{ secrets.SSH_HOST }}\n",[675,1854,1855,1858,1860],{"class":677,"line":864},[675,1856,1857],{"class":681},"        SSH_USER",[675,1859,686],{"class":685},[675,1861,1862],{"class":689}," ${{ secrets.SSH_USER }}\n",[675,1864,1865,1868,1870],{"class":677,"line":876},[675,1866,1867],{"class":681},"        SSH_PORT",[675,1869,686],{"class":685},[675,1871,1872],{"class":689}," ${{ secrets.SSH_PORT }}\n",[13,1874,1875,1876,1879,1880,1883],{},"まず",[194,1877,1878],{},"env:","にて使用する環境変数をコマンド変数に渡します。こうすることでコマンド内で",[194,1881,1882],{},"$SSH_KEY","として値を使用できます。キー、ホスト、ユーザー、ポートを出します。",[13,1885,1886,1887,1890],{},"ちなみに",[194,1888,1889],{},"${{ secrets.SSH_KEY }}","の記述はコンテキストと呼ばれています。ワークフローに関する情報やsecretsに保存した値にアクセスできます。",[187,1892,1894],{"className":1115,"code":1893,"language":1117,"meta":196,"style":196},"echo \"$SSH_KEY\" > id_rsa\nmkdir ~\u002F.ssh\nchmod 700 ~\u002F.ssh\nmv id_rsa ~\u002F.ssh\u002F\nchmod 600 ~\u002F.ssh\u002Fid_rsa\n",[194,1895,1896,1901,1906,1911,1916],{"__ignoreMap":196},[675,1897,1898],{"class":677,"line":678},[675,1899,1900],{"class":689},"echo \"$SSH_KEY\" > id_rsa\n",[675,1902,1903],{"class":677,"line":560},[675,1904,1905],{"class":689},"mkdir ~\u002F.ssh\n",[675,1907,1908],{"class":677,"line":557},[675,1909,1910],{"class":689},"chmod 700 ~\u002F.ssh\n",[675,1912,1913],{"class":677,"line":570},[675,1914,1915],{"class":689},"mv id_rsa ~\u002F.ssh\u002F\n",[675,1917,1918],{"class":677,"line":719},[675,1919,1920],{"class":689},"chmod 600 ~\u002F.ssh\u002Fid_rsa\n",[13,1922,1875,1923,1925,1926,1929,1930,1933,1934,1937],{},[194,1924,1882],{},"を",[194,1927,1928],{},"id_rsa","としてファイルに出力。そして",[194,1931,1932],{},"~\u002F.ssh","ディレクトリを作成してその配下に置いておきます。鍵と",[194,1935,1936],{},".ssh","ディレクトリの権限変更を忘れないようにしてください。",[187,1939,1941],{"className":1115,"code":1940,"language":1117,"meta":196,"style":196},"echo \"HOST deploy\" >> ~\u002F.ssh\u002Fconfig\necho \"HostName $SSH_HOST\" >> ~\u002F.ssh\u002Fconfig\necho \"user $SSH_USER\" >> ~\u002F.ssh\u002Fconfig\necho \"Port $SSH_PORT\" >> ~\u002F.ssh\u002Fconfig\necho \"IdentityFile $HOME\u002F.ssh\u002Fid_rsa\" >> ~\u002F.ssh\u002Fconfig\necho \"StrictHostKeyChecking no\" >> ~\u002F.ssh\u002Fconfig\necho \"UserKnownHostsFile=\u002Fdev\u002Fnull\" >> ~\u002F.ssh\u002Fconfig\nchmod 644 ~\u002F.ssh\u002Fconfig\n",[194,1942,1943,1948,1953,1958,1963,1968,1973,1978],{"__ignoreMap":196},[675,1944,1945],{"class":677,"line":678},[675,1946,1947],{"class":689},"echo \"HOST deploy\" >> ~\u002F.ssh\u002Fconfig\n",[675,1949,1950],{"class":677,"line":560},[675,1951,1952],{"class":689},"echo \"HostName $SSH_HOST\" >> ~\u002F.ssh\u002Fconfig\n",[675,1954,1955],{"class":677,"line":557},[675,1956,1957],{"class":689},"echo \"user $SSH_USER\" >> ~\u002F.ssh\u002Fconfig\n",[675,1959,1960],{"class":677,"line":570},[675,1961,1962],{"class":689},"echo \"Port $SSH_PORT\" >> ~\u002F.ssh\u002Fconfig\n",[675,1964,1965],{"class":677,"line":719},[675,1966,1967],{"class":689},"echo \"IdentityFile $HOME\u002F.ssh\u002Fid_rsa\" >> ~\u002F.ssh\u002Fconfig\n",[675,1969,1970],{"class":677,"line":728},[675,1971,1972],{"class":689},"echo \"StrictHostKeyChecking no\" >> ~\u002F.ssh\u002Fconfig\n",[675,1974,1975],{"class":677,"line":736},[675,1976,1977],{"class":689},"echo \"UserKnownHostsFile=\u002Fdev\u002Fnull\" >> ~\u002F.ssh\u002Fconfig\n",[675,1979,1980],{"class":677,"line":741},[675,1981,1982],{"class":689},"chmod 644 ~\u002F.ssh\u002Fconfig\n",[13,1984,1985,1988,1989,1992,1993,1996],{},[194,1986,1987],{},"~\u002F.ssh\u002Fconfig","ファイルにエイリアスの記述を書いておきます。SSHは初回接続時に警告をだすので",[194,1990,1991],{},"StrictHostKeyChecking no","を設定し、known_hostsを出さないように",[194,1994,1995],{},"UserKnownHostsFile=\u002Fdev\u002Fnull","としておきます。",[13,1998,1999,2000,2003,2004,2007],{},"最後に権限をきちんと設定すれば、",[194,2001,2002],{},"deploy","というSSHエイリアスが使える用意なります。手動で",[194,2005,2006],{},".ssh\u002Fconfig","の設定をしていたのを自動化した感じです。",[71,2009,2011],{"id":2010},"ビルド処理rsync処理を記述","ビルド処理・rsync処理を記述",[13,2013,2014],{},"SSHの設定はできたのでLaravelのアセットビルドをするコードを書きます。",[187,2016,2018],{"className":1115,"code":2017,"language":1117,"meta":196,"style":196},"- name: public build\n  run: |\n    npm install\n    npm run prod\n    rsync -av --delete \\\n    .\u002Fpublic\u002Fcss .\u002Fpublic\u002Fjs .\u002Fpublic\u002Fimages \\\n    deploy:$LARAVEL_PATH\u002Fpublic\u002F\n    scp .\u002Fpublic\u002Fmix-manifest.json deploy:$LARAVEL_PATH\u002Fpublic\u002Fmix-manifest.json\n  env:\n    LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}\n",[194,2019,2020,2030,2039,2044,2049,2054,2059,2064,2069,2076],{"__ignoreMap":196},[675,2021,2022,2024,2026,2028],{"class":677,"line":678},[675,2023,1597],{"class":685},[675,2025,856],{"class":681},[675,2027,686],{"class":685},[675,2029,861],{"class":689},[675,2031,2032,2035,2037],{"class":677,"line":560},[675,2033,2034],{"class":681},"  run",[675,2036,686],{"class":685},[675,2038,873],{"class":872},[675,2040,2041],{"class":677,"line":557},[675,2042,2043],{"class":689},"    npm install\n",[675,2045,2046],{"class":677,"line":570},[675,2047,2048],{"class":689},"    npm run prod\n",[675,2050,2051],{"class":677,"line":719},[675,2052,2053],{"class":689},"    rsync -av --delete \\\n",[675,2055,2056],{"class":677,"line":728},[675,2057,2058],{"class":689},"    .\u002Fpublic\u002Fcss .\u002Fpublic\u002Fjs .\u002Fpublic\u002Fimages \\\n",[675,2060,2061],{"class":677,"line":736},[675,2062,2063],{"class":689},"    deploy:$LARAVEL_PATH\u002Fpublic\u002F\n",[675,2065,2066],{"class":677,"line":741},[675,2067,2068],{"class":689},"    scp .\u002Fpublic\u002Fmix-manifest.json deploy:$LARAVEL_PATH\u002Fpublic\u002Fmix-manifest.json\n",[675,2070,2071,2074],{"class":677,"line":752},[675,2072,2073],{"class":681},"  env",[675,2075,725],{"class":685},[675,2077,2078,2081,2083],{"class":677,"line":759},[675,2079,2080],{"class":681},"    LARAVEL_PATH",[675,2082,926],{"class":685},[675,2084,929],{"class":689},[13,2086,2087],{},"ワークフローの初期位置はリポジトリルートと対応しています。最初にライブラリなどをインストールしてからビルドします。",[13,2089,2090,2091,2094],{},"終わったらrsyncを行います。エイリアスを定義しておいたので",[194,2092,2093],{},"deploy:$LARAVEL_PATH\u002Fpublic\u002F","と簡単な記述で済みます。",[71,2096,2098],{"id":2097},"nuxtjsのビルド処理を記述する","Nuxt.jsのビルド処理を記述する",[13,2100,2101,2102,2104],{},"次に",[194,2103,995],{},"に移動してnuxt.jsのビルド処理を記述します。",[187,2106,2108],{"className":1115,"code":2107,"language":1117,"meta":196,"style":196},"    - name: nuxt build\n      run: |\n        cd nuxt\n        touch .env\n        echo \"GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}\" >> .env\n        npm install\n        npm run generate\n        rsync -av --delete .\u002Fdist deploy:$LARAVEL_PATH\u002Fnuxt\u002F\n      env:\n        LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}\n",[194,2109,2110,2121,2129,2134,2139,2144,2148,2153,2158,2164],{"__ignoreMap":196},[675,2111,2112,2114,2116,2118],{"class":677,"line":678},[675,2113,770],{"class":685},[675,2115,856],{"class":681},[675,2117,686],{"class":685},[675,2119,2120],{"class":689}," nuxt build\n",[675,2122,2123,2125,2127],{"class":677,"line":560},[675,2124,867],{"class":681},[675,2126,686],{"class":685},[675,2128,873],{"class":872},[675,2130,2131],{"class":677,"line":557},[675,2132,2133],{"class":689},"        cd nuxt\n",[675,2135,2136],{"class":677,"line":570},[675,2137,2138],{"class":689},"        touch .env\n",[675,2140,2141],{"class":677,"line":719},[675,2142,2143],{"class":689},"        echo \"GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}\" >> .env\n",[675,2145,2146],{"class":677,"line":728},[675,2147,879],{"class":689},[675,2149,2150],{"class":677,"line":736},[675,2151,2152],{"class":689},"        npm run generate\n",[675,2154,2155],{"class":677,"line":741},[675,2156,2157],{"class":689},"        rsync -av --delete .\u002Fdist deploy:$LARAVEL_PATH\u002Fnuxt\u002F\n",[675,2159,2160,2162],{"class":677,"line":752},[675,2161,915],{"class":681},[675,2163,725],{"class":685},[675,2165,2166,2168,2170],{"class":677,"line":759},[675,2167,923],{"class":681},[675,2169,926],{"class":685},[675,2171,929],{"class":689},[138,2173,2175],{"id":2174},"envファイルを使うには",".envファイルを使うには",[13,2177,2178,2179,2181,2182,2185],{},"プロジェクトによっては",[194,2180,1028],{},"ファイルを使用して端末ごとに環境変数を定義していると思います。.envは大体",[194,2183,2184],{},"gitignore","されてバージョン管理されていないので、ワークフローないで作成します。",[187,2187,2189],{"className":1115,"code":2188,"language":1117,"meta":196,"style":196},"      run: |\n        cd nuxt\n        touch .env\n        echo \"GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}\" >> .env\n        npm install\n        npm run generate\n        rsync -av --delete .\u002Fdist deploy:$LARAVEL_PATH\u002Fnuxt\u002F\n      env:\n        LARAVEL_PATH : ${{ secrets.LARAVEL_PATH }}\n",[194,2190,2191,2199,2203,2207,2211,2215,2219,2223,2229],{"__ignoreMap":196},[675,2192,2193,2195,2197],{"class":677,"line":678},[675,2194,867],{"class":681},[675,2196,686],{"class":685},[675,2198,873],{"class":872},[675,2200,2201],{"class":677,"line":560},[675,2202,2133],{"class":689},[675,2204,2205],{"class":677,"line":557},[675,2206,2138],{"class":689},[675,2208,2209],{"class":677,"line":570},[675,2210,2143],{"class":689},[675,2212,2213],{"class":677,"line":719},[675,2214,879],{"class":689},[675,2216,2217],{"class":677,"line":728},[675,2218,2152],{"class":689},[675,2220,2221],{"class":677,"line":736},[675,2222,2157],{"class":689},[675,2224,2225,2227],{"class":677,"line":741},[675,2226,915],{"class":681},[675,2228,725],{"class":685},[675,2230,2231,2233,2235],{"class":677,"line":752},[675,2232,923],{"class":681},[675,2234,926],{"class":685},[675,2236,929],{"class":689},[13,2238,2239,2240,2242,2243,2246],{},"と必要な箇所で",[194,2241,1028],{},"ファイルを作って、",[194,2244,2245],{},"echo \"GOOGLE_MAP_API_KEY=${{ secrets.GOOGLE_MAP_API_KEY }}\" >> .env","とGithubの環境変数内容を出力します。これでOKです。",[13,2248,2249,2250,2253],{},"nuxtは静的書出すると",[194,2251,2252],{},"dist","が作成されるので、rsyncで転送します。",[71,2255,2256],{"id":2256},"保存する",[13,2258,2259,2260,2263],{},"記述が終わったら画面右上の「Start Commit」をおして内容をコミットします。ちなみにワークフローファイルはリポジトリの",[194,2261,2262],{},".github\u002Fworkflows","というディレクトリが作られ、そこに保存されます。",[26,2265,2267],{"id":2266},"全ビルドを実行手動","全ビルドを実行（手動）",[13,2269,2270],{},"ではビルドしましょう。Actionsで対象のデプロイ名を選択して「Run Workflow」を押して、対象ブランチを選択して実行します。",[170,2272],{":src":2273},"'github-actions-node-js\u002Fdispatch-job.png'",[13,2275,2276],{},"ビルド中の様子やログは随時確認することができます。ビルドが無事に終了すると以下のように全てチェックマークとなり、処理が終了します。どこかエラーが起きた場合はそこで処理が中止されます。",[170,2278],{":src":2279},"'github-actions-node-js\u002Fsuccess.png'",[13,2281,2282],{},"終わったら本番サーバーで対象のファイルが作られているかなどを確認してみましょう。",[26,2284,2285],{"id":2285},"使ってみた感想",[13,2287,2288],{},"少人数でこれぐらいであればローカルPCで誰でもできそうですが、ボタンひとつでビルドできるようになることや手違いもなくなるのでとてもおすすめです。色々自動化できるようにGithub Actionsを色々探ってみます。",[2290,2291,2292],"style",{},"html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sbqyR, html code.shiki .sbqyR{--shiki-default:#FF9CAC}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .s6cf3, html code.shiki .s6cf3{--shiki-default:#89DDFF;--shiki-default-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sC9rS, html code.shiki .sC9rS{--shiki-default:#464B5D;--shiki-default-font-style:italic}",{"title":196,"searchDepth":557,"depth":557,"links":2294},[2295,2299,2300,2301,2302,2312,2313],{"id":638,"depth":560,"text":639,"children":2296},[2297,2298],{"id":935,"depth":557,"text":935},{"id":941,"depth":557,"text":941},{"id":956,"depth":560,"text":956},{"id":1022,"depth":560,"text":1022},{"id":1097,"depth":560,"text":1097},{"id":634,"depth":560,"text":634,"children":2303},[2304,2305,2306,2307,2308,2311],{"id":1392,"depth":557,"text":1392},{"id":1643,"depth":557,"text":1643},{"id":1737,"depth":557,"text":1738},{"id":2010,"depth":557,"text":2011},{"id":2097,"depth":557,"text":2098,"children":2309},[2310],{"id":2174,"depth":570,"text":2175},{"id":2256,"depth":557,"text":2256},{"id":2266,"depth":560,"text":2267},{"id":2285,"depth":560,"text":2285},[597],"2026-02-11","not node.jsな環境でアセットをビルドして転送する。",{},"\u002Farticles\u002Fgithub-actions-node-js",{"title":612,"description":2316},"articles\u002Fgithub-actions-node-js",[607,2322],"node","tRNfJ9LFek0TNwphGk2rKIZmRCAhyvmVgSvx-MGlLXE",{"id":2325,"title":2326,"body":2327,"category":3205,"createdAt":3206,"description":3207,"extension":599,"index":600,"meta":3208,"navigation":602,"path":3209,"publish":602,"seo":3210,"series":600,"seriesTitle":600,"stem":3211,"tag":3212,"thumbnail":3213,"updatedAt":3206,"__hash__":3214},"articles\u002Farticles\u002Fs3-clioudfront-website.md","AWS S3を使ってSSL&独自ドメインの静的ブログをホストする",{"type":10,"value":2328,"toc":3187},[2329,2332,2349,2352,2359,2362,2370,2377,2381,2384,2387,2394,2397,2400,2403,2406,2425,2428,2431,2434,2437,2440,2443,2632,2648,2662,2668,2671,2674,2678,2681,2698,2701,2705,2714,2717,2720,2723,2726,2729,2732,2735,2738,2741,2744,2747,2750,2759,2763,2766,2769,2772,2775,2778,2781,2784,2787,2790,2793,2797,2806,2813,2816,2824,2827,2830,2833,2841,2844,2854,2861,2864,2867,2870,2873,2878,2884,2909,2912,2925,2934,2938,2944,2948,2951,2956,2959,2962,2965,2968,2971,2974,2977,2980,2983,2986,3007,3010,3014,3030,3058,3080,3086,3094,3097,3100,3114,3171,3174,3177,3181,3184],[13,2330,2331],{},"こんにちはjunです。会社で静的書き出ししたコンテンツをs3でホストし、cloudfrontを用いてwebサーバーの様にブログ内容をリクエストできる様な構成を作成しました。せっかくなので自分のブログも同じ様にやってみようと思い、復習兼ねて記事にしようと思います。今回は以下のことを説明します。",[39,2333,2334,2337,2340,2343,2346],{},[42,2335,2336],{},"S3の設定",[42,2338,2339],{},"cloudfrontの設定",[42,2341,2342],{},"独自ドメインの設定（DNSはお名前ドットコム）",[42,2344,2345],{},"IAMでのデプロイユーザーの作成",[42,2347,2348],{},"nuxt generate で転送する方法",[13,2350,2351],{},"私のこのブログはnuxt content を用いてnuxt generate をして静的書き出したものをサーバに転送しています。今まではレンタルサーバーの一部ディレクトリを使用していましたが、AWSの勉強ややってみたい機能をつけやすくするためにS3へ引っ越しました。それでは早速やっていきましょう。",[2353,2354,2358],"div",{"className":2355},[2356,2357],"alert","alert-danger","\nこの記事が説明している内容は2021年10月時点の情報です。\n",[26,2360,2361],{"id":2361},"参考資料",[13,2363,2364,2365],{},"\b",[631,2366,2369],{"href":2367,"rel":2368},"https:\u002F\u002Faws.amazon.com\u002Fjp\u002Fpremiumsupport\u002Fknowledge-center\u002Fcloudfront-serve-static-website#Using_a_website_endpoint_as_the_origin.2C_with_anonymous_.28public.29_access_allowed",[650],"CloudFront を使用して、Amazon S3 でホストされた静的ウェブサイトを公開するにはどうすればよいですか?",[13,2371,2372],{},[631,2373,2376],{"href":2374,"rel":2375},"https:\u002F\u002Fdocs.aws.amazon.com\u002Fja_jp\u002FRoute53\u002Flatest\u002FDeveloperGuide\u002Frouting-to-cloudfront-distribution.html",[650],"ドメイン名を使用したトラフィックの Amazon CloudFront ディストリビューションへのルーティング",[26,2378,2380],{"id":2379},"s3でデプロイ用のバケットを作成する","S3でデプロイ用のバケットを作成する。",[13,2382,2383],{},"では最初にまずホスティング元であるバケットを作成します。",[170,2385],{":src":2386,":width":173},"'s3-clioudfront-website\u002Fsch-iam-4.png'",[13,2388,2389,2390,2393],{},"バケットの名前は ",[35,2391,2392],{},"ホストするドメインの名前と同じ"," になるようにします。私の場合はバケット名が「jun-app.com」です。",[170,2395],{":src":2396,":width":173},"'s3-clioudfront-website\u002Fsch-s3-1.png'",[13,2398,2399],{},"設定した後にバケット一覧から選択し、プロパティを選びます。プロパティの一番下までスクロールすると「静的ウェブサイトホスティング」とあるのでここを編集します。",[170,2401],{":src":2402,":width":173},"'s3-clioudfront-website\u002Fsch-s3-2.png'",[170,2404],{":src":2405,":width":173},"'s3-clioudfront-website\u002Fsch-s3-3.png'",[13,2407,2408,2409,2412,2413,2416,2417,2420,2421,2424],{},"無効から有効に変更し、インデックスドキュメントに",[194,2410,2411],{},"index.html","を入力します。こうすると",[194,2414,2415],{},"https:\u002F\u002Fjun-app.com\u002Fdir\u002F","みたいにパスだけであっても",[194,2418,2419],{},"https:\u002F\u002Fjun-app.com\u002Fdir\u002Findex.html","に接続してくれます。また、エラードキュメントを指定しておくことで404リクエストの際のフォールバックとして利用できます。私の場合はルート直下の ",[194,2422,2423],{},"404.html","を指定しています。",[170,2426],{":src":2427,":width":173},"'s3-clioudfront-website\u002Fsch-s3-4.png'",[13,2429,2430],{},"編集後もういちど静的ウェブサイトホスティングの設定までいくと、一応URLが提供されますがアクセスしても「403 Forbidden」となります。これはバケットに対してパブリックアクセスがないからです。バケット作成時、デフォルトでは全てのパブリックアクセスが制限されていたので、その制限を外してあげます。バケットの画面から「アクセス許可」を選択し、「ブロックパブリックアクセス (バケット設定)」の編集をします。（ここを見ると「パブリックアクセスをすべて ブロック」が有効になっている）",[170,2432],{":src":2433,":width":173},"'s3-clioudfront-website\u002Fsch-s3-5.png'",[13,2435,2436],{},"編集の画面で「パブリックアクセスをすべて ブロック」のチェックを外して、全てのブロックを外します。",[170,2438],{":src":2439,":width":173},"'s3-clioudfront-website\u002Fsch-s3-6.png'",[13,2441,2442],{},"まだ終わりではありません。先ほどのはバケット単位の設定であり、アップロードされるオブジェクト（静的ファイル）には公開される設定がされません。毎回オブジェクトに対してパブリックアクセスを与えるのは面倒なので、「アクセス許可」の画面にあるバケットポリシーを以下のように編集します。",[187,2444,2448],{"className":2445,"code":2446,"language":2447,"meta":196,"style":196},"language-JSON shiki shiki-themes material-theme-ocean","{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"PublicReadGetObject\",\n            \"Effect\": \"Allow\",\n            \"Principal\": \"*\",\n            \"Action\": [\n                \"s3:GetObject\"\n            ],\n            \"Resource\": [\n                \"arn:aws:s3:::your-buget-name\u002F*\"\n            ]\n        }\n    ]\n}\n","JSON",[194,2449,2450,2455,2480,2494,2499,2521,2541,2561,2574,2585,2590,2603,2612,2617,2622,2627],{"__ignoreMap":196},[675,2451,2452],{"class":677,"line":678},[675,2453,2454],{"class":685},"{\n",[675,2456,2457,2460,2464,2467,2469,2472,2475,2477],{"class":677,"line":560},[675,2458,2459],{"class":685},"    \"",[675,2461,2463],{"class":2462},"sJ14y","Version",[675,2465,2466],{"class":685},"\"",[675,2468,686],{"class":685},[675,2470,2471],{"class":685}," \"",[675,2473,2474],{"class":689},"2012-10-17",[675,2476,2466],{"class":685},[675,2478,2479],{"class":685},",\n",[675,2481,2482,2484,2487,2489,2491],{"class":677,"line":557},[675,2483,2459],{"class":685},[675,2485,2486],{"class":2462},"Statement",[675,2488,2466],{"class":685},[675,2490,686],{"class":685},[675,2492,2493],{"class":685}," [\n",[675,2495,2496],{"class":677,"line":570},[675,2497,2498],{"class":685},"        {\n",[675,2500,2501,2504,2508,2510,2512,2514,2517,2519],{"class":677,"line":719},[675,2502,2503],{"class":685},"            \"",[675,2505,2507],{"class":2506},"s5Dmg","Sid",[675,2509,2466],{"class":685},[675,2511,686],{"class":685},[675,2513,2471],{"class":685},[675,2515,2516],{"class":689},"PublicReadGetObject",[675,2518,2466],{"class":685},[675,2520,2479],{"class":685},[675,2522,2523,2525,2528,2530,2532,2534,2537,2539],{"class":677,"line":728},[675,2524,2503],{"class":685},[675,2526,2527],{"class":2506},"Effect",[675,2529,2466],{"class":685},[675,2531,686],{"class":685},[675,2533,2471],{"class":685},[675,2535,2536],{"class":689},"Allow",[675,2538,2466],{"class":685},[675,2540,2479],{"class":685},[675,2542,2543,2545,2548,2550,2552,2554,2557,2559],{"class":677,"line":736},[675,2544,2503],{"class":685},[675,2546,2547],{"class":2506},"Principal",[675,2549,2466],{"class":685},[675,2551,686],{"class":685},[675,2553,2471],{"class":685},[675,2555,2556],{"class":689},"*",[675,2558,2466],{"class":685},[675,2560,2479],{"class":685},[675,2562,2563,2565,2568,2570,2572],{"class":677,"line":741},[675,2564,2503],{"class":685},[675,2566,2567],{"class":2506},"Action",[675,2569,2466],{"class":685},[675,2571,686],{"class":685},[675,2573,2493],{"class":685},[675,2575,2576,2579,2582],{"class":677,"line":752},[675,2577,2578],{"class":685},"                \"",[675,2580,2581],{"class":689},"s3:GetObject",[675,2583,2584],{"class":685},"\"\n",[675,2586,2587],{"class":677,"line":759},[675,2588,2589],{"class":685},"            ],\n",[675,2591,2592,2594,2597,2599,2601],{"class":677,"line":767},[675,2593,2503],{"class":685},[675,2595,2596],{"class":2506},"Resource",[675,2598,2466],{"class":685},[675,2600,686],{"class":685},[675,2602,2493],{"class":685},[675,2604,2605,2607,2610],{"class":677,"line":4},[675,2606,2578],{"class":685},[675,2608,2609],{"class":689},"arn:aws:s3:::your-buget-name\u002F*",[675,2611,2584],{"class":685},[675,2613,2614],{"class":677,"line":788},[675,2615,2616],{"class":685},"            ]\n",[675,2618,2619],{"class":677,"line":799},[675,2620,2621],{"class":685},"        }\n",[675,2623,2624],{"class":677,"line":811},[675,2625,2626],{"class":685},"    ]\n",[675,2628,2629],{"class":677,"line":818},[675,2630,2631],{"class":685},"}\n",[13,2633,2634,2635,2637,2638,2640,2641,2643,2644,2647],{},"上記のJSONは",[194,2636,2547],{},"はこのポリシーを付与するユーザーです。",[194,2639,2556],{},"としてゲストを含む全てのユーザーに",[194,2642,2581],{},"のアクション、つまりファイルの読み取りを",[194,2645,2646],{},"\"arn:aws:s3:::your-buget-name\u002F*\"","のバケットオブジェクトに許可するという意味です。",[13,2649,2650,2653,2654,2657,2658,2661],{},[194,2651,2652],{},"your-buget-name","にはあなたが設定したバケット名を入力します。そしてそのバケット配下の全オブジェクトに適用するため",[194,2655,2656],{},"your-buget-name\u002F*","とディレクトリのように指定します。",[194,2659,2660],{},"\"arn:aws:s3:::your-buget-name","という記述（Amazon リソースネーム）はバケットのプロパティで取得できます。",[13,2663,2664,2665,2667],{},"こうすればこのバケットないのファイルは公開されます。試しに",[194,2666,2411],{},"をアップロードして、提供されたオブジェクト URLにアクセスすると確かに見れます。",[170,2669],{":src":2670,":width":173},"'s3-clioudfront-website\u002Fsch-s3-7.png'",[13,2672,2673],{},"これでS3側の設定が完了しました。ただしドメインはS3の初期状態のままです。独自ドメインを割り当てとSSL化を行います。",[26,2675,2677],{"id":2676},"sslと独自ドメインを割り当てる","SSLと独自ドメインを割り当てる",[13,2679,2680],{},"SSL化した独自ドメインをS3に接続させるためにはcloudfrontの力が必要です。また今回使用するドメイン「jun-app.com」はお名前ドットコムで取得しているので、CNAMEを加えるなどの設定が必要です。クライアントがコンテンツを取得する流れは以下のようになります。",[265,2682,2683,2686,2689,2692,2695],{},[42,2684,2685],{},"クライアントがURLにアクセス",[42,2687,2688],{},"お名前ドットコムへDNS問い合わせ",[42,2690,2691],{},"お名前ドットコムはRoute53にNSを移譲しているので、問い合わせはRoute53へ",[42,2693,2694],{},"Route53 はcloudfrontのIPを返す",[42,2696,2697],{},"cloudfrontからS3に接続",[13,2699,2700],{},"といった流れです。",[71,2702,2704],{"id":2703},"route53と外部dnsの設定","Route53と外部DNSの設定",[13,2706,2707,2708,2713],{},"まずはRoute53でホストゾーンというものを作成して、お名前.comからNSサーバーをRoute53へ委任できるようにします。",[631,2709,2712],{"href":2710,"rel":2711},"https:\u002F\u002Fconsole.aws.amazon.com\u002Froute53\u002Fv2\u002Fhome#Dashboard",[650],"Route53","に移動して「ホストゾーンの作成」をします。",[170,2715],{":src":2716,":width":173},"'s3-clioudfront-website\u002Fsch-r53-1.png'",[13,2718,2719],{},"委任したいドメインを入力します。「パブリックホストゾーン」で大丈夫です。タグは管理上のものなので空欄で大丈夫です。問題なければ「ホストゾーンの作成」をクリックします。",[170,2721],{":src":2722,":width":173},"'s3-clioudfront-website\u002Fsch-r53-2.png'",[13,2724,2725],{},"作成後にはこのようにNSレコードとSOAレコードが作成されます。ドメイン自体が外部DNS（お名前.com）にある場合この「NSレコード」を指定することでRoute53に委任します。（ぼやけていますが４つ作成されます。）",[170,2727],{":src":2728,":width":173},"'s3-clioudfront-website\u002Fsch-r53-3.png'",[13,2730,2731],{},"このNSレコードをお名前.comの場合は「ネームサーバーの設定」を選択します。",[170,2733],{":src":2734,":width":173},"'s3-clioudfront-website\u002Fsch-r53-4.png'",[13,2736,2737],{},"そして「2.ネームサーバーの選択」＞「その他」＞「その他のネームサーバーを使う」にてRoute53で表示された４つのNSレコードをいれて「確認」クリックします。",[170,2739],{":src":2740,":width":173},"'s3-clioudfront-website\u002Fsch-r53-5.png'",[13,2742,2743],{},"「確認」の後にはDNSのNSが切り替わり、「jun-app.com」はまずお名前.comへ問い合わせられますが、結局Route53へたらい回しされます。これで「jun-app.com」のAレコードなどをRoute53で制御できるようになりました。",[13,2745,2746],{},"次はS3とcloudfrontと連携させてSSLを利用できるようにします。",[71,2748,2749],{"id":2749},"独自ドメインの証明書を取得する",[13,2751,2752,2753,2758],{},"まずcloudfrontの設定の前に独自ドメイン（jun-app.com）のSSL証明書をAWSで取得しておきます。AWSでは",[631,2754,2757],{"href":2755,"rel":2756},"https:\u002F\u002Fap-northeast-1.console.aws.amazon.com\u002Facm\u002Fhome",[650],"AWS Certificate Manager"," で取得できます。ただしここで注意点があります。",[2353,2760,2762],{"className":2761},[2356,2357],"\n以下の画像のようにAWS Certificate Managerでのカスタム証明書(独自ドメインの証明書)をcloudfrontに割り当てる場合、AWS Certificate Managerのリージョンが「米国東部 (バージニア北部) リージョン (us-east-1) 」でないといけません。私は間違って東京リージョンで作成してしまい、証明書がサジェストで出てこずはまりました。\n",[170,2764],{":src":2765,":width":173},"'s3-clioudfront-website\u002Fsch-cfm-1.png'",[13,2767,2768],{},"リージョンを「us-east-1」に変更したのち「証明書をリクエスト」をクリックして作成します。",[170,2770],{":src":2771,":width":173},"'s3-clioudfront-website\u002Fsch-cfm-2.png'",[13,2773,2774],{},"証明書のタイプは「パブリック証明書をリクエスト」を選択し、ドメイン名などを入力します。そして検証では「DNS検証」を行います。Route53で委任してあれば「DNS検証」ですぐに発行できます。DNS検証はドメインを管理しているDNSにAWS Certificate Managerで発行されたCNAMEを設定することで、ドメインの所有権を確認します。全て入力して「リクエスト」となります。",[170,2776],{":src":2777,":width":173},"'s3-clioudfront-website\u002Fsch-cfm-3.png'",[13,2779,2780],{},"リクエスト後には一覧に入力したドメインが現れ、対応するCNAMEが現れます。Route53で管理している場合は「Route53でレコードを作成」のボタンを押すだけで作ってくれます。手動で設定する場合は「CNAMEレコード」を作成して、その値を設定するだけです。",[170,2782],{":src":2783,":width":173},"'s3-clioudfront-website\u002Fsch-cfm-4.png'",[13,2785,2786],{},"このようにDNS検証に必要なCNAMEが追加されています。",[170,2788],{":src":2789,":width":173},"'s3-clioudfront-website\u002Fsch-cfm-5.png'",[13,2791,2792],{},"数分経つと証明書の検証が完了となりますので、これで「jun-app.com」の証明書の準備ができました。次はcloudfrontとS3を独自ドメインを用いて連携します。",[71,2794,2796],{"id":2795},"cloudfrontとs3を連携","cloudfrontとS3を連携",[13,2798,2799,2800,2805],{},"それではcloudfrontとS3を独自ドメインを連携します。",[631,2801,2804],{"href":2802,"rel":2803},"https:\u002F\u002Fconsole.aws.amazon.com\u002Fcloudfront\u002Fv3\u002Fhome?#\u002F",[650],"cloudfront","のコンソールに移動して「ディスりビーションの作成」をクリックします。",[13,2807,2808,2809,2812],{},"そしてcloudfrontと連携するAWSリソースやオリジンなどを設定します。「オリジンドメイン」でS3リソースを選択するのですがS3をwebサーバーとして利用する場合 ",[35,2810,2811],{},"サジェストに出てくる 「~~~~.s3.ap-northeast-1.amazonaws.com」 を選択してはいけません。"," これは単純に「S3オブジェクトURL」でありwebサーバーのような動きをしません。",[170,2814],{":src":2815,":width":173},"'s3-clioudfront-website\u002Fsch-clf-1.png'",[13,2817,2818,2819],{},"今回の構成ではS3の「静的ウェブサイトホスティング」を有効にした際に出現した（下図のボケているとこ）のバケットウェブサイトエンドポイントをいれます。このバケットウェブサイトエンドポイントは「S3をwebサーバーとして使用するときのドメイン」です。ここを忘れて「S3オブジェクトURL」に設定しても一応ルートはs3に接続はできるのですが、「",[631,2820,2823],{"href":2821,"rel":2822},"https:\u002F\u002Fjun-app.com\u002Ftest\u002F%E3%80%8D%E3%81%AE%E3%82%88%E3%81%86%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%99%E3%82%8B%E3%81%A8%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E7%99%BA%E7%94%9F%E3%81%97%E3%81%9F%E3%82%8A%E3%80%81%E6%80%9D%E3%81%86%E3%82%88%E3%81%86%E3%81%AB%E5%8B%95%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82%E7%B5%90%E6%A7%8B%E3%83%8F%E3%83%9E%E3%82%8A%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88%E3%81%A7%E3%81%99%E3%80%82",[650],"https:\u002F\u002Fjun-app.com\u002Ftest\u002F」のように接続するとエラーが発生したり、思うように動きません。結構ハマりポイントです。",[170,2825],{":src":2826,":width":173},"'s3-clioudfront-website\u002Fsch-clf-2.png'",[13,2828,2829],{},"オリジンの設定をしたら他の項目は基本的にデフォルトのままでOKです。下に進んで独自ドメインと証明書を設定する箇所があります。「代替ドメイン名 (CNAME)」に連携したいドメイン名を入力し、そのドメインに対応する証明書（先ほど取得した証明書）を選択します。",[170,2831],{":src":2832,":width":173},"'s3-clioudfront-website\u002Fsch-clf-3.png'",[13,2834,2835,2836],{},"最後にデフォルトルートオブジェクトに「index.html」を設定します。こうすると「",[631,2837,2840],{"href":2838,"rel":2839},"https:\u002F\u002Fjun-app.com\u002Ftest\u002F%E3%80%8D%E3%81%A8%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%81%97%E3%81%9F%E9%9A%9B%E3%80%8Chttps:\u002F\u002Fjun-app.com\u002Ftest\u002Findex.html%E3%80%8D%E3%81%8C%E8%87%AA%E5%8B%95%E7%9A%84%E3%81%AB%E8%BF%94%E3%81%95%E3%82%8C%E3%81%BE%E3%81%99%E3%80%82",[650],"https:\u002F\u002Fjun-app.com\u002Ftest\u002F」とリクエストした際「https:\u002F\u002Fjun-app.com\u002Ftest\u002Findex.html」が自動的に返されます。",[170,2842],{":src":2843,":width":173},"'s3-clioudfront-website\u002Fsch-clf-4.png'",[13,2845,2846,2847,2850,2851,2853],{},"これで一通りcloudfrontとS3の連携が完了しました。「ディストリビーションを作成」を行いますと一覧にて ",[194,2848,2849],{},"~~~~~~.cloudfront.net"," というS3オリジンに対するcloudfrontのドメインが作成されます。このドメインにアクセスしてみますと、SSL付きでS3上にアップロードした ",[194,2852,2411],{}," が表示されます。",[13,2855,2856,2857,2860],{},"つぎは cloudfrontのドメインが ",[194,2858,2859],{},"jun-app.com"," に向くようにRoute53を設定します。",[71,2862,2863],{"id":2863},"cloudfrontのドメインを独自ドメインに向ける",[13,2865,2866],{},"ではRoute53に戻ってcloudfrontのドメインが独自ドメインに向くようにします。ドメインのホストゾーンにて「レコードの作成」を選択します。そして以下のような画面が開きます。「レコード名」はサブドメインを作るわけでないので、空欄で大丈夫です。そしてレコードタイプは「A - ipvアドレスと..」を選択します。「トラフィックのルーティング先」のエイリアスをONにします。（トグルになっています）",[13,2868,2869],{},"Aレコードは普通、IPアドレスを入力しますがcloudfrontなどのAWSリソースでしているする場合「エイリアス」を使用します。エイリアスでは「CloudFront ディストリビューションへのエイリアス」を選択します。そしてその下にcloudfrontのディストリビューションの入力欄が現れますので、そこに先ほどのcloudfrontのドメインを入力します。",[170,2871],{":src":2872,":width":173},"'s3-clioudfront-website\u002Fsch-clf-r53-1.png'",[2353,2874,2877],{"className":2875},[2356,2876],"alert-info","\n本来であれば登録したcloudfrontのディストリビューションがサジェストに表示されますが、登録したてだと出てこないことがあります。ただディストリビューションがあればとりあえず登録できます。\n",[13,2879,2880,2881,2883],{},"そして最後に「レコードの作成」をクリックします。すると ",[194,2882,2859],{}," に対するAレコードがcloudfrontのディストリビューションに向くようになります。ここまでドメインの流れを追うと以下の通りになります。",[265,2885,2886,2891,2904],{},[42,2887,2888,2890],{},[194,2889,2859],{}," にリクエストしたとき、まずお名前.comに問い合わせるが「Route53」に委任されているのでRoute53へ問い合わせ",[42,2892,2893,2894,2896,2897,2900,2901,2903],{},"Route53では ",[194,2895,2859],{}," のAレコードが ",[194,2898,2899],{},"xxxx.cloudfront.net"," に向いているので、",[194,2902,2899],{},"へ接続。",[42,2905,2906,2908],{},[194,2907,2899],{}," は S3のwebホスティングURLに向いているので、そこに接続",[13,2910,2911],{},"となります。（結構ざっくりとしてます）\n以上でバックエンド側の準備ができました。すでにドメインを使用している場合はDNSキャッシュが効いていることがあります。別の端末からアクセスしたり、DNSキャッシュをクリアするコマンドを打ってみましょう。",[2353,2913,2916,2917,2920,2921,2924],{"className":2914},[2356,2915],"alert-success","\nDNSの設定がうまく、対象のサーバーに向いているかを調べるときは",[194,2918,2919],{},"nslookup","や",[194,2922,2923],{},"dig","コマンドを使って対象ドメインに紐づけられているサーバーを確かめてみましょう。\n",[13,2926,2927,2928,2930,2931,2933],{},"現在のところS3に",[194,2929,2411],{},"が置いてあれば、独自ドメイン＋SSLでその",[194,2932,2411],{},"が表示されていればOKです。",[26,2935,2937],{"id":2936},"aws-cliを用いたs3へのファイルのデプロイ","AWS CLIを用いたS3へのファイルのデプロイ",[13,2939,2940,2941,2943],{},"では最後にブログファイル群をS3にアップロードします。私の場合はNuxt.jsであらかじめ書き出しを行い、",[194,2942,2252],{},"ファイル配下を送信します。手動は毎回大変ですのでAWS CLIを用いて自動化と差分アップロード できるようにします。その手順を解説します。最初にAWS CLIをもちいて対象バケットにアクセスできるIAMユーザーを作成します。",[71,2945,2947],{"id":2946},"iamでデプロイユーザーを作成する","IAMでデプロイユーザーを作成する",[13,2949,2950],{},"AWSの運用ベストプラクティスでは",[641,2952,2953],{},[13,2954,2955],{},"AWS アカウントのルートユーザー のアクセスキーを使用しないでください。\nIAM により、複数のユーザーに AWS リソースへの安全なアクセスを簡単に提供できます。IAM により以下が可能となります。",[13,2957,2958],{},"とある様に基本的にIAMというものを用いてリソースにアクセスする様にします。例えば今回の様にAWS CLIを用いて自分のAWSリソースにアクセスする時にシークレットキーとアクセスキーを使用します。AWSを始めた時に作ったRootアカウントでも可能ですが、rootはCLIを通じで本当になんでもできてしまうので使うべきではありません。であればアクションとアクセスを制限されたユーザー（IAM）を使用すれば、もしキーが漏れたとしても被害は小さめです。なので今回のブログデプロイ用のIAMを作成してしまいます。",[13,2960,2961],{},"AWSにログインしてIAMに移動し、「ユーザーを追加」をクリックします。",[170,2963],{":src":2964,":width":173},"'s3-clioudfront-website\u002Fsch-iam-0.png'",[13,2966,2967],{},"ユーザー名を設定し、「プログラムによるアクセス」にチェックをし、次のアクセス権限の設定を行います。",[170,2969],{":src":2970,":width":173},"'s3-clioudfront-website\u002Fsch-iam-1.png'",[13,2972,2973],{},"ここでこのユーザーがアクセスできるアクションを設定できます。一応JSONを用いて細かい設定もできますが、今回はチュートリアル的な内容なので「AmazonS3FullAccess」を与えておきます。",[170,2975],{":src":2976,":width":173},"'s3-clioudfront-website\u002Fsch-iam-2.png'",[13,2978,2979],{},"次にタグを設定しますが、組織でなければ特に設定しません。最後に全体を確認して「ユーザーを作成」をします。これでS3だけにアクセスできるIAMができます。",[170,2981],{":src":2982,":width":173},"'s3-clioudfront-website\u002Fsch-iam-3.png'",[13,2984,2985],{},"このユーザー用のアクセスキーとシークレットキーがダウンロードできますので、控えておきます。まずデプロイ用のIAMユーザーができました。AWS CLIのインストールはここでは割愛しまが、ここで取得したIAMのキーをプロファイルに設定します。",[187,2987,2991],{"className":2988,"code":2989,"language":2990,"meta":196,"style":196},"language-bash shiki shiki-themes material-theme-ocean","aws configure --profile junapp-s3\n","bash",[194,2992,2993],{"__ignoreMap":196},[675,2994,2995,2998,3001,3004],{"class":677,"line":678},[675,2996,2997],{"class":2506},"aws",[675,2999,3000],{"class":689}," configure",[675,3002,3003],{"class":689}," --profile",[675,3005,3006],{"class":689}," junapp-s3\n",[13,3008,3009],{},"プロファイル名は分かりやすい名前にしておくといいです。これでIAMと転送のセットアップは完了です。",[71,3011,3013],{"id":3012},"ファイルを生成してs3へアップロード","ファイルを生成してS3へアップロード",[13,3015,3016,3017,3019,3020,3022,3023,3025,3026,3029],{},"私の環境では ",[194,3018,999],{}," で ",[194,3021,2252],{}," ファイルが生成され、必要なHTMLファイルとアセットが出力されます。その ",[194,3024,2252],{},"ファイル配下を全て",[194,3027,3028],{},"s3:\u002F\u002Fjun-app.com\u002F","へ転送します。そのときはAWS CLIで以下のコマンドを使用します。",[187,3031,3033],{"className":2988,"code":3032,"language":2990,"meta":196,"style":196},"aws s3 sync .\u002Fdist\u002F s3:\u002F\u002Fjun-app.com\u002F --delete --profile junapp-s3\n",[194,3034,3035],{"__ignoreMap":196},[675,3036,3037,3039,3042,3045,3048,3051,3054,3056],{"class":677,"line":678},[675,3038,2997],{"class":2506},[675,3040,3041],{"class":689}," s3",[675,3043,3044],{"class":689}," sync",[675,3046,3047],{"class":689}," .\u002Fdist\u002F",[675,3049,3050],{"class":689}," s3:\u002F\u002Fjun-app.com\u002F",[675,3052,3053],{"class":689}," --delete",[675,3055,3003],{"class":689},[675,3057,3006],{"class":689},[13,3059,3060,3063,3064,3067,3068,3071,3072,3075,3076,3079],{},[194,3061,3062],{},"s3 sync","は2回目以降、差分をみてあれば同期してくれます。二回目以降は転送量を節約できます。",[194,3065,3066],{},"--delete"," は同期先（S3）にて同期元（ローカル）にないファイルを消してくれます。例えばnuxt.jsではキャッシュ対策のため、",[194,3069,3070],{},"_nuxt","ディレクトリ配下に",[194,3073,3074],{},"34234324.js","みたいなハッシュ化したjsファイルが書き出しごとに生成されます。単純に転送していくと",[194,3077,3078],{},"__nuxt","配下にjsファイルが溜まっていくので差分を見て古いファイルを削除します。他にも「メニューなどにはないけれど、削除した記事がファイルとしては残ったままになっている」みたいな事故も防げます。",[13,3081,3082,3085],{},[194,3083,3084],{},"--profile"," にて先ほど設定したIAMのプロファイルを指定します。",[2353,3087,3089,3090,3093],{"className":3088},[2356,2876],"\nこのコマンドを実行する前に ",[194,3091,3092],{},"--dryrun","のオプションをいれてシミュレートしてから本番を実行しましょう。\n",[13,3095,3096],{},"準備ができたらコマンドを打ちます。終わったらバケットを確認して終了です。",[138,3098,3099],{"id":3099},"スクリプトに入れておくと便利",[13,3101,3102,3103,3105,3106,3109,3110,3113],{},"Nuxt.jsで",[194,3104,999],{},"した際に",[194,3107,3108],{},"sync","されるように",[194,3111,3112],{},"package.json","を以下のように編集しておきました。",[187,3115,3120],{"className":3116,"code":3117,"filename":3118,"language":3119,"meta":196,"style":196},"language-json shiki shiki-themes material-theme-ocean","{\n\"scripts\": {\n    ...\n    \"generate-production\": \"nuxt generate && aws s3 sync .\u002Fdist\u002F s3:\u002F\u002Fjun-app.com\u002F --delete --profile junapp-s3\"\n}\n}\n","pakcage.json","json",[194,3121,3122,3126,3140,3145,3163,3167],{"__ignoreMap":196},[675,3123,3124],{"class":677,"line":678},[675,3125,2454],{"class":685},[675,3127,3128,3130,3133,3135,3137],{"class":677,"line":560},[675,3129,2466],{"class":685},[675,3131,3132],{"class":2462},"scripts",[675,3134,2466],{"class":685},[675,3136,686],{"class":685},[675,3138,3139],{"class":685}," {\n",[675,3141,3142],{"class":677,"line":557},[675,3143,3144],{"class":755},"    ...\n",[675,3146,3147,3149,3152,3154,3156,3158,3161],{"class":677,"line":570},[675,3148,2459],{"class":685},[675,3150,3151],{"class":2506},"generate-production",[675,3153,2466],{"class":685},[675,3155,686],{"class":685},[675,3157,2471],{"class":685},[675,3159,3160],{"class":689},"nuxt generate && aws s3 sync .\u002Fdist\u002F s3:\u002F\u002Fjun-app.com\u002F --delete --profile junapp-s3",[675,3162,2584],{"class":685},[675,3164,3165],{"class":677,"line":719},[675,3166,2631],{"class":685},[675,3168,3169],{"class":677,"line":728},[675,3170,2631],{"class":685},[138,3172,3173],{"id":3173},"cloudfrontのキャッシュに注意",[13,3175,3176],{},"cloudfrontはCDNであり、キャッシュが強いです。更新したのに本番が変わらないときはキャッシュのせいかもしれません。cloudfrontでは明示的にキャッシュをクリアすることもできますし、キャッシュの期間を変更することもできます。閲覧数などに合わせて設定しましょう。",[26,3178,3180],{"id":3179},"以上","以上！",[13,3182,3183],{},"以上で S3 x SSL x 独自ドメインな静的ブログを構築できました。利用量によっては無料枠でも収まりそうです。しばらく料金の方も見てみてレンサバよりお得かを確認してみます。",[2290,3185,3186],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}",{"title":196,"searchDepth":557,"depth":557,"links":3188},[3189,3190,3191,3197,3204],{"id":2361,"depth":560,"text":2361},{"id":2379,"depth":560,"text":2380},{"id":2676,"depth":560,"text":2677,"children":3192},[3193,3194,3195,3196],{"id":2703,"depth":557,"text":2704},{"id":2749,"depth":557,"text":2749},{"id":2795,"depth":557,"text":2796},{"id":2863,"depth":557,"text":2863},{"id":2936,"depth":560,"text":2937,"children":3198},[3199,3200],{"id":2946,"depth":557,"text":2947},{"id":3012,"depth":557,"text":3013,"children":3201},[3202,3203],{"id":3099,"depth":570,"text":3099},{"id":3173,"depth":570,"text":3173},{"id":3179,"depth":560,"text":3180},[597],"2025-07-18","AWS S3とcloudfrontを合わせることでwebサーバの様に扱う方法",{},"\u002Farticles\u002Fs3-clioudfront-website",{"title":2326,"description":3207},"articles\u002Fs3-clioudfront-website",[607,2997],"s3-clioudfront-website\u002Fthumbnail.png","TS4Cse0E-KmfWg0S6g6WJdYqcKJXhparmDnjSsmNt20",{"id":3216,"title":3217,"body":3218,"category":3518,"createdAt":3519,"description":3520,"extension":599,"index":600,"meta":3521,"navigation":602,"path":3522,"publish":602,"seo":3523,"series":600,"seriesTitle":600,"stem":3524,"tag":3525,"thumbnail":3528,"updatedAt":600,"__hash__":3529},"articles\u002Farticles\u002Fsecurity-incident-by-git-deplay.md","ドキュメントルート配下のコンテンツをGitを用いてデプロイする時のセキュリティ上の注意点",{"type":10,"value":3219,"toc":3504},[3220,3227,3230,3233,3250,3254,3257,3261,3269,3272,3275,3278,3281,3300,3306,3310,3320,3334,3337,3341,3344,3347,3350,3353,3357,3365,3371,3378,3381,3401,3416,3422,3426,3437,3440,3449,3452,3455,3461,3465,3471,3477,3480,3486,3489,3495,3498],[13,3221,3222,3223,3226],{},"こんにちはjunです。最近関わっているプロジェクトではGitを用いた本番環境での運用を行っています。本番環境にgitを置くことによって",[194,3224,3225],{},"git pull","するだけで改修したコードをすぐに反映できます。さらにブランチを分ければABテストや選択的なデプロイなども行えます。そのためシステム開発においてはGitによる本番環境での運用は欠かせません。",[13,3228,3229],{},"Laravelの様なシステム以外にも最近はwordpressのカスタムテーマやカスタムプラグインをgit管理し、本番環境にpullすることがあります。しかしその際の設定によってはプライベートのソースコードが流失したり、書き換えられたりなどセキュリティインシデントを犯しかねない設定になることがあります。私が公開前に止められたヒヤリハットとしてぜひ共有したいと思います。",[13,3231,3232],{},"今回解説するGitの管理と運用は以下のとおりです。",[39,3234,3235,3238,3241,3244,3247],{},[42,3236,3237],{},"プライベートリポジトリ",[42,3239,3240],{},"リモートはgithub",[42,3242,3243],{},"管理しているソースはwordpressのカスタムテーマ",[42,3245,3246],{},".gitがドキュメントルート配下にある",[42,3248,3249],{},"サーバはxserver（法人用レンタルサーバ）",[26,3251,3253],{"id":3252},"今回何が危なかったのか","今回何が危なかったのか？",[13,3255,3256],{},"まず結論から先に述べますと「パーソナルアクセストークンを用いたgit設定がドキュメントルート配下にあった」ことです。わかる人は結構やべーとわかるかもしれません。取り合えず解説していきます。",[71,3258,3260],{"id":3259},"パーソナルアクセストークンpatとは","パーソナルアクセストークン（PAT）とは",[13,3262,3263,3264],{},"パーソナルアクセストークンとはgithubにて使用されるパスワードの代わりとなるアクセストークンです。",[631,3265,3268],{"href":3266,"rel":3267},"https:\u002F\u002Fdocs.github.com\u002Fja\u002Fauthentication\u002Fkeeping-your-account-and-data-secure\u002Fcreating-a-personal-access-token",[650],"参考",[13,3270,3271],{},"一昔前はプライベートリポジトリにURL（HTTP）でアクセスする場合はドメインの部分にGithubアカウントのIDとパスワードを合わせる方法がとられていました（Basic認証）。ただしその方法はセキュリティ上危ないので、廃止され現在はパーソナルアクセストークン という予測がしづらく、行える操作スコープと使用期限が設定されたトークンを発行してパスワードの代わりに使用する様になりました。",[13,3273,3274],{},"そしてgitはpull,pushなどを行う際にそのorigin（リモートリポジトリ）のURL（HTTP）かSSHを使用します。SSHは環境によって難しかったり設定が大変なこともあり、PAT付きのURLを用いて接続すると簡単にプライベートリポジトリに接続ができます。基本的にパーソナルアクセストークン はこの様にgithubのアカウントが必要なプライベートリポジトリの読み取り、リポジトリ操作を行う際に使用します。",[13,3276,3277],{},"今回のテーマファイルのリポジトリはもちろんプライベートなので、トークン付きのURLかSSHで接続する必要があります。そして今回はPATをメインに使用して、gitの操作を行っていました。",[71,3279,3280],{"id":3280},"git設定ファイルとは",[13,3282,3283,3284,3287,3288,3291,3292,3295,3296,3299],{},"git設定ファイルとはリモートリポジトリ の接続先、ブランチ構成、ユーザーなどgit管理に必要な設定ファイルのことです。",[194,3285,3286],{},"git init","してローカルリポジトリ を作成した際に",[194,3289,3290],{},"ls -la","と打つと、",[194,3293,3294],{},".git","という隠しディレクトリが表示されます。それが設定ディレクトリであり、中に移動すると",[194,3297,3298],{},".git\u002Fconfig","という設定ファイルがあります。",[13,3301,3302,3303,3305],{},"先ほどのパーソナルアクセストークンを用いたURLなどはその",[194,3304,3298],{},"に書かれます。実際にlessやcatを使用してみてみると、リモートのURLなどが記載されています。",[71,3307,3309],{"id":3308},"なぜ読み取れた","なぜ読み取れた？",[13,3311,3312,3313,3316,3317,3319],{},"今回gitで運用しようとしていたwordpressのテーマファイルはドキュメントルート配下に設定します。ルートからみて　",[194,3314,3315],{},"\u002Fwp-content\u002Fthemes\u002Fcustom","というリポジトリ名にもなるテーマディレクトリを作成してそこに",[194,3318,3286],{},"をして接続先の情報を記載しました。上記のとおりPATを用いています。",[13,3321,3322,3323,2920,3326,3329,3330,3333],{},"インフラに詳しい人ならわかると思いますが、基本的にドキュメントルート配下のファイルは",[194,3324,3325],{},".htaccess",[194,3327,3328],{},"Apache","で何かしら設定されていない場合、自由にみることができます。本来アクセスされない様なファイルにも例えば、",[194,3331,3332],{},"https:\u002F\u002Fexample.comm\u002Fwp-content\u002Fthemes\u002Fcustom\u002F.git\u002Fconfig","とURLでアクセスすると読み取れることがあります。",[13,3335,3336],{},"xserverの場合はconfigファイルがダウンロードされ、もちろん接続先情報は記載されていました。そのためパーソナルアクセストークン が記載されたgitの設定ファイルが第三者にダウンロード可能な状態で公開しうるとこでした。",[71,3338,3340],{"id":3339},"どうゆうことが起きかねる","どうゆうことが起きかねる？",[13,3342,3343],{},"仮に公開し、攻撃者がこの存在に気づくと何が起こり得るでしょうか？まず、パーソナルアクセストークン が盗まれリポジトリに対して不正アクセスされます。まだwebサーバを通じて設定ファイルを読み取っただけなので、gitコマンドを打たれて本番環境を破壊されることはないと思いますが、プライベートリポジトリに何かしらの攻撃をされるでしょう。本来プライベートなリポジトリ の情報を取得されてしまうのです。",[13,3345,3346],{},"またパーソナルアクセストークン には操作範囲を設定できます。今回のはリポジトリに対する読み書き操作でしたが、他にも管理者権限レベルの操作を付与できるスコープもあります。つまり、権限の強いトークンの場合はリポジトリ の内容が盗まれたり改変されるだけでなく、アカウント全体に影響が出かねないものになります。",[26,3348,3349],{"id":3349},"対策",[13,3351,3352],{},"ドキュメントルート配下にリポジトリを設定する場合は設定ファイルにアクセスできない様にする必要があります。またはPATを記載しないことです。",[71,3354,3356],{"id":3355},"gitディレクトリへのアクセスを404にする",".gitディレクトリへのアクセスを404にする",[13,3358,3359,3360,996,3362,3364],{},"まず手取り早くできるのは",[194,3361,3325],{},[194,3363,3294],{},"を含むURLがあったら404にしてしまうことです。",[187,3366,3369],{"className":3367,"code":3368,"language":192},[190],"RedirectMatch 404 \u002F\\.git\n",[194,3370,3368],{"__ignoreMap":196},[13,3372,3373],{},[631,3374,3377],{"href":3375,"rel":3376},"https:\u002F\u002Fstackoverflow.com\u002Fquestions\u002F6142437\u002Fmake-git-directory-web-inaccessible",[650],"こちらのStacoverflowが役に立ちました。",[13,3379,3380],{},"解説によると",[39,3382,3383,3386,3395,3398],{},[42,3384,3385],{},"ドキュメントルート配下すべての.gitディレクトリ （設定ファイル）へのアクセスを禁止できる。つまり複数のリポジトリがあっても一気に対応可能。",[42,3387,3388,2920,3391,3394],{},[194,3389,3390],{},".gitignore",[194,3392,3393],{},".gitmodules","にも対応できる。",[42,3396,3397],{},"これから新しく追加される.gitにも対応できる。",[42,3399,3400],{},"404にすることでリポジトリ の存在を悟らせない。",[13,3402,3403,3404,3406,3407,3409,3410,3412,3413,3415],{},"実際に",[194,3405,3325],{},"で設定すると、",[194,3408,3332],{},"へのアクセスは404になりました。上記の設定の場合はURLに",[194,3411,3294],{},"が含まれた瞬間、404になるのがコツです。さすがにないと思いますがURLに",[194,3414,3294],{},"を使用するコンテンツがある場合も404になるのでそこは注意が必要です。",[13,3417,3418,3419,3421],{},"webサーバによる読み取りとgitコマンドは関係ないので、上記の設定をしたとしても",[194,3420,3225],{},"など操作は引き続き使えます。",[71,3423,3425],{"id":3424},"sshに切り替える","SSHに切り替える",[13,3427,3428,3429,3432,3433,3436],{},"また可能であればSSHによる接続に切り替えることです。SSHによる接続のURLは",[194,3430,3431],{},"git@github.com:example:repository.git","となります。前半の",[194,3434,3435],{},"git@github.com","はsshのgitユーザーでgitub.comに接続するという意味です。そのユーザーで接続する際の秘密鍵やそのパスの設定はwebサーバーからは読み取ることができません。（上記のURLに直に書いてればべつだけど）",[13,3438,3439],{},"そのためパーソナルアクセストークンよりかはSSHでGitに接続するほうが安全性的にかなりベストです。PATより堅牢な方法です。",[13,3441,3442,3443,3448],{},"ちなみに本番環境からリポジトリへSSHで接続する際は",[631,3444,3447],{"href":3445,"rel":3446},"https:\u002F\u002Fdocs.github.com\u002Fja\u002Fauthentication\u002Fkeeping-your-account-and-data-secure\u002Freviewing-your-deploy-keys",[650],"デプロイキー","を使用するべきです。デプロイキーは特定のリポジトリのみのアクセスに限定するとともに、読み込み専用にすることができます。",[13,3450,3451],{},"PATでは読みに加えて書き込み権限と付与すればその他の管理者権限が使用できます。つまり盗まれた際の被害が甚大に対して、デプロイキーは特定のリポジトリ の読み込み権限のみを許可出るので被害が小さく済みます。",[71,3453,3454],{"id":3454},"対策まとめ",[13,3456,3457,3458,3460],{},"一番はwebサーバーで",[194,3459,3294],{},"に対するアクセス権限をなくすことです。これでパーソナルアクセストークンであっても外部から見られる心配はありません。ただし可能な限りまずはより安全なデプロイキーによるSSHで接続できる様にし、かつwebサーバの設定を行うことがベストです。",[26,3462,3464],{"id":3463},"うちは大丈夫チェック方法linux","うちは大丈夫？チェック方法(linux)",[13,3466,3467,3468,3470],{},"まずはドキュメントルート配下に",[194,3469,3294],{},"がいるかをチェックしましょう。Linuxの場合はドキュメントルート配下に以下のコマンドで探せます。",[187,3472,3475],{"className":3473,"code":3474,"language":192},[190],"find \u002FDOCUMENT\u002FROOT\u002F -name .git -type d\n",[194,3476,3474],{"__ignoreMap":196},[13,3478,3479],{},"もしあった場合",[187,3481,3484],{"className":3482,"code":3483,"language":192},[190],"\u002FDOCUMENT\u002FROOT\u002Fwp-content\u002Fthemes\u002Fexample\u002F.git\n",[194,3485,3483],{"__ignoreMap":196},[13,3487,3488],{},"このように結果が出てきますので、URLに載せて",[187,3490,3493],{"className":3491,"code":3492,"language":192},[190],"https:\u002F\u002Fexample.com\u002Fwp-content\u002Fthemes\u002Fexample\u002F.git\nhttps:\u002F\u002Fexample.com\u002Fwp-content\u002Fthemes\u002Fexample\u002F.git\u002Fconfig\n",[194,3494,3492],{"__ignoreMap":196},[13,3496,3497],{},"の２種類にアクセスしてディレクトリ 、configが閲覧されるかをチェックしましょう。サーバによっては対策済みの場合があります。",[13,3499,3500,3501,3503],{},"見れてしまったらまず",[194,3502,3325],{},"で閲覧できなくしましょう。中を見てパスワードやパーソナルアクセストークンがあったら今すぐ対処が必要です！！",{"title":196,"searchDepth":557,"depth":557,"links":3505},[3506,3512,3517],{"id":3252,"depth":560,"text":3253,"children":3507},[3508,3509,3510,3511],{"id":3259,"depth":557,"text":3260},{"id":3280,"depth":557,"text":3280},{"id":3308,"depth":557,"text":3309},{"id":3339,"depth":557,"text":3340},{"id":3349,"depth":560,"text":3349,"children":3513},[3514,3515,3516],{"id":3355,"depth":557,"text":3356},{"id":3424,"depth":557,"text":3425},{"id":3454,"depth":557,"text":3454},{"id":3463,"depth":560,"text":3464},[597],"2022-04-21","wordpressテーマやドキュメントルート配下にGitを置く際の注意点",{},"\u002Farticles\u002Fsecurity-incident-by-git-deplay",{"title":3217,"description":3520},"articles\u002Fsecurity-incident-by-git-deplay",[3526,607,3527],"security","git","_common\u002Fsecurity.jpg","zHB7HHf-61vEYna3ziFZoIxx8rS0KxIKcw1QiPSv20k",{"id":3531,"title":3532,"body":3533,"category":3749,"createdAt":3751,"description":3532,"extension":599,"index":600,"meta":3752,"navigation":602,"path":3753,"publish":602,"seo":3754,"series":600,"seriesTitle":600,"stem":3755,"tag":3756,"thumbnail":600,"updatedAt":600,"__hash__":3757},"articles\u002Farticles\u002Fpreflight-redirect-cors-error.md","URL正規化によって Redirect is not allowed for a preflight request でCORSエラーが起きた",{"type":10,"value":3534,"toc":3747},[3535,3538,3544,3550,3576,3590,3593,3724,3738,3744],[13,3536,3537],{},"こんにちはjunです。LaravelとNuxt SPAでアプリを作っていたのですがCORS設定をしているのに偶に以下のようなエラーが発生していました。",[187,3539,3542],{"className":3540,"code":3541,"language":192},[190],"Access to XMLHttpRequest at 'http:\u002F\u002Flocalhost\u002Fapi\u002Fv1\u002Ftest\u002F' from origin 'http:\u002F\u002Flocalhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.\n",[194,3543,3541],{"__ignoreMap":196},[13,3545,3546,3547,3549],{},"エラー内容の通り原因はpreflightリクエストがリダイレクトされてしまっていることが原因です。開発者ツールでnetworkを見ると確かにpreflightリクエストが301となっていることが原因です。しかしなぜリダイレクト？Laravelでredirectを返すメソッドがあるのかと思いましたが、原因は",[194,3548,3325],{},"の以下の記述でした。",[187,3551,3554],{"className":3552,"code":3553,"language":3325,"meta":196,"style":196},"language-.htaccess shiki shiki-themes material-theme-ocean","#Redirect Trailing Slashes If Not A Folder...\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteCond %{REQUEST_URI} (.+)\u002F$\nRewriteRule ^ %1 [L,R=301]\n",[194,3555,3556,3561,3566,3571],{"__ignoreMap":196},[675,3557,3558],{"class":677,"line":678},[675,3559,3560],{},"#Redirect Trailing Slashes If Not A Folder...\n",[675,3562,3563],{"class":677,"line":560},[675,3564,3565],{},"RewriteCond %{REQUEST_FILENAME} !-d\n",[675,3567,3568],{"class":677,"line":557},[675,3569,3570],{},"RewriteCond %{REQUEST_URI} (.+)\u002F$\n",[675,3572,3573],{"class":677,"line":570},[675,3574,3575],{},"RewriteRule ^ %1 [L,R=301]\n",[13,3577,3578,3579,3581,3582,3585,3586,3589],{},"上記はLaravelが使用するURLの正規化を行う",[194,3580,3325],{},"の記述です。URLの末尾にスラッシュがある場合、ないように正規化してくれます。",[194,3583,3584],{},"http:\u002F\u002Flocalhost\u002Ftest\u002F","→",[194,3587,3588],{},"http:\u002F\u002Flocalhost\u002Ftest"," のようにリダイレクトがおきます。これはAPIルートでも発生します。",[13,3591,3592],{},"私のAPIリクエストを見てみると",[187,3594,3598],{"className":3595,"code":3596,"language":3597,"meta":196,"style":196},"language-javascript shiki shiki-themes material-theme-ocean","async test(){\n    this.$axios.post('\u002Fv1\u002Ftest\b\u002F')\n    .then(res=>[\n        console.log(res)\n    ])\n    .catch(err=>{\n        console.log(err)\n    })\n}\n","javascript",[194,3599,3600,3614,3642,3662,3678,3683,3699,3713,3720],{"__ignoreMap":196},[675,3601,3602,3605,3609,3612],{"class":677,"line":678},[675,3603,3604],{"class":755},"async ",[675,3606,3608],{"class":3607},"sdLwU","test",[675,3610,3611],{"class":755},"()",[675,3613,2454],{"class":685},[675,3615,3616,3619,3622,3625,3628,3631,3634,3637,3639],{"class":677,"line":560},[675,3617,3618],{"class":685},"    this.",[675,3620,3621],{"class":755},"$axios",[675,3623,3624],{"class":685},".",[675,3626,3627],{"class":3607},"post",[675,3629,3630],{"class":681},"(",[675,3632,3633],{"class":685},"'",[675,3635,3636],{"class":689},"\u002Fv1\u002Ftest\b\u002F",[675,3638,3633],{"class":685},[675,3640,3641],{"class":681},")\n",[675,3643,3644,3647,3650,3652,3656,3659],{"class":677,"line":557},[675,3645,3646],{"class":685},"    .",[675,3648,3649],{"class":3607},"then",[675,3651,3630],{"class":681},[675,3653,3655],{"class":3654},"s7ZW3","res",[675,3657,3658],{"class":2462},"=>",[675,3660,3661],{"class":681},"[\n",[675,3663,3664,3667,3669,3672,3674,3676],{"class":677,"line":570},[675,3665,3666],{"class":755},"        console",[675,3668,3624],{"class":685},[675,3670,3671],{"class":3607},"log",[675,3673,3630],{"class":681},[675,3675,3655],{"class":755},[675,3677,3641],{"class":681},[675,3679,3680],{"class":677,"line":719},[675,3681,3682],{"class":681},"    ])\n",[675,3684,3685,3687,3690,3692,3695,3697],{"class":677,"line":728},[675,3686,3646],{"class":685},[675,3688,3689],{"class":3607},"catch",[675,3691,3630],{"class":681},[675,3693,3694],{"class":3654},"err",[675,3696,3658],{"class":2462},[675,3698,2454],{"class":685},[675,3700,3701,3703,3705,3707,3709,3711],{"class":677,"line":736},[675,3702,3666],{"class":755},[675,3704,3624],{"class":685},[675,3706,3671],{"class":3607},[675,3708,3630],{"class":681},[675,3710,3694],{"class":755},[675,3712,3641],{"class":681},[675,3714,3715,3718],{"class":677,"line":741},[675,3716,3717],{"class":685},"    }",[675,3719,3641],{"class":681},[675,3721,3722],{"class":677,"line":752},[675,3723,2631],{"class":685},[13,3725,3726,3727,3729,3730,3733,3734,3737],{},"URLをみてみると",[194,3728,3636],{},"と末尾にスケジュール があります。そしてXHRは ",[194,3731,3732],{},"POST + contetnt-type:application\u002Fjson"," のようなリクエストではpreflightリクエストが飛びますが、そのリクエストはリダイレクトをしてはいけません。そのためURLを",[194,3735,3736],{},"\u002Fv1\u002Ftest\b","と末尾をなくしてあげたらリダイレクトが起きず、問題なくCORSが起きなくなりました。",[13,3739,3740,3741,3743],{},"CORSの設定やLaravelのメソッドを調べていましたが、結構簡単な",[194,3742,3325],{},"が原因でした。",[2290,3745,3746],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s-wAU, html code.shiki .s-wAU{--shiki-default:#F07178}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s7ZW3, html code.shiki .s7ZW3{--shiki-default:#BABED8;--shiki-default-font-style:italic}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}",{"title":196,"searchDepth":557,"depth":557,"links":3748},[],[3750],"ministack","2021-09-19",{},"\u002Farticles\u002Fpreflight-redirect-cors-error",{"title":3532,"description":3532},"articles\u002Fpreflight-redirect-cors-error",[607,608],"ia4jjF7K85Ze8kJeV-fqRUKhfJsuBqIgYCJYkocy2u0",{"id":3759,"title":3760,"body":3761,"category":4104,"createdAt":4105,"description":4106,"extension":599,"index":600,"meta":4107,"navigation":602,"path":4108,"publish":602,"seo":4109,"series":600,"seriesTitle":600,"stem":4110,"tag":4111,"thumbnail":600,"updatedAt":600,"__hash__":4113},"articles\u002Farticles\u002Ffirebase-emulator-port-token.md","ポートが使用されていてFirebaseエミュレータが起動できない時の対処法",{"type":10,"value":3762,"toc":4102},[3763,3766,3772,3775,3781,3788,3794,3976,3979,3982,3995,3998,4071,4074,4087,4090,4096,4099],[13,3764,3765],{},"こんにちはjunです、最近Firebaseを使用したアプリケーション開発をしています。エミュレータがあるのでそこでFirestoreやAuthenticationのテストをしています。ある日、開発の続きをやろうとしてエミュレータを起動させました。",[187,3767,3770],{"className":3768,"code":3769,"language":192},[190],"firebase emulators:start\n",[194,3771,3769],{"__ignoreMap":196},[13,3773,3774],{},"しかし",[187,3776,3779],{"className":3777,"code":3778,"language":192},[190],"⚠  firestore: Port 8081 is not open on localhost, could not start Firestore Emulator.\n⚠  firestore: To select a different host\u002Fport, specify that host\u002Fport in a firebase.json config file:\n      {\n        \u002F\u002F ...\n        \"emulators\": {\n          \"firestore\": {\n            \"host\": \"HOST\",\n            \"port\": \"PORT\"\n          }\n        }\n      }\ni  emulators: Shutting down emulators.\n\nError: Could not start Firestore Emulator, port taken.\n",[194,3780,3778],{"__ignoreMap":196},[13,3782,3783,3784,3787],{},"あらら、、起動に失敗してしまいました。エミュレーター二回目の起動の時によく発生します。原因は",[194,3785,3786],{},"Could not start Firestore Emulator, port taken.","とある様にポートが使用中だからです。",[13,3789,3790,3793],{},[194,3791,3792],{},"firebase.json","にはエミュレーターのポートを定義できます。私の場合は以下の通りです。",[187,3795,3797],{"className":3116,"code":3796,"language":3119,"meta":196,"style":196},"\"emulators\": {\n    \"auth\": {\n        \"port\": 9099\n    },\n    \"functions\": {\n        \"port\": 5001\n    },\n    \"firestore\": {\n        \"port\": 8081\n    },\n    \"database\": {\n        \"port\": 8082\n    },\n    \"ui\": {\n        \"enabled\": true\n    }\n},\n",[194,3798,3799,3813,3826,3842,3847,3860,3873,3877,3890,3903,3907,3920,3933,3937,3950,3964,3969],{"__ignoreMap":196},[675,3800,3801,3803,3806,3808,3811],{"class":677,"line":678},[675,3802,2466],{"class":685},[675,3804,3805],{"class":689},"emulators",[675,3807,2466],{"class":685},[675,3809,3810],{"class":755},": ",[675,3812,2454],{"class":685},[675,3814,3815,3817,3820,3822,3824],{"class":677,"line":560},[675,3816,2459],{"class":685},[675,3818,3819],{"class":2462},"auth",[675,3821,2466],{"class":685},[675,3823,686],{"class":685},[675,3825,3139],{"class":685},[675,3827,3828,3831,3834,3836,3838],{"class":677,"line":557},[675,3829,3830],{"class":685},"        \"",[675,3832,3833],{"class":2506},"port",[675,3835,2466],{"class":685},[675,3837,686],{"class":685},[675,3839,3841],{"class":3840},"sx098"," 9099\n",[675,3843,3844],{"class":677,"line":570},[675,3845,3846],{"class":685},"    },\n",[675,3848,3849,3851,3854,3856,3858],{"class":677,"line":719},[675,3850,2459],{"class":685},[675,3852,3853],{"class":2462},"functions",[675,3855,2466],{"class":685},[675,3857,686],{"class":685},[675,3859,3139],{"class":685},[675,3861,3862,3864,3866,3868,3870],{"class":677,"line":728},[675,3863,3830],{"class":685},[675,3865,3833],{"class":2506},[675,3867,2466],{"class":685},[675,3869,686],{"class":685},[675,3871,3872],{"class":3840}," 5001\n",[675,3874,3875],{"class":677,"line":736},[675,3876,3846],{"class":685},[675,3878,3879,3881,3884,3886,3888],{"class":677,"line":741},[675,3880,2459],{"class":685},[675,3882,3883],{"class":2462},"firestore",[675,3885,2466],{"class":685},[675,3887,686],{"class":685},[675,3889,3139],{"class":685},[675,3891,3892,3894,3896,3898,3900],{"class":677,"line":752},[675,3893,3830],{"class":685},[675,3895,3833],{"class":2506},[675,3897,2466],{"class":685},[675,3899,686],{"class":685},[675,3901,3902],{"class":3840}," 8081\n",[675,3904,3905],{"class":677,"line":759},[675,3906,3846],{"class":685},[675,3908,3909,3911,3914,3916,3918],{"class":677,"line":767},[675,3910,2459],{"class":685},[675,3912,3913],{"class":2462},"database",[675,3915,2466],{"class":685},[675,3917,686],{"class":685},[675,3919,3139],{"class":685},[675,3921,3922,3924,3926,3928,3930],{"class":677,"line":4},[675,3923,3830],{"class":685},[675,3925,3833],{"class":2506},[675,3927,2466],{"class":685},[675,3929,686],{"class":685},[675,3931,3932],{"class":3840}," 8082\n",[675,3934,3935],{"class":677,"line":788},[675,3936,3846],{"class":685},[675,3938,3939,3941,3944,3946,3948],{"class":677,"line":799},[675,3940,2459],{"class":685},[675,3942,3943],{"class":2462},"ui",[675,3945,2466],{"class":685},[675,3947,686],{"class":685},[675,3949,3139],{"class":685},[675,3951,3952,3954,3957,3959,3961],{"class":677,"line":811},[675,3953,3830],{"class":685},[675,3955,3956],{"class":2506},"enabled",[675,3958,2466],{"class":685},[675,3960,686],{"class":685},[675,3962,3963],{"class":685}," true\n",[675,3965,3966],{"class":677,"line":818},[675,3967,3968],{"class":685},"    }\n",[675,3970,3971,3974],{"class":677,"line":835},[675,3972,3973],{"class":685},"}",[675,3975,2479],{"class":755},[13,3977,3978],{},"とりあえず8081と8082でどんなプロセスが動いているか確かめましょう。（この時はfirestoreだけでなくdatabaseも取られていました。）",[13,3980,3981],{},"Macで任意ポートで使用されているプロセスを調べる時は以下の様なコマンドを打ちます。",[187,3983,3985],{"className":2988,"code":3984,"language":2990,"meta":196,"style":196},"lsof -i:PORT\n",[194,3986,3987],{"__ignoreMap":196},[675,3988,3989,3992],{"class":677,"line":678},[675,3990,3991],{"class":2506},"lsof",[675,3993,3994],{"class":689}," -i:PORT\n",[13,3996,3997],{},"なので今回は",[187,3999,4001],{"className":2988,"code":4000,"language":2990,"meta":196,"style":196},"lsof -i:8081\nOMMAND  PID       USER   FD   TYPE            DEVICE SIZE\u002FOFF NODE NAME\njava    2322       jun   93u  IPv6 0x3f5922436f29fd5      0t0  TCP localhost:sunproxyadmin (LISTEN)\n",[194,4002,4003,4010,4039],{"__ignoreMap":196},[675,4004,4005,4007],{"class":677,"line":678},[675,4006,3991],{"class":2506},[675,4008,4009],{"class":689}," -i:8081\n",[675,4011,4012,4015,4018,4021,4024,4027,4030,4033,4036],{"class":677,"line":560},[675,4013,4014],{"class":2506},"OMMAND",[675,4016,4017],{"class":689},"  PID",[675,4019,4020],{"class":689},"       USER",[675,4022,4023],{"class":689},"   FD",[675,4025,4026],{"class":689},"   TYPE",[675,4028,4029],{"class":689},"            DEVICE",[675,4031,4032],{"class":689}," SIZE\u002FOFF",[675,4034,4035],{"class":689}," NODE",[675,4037,4038],{"class":689}," NAME\n",[675,4040,4041,4044,4047,4050,4053,4056,4059,4062,4065,4068],{"class":677,"line":557},[675,4042,4043],{"class":2506},"java",[675,4045,4046],{"class":3840},"    2322",[675,4048,4049],{"class":689},"       jun",[675,4051,4052],{"class":689},"   93u",[675,4054,4055],{"class":689},"  IPv6",[675,4057,4058],{"class":3840}," 0x3f5922436f29fd5",[675,4060,4061],{"class":689},"      0t0",[675,4063,4064],{"class":689},"  TCP",[675,4066,4067],{"class":689}," localhost:sunproxyadmin",[675,4069,4070],{"class":755}," (LISTEN)\n",[13,4072,4073],{},"なんだろう？とりえずエミュレーター系だと思う。なのでこのプロセスをkillする",[187,4075,4077],{"className":2988,"code":4076,"language":2990,"meta":196,"style":196},"kill 2322\n",[194,4078,4079],{"__ignoreMap":196},[675,4080,4081,4084],{"class":677,"line":678},[675,4082,4083],{"class":3607},"kill",[675,4085,4086],{"class":3840}," 2322\n",[13,4088,4089],{},"そしてもう一度起動",[187,4091,4094],{"className":4092,"code":4093,"language":192},[190],"firebase emulators:start\n┌─────────────────────────────────────────────────────────────┐\n│ ✔  All emulators ready! It is now safe to connect your app. │\n│ i  View Emulator UI at http:\u002F\u002Flocalhost:4002                │\n└─────────────────────────────────────────────────────────────┘\n",[194,4095,4093],{"__ignoreMap":196},[13,4097,4098],{},"OK!これで起動完了。以上がFirestore、Databaseでポートが取られて起動できない時の対処法です。Authとかは起きないのに、なぜかfirestoreとDatabaseだけ発生します。。",[2290,4100,4101],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}",{"title":196,"searchDepth":557,"depth":557,"links":4103},[],[3750],"2021-05-31","ポートが使用されていてFirebaseエミュレータが起動的無い時の対処法",{},"\u002Farticles\u002Ffirebase-emulator-port-token",{"title":3760,"description":4106},"articles\u002Ffirebase-emulator-port-token",[607,4112],"firebase","WZCWojY2PQc1aA0-QDiGPzMKO6InsuB6Hbr1wZtO8aI",{"id":4115,"title":4116,"body":4117,"category":4522,"createdAt":4523,"description":4116,"extension":599,"index":600,"meta":4524,"navigation":602,"path":4525,"publish":602,"seo":4526,"series":600,"seriesTitle":600,"stem":4527,"tag":4528,"thumbnail":4529,"updatedAt":600,"__hash__":4530},"articles\u002Farticles\u002Fvps-ssh-first.md","VPSでやっておきたいSSHの最低限のセキュティ設定。",{"type":10,"value":4118,"toc":4510},[4119,4122,4125,4128,4142,4154,4157,4161,4164,4170,4173,4176,4184,4187,4190,4201,4204,4207,4210,4216,4219,4225,4232,4238,4268,4271,4283,4290,4296,4299,4302,4305,4308,4314,4317,4323,4329,4335,4344,4350,4358,4364,4371,4388,4391,4394,4401,4407,4425,4428,4434,4437,4443,4446,4450,4453,4456,4459,4465,4468,4471,4477,4487,4493,4496,4502,4505,4507],[13,4120,4121],{},"こんにちはjunです。webエンジニアとして働いていますが会社の人数が少なく、インフラの構築をすることがあります。と言ってもLAMP環境を作成するぐらいですけど。",[13,4123,4124],{},"構築は慣れてきましたがその中で、私が一番考えるのはセキュリティーです。構築するアプリケーションによってはセキュリティー設定はことなりますが、今回は自分でサーバを構築する時に最低限やった方がいいSSHの設定をメモがてら記事にしようと思います。",[13,4126,4127],{},"今回行う設定は以下の通りです。",[39,4129,4130,4133,4136,4139],{},[42,4131,4132],{},"rootユーザーのリモートログイン禁止化",[42,4134,4135],{},"パスワード認証禁止と鍵認証化",[42,4137,4138],{},"鍵認証の実装方法",[42,4140,4141],{},"ポート変更とfirewallの設定",[2353,4143,4145,4146],{"className":4144},[2356,2915],"\nなお今回説明する環境\n",[39,4147,4148,4151],{},[42,4149,4150],{},"サービス：GMO conoha VPS",[42,4152,4153],{},"OS：centos8",[13,4155,4156],{},"この設定をすべき理由や背景などから話すため、さっさと方法を知りたい場合は「root以外のユーザーを作成していく」から見てください。",[26,4158,4160],{"id":4159},"sshはめちゃくちゃ狙われている","SSHはめちゃくちゃ狙われている",[13,4162,4163],{},"SSHはリモートでサーバーを操作できる口のため、一番厳重にしなければなりません。あまり運用していないサーバー、購入したばかりでドメインと紐づけられていなくても世界中からBOTによる不正アクセス試行が発生します。私がVPSで購入してイメージが立った時も早速ログを見たところ以下の様になっていました。",[187,4165,4168],{"className":4166,"code":4167,"language":192},[190],"April  8 12:10:04 xxx-xxx-xx-xxx sshd[6887]: Failed password for root from 209.141.36.197 port 54506 ssh2\nApril  8 12:10:04 xxx-xxx-xx-xxx sshd[6891]: Failed password for invalid user oracle from 209.141.36.197 port 54518 ssh2\nApril  8 12:10:04 xxx-xxx-xx-xxx sshd[6892]: Failed password for invalid user test from 209.141.36.197 port 54512 ssh2\nApril  8 12:10:04 xxx-xxx-xx-xxx sshd[6889]: Failed password for root from 209.141.36.197 port 54520 ssh2\nApril  8 12:10:06 xxx-xxx-xx-xxx sshd[6904]: Failed password for root from 222.187.238.136 port 58496 ssh2\nApril  8 12:10:10 xxx-xxx-xx-xxx sshd[6904]: Failed password for root from 222.187.238.136 port 58496 ssh2\nApril  8 12:16:26 xxx-xxx-xx-xxx sshd[6909]: Failed password for root from 221.181.185.220 port 28787 ssh2\nApril  8 12:16:30 xxx-xxx-xx-xxx sshd[6909]: Failed password for root from 221.181.185.220 port 28787 ssh2\nApril  8 12:16:33 xxx-xxx-xx-xxx sshd[6909]: Failed password for root from 221.181.185.220 port 28787 ssh2\nApril  8 12:16:37 xxx-xxx-xx-xxx sshd[6911]: Failed password for root from 221.181.185.220 port 55152 ssh2\nApril  8 12:16:41 xxx-xxx-xx-xxx sshd[6911]: Failed password for root from 221.181.185.220 port 55152 ssh2\nApril  8 12:16:45 xxx-xxx-xx-xxx sshd[6911]: Failed password for root from 221.181.185.220 port 55152 ssh2\nApril  8 12:16:49 xxx-xxx-xx-xxx sshd[6913]: Failed password for root from 221.181.185.220 port 39938 ssh2\nApril  8 12:16:53 xxx-xxx-xx-xxx sshd[6913]: Failed password for root from 221.181.185.220 port 39938 ssh2\nApril  8 12:16:56 xxx-xxx-xx-xxx sshd[6913]: Failed password for root from 221.181.185.220 port 39938 ssh2\nApril  8 12:27:50 xxx-xxx-xx-xxx sshd[6918]: Failed password for root from 222.187.239.109 port 32720 ssh2\nApril  8 12:27:54 xxx-xxx-xx-xxx sshd[6918]: Failed password for root from 222.187.239.109 port 32720 ssh2\nApril  8 12:27:57 xxx-xxx-xx-xxx sshd[6918]: Failed password for root from 222.187.239.109 port 32720 ssh2\n",[194,4169,4167],{"__ignoreMap":196},[13,4171,4172],{},"これはSSHの接続失敗の履歴です、同じIPで定間隔でrootユーザーによるパスワード接続を試みています。これはパスワードリスト攻撃・総当たり攻撃というものです。確率は低いですがrootのパスワードが万が一にあった場合、サーバの最上権限であるrootが第三者に掌握されます。",[13,4174,4175],{},"ドメインに紐づけられておらずIPだけでもこの様にBOTがインターネットを徘徊して、脆弱なサーバを狙っています。VPSを購入したらすぐにデフォルトの設定を変えて、比較的安全なものに変更しましょう。",[2353,4177,4179,4180,4183],{"className":4178},[2356,2876],"\nターミナルで",[194,4181,4182],{},"whois","コマンドを使用してIPのwois情報を調べられます。登録された国などもわかります。ちなみに上記のIPのほとんどが中国でした。\n",[26,4185,4186],{"id":4186},"安全にするために変更する設定",[13,4188,4189],{},"デフォルトの設定から以下の変更を行います。",[39,4191,4192,4195,4198],{},[42,4193,4194],{},"rootによるリモートログインを禁止にする。",[42,4196,4197],{},"SSHをパスワード認証でなく、鍵認証にする",[42,4199,4200],{},"ポートを変更する",[13,4202,4203],{},"これらの設定は最低限行うべきものです。より強固にする場合は、色々と他に設定しますがまずはこれでいきましょう。",[71,4205,4206],{"id":4206},"root以外のユーザーを作成していく",[13,4208,4209],{},"最終的にはrootのリモートログインを禁止するため別の操作ユーザーを作成していきます。まずはrootでログインしましましょう。",[187,4211,4214],{"className":4212,"code":4213,"language":192},[190],"ssh root@123.456.78.901\n（IPなどは自分のものに置き換えてください）\n",[194,4215,4213],{"__ignoreMap":196},[13,4217,4218],{},"開発用・SSH接続用ユーザーを作成します。",[187,4220,4223],{"className":4221,"code":4222,"language":192},[190],"# useradd develop\n# passwd develop\n",[194,4224,4222],{"__ignoreMap":196},[13,4226,4227,4228,4231],{},"これでユーザーとそのパスワードが設定されました。次にそのユーザーを",[194,4229,4230],{},"wheel","グループに所属させます。",[187,4233,4236],{"className":4234,"code":4235,"language":192},[190],"# usermod -G wheel develop\n",[194,4237,4235],{"__ignoreMap":196},[13,4239,4240,4242,4243,4246,4247,4250,4251,4254,4255,4258,4259,4261,4262,4264,4265,4267],{},[194,4241,4230],{},"グループに所属することで",[194,4244,4245],{},"develop","が",[194,4248,4249],{},"sudo","を使用できる様になり、また",[194,4252,4253],{},"su","にてrootになることができます。",[194,4256,4257],{},"\u002Fetc\u002Fsudoers","では",[194,4260,4230],{},"グループで行える操作などを定義してあり、基本的にはrootを使用せずdevelopでsshログインをして操作します。yumで何かインストールしたい時とかは",[194,4263,4249],{},"したり",[194,4266,4253],{},"でrootになります。",[138,4269,4270],{"id":4270},"wheelのみがsuできる様にする",[13,4272,4273,4274,4276,4277,4279,4280,4282],{},"デフォルトではsuでどのユーザーもrootになれます。",[194,4275,4245],{},"意外にもユーザは存在し、そのユーザーが狙われることもあります。そのため",[194,4278,4230],{},"グループに属しているユーザーだけが",[194,4281,4253],{},"を用いてrootになれる様にしましょう。",[13,4284,4285,4286,4289],{},"suの設定は",[194,4287,4288],{},"\u002Fetc\u002Fpam.d\u002Fsu","に記述されています。",[187,4291,4294],{"className":4292,"code":4293,"language":192},[190],"# vi \u002Fetc\u002Fpam.d\u002Fsu\n\n--------\n# コメントアウトしているこの箇所を外す\n# auth            required        pam_wheel.so use_uid\n↓\nauth            required        pam_wheel.so use_uid\n--------\n",[194,4295,4293],{"__ignoreMap":196},[13,4297,4298],{},"コメントアウトされている箇所を外します。これでsuでrootになるためにwheelグループに属したユーザーから行うという制限ができました。",[71,4300,4301],{"id":4301},"develop用のssh鍵を作成",[13,4303,4304],{},"現在sshはパスワードでログインできますが、最終的にはパスワード認証を禁止にします。そしてよりセキュアな鍵認証式に変更します。基本的にログインの手間やセキュリティ的に鍵認証にした方がいいです。鍵認証の原理は今回は省きます。それではdevelop用の鍵を作成します。",[13,4306,4307],{},"クライアント側で秘密鍵と公開書きを作成します。",[187,4309,4312],{"className":4310,"code":4311,"language":192},[190],"% ssh-keygen\nGenerating public\u002Fprivate rsa key pair.\nEnter file in which to save the key (\u002FUsers\u002Fyou\u002F.ssh\u002Fid_rsa): #id_rsaというファイル名でよければそのままEnter\nEnter passphrase (empty for no passphrase): 　#パースフレーズを設定する場合は入力。なければEnter\nEnter same passphrase again:\n",[194,4313,4311],{"__ignoreMap":196},[13,4315,4316],{},"これで秘密鍵と公開鍵が生成されます。秘密鍵をクライアントに置いておき、公開鍵をサーバに転送します。",[187,4318,4321],{"className":4319,"code":4320,"language":192},[190],"scp .\u002Fid_rsa.pub develop@123.456.78.902:~\u002F\n",[194,4322,4320],{"__ignoreMap":196},[13,4324,4325,4326,4328],{},"サーバー側に戻ります。developのホームディレクトリに",[194,4327,1936],{},"というディレクトリがあるかを確認します。",[187,4330,4333],{"className":4331,"code":4332,"language":192},[190],"$ ls -a ~\u002F\n",[194,4334,4332],{"__ignoreMap":196},[13,4336,4337,4339,4340,4343],{},[194,4338,1936],{},"は隠しフォルダなので",[194,4341,4342],{},"ls -a","を使用します。無い場合はディレクトリを作成します。今回は無かったとしましょう。",[187,4345,4348],{"className":4346,"code":4347,"language":192},[190],"$ mkdir ~\u002F.ssh\n$ chmod 700 ~\u002F.ssh \n",[194,4349,4347],{"__ignoreMap":196},[13,4351,4352,4354,4355,4357],{},[194,4353,1936],{},"は権限を700にしましょう。そうで無いと権限エラーによってdevelopに対するsshを行うことができません。そしてクライアントから転送された公開側の名前を変更して",[194,4356,1936],{},"配下に置いておきます。",[187,4359,4362],{"className":4360,"code":4361,"language":192},[190],"$ cp ~\u002Fid_rsa.pub ~\u002F.ssh\u002Fauthorized_keys\n$ chmod 600 ~\u002F.ssh\u002Fauthorized_keys\n$ rm ~\u002Fid_rsa.pub\n",[194,4363,4361],{"__ignoreMap":196},[13,4365,4366,4367,4370],{},"ここでも",[194,4368,4369],{},"authorized_keys","は600権限を付けないと使用できません。",[2353,4372,4374,4377,4385],{"className":4373},[2356,2876],[13,4375,4376],{},"authorized_keysにリネームする理由",[13,4378,4379,4380,651],{},"The authorized_keys file in SSH specifies the SSH keys that can be used for logging into the user account for which the file is configured.(",[631,4381,4384],{"target":4382,"href":4383},"_blank","https:\u002F\u002Fwww.ssh.com\u002Facademy\u002Fssh\u002Fauthorized-keys-file#:~:text=The%20authorized_keys%20file%20in%20SSH,keys%20and%20needs%20proper%20management.","参照",[13,4386,4387],{},"authorized_keysファイルはその公開鍵に紐づく秘密鍵を用いてログインできるユーザーを特定します。簡単な話、authorized_keysにしておけばsshが自動的に鍵を判別してくれるのでその名前にしておく。",[13,4389,4390],{},"これでdevelopは鍵認証を用いてログインできる様になりました。",[71,4392,4393],{"id":4393},"rootのリモートログインとパスワード認証を禁止にする",[13,4395,4396,4397,4400],{},"developで鍵認証で接続できることを確認したら次はrootのリモートログインとパスワード認証を禁止にします。",[194,4398,4399],{},"\u002Fetc\u002Fssh\u002Fsshd_config","を編集していきます。",[187,4402,4405],{"className":4403,"code":4404,"language":192},[190],"# vi \u002Fetc\u002Fssh\u002Fsshd_config\n\n---------- 以下行を追加 -----------\nPermitRootLogin no\n---------- 以上行を追加 -----------\n\n--------------以下を変更--------------\nPasswordAuthentication yes\n#RSAAuthentication yes\n#PubkeyAuthentication yes\n--------------↓--------------\nPasswordAuthentication no\nRSAAuthentication yes\nPubkeyAuthentication yes\n------------------------------------------\n",[194,4406,4404],{"__ignoreMap":196},[13,4408,4409,4412,4413,4416,4417,4420,4421,4424],{},[194,4410,4411],{},"PermitRootLogin no","という記述をつけます。名の通りルートのログインを禁止にさせました。そして",[194,4414,4415],{},"PasswordAuthentication no","としパスワード認証を禁止。",[194,4418,4419],{},"RSAAuthentication yes","と",[194,4422,4423],{},"PubkeyAuthentication yes","のコメントアウトを外して鍵認証のみでつなげる様に明示的に設定します。",[13,4426,4427],{},"これであとはsshdをリスタートさせれば反映させます。",[187,4429,4432],{"className":4430,"code":4431,"language":192},[190],"# systemctl restart sshd\n",[194,4433,4431],{"__ignoreMap":196},[13,4435,4436],{},"試しにチェックしましょう。",[187,4438,4441],{"className":4439,"code":4440,"language":192},[190],"ssh root@xxx.xxx.xxx\nroot@xxx.xxx.xxx: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).\n\nssh develop@xxx.xxx.xxx\ndevelop@xxx.xxx.xxx: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).\n",[194,4442,4440],{"__ignoreMap":196},[13,4444,4445],{},"OKです。逆にdevelopで鍵認証で接続したのに弾かれたら設定をミスっています。",[2353,4447,4449],{"className":4448},[2356,2357],"\n接続系を設定するときは2つのターミナルタブを開いていておき、片方はずっとroot化できる状態でサーバーにログインしておき、片方で接続テストをしましょう。もし失敗してどのユーザー・方法でも接続できなくなると二度とサーバーに接続できなくなります。\n",[71,4451,4452],{"id":4452},"sshの接続ポートを変更する",[13,4454,4455],{},"sshはデフォルトで22のポートで接続します。しかしこのポートはwell-knownポートとして知られており、攻撃者もデフォルトのポートを狙ってきます。そこでsshのポートを変更してさらに攻撃されにくくします。sshに接続するためにはユーザー名、鍵・パスワード、ポートが合わないといけないからです。",[13,4457,4458],{},"まずはsshdのデフォルトポートを変更します。変更するポート番号は49513～65535あたりから自由に設定しましょう。",[187,4460,4463],{"className":4461,"code":4462,"language":192},[190],"# vi \u002Fetc\u002Fssh\u002Fsshd_config\n--------------以下を変更--------------\n#Port 22    \n--------------↓--------------\nPort 49510\n------------------------------------------\n",[194,4464,4462],{"__ignoreMap":196},[13,4466,4467],{},"そしてfirewallが有効な場合、sshによる22は許可していてもカスタムしたポートは許可していないことがあります。これではカスタムポートへ接続する前にfirewallで弾かれるので設定します。",[13,4469,4470],{},"まずはsshdのfirewallの設定ファイルをコピーします。",[187,4472,4475],{"className":4473,"code":4474,"language":192},[190],"cp \u002Fusr\u002Flib\u002Ffirewalld\u002Fservices\u002Fssh.xml \u002Fetc\u002Ffirewalld\u002Fservices\u002F\n",[194,4476,4474],{"__ignoreMap":196},[13,4478,4479,4482,4483,4486],{},[194,4480,4481],{},"\u002Fetc\u002Ffirewalld\u002Fservices\u002F","にて追加の設定を行うことができます。コピーした",[194,4484,4485],{},"ssh.xml","を編集します。",[187,4488,4491],{"className":4489,"code":4490,"language":192},[190],"# vi \u002Fetc\u002Ffirewalld\u002Fservices\u002F\n\u003C?xml version=\"1.0\" encoding=\"utf-8\"?>\n  \u003Cservice>\n    \u003Cshort>SSH\u003C\u002Fshort>\n    \u003Cdescription>Secure Shell (SSH) is a protocol ...\u003C\u002Fdescription>\n    \u003Cport protocol=\"tcp\" port=\"22\"\u002F>\n    \u003Cport protocol=\"tcp\" port=\"49510\"\u002F> # 追加\n\u003C\u002Fservice>\n",[194,4492,4490],{"__ignoreMap":196},[13,4494,4495],{},"上記の設定でsshサービスによる49510ポートの接続が許可されました。\nそして設定が終わったらfirewallをリロードします。またsshdも設定を変えたのでリロードします。",[187,4497,4500],{"className":4498,"code":4499,"language":192},[190],"# firewall-cmd --reload\n# systemctl restart sshd\n",[194,4501,4499],{"__ignoreMap":196},[13,4503,4504],{},"これでOKです。ポートをカスタムのものに指定して接続して通れば問題ありません。そして22（デフォルト）で接続して弾かれるかも確認しましょう。",[26,4506,3180],{"id":3179},[13,4508,4509],{},"以上がsshの最低限必要な設定です。インフラ系では結構基礎的な内容だそうです。sshは狙われており、適切に設定することで安全に使用することができます。",{"title":196,"searchDepth":557,"depth":557,"links":4511},[4512,4513,4521],{"id":4159,"depth":560,"text":4160},{"id":4186,"depth":560,"text":4186,"children":4514},[4515,4518,4519,4520],{"id":4206,"depth":557,"text":4206,"children":4516},[4517],{"id":4270,"depth":570,"text":4270},{"id":4301,"depth":557,"text":4301},{"id":4393,"depth":557,"text":4393},{"id":4452,"depth":557,"text":4452},{"id":3179,"depth":560,"text":3180},[3750],"2021-04-25",{},"\u002Farticles\u002Fvps-ssh-first",{"title":4116,"description":4116},"articles\u002Fvps-ssh-first",[3526,607,608],"_mix\u002Fcyber-security-3400657_640.jpg","0p7STSITYfCR0ETcCcYcMeNhmXEtc_cRA-W1MKHcN_8",{"id":4532,"title":4533,"body":4534,"category":5024,"createdAt":5025,"description":4533,"extension":599,"index":600,"meta":5026,"navigation":602,"path":5027,"publish":602,"seo":5028,"series":600,"seriesTitle":600,"stem":5029,"tag":5030,"thumbnail":5034,"updatedAt":600,"__hash__":5035},"articles\u002Farticles\u002Flaravel-mixx-heroku-fail.md","Laravel mixのアセットがherokuで動かない時の対処法",{"type":10,"value":4535,"toc":5015},[4536,4539,4542,4545,4549,4556,4559,4562,4566,4580,4584,4587,4590,4594,4608,4624,4637,4647,4651,4658,4668,4829,4832,4979,4988,4991,4994,5005,5012],[13,4537,4538],{},"こんにちはjunです。最近よくLaravelの開発を行っていて、プロトタイプとかをherokuにあげるのですがLaravel mixのアセットが動かない（main.jsが404）でちょっと困ったので、今回はその対処法を書きたいと思います。",[13,4540,4541],{},"Laravel\bmixの説明を軽くするので、さっさと解決策みたいひとは「ビルドアセットをgitignoreしていた」から参照してください。なお使用環境は以下の通りです。",[13,4543,4544],{},"Laravel 6\nPHP 7.4\nNode.js 12.21（開発）\nNode.js 14.16（heroku）",[26,4546,4548],{"id":4547},"laravel-mixって","Laravel Mixって？",[13,4550,4551,4552,4555],{},"Laravel MixはLaravelが公式に出している、JS・CSSのアセットコンパイラとモジュールバンドラです。",[194,4553,4554],{},"resource","配下のjsやsassをコンパイルしたり、バンドルするwebpackの設定がすでにLaraveに最適化されています。webpackをほとんど触らずともvue、react、sass、そのほかjsライブラリをもちいた開発ができます。",[13,4557,4558],{},"resource 配下のアセットはLaravel Mixによってpublic配下に自動的に吐かれるようになっています。開発時にはnpm run watchをしていますが、よく見るとpublic配下に開発用ビルドしたアセットファイルが逐一置かれています。",[13,4560,4561],{},"大体のLaraveフロントエンドではこのMixを用いて開発していることが多いと思います。しかしherokuや本番環境にあげた時にちょっと問題がおきました。",[26,4563,4565],{"id":4564},"mainjs-is-not-found","main.js is not found",[13,4567,4568,4569,4571,4572,4575,4576,4579],{},"Laravel Mixでフロントを構築して、ある程度バック含めて完成したのでherokuにデプロイしてみました。ビルドは普通に成功し、満を辞して目的の画面をみても",[194,4570,4565],{},"となってしましました。",[194,4573,4574],{},"main.js","にはビルドしたvue.jsのプロジェクトがあるはずなのにと思い、サーバーに入って",[194,4577,4578],{},"public\u002Fjs","配下をみてみたところ、何もありませんでした。",[71,4581,4583],{"id":4582},"原因その１ビルドアセットをgitignoreしていた","原因その１：ビルドアセットをgitignoreしていた",[13,4585,4586],{},"ビルドされたアセットはpublic配下に置かれますが、ファイル量が膨大だったり、開発モードと本番モードが混じる可能性があること、あとどうせコロコロ変わるのでバージョン管理から外そうと思い、public\u002Fjsとpublic\u002Fcssはバージョン管理から外していました。",[13,4588,4589],{},"herokuは基本的にgitを用いてデプロイします。管理対象外のファイルはもちろんherokuサーバー上にないので、アセットがあるはずもありません。であればherokuにデプロイした時にLaravel Mixを叩いて、ビルドすれば解決します。",[71,4591,4593],{"id":4592},"原因その２laravel-mixがdevdependencies","原因その２：Laravel MixがdevDependencies",[13,4595,4596,4597,4246,4600,4603,4604,4607],{},"Herokuでは",[194,4598,4599],{},"NODE_ENV",[194,4601,4602],{},"production","（本番環境）で定義されていると、",[194,4605,4606],{},"devDependencies","がプリーニングされてしまい、ビルドがうまく走りません。",[2353,4609,4611,4612,4615],{"className":4610},[2356,2915],"\nデフォルトでは、Heroku は ​package.json​ の ​dependencies​ および ​devDependencies​ に記載されているすべての依存関係をインストールします。\n",[13,4613,4614],{},"インストールおよび​ビルドステップ​を実行した後、 Heroku はアプリケーションをデプロイする前に、​devDependencies​ に宣言されているパッケージを取り除きます。",[13,4616,4617],{},[4618,4619,4620],"small",{},[631,4621,4622],{"href":4622,"rel":4623},"https:\u002F\u002Fdevcenter.heroku.com\u002Fja\u002Farticles\u002Fnodejs-support#skip-pruning",[650],[13,4625,4626,4627,4632,4633,4636],{},"インストールおよび​",[631,4628,4631],{"href":4629,"rel":4630},"https:\u002F\u002Fdevcenter.heroku.com\u002Farticles\u002Fnodejs-support#heroku-specific-build-steps",[650],"ビルドステップ","​を実行した後、 Heroku はアプリケーションをデプロイする前に、",[194,4634,4635],{},"​devDependencies​"," に宣言されているパッケージを取り除きます。",[13,4638,4639,4640,4642,4643,4646],{},"対策としては",[194,4641,3112],{},"をいじって",[194,4644,4645],{},"dependencies","に移動します。デフォルトでLaravel Mixはdevの方にインストールされます。それを移動してプッシュすればひとまずLaravel Mixのビルドがうまくいきます。",[71,4648,4650],{"id":4649},"原因その３npm-run-productionを動かすように設定","原因その３：npm run productionを動かすように設定",[13,4652,4653,4654,4657],{},"その２に加えて、今度はherokuデプロイの際にLaravel Mixのビルドスクリプトがキックされるように設定します。herokuはNode.jsのプロジェクトがあり、そのスクリプトに",[194,4655,4656],{},"npm run build","がある場合はそれを実行してくれます。",[13,4659,4660,4661,4663,4664,4667],{},"初期の",[194,4662,3112],{},"のスクリプトは",[194,4665,4666],{},"build","がないので、mixが実行されません。",[187,4669,4672],{"className":3116,"code":4670,"filename":4671,"language":3119,"meta":196,"style":196},"\"scripts\": {\n    \"dev\": \"npm run development\",\n    \"development\": \"cross-env NODE_ENV=development node_modules\u002Fwebpack\u002Fbin\u002Fwebpack.js --progress --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js\",\n    \"watch\": \"npm run development -- --watch\",\n    \"watch-poll\": \"npm run watch -- --watch-poll\",\n    \"hot\": \"cross-env NODE_ENV=development node_modules\u002Fwebpack-dev-server\u002Fbin\u002Fwebpack-dev-server.js --inline --hot --disable-host-check --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js\",\n    \"prod\": \"npm run production\",\n    \"production\": \"cross-env NODE_ENV=production node_modules\u002Fwebpack\u002Fbin\u002Fwebpack.js --no-progress --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js\"\n},\n","pakage.json",[194,4673,4674,4686,4706,4726,4746,4766,4786,4806,4823],{"__ignoreMap":196},[675,4675,4676,4678,4680,4682,4684],{"class":677,"line":678},[675,4677,2466],{"class":685},[675,4679,3132],{"class":689},[675,4681,2466],{"class":685},[675,4683,3810],{"class":755},[675,4685,2454],{"class":685},[675,4687,4688,4690,4693,4695,4697,4699,4702,4704],{"class":677,"line":560},[675,4689,2459],{"class":685},[675,4691,4692],{"class":2462},"dev",[675,4694,2466],{"class":685},[675,4696,686],{"class":685},[675,4698,2471],{"class":685},[675,4700,4701],{"class":689},"npm run development",[675,4703,2466],{"class":685},[675,4705,2479],{"class":685},[675,4707,4708,4710,4713,4715,4717,4719,4722,4724],{"class":677,"line":557},[675,4709,2459],{"class":685},[675,4711,4712],{"class":2462},"development",[675,4714,2466],{"class":685},[675,4716,686],{"class":685},[675,4718,2471],{"class":685},[675,4720,4721],{"class":689},"cross-env NODE_ENV=development node_modules\u002Fwebpack\u002Fbin\u002Fwebpack.js --progress --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js",[675,4723,2466],{"class":685},[675,4725,2479],{"class":685},[675,4727,4728,4730,4733,4735,4737,4739,4742,4744],{"class":677,"line":570},[675,4729,2459],{"class":685},[675,4731,4732],{"class":2462},"watch",[675,4734,2466],{"class":685},[675,4736,686],{"class":685},[675,4738,2471],{"class":685},[675,4740,4741],{"class":689},"npm run development -- --watch",[675,4743,2466],{"class":685},[675,4745,2479],{"class":685},[675,4747,4748,4750,4753,4755,4757,4759,4762,4764],{"class":677,"line":719},[675,4749,2459],{"class":685},[675,4751,4752],{"class":2462},"watch-poll",[675,4754,2466],{"class":685},[675,4756,686],{"class":685},[675,4758,2471],{"class":685},[675,4760,4761],{"class":689},"npm run watch -- --watch-poll",[675,4763,2466],{"class":685},[675,4765,2479],{"class":685},[675,4767,4768,4770,4773,4775,4777,4779,4782,4784],{"class":677,"line":728},[675,4769,2459],{"class":685},[675,4771,4772],{"class":2462},"hot",[675,4774,2466],{"class":685},[675,4776,686],{"class":685},[675,4778,2471],{"class":685},[675,4780,4781],{"class":689},"cross-env NODE_ENV=development node_modules\u002Fwebpack-dev-server\u002Fbin\u002Fwebpack-dev-server.js --inline --hot --disable-host-check --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js",[675,4783,2466],{"class":685},[675,4785,2479],{"class":685},[675,4787,4788,4790,4793,4795,4797,4799,4802,4804],{"class":677,"line":736},[675,4789,2459],{"class":685},[675,4791,4792],{"class":2462},"prod",[675,4794,2466],{"class":685},[675,4796,686],{"class":685},[675,4798,2471],{"class":685},[675,4800,4801],{"class":689},"npm run production",[675,4803,2466],{"class":685},[675,4805,2479],{"class":685},[675,4807,4808,4810,4812,4814,4816,4818,4821],{"class":677,"line":741},[675,4809,2459],{"class":685},[675,4811,4602],{"class":2462},[675,4813,2466],{"class":685},[675,4815,686],{"class":685},[675,4817,2471],{"class":685},[675,4819,4820],{"class":689},"cross-env NODE_ENV=production node_modules\u002Fwebpack\u002Fbin\u002Fwebpack.js --no-progress --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js",[675,4822,2584],{"class":685},[675,4824,4825,4827],{"class":677,"line":752},[675,4826,3973],{"class":685},[675,4828,2479],{"class":755},[13,4830,4831],{},"ちょうどprodというのがあるのでbuildに変えてやりましょう。",[187,4833,4835],{"className":3116,"code":4834,"filename":4671,"language":3119,"meta":196,"style":196},"\"scripts\": {\n    \"dev\": \"npm run development\",\n    \"development\": \"cross-env NODE_ENV=development node_modules\u002Fwebpack\u002Fbin\u002Fwebpack.js --progress --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js\",\n    \"watch\": \"npm run development -- --watch\",\n    \"watch-poll\": \"npm run watch -- --watch-poll\",\n    \"hot\": \"cross-env NODE_ENV=development node_modules\u002Fwebpack-dev-server\u002Fbin\u002Fwebpack-dev-server.js --inline --hot --disable-host-check --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js\",\n    \"build\": \"npm run production\",\n    \"production\": \"cross-env NODE_ENV=production node_modules\u002Fwebpack\u002Fbin\u002Fwebpack.js --no-progress --config=node_modules\u002Flaravel-mix\u002Fsetup\u002Fwebpack.config.js\"\n},\n",[194,4836,4837,4849,4867,4885,4903,4921,4939,4957,4973],{"__ignoreMap":196},[675,4838,4839,4841,4843,4845,4847],{"class":677,"line":678},[675,4840,2466],{"class":685},[675,4842,3132],{"class":689},[675,4844,2466],{"class":685},[675,4846,3810],{"class":755},[675,4848,2454],{"class":685},[675,4850,4851,4853,4855,4857,4859,4861,4863,4865],{"class":677,"line":560},[675,4852,2459],{"class":685},[675,4854,4692],{"class":2462},[675,4856,2466],{"class":685},[675,4858,686],{"class":685},[675,4860,2471],{"class":685},[675,4862,4701],{"class":689},[675,4864,2466],{"class":685},[675,4866,2479],{"class":685},[675,4868,4869,4871,4873,4875,4877,4879,4881,4883],{"class":677,"line":557},[675,4870,2459],{"class":685},[675,4872,4712],{"class":2462},[675,4874,2466],{"class":685},[675,4876,686],{"class":685},[675,4878,2471],{"class":685},[675,4880,4721],{"class":689},[675,4882,2466],{"class":685},[675,4884,2479],{"class":685},[675,4886,4887,4889,4891,4893,4895,4897,4899,4901],{"class":677,"line":570},[675,4888,2459],{"class":685},[675,4890,4732],{"class":2462},[675,4892,2466],{"class":685},[675,4894,686],{"class":685},[675,4896,2471],{"class":685},[675,4898,4741],{"class":689},[675,4900,2466],{"class":685},[675,4902,2479],{"class":685},[675,4904,4905,4907,4909,4911,4913,4915,4917,4919],{"class":677,"line":719},[675,4906,2459],{"class":685},[675,4908,4752],{"class":2462},[675,4910,2466],{"class":685},[675,4912,686],{"class":685},[675,4914,2471],{"class":685},[675,4916,4761],{"class":689},[675,4918,2466],{"class":685},[675,4920,2479],{"class":685},[675,4922,4923,4925,4927,4929,4931,4933,4935,4937],{"class":677,"line":728},[675,4924,2459],{"class":685},[675,4926,4772],{"class":2462},[675,4928,2466],{"class":685},[675,4930,686],{"class":685},[675,4932,2471],{"class":685},[675,4934,4781],{"class":689},[675,4936,2466],{"class":685},[675,4938,2479],{"class":685},[675,4940,4941,4943,4945,4947,4949,4951,4953,4955],{"class":677,"line":736},[675,4942,2459],{"class":685},[675,4944,4666],{"class":2462},[675,4946,2466],{"class":685},[675,4948,686],{"class":685},[675,4950,2471],{"class":685},[675,4952,4801],{"class":689},[675,4954,2466],{"class":685},[675,4956,2479],{"class":685},[675,4958,4959,4961,4963,4965,4967,4969,4971],{"class":677,"line":741},[675,4960,2459],{"class":685},[675,4962,4602],{"class":2462},[675,4964,2466],{"class":685},[675,4966,686],{"class":685},[675,4968,2471],{"class":685},[675,4970,4820],{"class":689},[675,4972,2584],{"class":685},[675,4974,4975,4977],{"class":677,"line":752},[675,4976,3973],{"class":685},[675,4978,2479],{"class":755},[13,4980,4981,4982,4984,4985,4987],{},"こうすれば",[194,4983,4656],{}," が ",[194,4986,4801],{}," を実行して本番用のアセットを作ってくれます。これで解決です。",[26,4989,4990],{"id":4990},"ビルドアセットがうまく出力されない時に考えるべきこと",[13,4992,4993],{},"今回はいくつかのファイルをビルドする必要があり、デプロイ作業が自動で行われる状況でした。開発環境ではアセットがあるのに、本番だとなくなっているという場合は以下のことを考えましょう。",[39,4995,4996,4999,5002],{},[42,4997,4998],{},"ファイルはある？（サーバーに入ってlsしてチェック）",[42,5000,5001],{},"ビルドに必要なモジュールがインストールされているか？",[42,5003,5004],{},"ビルドスクリプトはキックされているか？",[13,5006,5007,5008,5011],{},"大体こうゆうときはビルドがうまくいっていないので、そこからチェックしていくといいです。ちなみに私が検索した時のワードは ",[35,5009,5010],{},"「heroku laravel mix ビルド」"," でした。それではまた。",[2290,5013,5014],{},"html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sJ14y, html code.shiki .sJ14y{--shiki-default:#C792EA}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":196,"searchDepth":557,"depth":557,"links":5016},[5017,5018,5023],{"id":4547,"depth":560,"text":4548},{"id":4564,"depth":560,"text":4565,"children":5019},[5020,5021,5022],{"id":4582,"depth":557,"text":4583},{"id":4592,"depth":557,"text":4593},{"id":4649,"depth":557,"text":4650},{"id":4990,"depth":560,"text":4990},[597],"2021-03-27",{},"\u002Farticles\u002Flaravel-mixx-heroku-fail",{"title":4533,"description":4533},"articles\u002Flaravel-mixx-heroku-fail",[5031,5032,5033,607],"js","webpack","laravel","_mix\u002F8_laravel-icon.3f70de72f3.jpg","zvECdzfredOonr51btVrUrKqFCKw247gmW-jXba47XU",{"id":5037,"title":5038,"body":5039,"category":5194,"createdAt":5195,"description":5038,"extension":599,"index":600,"meta":5196,"navigation":602,"path":5197,"publish":602,"seo":5198,"series":600,"seriesTitle":600,"stem":5199,"tag":5200,"thumbnail":600,"updatedAt":600,"__hash__":5201},"articles\u002Farticles\u002Fssh-on-xserver.md","XserverでSSH接続を行い、ターミナルで操作する",{"type":10,"value":5040,"toc":5187},[5041,5044,5047,5051,5058,5061,5064,5067,5070,5073,5076,5079,5083,5086,5089,5095,5102,5108,5112,5121,5127,5130,5136,5149,5159,5162,5165,5171,5174,5178,5181,5184],[13,5042,5043],{},"こんにちはJunです。vagrant、Docker、VPSなどを構築しているとわかりますが、レンタルサーバーは手軽に構築できて便利です。エンジニア的には自由に環境を構築できた方がいろんなアプリを作ることができますが、ブログ程度であればXserverで十分です。",[13,5045,5046],{},"DBや細かい設定もGUIで完結できる様になっているので初心者にはもってこいです。しかし私が別で構築しているブログを今管理しているXserverに移行する時、画像やDBが膨大すぎて手動・GUIでは移行に限界がありました。そのためSSHを使用してXserverに繋いてで操作することにしました。今回はその忘備録です。",[26,5048,5050],{"id":5049},"sshを有効にする","SSHを有効にする",[13,5052,5053,5054,5057],{},"「SSHとはなんぞや？」という人は",[631,5055,5056],{"href":603},"こちらの記事","でわかりやすく説明したものがあるのでご覧ください。",[13,5059,5060],{},"最初にXserverでSSH接続を有効にする必要があります。Xserverサーバーパネルにログインして、「SSH設定」という箇所のページを開きます。",[170,5062],{":src":5063,":width":173},"'_mix\u002Fsch-2021-01-11-14.59.00.png'",[13,5065,5066],{},"そこで「変更」をONにして「設定する」をクリック。しますとSSHが有効になります。",[26,5068,5069],{"id":5069},"秘密鍵を生成する",[13,5071,5072],{},"SSHは鍵交換という方法を用いてサーバーへのログインを管理しています。自身のPCからXserverのサーバーへアクセスするには鍵を発行します。「公開鍵認証用鍵ペアの生成」をクリックします。以下の画面が表示されるので、「パスフレーズ」（パスワードの様なもの）を入れて「確認画面」へ進みます。",[170,5074],{":src":5075,":width":173},"'_mix\u002Fsch-2021-01-11-17.43.09.png'",[13,5077,5078],{},"確認が終了すると~~~.keyという拡張子のファイルがダウンロードされます。このファイルは鍵ファイルといい、サーバーの中にアクセスする際に使用されます。",[26,5080,5082],{"id":5081},"sshの設定をする","SSHの設定をする",[13,5084,5085],{},"ここからはローカル（自分のPC）の話になります。SSHでアクセスするために、ローカルでのSSH設定を行います。またローカルにはsshdがあり、今回はMacOSターミナルでの操作を前提としています。",[13,5087,5088],{},"ターミナルを立ち上げ、ひとまずホームディレクトリに移動し、さらにDownloadsへ移動し、先ほどダウンロードしたkeyファイルを見つけます。",[187,5090,5093],{"className":5091,"code":5092,"language":192},[190],"jun@MacBook-Pro % cd ~\njun@MacBook-Pro ~ % cd downloads\njun@MacBook-Pro downloads % ls\n...\nserver.key\n...\n",[194,5094,5092],{"__ignoreMap":196},[13,5096,5097,5098,5101],{},"keyファイルをひとまずホームディレクトリ配下にある",[194,5099,5100],{},".ssh\u002F","へ移動させます。",[187,5103,5106],{"className":5104,"code":5105,"language":192},[190],"jun@MacBook-Pro downloads % mv server.key ~\u002F.ssh\u002F\n",[194,5107,5105],{"__ignoreMap":196},[2353,5109,5111],{"className":5110},[2356,2876],"\nTIPS:\nsshdがある環境ではユーザーごとに.sshというディレクトリが与えられ、そこで個人のssh設定を行います。しかし.sshは隠しファイルなので、ホームディレクトリでlsをしても普通には出てきません。ls -a とすることで隠しファイルを含めて表示させると、.sshというディレクトリを確認できます。\n",[13,5113,5114,5116,5117,5120],{},[194,5115,1936],{},"に移動してkeyを確認。そして権限を変更します。権限を変更しないと ",[194,5118,5119],{},"WARNING: UNPROTECTED PRIVATE KEY FILE!"," と怒られます。",[187,5122,5125],{"className":5123,"code":5124,"language":192},[190],"jun@MacBook-Pro .ssh % ls\nconfig      server.key\n\njun@MacBook-Pro .ssh % chmod 400 server.key\n",[194,5126,5124],{"__ignoreMap":196},[13,5128,5129],{},"これでOKです。lsをした時にconfigというファイルがあったと思います。そのファイルにsshの設定が記述されていますので、以下の様に編集をします。",[187,5131,5134],{"className":5132,"code":5133,"language":192},[190],"jun@MacBook-Pro .ssh % vi config\n\nHost my-site\n HostName svExample.xserver.jp\n Port 10022\n user idName\n IdentitiesOnly yes\n IdentityFile \u002FUsers\u002Fjunjiishii\u002F.ssh\u002Fserver.key\n",[194,5135,5133],{"__ignoreMap":196},[13,5137,5138,5141,5142,5145,5146,5148],{},[194,5139,5140],{},"HostName","はxserverのホスト名を入力し。",[194,5143,5144],{},"user","にはサーバーIDを入力します。",[194,5147,5140],{},"はxserverのサーバーパネルの「サーバー情報」、サーバーIDは「パスワード変更」で確認できます。",[13,5150,5151,5154,5155,5158],{},[194,5152,5153],{},"config","で設定しておくとsshコマンドを打つ時、Hostの名前でつまり、",[194,5156,5157],{},"ssh my-site"," とするだけで設定した値の接続先にsshしてくれます。",[26,5160,5161],{"id":5161},"xserverへsshをする",[13,5163,5164],{},"それではsshを行ってみます。",[187,5166,5169],{"className":5167,"code":5168,"language":192},[190],"ssh my-site\nEnter passphrase for key '\u002FUsers\u002Fjun\u002F.ssh\u002Fjunji1996.key': ＃設定したパースフレーズを入力\n\n#もし、以下の文章が表示されたら yesをおす\nECDSA key fingerprint is SHA256:V0GmZVuUlP6tQw5MYbGelfcq+IQwq\u002F6+HnH1OPAcaLo.\nAre you sure you want to continue connecting (yes\u002Fno\u002F[fingerprint])? yes\n\n[idName@svExample ~]$\n",[194,5170,5168],{"__ignoreMap":196},[13,5172,5173],{},"ターミナルの表記がとなればxserverへ入れて、その中を操作していることを示しており、ログイン成功です。以上がxserverへssh接続する方法です。",[26,5175,5177],{"id":5176},"sshは何がいいの","SSHは何がいいの？",[13,5179,5180],{},"以上がxserverでSSHを行う手順です。",[13,5182,5183],{},"基本的にレンタルサーバーでwordpressを使ってブログを書くぐらいならFTP程度で十分であり、SSHを使うこともないと思います。しかし膨大な量のデータを移行したり、phpmyadmin（データベースの操作ができる）で出力・挿入不可なほどのデータベース移行をする際にはコマンドで打てる環境があるとやりやすいです。",[13,5185,5186],{},"また鍵交換方式は鍵ファイルさえ流出しなければ不正にサーバーに侵入されるリスクがパスワード方式よりも低いです。",{"title":196,"searchDepth":557,"depth":557,"links":5188},[5189,5190,5191,5192,5193],{"id":5049,"depth":560,"text":5050},{"id":5069,"depth":560,"text":5069},{"id":5081,"depth":560,"text":5082},{"id":5161,"depth":560,"text":5161},{"id":5176,"depth":560,"text":5177},[3750],"2021-01-11",{},"\u002Farticles\u002Fssh-on-xserver",{"title":5038,"description":5038},"articles\u002Fssh-on-xserver",[608,607],"rRtfurJyt2-gDA2kIQLYcHALvE4zCwVc87qoUW28CXY",{"id":5203,"title":5204,"body":5205,"category":5760,"createdAt":5761,"description":5204,"extension":599,"index":600,"meta":5762,"navigation":602,"path":5763,"publish":602,"seo":5764,"series":600,"seriesTitle":600,"stem":5765,"tag":5766,"thumbnail":600,"updatedAt":600,"__hash__":5767},"articles\u002Farticles\u002Fstuck-on-docker-centos8.md","Docker でcentos8+Apache2.4 の環境を作ろうとして詰まった",{"type":10,"value":5206,"toc":5756},[5207,5210,5218,5221,5224,5232,5236,5239,5342,5345,5370,5373,5399,5406,5514,5521,5525,5532,5539,5542,5700,5703,5734,5744,5753],[13,5208,5209],{},"この記事はosからイメージを指定して作ろうとして、FROM centos から構築して",[13,5211,5212,5215],{},[194,5213,5214],{},"Failed to connect to bus: No such file or directory docker",[194,5216,5217],{},"System has not been booted with systemd as init system (PID 1). Can't operate. Failed to connect to bus: Host is down",[13,5219,5220],{},"というエラーで詰まってブチ切れそうになっている人は以下の方法を確認してみてください。原因は「公式に解決法がありました」から述べていきます。",[13,5222,5223],{},"この記事で使用したOSとdockerのバージョン",[39,5225,5226,5229],{},[42,5227,5228],{},"docker：19.03.13",[42,5230,5231],{},"maxOS Catalina 10.15.5",[26,5233,5235],{"id":5234},"dockerfileからcentos8apache24の環境作ろうとした","Dockerfileからcentos8+apache2.4の環境作ろうとした",[13,5237,5238],{},"apacheのイメージを入れるとosがUbuntuだったりで、できたらosから指定したいなーと思ってcenots8の環境にapacheを入れて行こうと思い以下のようにDockerfileを記述",[187,5240,5245],{"className":5241,"code":5242,"filename":5243,"language":5244,"meta":196,"style":196},"language-dockerfile shiki shiki-themes material-theme-ocean","FROM centos:8\n\nRUN \u002Fbin\u002Fcp \u002Fusr\u002Fshare\u002Fzoneinfo\u002FAsia\u002FTokyo \u002Fetc\u002Flocaltime\n\nRUN yum install -y epel-release && yum clean all\n\nRUN rpm -ivh http:\u002F\u002Fftp.riken.jp\u002FLinux\u002Fremi\u002Fenterprise\u002Fremi-release-8.rpm\n\nRUN yum -y update && yum clean all\n\nRUN yum -y install httpd && yum clean all\n\nRUN yum -y install php74-php php74-php-mysqli php74-php-gd php74-php-mbstring php74-php-opcache php74-php-xml php74-php-pear php74-php-devel php74-php-pecl-imagick php74-php-pecl-imagick-devel php74-php-pecl-zip\n\nRUN ln \u002Fusr\u002Fbin\u002Fphp74 \u002Fusr\u002Fbin\u002Fphp\n\nRUN chown -R apache:apache \u002Fvar\u002Fwww\u002Fhtml\n\nRUN systemctl enable php74-php-fpm\n\nRUN systemctl enable httpd \n","Dockerfile","dockerfile",[194,5246,5247,5252,5256,5261,5265,5270,5274,5279,5283,5288,5292,5297,5301,5306,5310,5315,5319,5324,5328,5333,5337],{"__ignoreMap":196},[675,5248,5249],{"class":677,"line":678},[675,5250,5251],{},"FROM centos:8\n",[675,5253,5254],{"class":677,"line":560},[675,5255,695],{"emptyLinePlaceholder":602},[675,5257,5258],{"class":677,"line":557},[675,5259,5260],{},"RUN \u002Fbin\u002Fcp \u002Fusr\u002Fshare\u002Fzoneinfo\u002FAsia\u002FTokyo \u002Fetc\u002Flocaltime\n",[675,5262,5263],{"class":677,"line":570},[675,5264,695],{"emptyLinePlaceholder":602},[675,5266,5267],{"class":677,"line":719},[675,5268,5269],{},"RUN yum install -y epel-release && yum clean all\n",[675,5271,5272],{"class":677,"line":728},[675,5273,695],{"emptyLinePlaceholder":602},[675,5275,5276],{"class":677,"line":736},[675,5277,5278],{},"RUN rpm -ivh http:\u002F\u002Fftp.riken.jp\u002FLinux\u002Fremi\u002Fenterprise\u002Fremi-release-8.rpm\n",[675,5280,5281],{"class":677,"line":741},[675,5282,695],{"emptyLinePlaceholder":602},[675,5284,5285],{"class":677,"line":752},[675,5286,5287],{},"RUN yum -y update && yum clean all\n",[675,5289,5290],{"class":677,"line":759},[675,5291,695],{"emptyLinePlaceholder":602},[675,5293,5294],{"class":677,"line":767},[675,5295,5296],{},"RUN yum -y install httpd && yum clean all\n",[675,5298,5299],{"class":677,"line":4},[675,5300,695],{"emptyLinePlaceholder":602},[675,5302,5303],{"class":677,"line":788},[675,5304,5305],{},"RUN yum -y install php74-php php74-php-mysqli php74-php-gd php74-php-mbstring php74-php-opcache php74-php-xml php74-php-pear php74-php-devel php74-php-pecl-imagick php74-php-pecl-imagick-devel php74-php-pecl-zip\n",[675,5307,5308],{"class":677,"line":799},[675,5309,695],{"emptyLinePlaceholder":602},[675,5311,5312],{"class":677,"line":811},[675,5313,5314],{},"RUN ln \u002Fusr\u002Fbin\u002Fphp74 \u002Fusr\u002Fbin\u002Fphp\n",[675,5316,5317],{"class":677,"line":818},[675,5318,695],{"emptyLinePlaceholder":602},[675,5320,5321],{"class":677,"line":835},[675,5322,5323],{},"RUN chown -R apache:apache \u002Fvar\u002Fwww\u002Fhtml\n",[675,5325,5326],{"class":677,"line":850},[675,5327,695],{"emptyLinePlaceholder":602},[675,5329,5330],{"class":677,"line":864},[675,5331,5332],{},"RUN systemctl enable php74-php-fpm\n",[675,5334,5335],{"class":677,"line":876},[675,5336,695],{"emptyLinePlaceholder":602},[675,5338,5339],{"class":677,"line":882},[675,5340,5341],{},"RUN systemctl enable httpd\n",[13,5343,5344],{},"php入っていますがとりあえず上のような感じで必要なものを入れて、apacheを常にONにすれば行けるだろ思い、ビルドする",[187,5346,5348],{"className":2988,"code":5347,"language":2990,"meta":196,"style":196},"$ docker build -t centos_apche:1.0 .\n",[194,5349,5350],{"__ignoreMap":196},[675,5351,5352,5355,5358,5361,5364,5367],{"class":677,"line":678},[675,5353,5354],{"class":2506},"$",[675,5356,5357],{"class":689}," docker",[675,5359,5360],{"class":689}," build",[675,5362,5363],{"class":689}," -t",[675,5365,5366],{"class":689}," centos_apche:1.0",[675,5368,5369],{"class":689}," .\n",[13,5371,5372],{},"ビルドは普通に成功しました。イメージが作られたのを確認していざコンテナを起動。",[187,5374,5376],{"className":2988,"code":5375,"language":2990,"meta":196,"style":196},"docker run -t -d -p 9000:80 centos_apche:1.0\n",[194,5377,5378],{"__ignoreMap":196},[675,5379,5380,5383,5385,5387,5390,5393,5396],{"class":677,"line":678},[675,5381,5382],{"class":2506},"docker",[675,5384,1344],{"class":689},[675,5386,5363],{"class":689},[675,5388,5389],{"class":689}," -d",[675,5391,5392],{"class":689}," -p",[675,5394,5395],{"class":689}," 9000:80",[675,5397,5398],{"class":689}," centos_apche:1.0\n",[13,5400,5401,5402,5405],{},"しかし localhost:9000 にアクセスすると「データが送信されませんでした」と真っ黒（chrome）。",[194,5403,5404],{},"docker ps"," で稼働状態を調べてもコンテナはきちんと動いている。つまりコンテナの中で何か起きている。",[187,5407,5409],{"className":2988,"code":5408,"language":2990,"meta":196,"style":196},"docker exec -it {container_id or name} \u002Fbin\u002Fbash\n...\n[root@32212888398b \u002F]# \n[root@32212888398b \u002F]# systemctl httpd status \nSystem has not been booted with systemd as init system (PID 1). Can't operate. \nFailed to connect to bus: Host is down\n",[194,5410,5411,5433,5438,5452,5463,5509],{"__ignoreMap":196},[675,5412,5413,5415,5418,5421,5424,5427,5430],{"class":677,"line":678},[675,5414,5382],{"class":2506},[675,5416,5417],{"class":689}," exec",[675,5419,5420],{"class":689}," -it",[675,5422,5423],{"class":689}," {container_id",[675,5425,5426],{"class":689}," or",[675,5428,5429],{"class":689}," name}",[675,5431,5432],{"class":689}," \u002Fbin\u002Fbash\n",[675,5434,5435],{"class":677,"line":560},[675,5436,5437],{"class":3607},"...\n",[675,5439,5440,5443,5446,5449],{"class":677,"line":557},[675,5441,5442],{"class":685},"[",[675,5444,5445],{"class":755},"root@32212888398b \u002F",[675,5447,5448],{"class":685},"]",[675,5450,5451],{"class":755},"# \n",[675,5453,5454,5456,5458,5460],{"class":677,"line":570},[675,5455,5442],{"class":685},[675,5457,5445],{"class":755},[675,5459,5448],{"class":685},[675,5461,5462],{"class":755},"# systemctl httpd status \n",[675,5464,5465,5468,5471,5474,5477,5480,5483,5486,5489,5492,5495,5498,5501,5504,5506],{"class":677,"line":719},[675,5466,5467],{"class":2506},"System",[675,5469,5470],{"class":689}," has",[675,5472,5473],{"class":689}," not",[675,5475,5476],{"class":689}," been",[675,5478,5479],{"class":689}," booted",[675,5481,5482],{"class":689}," with",[675,5484,5485],{"class":689}," systemd",[675,5487,5488],{"class":689}," as",[675,5490,5491],{"class":689}," init",[675,5493,5494],{"class":689}," system",[675,5496,5497],{"class":755}," (PID ",[675,5499,5500],{"class":3840},"1",[675,5502,5503],{"class":755},"). Can",[675,5505,3633],{"class":685},[675,5507,5508],{"class":689},"t operate. \n",[675,5510,5511],{"class":677,"line":728},[675,5512,5513],{"class":689},"Failed to connect to bus: Host is down\n",[13,5515,5516,5517,5520],{},"「は？」とりあえずhttpdが動いていないそうな上に「Host is down」とos自体がダメと言うことか？",[194,5518,5519],{},"systemctl","だけ打ってもエラーしか出ない。",[26,5522,5524],{"id":5523},"公式に解決法がありました","公式に解決法がありました。",[13,5526,5527,5528,5531],{},"いろいろ調べましたが ",[194,5529,5530],{},"systemd"," を起動する方法がcentos7、centos:latest（つまり８）ではデフォルトでアクティブにならず一工夫必要だそうです。",[13,5533,5534],{},[631,5535,5538],{"href":5536,"rel":5537},"https:\u002F\u002Fhub.docker.com\u002F_\u002Fcentos",[650],"公式ドキュメント",[13,5540,5541],{},"私も詳しい仕組みまではわからないのですが、まずDockerfileを以下のように追記します。",[187,5543,5545],{"className":5241,"code":5544,"filename":5243,"language":5244,"meta":196,"style":196},"FROM centos:8\n#ここから\nENV container docker\nRUN (cd \u002Flib\u002Fsystemd\u002Fsystem\u002Fsysinit.target.wants\u002F; for i in *; do [ $i == \\\nsystemd-tmpfiles-setup.service ] || rm -f $i; done); \\\nrm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fmulti-user.target.wants\u002F*;\\\nrm -f \u002Fetc\u002Fsystemd\u002Fsystem\u002F*.wants\u002F*;\\\nrm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Flocal-fs.target.wants\u002F*; \\\nrm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fsockets.target.wants\u002F*udev*; \\\nrm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fsockets.target.wants\u002F*initctl*; \\\nrm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fbasic.target.wants\u002F*;\\\nrm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fanaconda.target.wants\u002F*;\nVOLUME [ \"\u002Fsys\u002Ffs\u002Fcgroup\" ]\nCMD [\"\u002Fusr\u002Fsbin\u002Finit\"]\n#ここまで\nRUN \u002Fbin\u002Fcp \u002Fusr\u002Fshare\u002Fzoneinfo\u002FAsia\u002FTokyo \u002Fetc\u002Flocaltime\n\nRUN yum install -y epel-release && yum clean all\n\nRUN rpm -ivh http:\u002F\u002Fftp.riken.jp\u002FLinux\u002Fremi\u002Fenterprise\u002Fremi-release-8.rpm\n\nRUN yum -y update && yum clean all\n\nRUN yum -y install httpd && yum clean all\n\nRUN yum -y install php74-php php74-php-mysqli php74-php-gd php74-php-mbstring php74-php-opcache php74-php-xml php74-php-pear php74-php-devel php74-php-pecl-imagick php74-php-pecl-imagick-devel php74-php-pecl-zip\n\nRUN ln \u002Fusr\u002Fbin\u002Fphp74 \u002Fusr\u002Fbin\u002Fphp\n\nRUN chown -R apache:apache \u002Fvar\u002Fwww\u002Fhtml\n\nRUN systemctl enable php74-php-fpm\n\nRUN systemctl enable httpd \n",[194,5546,5547,5551,5556,5561,5566,5571,5576,5581,5586,5591,5596,5601,5606,5611,5616,5621,5625,5629,5633,5637,5641,5645,5649,5653,5657,5661,5665,5669,5673,5677,5681,5685,5690,5695],{"__ignoreMap":196},[675,5548,5549],{"class":677,"line":678},[675,5550,5251],{},[675,5552,5553],{"class":677,"line":560},[675,5554,5555],{},"#ここから\n",[675,5557,5558],{"class":677,"line":557},[675,5559,5560],{},"ENV container docker\n",[675,5562,5563],{"class":677,"line":570},[675,5564,5565],{},"RUN (cd \u002Flib\u002Fsystemd\u002Fsystem\u002Fsysinit.target.wants\u002F; for i in *; do [ $i == \\\n",[675,5567,5568],{"class":677,"line":719},[675,5569,5570],{},"systemd-tmpfiles-setup.service ] || rm -f $i; done); \\\n",[675,5572,5573],{"class":677,"line":728},[675,5574,5575],{},"rm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fmulti-user.target.wants\u002F*;\\\n",[675,5577,5578],{"class":677,"line":736},[675,5579,5580],{},"rm -f \u002Fetc\u002Fsystemd\u002Fsystem\u002F*.wants\u002F*;\\\n",[675,5582,5583],{"class":677,"line":741},[675,5584,5585],{},"rm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Flocal-fs.target.wants\u002F*; \\\n",[675,5587,5588],{"class":677,"line":752},[675,5589,5590],{},"rm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fsockets.target.wants\u002F*udev*; \\\n",[675,5592,5593],{"class":677,"line":759},[675,5594,5595],{},"rm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fsockets.target.wants\u002F*initctl*; \\\n",[675,5597,5598],{"class":677,"line":767},[675,5599,5600],{},"rm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fbasic.target.wants\u002F*;\\\n",[675,5602,5603],{"class":677,"line":4},[675,5604,5605],{},"rm -f \u002Flib\u002Fsystemd\u002Fsystem\u002Fanaconda.target.wants\u002F*;\n",[675,5607,5608],{"class":677,"line":788},[675,5609,5610],{},"VOLUME [ \"\u002Fsys\u002Ffs\u002Fcgroup\" ]\n",[675,5612,5613],{"class":677,"line":799},[675,5614,5615],{},"CMD [\"\u002Fusr\u002Fsbin\u002Finit\"]\n",[675,5617,5618],{"class":677,"line":811},[675,5619,5620],{},"#ここまで\n",[675,5622,5623],{"class":677,"line":818},[675,5624,5260],{},[675,5626,5627],{"class":677,"line":835},[675,5628,695],{"emptyLinePlaceholder":602},[675,5630,5631],{"class":677,"line":850},[675,5632,5269],{},[675,5634,5635],{"class":677,"line":864},[675,5636,695],{"emptyLinePlaceholder":602},[675,5638,5639],{"class":677,"line":876},[675,5640,5278],{},[675,5642,5643],{"class":677,"line":882},[675,5644,695],{"emptyLinePlaceholder":602},[675,5646,5647],{"class":677,"line":888},[675,5648,5287],{},[675,5650,5651],{"class":677,"line":894},[675,5652,695],{"emptyLinePlaceholder":602},[675,5654,5655],{"class":677,"line":900},[675,5656,5296],{},[675,5658,5659],{"class":677,"line":906},[675,5660,695],{"emptyLinePlaceholder":602},[675,5662,5663],{"class":677,"line":912},[675,5664,5305],{},[675,5666,5667],{"class":677,"line":920},[675,5668,695],{"emptyLinePlaceholder":602},[675,5670,5671],{"class":677,"line":1326},[675,5672,5314],{},[675,5674,5675],{"class":677,"line":1339},[675,5676,695],{"emptyLinePlaceholder":602},[675,5678,5679],{"class":677,"line":1352},[675,5680,5323],{},[675,5682,5683],{"class":677,"line":1364},[675,5684,695],{"emptyLinePlaceholder":602},[675,5686,5688],{"class":677,"line":5687},32,[675,5689,5332],{},[675,5691,5693],{"class":677,"line":5692},33,[675,5694,695],{"emptyLinePlaceholder":602},[675,5696,5698],{"class":677,"line":5697},34,[675,5699,5341],{},[13,5701,5702],{},"そしてビルドは普通に行い、コンテナを立ち上げる際はボリュームともう一つオプションを指定します。",[187,5704,5706],{"className":2988,"code":5705,"language":2990,"meta":196,"style":196},"docker run -v \u002Fsys\u002Ffs\u002Fcgroup:\u002Fsys\u002Ffs\u002Fcgroup:ro --privileged -t -d -p 9000:80 centos_apched:1.0\n",[194,5707,5708],{"__ignoreMap":196},[675,5709,5710,5712,5714,5717,5720,5723,5725,5727,5729,5731],{"class":677,"line":678},[675,5711,5382],{"class":2506},[675,5713,1344],{"class":689},[675,5715,5716],{"class":689}," -v",[675,5718,5719],{"class":689}," \u002Fsys\u002Ffs\u002Fcgroup:\u002Fsys\u002Ffs\u002Fcgroup:ro",[675,5721,5722],{"class":689}," --privileged",[675,5724,5363],{"class":689},[675,5726,5389],{"class":689},[675,5728,5392],{"class":689},[675,5730,5395],{"class":689},[675,5732,5733],{"class":689}," centos_apched:1.0\n",[13,5735,5736,5739,5740,5743],{},[194,5737,5738],{},"-v \u002Fsys\u002Ffs\u002Fcgroup:\u002Fsys\u002Ffs\u002Fcgroup:ro","でファイルシステムをホストマシンからボリュームし、",[194,5741,5742],{},"--privileged","でコンテナにホストマシンのroot権限を与ます。どちらか片方が抜けてもいけません。",[13,5745,5746,5747,5749,5750,5752],{},"このオプションとボリュームを指定すると",[194,5748,5530],{},"が動きます。実際にコンテナに入っていくと",[194,5751,5519],{},"コマンドが実行されました。",[2290,5754,5755],{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s5Dmg, html code.shiki .s5Dmg{--shiki-default:#FFCB6B}html pre.shiki code .sfyAc, html code.shiki .sfyAc{--shiki-default:#C3E88D}html pre.shiki code .sdLwU, html code.shiki .sdLwU{--shiki-default:#82AAFF}html pre.shiki code .sAklC, html code.shiki .sAklC{--shiki-default:#89DDFF}html pre.shiki code .s0W1g, html code.shiki .s0W1g{--shiki-default:#BABED8}html pre.shiki code .sx098, html code.shiki .sx098{--shiki-default:#F78C6C}",{"title":196,"searchDepth":557,"depth":557,"links":5757},[5758,5759],{"id":5234,"depth":560,"text":5235},{"id":5523,"depth":560,"text":5524},[597],"2020-11-27",{},"\u002Farticles\u002Fstuck-on-docker-centos8",{"title":5204,"description":5204},"articles\u002Fstuck-on-docker-centos8",[607,5382],"yvD5JRk2N7X9ToHbPIm-hQQm0dyCSLPsVEnjEF9H-RE",1780987136846]