12月 22, 2020 Nginx SSL
> Source: https://www.vultr.com/docs/setup-letsencrypt-on-linux

### Introduction

Let’s Encrypt is an automated, open certificate authority that offers free TLS/SSL certificates for the public’s benefit. The service is provided by the Internet Security Research Group (ISRG). This tutorial shows how to install a Let's Encrypt SSL certificate on One-Click LAMP & LEMP apps using the certbot installation wizard. After completing this tutorial, the server will have a valid certificate and redirect all HTTP requests to HTTPS.

### Prerequisites

This tutorial assumes that you have deployed a Vultr One-Click LAMP (Apache) or One-Click LEMP (Nginx) VPS, have a domain name pointing to your server IP address, and you are logged in as root.

### 1. Install certbot

Install certbot with `apt`.

- One-Click LAMP (Apache)

```sh
# apt update && apt install certbot python-certbot-apache -y
```

- One-Click LEMP (Nginx)

```sh
# apt update && apt install certbot python-certbot-nginx -y
```

### 2. Install Certificate

Run `certbot` to install the certificate. Full examples are below, here are descriptions of the command line options:

- --apache
- - Use the Apache web server
- --nginx
- - Use the nginx web server
- --redirect
- - Redirect all HTTP requests to HTTPS.
- -d example.com -d www.example.com
- - Install a multiple domain (SAN) certificate. You may use up to 100 -d domain entries.
- -m admin@example.com
- - The notification email address for this certificate.
- --agree-tos
- - Agree to the terms of service.

Use `certbot --help` for more information.

### Example: One-Click LAMP (Apache)

Run certbot for Apache.

```sh
# certbot --apache --redirect -d example.com -d www.example.com -m admin@example.com --agree-tos
```

### Example: One-Click LEMP (Nginx)

1. Before running certbot, make sure server_name is set properly. Edit your Nginx configuration:

```sh
# nano /etc/nginx/conf.d/default.conf
```

2. Update server_name to include your domain name.

```sh
server {
    server_name  example.com www.example.com;
```

3. Save and exit the file.

4. Run certbot for Nginx.

```sh
# certbot --nginx --redirect -d example.com -d www.example.com -m admin@example.com --agree-tos
```

### 3. Verify Automatic Renewal

Let's Encrypt certificates are valid for 90 days. The certbot wizard updates the systemd timers and crontab to automatically renew your certificate.

1. Verify the timer is active.

```sh
# systemctl list-timers | grep 'certbot\|ACTIVATES'
```

2. Verify the crontab entry exists.

```sh
# ls -l /etc/cron.d/certbot
```

3. Verify the renewal process works with a dry run.

```sh
# certbot renew --dry-run
```

### Summary

Installing a free Let's Encrypt certificate is simple with certbot. For more information, see the official certbot installation documentation.
11月 12, 2020 Ubuntu
> Source: https://www.vultr.com/docs/update-ubuntu-server-best-practices

### Introduction

It is a best practice to update your server on a regular schedule for security and stability. Use this guide to keep your Ubuntu server updated.

Supported Versions
This guide applies to:

- Ubuntu 20.04 LTS
- Ubuntu 19.10
- Ubuntu 18.04 LTS
- Ubuntu 16.04 LTS

### Make a Backup

Always make a backup before updating your system.

### 1. Update the Package Lists

This command updates the package lists from the enabled repositories.

```sh
$ sudo apt update
```

### 2. List the Upgradable Packages

This step is optional. To view the upgradable packages before performing the upgrade, use the apt list command.

```sh
$ sudo apt list --upgradable
```

### 3. Upgrade Packages

This command will upgrade all the upgradeable packages.

```sh
$ sudo apt upgrade
```

### 4. Restart the Server

```sh
$ sudo reboot
```

### One Line Upgrade

If you want to accept all the defaults and perform the upgrade without intervention, use this command:

```sh
$ sudo apt update && sudo apt upgrade -y
```

### Optional - Autoremove

Use apt to remove old packages and dependencies automatically.

```sh
$ sudo apt autoremove
```
11月 11, 2020 Ubuntu
> Source: https://www.vultr.com/docs/create-a-sudo-user-on-ubuntu-best-practices

### Introduction

Performing server administration as a non-root user is a best practice for security. After launching your Vultr VPS, your first task as root should be to set up a non-root user with sudo access.

This guide applies to the following versions:

- Ubuntu 20.04 LTS
- Ubuntu 19.10
- Ubuntu 18.04 LTS
- Ubuntu 16.04 LTS

### 1. Add a New User Account

Create a new user account with the `adduser` command. Use a strong password for the new user. You can enter values for the user information, or press `ENTER` to leave those fields blank.

```sh
# adduser example_user
```

### 2. Add the User to the Sudo Group

Add the new user to the sudo group with usermod.

```sh
# usermod -aG sudo example_user
```

### 3. Test

Switch to the new user.

```sh
# su - example_user
```

Verify you are the new user with whoami, then test sudo access with sudo whoami, which should return root.

```sh
$ whoami
example_user
$ sudo whoami
[sudo] password for example_user:
root
```
10月 21, 2020 React
### Bundle

在使用 React 時是一定會使用到 Webpack 等等工具來把 JSX、CSS、IMAGES... 等等進行打包。如果你的 APP 已經建立得非常大時,產生的 Bundle 檔案也會非常巨大。使用者在下載時就會花上很多時間了喔 !

### 解決方法

我們可以通過使用 React 內建的 Lazy loading 來解決一次過下載巨大 Bundle 檔案的問題。它的原理是把單一的 Bundle 檔案依不同的 package 來分割開,然後在使用者實際使用時才動態載入。

### 內裏是 Promise

我們有以下的 module ,作用把兩個傳入的數字相加。

```js
// math.js
export default sum(a, b) => a + b;
```

在傳統的使用方法,我們是以下這樣 :

```js
import sum from './math.js';

console.log(sum(1, 2)); // 3
```

使用 Lazy Loading 的話,載入的 object 就會變成了 Promise 物件:

```js
import('./math.js')
	.then(sum => console.log(sum(1, 2))); // 3
```

### 實際使用

在實際使用上,我們可以通過使用 `React.lazy` 方法來簡單化整個載入的流程。

```js
// 載入 SomeComponent
const SomeComponent = React.lazy(() => import('./SomeComponent.jsx'));
```

然可以作為一般的 Component 來使用,但是需要放在 React.Suspense 元件內。

```js
<React.Suspense fallback={<div>Loading...</div>}>
	<SomeComponent />
</React.Suspense>
```

React.Suspense 是處理其子 Component 如果有 Lazy Loading 動作時,就會劃出 fallback 的元件出來,等待 Lazy Load 完成後,就會顯示元件。

### 筆者推介使用方法

因為在 React 內得多元件都可以重用,但是如果有使用 React Router 的話,不同 URL 之間的元件是一定不會重用的,所以我們可以簡單把 React.Suspense 包住整個 Router。然後把不同 Route 內的 Component 都轉成使用 Lazy Load,這樣就已經可以簡單快速地分割出合適的 Bundle 檔案了。

### 官方文件

官方文件 : https://zh-hant.reactjs.org/docs/code-splitting.html
10月 21, 2020 React
### Image slider / Carousels

在網站上很多時都會使用流水式的 Banner 來告訴使用者最近的事情。

![](https://cdn.19site.net/files/c7/fe/c7fe495b-dd20-41f2-85f0-9e57e10d96e2.png 'Image Slider 都概像這樣子')

### 選擇現成的 Library

初時筆者找到了 `react-alice-carousel` 這個套件,好像很簡單易用,所以後快速的試了一下。不過發現有個問題到現時最新的 Version 都好像還沒有修正好,就是在圖片滑動的中途,如果整個 Component 出現 unmount 的情況,就會出現 Error : Updated on unmounted component。

雖然在它們的 github 上好像沒有人 report 過這樣的 issue。不過筆者確實是遇到了,所以還是選擇另家的好了。

### nuka-carousel

這是另一家大神寫出來的 Image slider,使用上也是非常之簡單。  
Github: https://github.com/FormidableLabs/nuka-carousel

下面會簡單記錄一下使用的方法。

### 安裝

可以使用 npm 來安裝。

```sh
$ npm install nuka-carousel
```

### 使用

使用上也是十分之簡單,只要用 Carousel 包住想要用來 Slide 的內容就可以了,高度是自動的,內容可以用 Array 填入就可以。配上 Div 使用 background 來使用就非常得心應手。

```js
import React from 'react';
import Carousel from 'nuka-carousel';

export default class extends React.Component {
	render() {
		return (		
			<Carousel>
				<img src="https://via.placeholder.com/400/ffffff/c0392b/&text=slide1" />
				<img src="https://via.placeholder.com/400/ffffff/c0392b/&text=slide2" />
				<img src="https://via.placeholder.com/400/ffffff/c0392b/&text=slide3" />
				<img src="https://via.placeholder.com/400/ffffff/c0392b/&text=slide4" />
				<img src="https://via.placeholder.com/400/ffffff/c0392b/&text=slide5" />
				<img src="https://via.placeholder.com/400/ffffff/c0392b/&text=slide6" />
			</Carousel>
		);
	}
}
```

送上 div 顯示圖片的咒語:

```js
<div
	style={{
		background: '#FFFFFF url(https://via.placeholder.com/400/ffffff/c0392b/&text=slide1) center center / cover no-repeat',
		height: '0px',
		paddingBottom: '30%'
	}}
/>
```

以下是筆者使用的 Config:

```js
<Carousel 
	autoplay={ true }
	autoplayInterval={ 4000 }
	withoutControls={ false }
	wrapAround={ true }
	speed={ 1000 }
	renderCenterLeftControls={ () => {} }
	renderCenterRightControls={ () => {} }
>
	{items}
</Carousel>
```
### 設定 Nginx

要在 nginx 上取得 proxy 的 client address,需要事先在設定 nginx 時就要加入下
`--with-http_realip_module` 的設定。如果安裝的 nginx 是由 apt 上下載的,就可以使用以下指令來查看你的 nginx 有沒有設定 `--with-http_realip_module` 模組。

```sh
$ nginx -V

nginx version: nginx/1.18.0 (Ubuntu)
built with OpenSSL 1.1.1f  31 Mar 2020
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-5J5hor/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module
```

如果在輸出的結看看到了模組的名稱,就代表已經設定好了。

### 設定來自 Cloudflare 的 IP address

然後需要把來自 Cloudflare 的 IP address 設定到 nginx.conf 檔案內。

參考 Cloudflare 的網站 : https://support.cloudflare.com/hc/en-us/articles/200170786-Restoring-original-visitor-IPs-Logging-visitor-IP-addresses-with-mod-cloudflare-

```txt
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/12;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2c0f:f248::/32;
set_real_ip_from 2a06:98c0::/29;
```

再設定 Cloudflare 的 IP 寫入 header 欄位名稱。

```txt
real_ip_header CF-Connecting-IP;
#real_ip_header X-Forwarded-For;
```

設定好後,在 Nginx 的 Virtual Host Config 檔案內使用變數 $remote_addr 時,就可以取得 Cloudflare 傳入的真正地址了。

下面是 Virtual Host Config 檔案使用 Reverse proxy 的例子 :

```txt
location / {
	proxy_set_header X-Forwarded-For $remote_addr;
	proxy_set_header Host $http_host;
	proxy_pass https://localhost:81;
}
```
10月 05, 2020 Javascript
由於不同之間的 browser 都有差異,所以如果要保險起見,需要以多種的語法來最最得 scroll top 值來確保安全。而已經有大神寫好了這個簡單的語法 !

```js
window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
```
過去文章
2025 (9)
4 (5)
3 (1)
2 (3)
2024 (25)
11 (3)
10 (3)
9 (1)
3 (18)
2022 (6)
10 (1)
6 (2)
5 (1)
3 (1)
1 (1)
2021 (21)
11 (7)
7 (1)
6 (2)
5 (2)
4 (6)
3 (2)
2 (1)
2020 (92)
12 (1)
11 (2)
10 (4)
9 (10)
8 (5)
7 (1)
6 (3)
5 (1)
4 (4)
3 (25)
2 (7)
1 (29)
2019 (57)
12 (25)
11 (7)
9 (25)