---
# System prepended metadata

title: 使用 AWS 雲端主機部署網站的流程 + 除錯紀錄

---

# 使用 AWS 雲端主機部署網站的流程 + 除錯紀錄

[好讀版](https://hackmd.io/@ouR5x-oVSMy4d8R5uFsKNg/BycsvIXnd)

> 流程主要是參考 [AWS、LAMP](https://mtr04-note.coderbridge.io/2020/09/15/-%E7%B4%80%E9%8C%84-%08-%E9%83%A8%E5%B1%AC-aws-ec2-%E9%9B%B2%E7%AB%AF%E4%B8%BB%E6%A9%9F-/) 和 [設定子網](https://nicolakacha.coderbridge.io/2020/09/16/launch-website/) 的流程，不過我還是遇到一些問題，所以也一併記錄除錯過程在最後面

前情提要：
* 從 W6 開始，作業寫了餐廳網站、Twitch API 串接網站等，它們屬於靜態網站，不需要透過 Server 做額外處理，可以在 github 直接部署，相關設定與 url 如下：
  ![](https://i.imgur.com/AIl7UXF.png)
* W9 開始，需要自己建 DB 和 Server，使用的是 Xampp 這個程式來做管理（類似 LAMP，同時把 db、server、ftp 相關程式設定好的大補包），這裡所寫的作業(Blog, message-board, todo) 屬於動態網站，需要經過 Server 處理再 response 給 client，因此需要一個可以運行這些事情的主機，這時候我們是使用 Huli 提供的站台來上傳（運行）作業。
* 接著是 W14，開始要生出一個自己的站台來部署之前寫過的各種網站啦~

## 取得主機

主機主要可以分成實體主機和虛擬主機，例如圖片中的 VPS / Dedicated Host，實體主機一台就是給一個使用者用，虛擬主機則是把主機空間切割成獨立區塊，每個區塊分別給不同使用者使用（有點類似公共澡堂和自家浴室的感覺）。
![](https://i.imgur.com/R8Hj3jG.png)

這次選擇使用 AWS 的虛擬主機，因為它有提供一年免費的服務，但也有說明如果流量超過限制會開始收費，申請步驟如下：

1. 註冊 AWS 會員
1. 進入 「AWS 管理控制台」頁面
1. 這裡可以在右上角選擇主機所在的地區
   ![](https://i.imgur.com/sR7pYys.png)
1. 選擇「啟動虛擬主機」
1. 選擇「Ubuntu Server 18.04 LTS (HVM), SSD Volume Typ」 > 選免費方案（綠色標章） > 接著就是一路 Next 到 Step 6 > Step 6 選擇「Add Rule」，新增「HTTP 跟 HTTPS」* > Step 7 會確認之前的設定，確認無誤之後按 Launch >　跳出選擇已有的私鑰或新建私鑰的視窗，選擇「新建私鑰」並下載保存（用來登入自己的主機）　＞　最後按　「Launch Instances」就建好了，選擇剛剛建立的主機(Instance)並按下 Connect。
2. 按下 Connect 之後，會顯示連線到主機的指令，開啟自己的 CLI 來做連線
```javascript=
chmod 400 <私鑰檔案路徑>
ssh -i "<私鑰檔案路徑>" ubuntu@ec2-< IPv4 位置>.us-east-2.compute.amazonaws.com
```

## 在主機上設定 LAMP

因為這次申請主機的目的是部署網站，所以要建立 php, server...等在主機上面，才可以提供網站給 client 使用，在 CLI 連線到虛擬主機之後，做下面的步驟。

### 裝 Server

1. 更新虛擬主機的 Ubuntu 系統，`sudo apt update && sudo apt upgrade && sudo apt dist-upgrade`
1. 安裝 Tasksel，`sudo apt install tasksel`
1. 用 Tasksel 下載 lamp-server，`sudo tasksel install lamp-server`
2. 輸入 url `http://<Ipv4>/` 測試是否成功安裝 Server
![](https://i.imgur.com/VDrhQSd.png)

> 自我檢討有提到 AWS 的 ip 是會變得，可以自己把 IP 固定，[參考方法](http://jyeh-blog.logdown.com/posts/712216-aws-ec2-service-for-ec2-specifying-a-fixed-ip)，但我這邊沒做固定，因為參考中有提到不使用之後要自己釋放那個 IP (懶)，不然會被收費
 
### 裝 phpmyadmin

1. 下載 phpmyadmin，`sudo apt install phpmyadmin`，下載完之後連接 apache2 並且設定 phpmyadmin 的密碼。
1. 改變 phpmyadmin 登入的設定，改成用密碼登入：
    ```javascript=
    sudo mysql -u root mysql
    ```
    ```javascript=
    UPDATE user SET plugin='mysql_native_password' WHERE User='root';
    FLUSH PRIVILEGES;
    ```
    ```javascript=
    exit
    ```
3. 接著設定密碼：
    ```javascript=
    sudo mysql_secure_installation
    ```
4. 設定完成之後，輸入 url `IPv4/phpmyadmin`測試是否可以成功登入 phpmyadmin

### 測試是否成功部署網站

1. 這個是虛擬主機的檔案目錄圖：
![](https://i.imgur.com/yIJ02IX.png)
1. 要對外提供使用者訪問的網站檔案要放在`/var/html/` 路徑下面，`/var/log` 則是放日誌的地方，如果部署過程發生了 google 也找不到解決方法的時候，試試來這裡看看，我這次遇到的部署問題都是靠它解決的。
![](https://i.imgur.com/CQt5HSI.png)
1. 把之前寫的作業放到`/var/html/` 路徑下面之後，就可以到 url`<Ipv4>/檔案路徑`去查看，例如範例圖片中的 Todo 就可以去 `http://<Ipv4>/Lidemy/Todo/index.html`查看(URL 除了 query string 以外其實不分大小寫，但通常會用小寫)。

### 設定域名

1. 到 gendi.net 註冊並購買網域（選擇 .tw 的網域）以及設定 domain name
2. 進入管理介面 > 域名 > 選擇剛剛設定的 domain name > 區域檔紀錄 > 把類型 A 的 IPv4 改成 AWS 的 IP
3. 完成之後就可以用`<domainName>.tw/`

### 設定子網域

這個算是額外選項，一樣是用 CLI 操作，目的是要讓 `http://<Ipv4>/Lidemy/Todo/index.html`，可以直接用 `http://www.todo.umer.tw/` 的形式來連結。

以下面路徑的 Todo 為例：
![](https://i.imgur.com/CQt5HSI.png)

1. 首先要去複製 `/etc/apache2/sites-available` 路徑下面的`000-default.conf` 並命名`todo.conf`
![](https://i.imgur.com/4jgtg3u.png)
1. 修改裡面的內容，修改成第12-14行的樣子，第22-23是日誌也可以一併修改，可以記錄各種錯誤發生的情況，日誌可以去`/var/log`查看。

```c=
<VirtualHost *:80>
	# The ServerName directive sets the request scheme, hostname and port that
	# the server uses to identify itself. This is used when creating
	# redirection URLs. In the context of virtual hosts, the ServerName
	# specifies what hostname must appear in the request's Host: header to
	# match this virtual host. For the default virtual host (this file) this
	# value is not decisive as it is used as a last resort host regardless.
	# However, you must set it for any further virtual host explicitly.
	#ServerName www.example.com

	ServerAdmin webmaster@localhost
        ServerName Todo.Umer.tw
        ServerAlias www.Todo.Umer.tw
	DocumentRoot /var/www/html/Lidemy/Todo

	# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
	# error, crit, alert, emerg.
	# It is also possible to configure the loglevel for particular
	# modules, e.g.
	#LogLevel info ssl:warn

	ErrorLog ${APACHE_LOG_DIR}/Todo_error.log
	CustomLog ${APACHE_LOG_DIR}/Todo_access.log combined

	# For most configuration files from conf-available/, which are
	# enabled or disabled at a global level, it is possible to
	# include a line for only one particular virtual host. For example the
	# following line enables the CGI configuration for this host only
	# after it has been globally disabled with "a2disconf".
	#Include conf-available/serve-cgi-bin.conf
</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

```
3. 最後存檔，並輸入指令`sudo a2ensite todo.conf` 重啟設定檔，然後再輸入指令`sudo service apache2 restart` 來重啟 Server。
4. 去 gandi 設定 domain name
![](https://i.imgur.com/DmGaf8Z.png)
5. 輸入 url 來測試是否成功設定，`http://www.todo.umer.tw/`

### 設定 File Zilla

這個算是額外選項，單靠 CLI 其實就可以管理虛擬主機了，如果想要用圖形化的方式方便上傳檔案的話，可以考慮安裝它。

[AWS 透過 FileZilla 使用 key-pairs 登入 AWS EC2 存取檔案](http://www.jysblog.com/coding/web/aws-%E9%80%8F%E9%81%8E-filezilla-%E4%BD%BF%E7%94%A8-key-pairs-%E7%99%BB%E5%85%A5-aws-ec2-%E5%AD%98%E5%8F%96%E6%AA%94%E6%A1%88/)


## 設定 SSL 憑證

未申請 SSL 憑證的網站，在 Chrome 裡面會顯示 "Not secure" 的提醒。
![](https://i.imgur.com/rVWUXk5.png)

一般 SSL 憑證都是需要付費申請才有的，這次使用 [Let's Encrypt](https://letsencrypt.org/zh-tw/getting-started/) 這家憑證頒發機構所提供的免付費憑證。進入[安裝教學網頁](https://certbot.eff.org/)，選好雲端主機的 OS 和 Server 種類之後，就可以根據提供的指令進襲安裝。

1. 安裝 snapd (EC2 的 Ubuntu 已經有內建)
1. 更新 snapd: `sudo snap install core; sudo snap refresh core`
1. 安裝 Certbot: `sudo snap install --classic certbot`
1. 確認 Cerbot 有安裝完成: `sudo ln -s /snap/bin/certbot /usr/bin/certbot`
1. 設定要使用 SSL 的網址: `sudo certbot --apache`，紅色框框處
   ![](https://i.imgur.com/XxMcyVo.png)
1. 重啟 Cerbot: `sudo certbot renew --dry-run`
2. 回到剛剛申請憑證的網址，使用 https 查詢可以看到鎖頭出現
    ![](https://i.imgur.com/IqcFjzI.png)


## 除錯紀錄

### 靜態網站可以正常顯示，動態網站也可以正常顯示，但卻連接不到資料庫!?

首先我已經確認`connection.php`的連線指令`$connection = new mysqli('localhost', 'username' , 'password' , 'db_name');` 是正確無誤的。

然後也 google 不到有效的解法，最後去主機的 `/var/log/apache2` 下面查看日誌，發現到這一行
```javascript=
 PHP Warning:  require_once(connection.php): failed to open stream: No such file or directory in /var/<省略>/Todo/api_todo.php on line 2
```
原來是我的檔案名稱 `connection.php` 寫錯。

### 出現 connect ECONNREFUSED <Ipv4>:443

(Postman 顯示的錯誤訊息↓)
![](https://i.imgur.com/L71cU1l.png)

port 443 是 HTTPS 使用，但我當時沒有申請 SSL 憑證(要錢)，連線到主機的時候也不會看到有 SSL 的鎖頭圖示。
![](https://i.imgur.com/VRxrKbN.png)

出現錯誤的原因是 Url 寫錯，不是 `https` 而是 `http`。

### 遠端對 instance 下指令`$ sudo ufw enable`，之後無法用 ssh 登入

原本可以正常用 ssh 登入，但在下完指令`$ sudo ufw enable`之後沒過多久，流程如下

```javascript=
ubuntu@ip-xxx-xxx-xxx-xxx:~$ sudo ufw status
Status: inactive
ubuntu@ip-xxx-xxx-xxx-xxx:~$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
ubuntu@ip-xxx-xxx-xxx-xxx:~$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
3306                       ALLOW       Anywhere
443                        ALLOW       Anywhere
3306 (v6)                  ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

ubuntu@ip-172-xx-xx-xx:~$ client_loop: send disconnect: Connection reset by peer
```

之後使用金鑰登入都會顯示訊息`ssh: connect to host ec2-xx-xxx-xxx-xxx.us-east-2.compute.amazonaws.com port 22: Connection timed out`。

猜測是因為 port22 沒打開，但我也登入不了，所以就去 EC2 console 查看 security group，結果卻顯示有打開。
![](https://i.imgur.com/V3pgIQi.png)

去之前設定好的子網，可以連線成功，但是我 ping 這台 instance 的 ip 卻顯示`Request timed out.`，原因大概是跟 iptables(用 ufw 做設定) 的設定有關，我還不太理解。

總之，現在要想辦法登入進去然後把 ufw 給關掉，不使用金鑰的又想操作 instance 的方法之一是 AWS 提供的連線方式 session manager，可以在瀏覽器上面操作 insance terminal。步驟如下。

> 這邊使用新版的 AWS 介面(20210718)，網路上可以查到不少 session manager 的操作，舊版的操作看起來滿複雜的，跟我的步驟差滿多的

![](https://i.imgur.com/eVt1Qtt.png)

進去之後選擇 Create new IAM role > Create role
* `Choose a use case` 這邊要記得選擇EC2 並且在 `Attach permissions policies` 這邊選擇  AmazonEC2RoleforSSM，其他設定就如同說明。

然後去選擇使用剛剛新增的 IAM role，
> 下方這個介面出來需要一段時間，不會剛設定完 IAM role 之後就可以馬上看到

![](https://i.imgur.com/Hsa7mah.png)

最後就可以連線了，
![](https://i.imgur.com/bC8J7Iu.png)
![](https://i.imgur.com/9PO3yBe.png)


> 所以用任何指令之前最好先搞清楚原理在做操作Q_Q，ufw 其實應該要先把哪些port要開哪些port要關先設定好之後再打開，而不是打開之後再去做相關設定，相關參考設定[1](https://www.digitalocean.com/community/questions/port-22-connection-timed-out)[2](https://noob.tw/ufw/)
