Hello World with Nginx + uWSGI + Flask on GCE Ubuntu 18.04

# Goal
- Do a Hello World with a minimal web server.

# Steps
1. Set up a VM in the cloud.
2. Install necessary tools.
3. Create an app.
4. Establish connection with WSGI protocol.
5. Set up an web server.
6. Tada!

## 1. Set up a VM in the cloud
Create a GCE f1-micro instance.

- Required:
    - Somewhere in the U.S. for using free tier.
    - Allow HTTP traffic.
- This time in GUI.
- Using Ubuntu 18.04.


<img width="576" alt="Screen Shot 2018-12-16 at 12.52.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/327335/b22a2a56-7bd8-5a2f-64bf-d4084a84b4e6.png">


## 2. Install necessary tools

- Open terminal.

- Install the `gcloud` CLI.
    - See: [Using the Google Cloud SDK installer ](https://cloud.google.com/sdk/docs/downloads-interactive)

```
$ curl https://sdk.cloud.google.com | bash
$ exec -l $SHELL
$ gcloud init
```


- SSH into the VM.
    - We don't have to remember this command, as it's shown in the web console.
    - Go to the instances list page, click triangular icon right next to the `SSH` button, and then click `view gcloud command`.

```
$ gcloud compute --project "YOUR_PROJECT_ID" ssh --zone "us-east1-b" "YOUR_INSTANCE_NAME"
```

- Update the package manager and installed packages.

```
$ sudo apt update
$ sudo apt upgrade
```


## 3. Create an app

- Install python3.
    - This enables the `pip3` command.

```
$ sudo apt install python3 python3-dev python3-pip
```

- Install virtualenv (may not be needed).

```
$ sudo apt install python3-vitualenv
```

- Install Flask and uWSGI with **pip3 (this time not apt)**.

```
$ sudo pip3 install flask
```

- Create a Flask template file in the current directory.

```~/hello.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello World!"

if __name__ == "__main__":
    app.run()
```

- Tell Flask about the app.

```
$ export FLASK_APP=hello.py
```

## 4. Establish connection with WSGI protocol.

- Install uWSGI.

```
$ sudo pip3 install uwsgi
```

- Create an uWSGI ini file.

```~/uwsgi.ini
[uwsgi]

socket = /tmp/uwsgi.sock
chmod-socket = 666

chdir = %d
wsgi-file = /home/YOUR_USER_NAME/hello.py
module = hello:app
callable = app

master = 1
processes = 1

logto = /var/log/uwsgi/uwsgi.log
```

- Create a service definition for systemd.
    - `Restart = always` allowed?
    - `ExecStart` should be noted absolute.

```/etc/systemd/system/uwsgi.service
[Unit]
Description = uwsgi

[Service]
Restart = no
ExecStart = /usr/YOUR_USER_NAME/.local/bin/uwsgi --ini=/home/YOUR_USER_NAME/uwsgi.ini
ExecReload = /bin/kill -s HUP ${MAINPID}
KillSignal = QUIT

[Install]
WantedBy = multi-user.target
```

- Enable (auto-restart) and start uwsgi manually.

```
$ sudo systemctl enable uwsgi
$ sudo systemctl start uwsgi
```


## 5. Set up an web server.

- Install Nginx.

```
$ sudo apt install nginx
```

- Note that configuration files are located under `/etc/nginx`.
    - `nginx.conf` file is for global configuration and `conf.d` directory is for local one.
    - Any `.conf` file put here is included into `nginx.conf`.
        - Look inside `nginx.conf` and see an `include` directive.

```
$ ls /etc/nginx | grep conf
conf.d
fastcgi.conf
nginx.conf
```

- Remove the default conf file.

```
$ sudo rm /etc/nginx/sites-enabled/default
```

- Create an Nginx conf file.
    - `uwsgi_pass` directive specifies an unix socket.
    - For details, look at [this article](https://qiita.com/morinokami/items/e0efb2ae2aa04a1b148b#nginx%E3%81%AE%E8%A8%AD%E5%AE%9A).

```conf:/etc/nginx/conf.d/hello.conf
server {
  listen 80 default_server;
  server_name _;

  location / {
    include uwsgi_params;
    uwsgi_pass unix:///tmp/uwsgi.sock;
  }
}
```

- Enable and start Nginx.

```
$ sudo systemctl enable nginx
$ sudo systemctl start nginx
```

## 6. Tada!

- Open the fixed IP address in browser.
<img width="621" alt="Screen Shot 2018-12-17 at 2.33.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/327335/25a49c38-afac-4f45-9743-0f54aec1ec29.png">

- That's it!


# If something's wrong...

- First, do an research by taking a look at:
    - on Nginx:
        - service status at `$ systemctl status nginx`
        - service declaration at `/etc/systemd/system/uwsgi.service`
        - conf files at `/etc/nginx/nginx.conf` or `/etc/nginx/conf.d/hello.conf`
    - on uWSGI:
        - log at `/var/log/uwsgi/uwsgi.log` (if specified in `logto` directive in `~/uwsgi.ini`)
        - service status at `$ systemctl status uwsgi`
        - conf file at `~/uwsgi.ini`
    - in general:
        - `/var/log/syslog`
        - `$ history`

# References

- in general:
    - [Ubuntu 16.04 で Flask アプリケーションを動かすまでにやることまとめ](https://qiita.com/hoto17296/items/845850c8854dd18f6fff)
    - [Flask + uWSGI + Nginx でハローワールドするまで @ さくらのVPS (CentOS 6.6)](https://qiita.com/morinokami/items/e0efb2ae2aa04a1b148b#nginx%E3%81%AE%E8%A8%AD%E5%AE%9A)
        - for better understanding of each command.
    - [Deploying Python Flask using uWSGI and Nginx on Ubuntu 14.04](https://code-maven.com/deploying-python-flask-using-uwsgi-on-ubuntu-14-04)
        - for errors like `ImportError: No module named flask`

- uWSGI docs
    - quickstart https://uwsgi-docs.readthedocs.io/en/latest/Configuration.html)
    - details https://uwsgi-docs.readthedocs.io/en/latest/Options.html

- Nginx configuration
    - [nginx初期構成](https://gakumon.tech/nginx/nginx_directory.html)

- `systemctl` commands
    - (https://qiita.com/sinsengumi/items/24d726ec6c761fc75cc9)

- Flask basics
    - http://flask.pocoo.org/docs/1.0/quickstart/

- Python environments (e.g. difference among venv, virtualenv or pyenv)
    - [Pythonの環境構築を自分なりに整理してみる](https://medium.com/@chezou/python%E3%81%AE%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%82%92%E8%87%AA%E5%88%86%E3%81%AA%E3%82%8A%E3%81%AB%E6%95%B4%E7%90%86%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B-dc8d8f2fe989)