# Nginx
[TOC]
## What is Nginx
- Nginx was originally created as a web server to solve the [C10k problem](https://en.wikipedia.org/wiki/C10k_problem).
> The problem of optimizing network sockets to handle a large number of clients at the same time.
> (C10k: concurrently handling ten thousand connections)
- Much more than just a web server
- As a **reverse proxy**, making for easy integration with slower upstream servers.
- Distribute your traffic properly (**load balancing**), stream media, resize your images on the fly, cache content.
### The basic nginx architecture
#### Master
- The master is supposed to read the configuration file and maintain worker processes.
#### Worker
- Workers do the actual processing of requests.
## Config file
### Path
- Nginx's main config file will be at *`/etc/nginx/nginx.conf`*
- Config files for different domain names will inside *`/etc/nginx/conf.d/`*
> It should be included in main config file like
> ```
> include /etc/nginx/conf.d/*.conf;
> ```
- It's better to seperate virtual hosts from global server
- `conf.d/`: global server
- `sites-available/`: store all the virtual hosts you created
- `sites-enabled/`: running virtual hosts, it's recommanded to contain **symlinks** to files in the `sites-available` folder.
> [Difference between `sites-available/`&`sites-enabled/`&`conf.d`](https://serverfault.com/questions/527630/difference-in-sites-available-vs-sites-enabled-vs-conf-d-directories-nginx)
### Architecture
- **Directive**
- Consists of **name** and **parameters**, end with semicolon.
```
gzip on;
```
- 3 types of directives, each with its own inheritance model
- Normal
- It can be **defined only once** in the context.
- Array
- Adding multiple directives in the same context will **add to the values** instead of overwriting them altogether.
- Defining a directive in a subcontext will **override ALL parent values** in the given subcontext.
- Action
- change things
- **Context**
- section where you can declare directives
```
worker_processes 2; # directive in global context
event { # event context
...
}
http { # http context
gzip on; # directive in http context
server { # server context
listen 80; # directive in server context
location{ # location context
...
}
}
}
```
- **Virtual host/server**
- Inside nginx, you can specify multiple virtual servers, each described by a `server { }` context.
#### `gzip`
- Compression, reduce payload or file size in order to improve transmission efficiency.
```nginx=
gzip on;
```
#### `root`
- Sets the root directory for requests, allowing nginx to map the incoming request onto the file system.
```nginx=
root /var/www/foo.co
```
#### `return`
```nginx=
return 200;
return 404;
```
```nginx=
return 200 "Hello from foo.co";
```
#### `listen`
```nginx=
listen *:80;
listen 127.0.0.1; # by default port :80 is used
listen 81; # by default all ips are used
listen [::]:80; # IPv6 addresses
listen [::1]; # IPv6 addresses
listen localhost:80; # had better not to use hostnames, might cause error
```
- Rules order
1. Server listing on IP:port, with a matching server_name directive
2. Server listing on IP:port, with the default_server flag
3. Server listing on IP:port, first one defined
4. If there are no matches, refuse the connection
#### `server_name`
```nginx=
server_name netguru.co www.netguru.co; # exact match
server_name *.netguru.co; # wildcard matching
server_name netguru.*; # wildcard matching
server_name ~^[0-9]*\.netguru\.co$; # regexp matching
```
- Rules order
1. Exact name
2. Longest wildcard name starting with an asterisk
- e.g. `*.example.org`
3. Longest wildcard name ending with an asterisk
- e.g. `mail.*`
4. First matching regular expression (in the order of appearance in the configuration file)
#### `location`
```nginx=
location [modifier] path
```
- [modifier]
```
= - Exact match
^~ - Preferential match
~ && ~* - Regex match
no modifier - Prefix match
```
> When no `modifier` is specified, the path is treated as prefix, after which anything can follow.
#### `try_files`
- Try different paths, returning whichever is found.
```nginx=
try_files $uri index.html =404;
```
> It will return files in the following order:
> 1. $uri ( /foo.html )
> 2. index.html
> 3. If none is found --> 404
## Implementation
### Installation
- Install
```bash=
sudo apt-get install nginx
```
- Ensure
```bash=
sudo netstat -tlnp | grep nginx
```
```
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 20687/nginx: master
tcp6 0 0 :::80 :::* LISTEN 20687/nginx: master
```
- Basic operations
```bash=
sudo nginx -s *signal*
```
> *signal* can be:
> - `stop`: fast shutdown
> - `quit`: graceful shutdown (wait for workers to finish their processes)
> - `reload`: reload the configuration file
> - `reopen`: reopen the log files
- Test the config file
```bash=
sudo nginx -t
```
### Simple Practice - ref Official[2]
- `/etc/nginx/sites-enabled/practice`
```nginx=
server {
listen 81;
listen [::]:81;
server_name example.ubuntu.com;
root /var/www/practice;
index index.html;
location / {
try_files $uri $uri/ =404;
}
location /test {
try_files $uri/test.html =404;
}
location /redirect {
return 301 /test;
}
}
```
> `$uri` means the path you access now (according to the `location`)
> eg. In line 14, `$uri`=`/var/www/practice/test`
- `/var/www/practice/index.html`
```html=
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Hello, Nginx!</title>
</head>
<body>
<h1>Hello, Nginx!</h1>
<p>We have just configured our Nginx web server on Ubuntu Server!</p>
</body>
</html>
```
- Restart nginx
```bash=
sudo service nginx restart
```
- Check
```
lynx localhost:81
```
> Remember to allow port 81 (ufw) if you want to visit the website from other hosts.
> ```bash=
> sudo ufw allow 81
> ```
### Load Balancer & Reverse Proxy
- 透過路徑上的代理來轉發流量
#### `upstream`
```nginx=
upstream myapp1 {
server srv1.example.com weight=3; # 倍數
server srv2.example.com;
server srv3.example.com;
least_conn; # 選擇最少連線數
}
server {
listen 80;
location / {
proxy_pass http://myapp1;
}
}
```
#### `proxy_pass`
### HTTPS
#### 取得 SSL certificate - `certbot`
> [[HOWTO] Freeswitch deploy verto communicate](https://hackmd.io/@txLtb1_dT1eziDq4utYbqA/Sk9xM4xlY)
- Use [**Let’s Encrypt**](https://letsencrypt.org/zh-tw/getting-started/#)
- Install via [**`certbot`**](https://certbot.eff.org/)
```bash=
sudo apt-get install certbot
certbot certonly --standalone -d DOMAIN_NAME
```
- 自動更新 Let’s Encrypt 憑證
```bash=
sudo certbot --nginx -d test.domain.com
sudo certbot delete --cert-name test.domain.com
sudo certbot renew --dry-run
```
- 寫進 shell 檔透過 Linux 排程設定(crontab)定時更新憑證
```shell=
#!/bin/bash
...
```
:::info
[crontab 防呆測試](https://crontab.guru/)
:::
## Reference
### Official
1. [NGINX Doc](https://nginx.org/en/docs/)
2. [Ubuntu - Install and configure Nginx](https://ubuntu.com/tutorials/install-and-configure-nginx#1-overview)
3. [Full Example Configuration](https://www.nginx.com/resources/wiki/start/topics/examples/full/)
### Article
1. [Nginx Tutorial #1: Basic Concepts](https://www.netguru.com/blog/nginx-tutorial-basics-concepts)
2. [淺談 Nginx 基本配置、負載均衡、緩存和反向代理](https://www.maxlist.xyz/2020/06/18/flask-nginx/)
3. [常用的 Nginx Config 與相關指令教學](https://linyencheng.github.io/2019/07/13/tool-nginx/)
### Video
1. [Learn Nginx Fundamentals | Deploy a Web Application Using Nginx](https://www.youtube.com/watch?v=1ndlRiaYiWQ&ab_channel=edureka%21)
2. [How to Set Up SSL with NGINX](https://www.youtube.com/watch?v=X3Pr5VATOyA&ab_channel=NGINX%2CInc)