# DevOps Training Session 5: NGINX ###### tags: `devops` `research` `reliable` Hello, btb today --> i have mission with nginx-webserver if you want to understand nginx --> go for my [@xeusnguyen](https://hackmd.io/@xeusnguyen) - NGINX and Apache on vietnamese - If you want to english version so don't wrr i will back to another version of that. Enjoy the lab --> [:coffee:](https://drive.google.com/file/d/1y4iQcC3V6rqYGf2L4pkZL63DwvbvcNm3/view?usp=sharing) ## Setup the docker file and make interaction with ~~Using the multi-stage for solving that problem --> identify what need to target and build it~~ ![](https://i.imgur.com/RM2rRkA.png) **Update: after time for implement --> ajust docker file into 2 file individual --> easy to using with each others** Docker/Dockerfile.web: ``` FROM node:14 WORKDIR /app # RUN apk add --update curl git zip COPY ./src/ /app RUN npm install CMD ["npm", "start"] ``` Docker/Dockerfile.nginx: ``` FROM nginx:1.23.3 COPY ./conf / ARG domain_key ENV domain_key=${domain_key} ARG domain_crt ENV domain_crt=${domain_crt} RUN mv *.key /etc/nginx/ RUN mv *.crt /etc/nginx/ RUN mv nginx.conf default.conf.template RUN envsubst < default.conf.template > /etc/nginx/conf.d/default.conf ``` After building complete dockerfile we need to compose it into one for building project with docker-compose **docker-compose.yaml** ``` version: "3" networks: my_network1: my_network2: my_network3: my_network4: services: nginx_alb: image: nginx_alb:latest container_name: web-server ports: - 80:80 - 443:443 networks: - my_network1 - my_network2 - my_network3 - my_network4 restart: always app1: image: webpage8001:latest container_name: app1 expose: - 8001 networks: - my_network1 environment: - MESSAGE="App 1 !" - PORT=8001 app2: image: webpage8002:latest container_name: app2 expose: - 8002 networks: - my_network2 environment: - MESSAGE="App 2 !" - PORT=8002 app3: image: webpage8003:latest container_name: app3 expose: - 8003 networks: - my_network3 environment: - MESSAGE="App 3 !" - PORT=8003 app4: image: webpage8004:latest container_name: app4 expose: - 8004 networks: - my_network4 environment: - MESSAGE="App 4 !" - PORT=8004 ``` nginx.conf ``` upstream alb { server app1:8001; server app2:8002; } server { listen 80 default_server; server_name _; return 301 https://$host$request_uri; } server{ listen 443 ssl; ssl on; server_name _; ssl_certificate ${domain_crt}; ssl_certificate_key ${domain_key}; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; location / { return 404; } location /original { proxy_pass http://alb; } location /v1 { return 307 /original; } location /v2 { return 307 /original; } location /v3 { proxy_pass http://app3:8003; } location /v4 { proxy_pass http://app4:8004; } } ``` And last one, we need onething to run all with bash script **run_setup.sh** ``` #!/bin/bash export docker_err=100 export syspath_err=101 # Get the absolution of path abs_path_file_execute=$(realpath "$0") abs_path_folder_script=$(dirname "$abs_path_file_execute") abs_path_folder_root=$(dirname "$(dirname "$abs_path_file_execute")") abs_path_folder_docker="$abs_path_folder_root""/docker/" abs_path_folder_src="$abs_path_folder_root""/src/" abs_path_folder_conf="$abs_path_folder_docker/conf" source "$abs_path_folder_script/try_catch.sh" # Generate the ssl certificate # Write a Powershell script and a Bash script that generate a self-signed SSL certificate DOMAIN="$1" if [ -z "$DOMAIN" ]; then echo "Usage: $(basename $0) <domain>" exit 11 fi fail_if_error() { [ $1 != 0 ] && { unset PASSPHRASE exit 10 } } # Generate a passphrase export PASSPHRASE=$(head -c 500 /dev/urandom | tr -dc a-z0-9A-Z | head -c 128; echo) # Certificate details; replace items in angle brackets with your own info subj=" C=VN ST=blah O=Blah localityName=vietnam commonName=$DOMAIN organizationalUnitName=Blah emailAddress=admin@example.com " # Generate the server private key openssl genrsa -des3 -out "$abs_path_folder_conf/$DOMAIN.key" -passout env:PASSPHRASE 2048 fail_if_error $? # Generate the CSR openssl req \ -new \ -batch \ -subj "$(echo -n "$subj" | tr "\n" "/")" \ -key "$abs_path_folder_conf/$DOMAIN.key" \ -out "$abs_path_folder_conf/$DOMAIN.csr" \ -passin env:PASSPHRASE fail_if_error $? cp "$abs_path_folder_conf/$DOMAIN.key" "$abs_path_folder_conf/$DOMAIN.key.org" fail_if_error $? # Strip the password so we don't have to type it every time we restart Apache openssl rsa -in "$abs_path_folder_conf/$DOMAIN.key.org" -out "$abs_path_folder_conf/$DOMAIN.key" -passin env:PASSPHRASE fail_if_error $? # Generate the cert (good for 10 years) openssl x509 -req -days 3650 -in "$abs_path_folder_conf/$DOMAIN.csr" -signkey "$abs_path_folder_conf/$DOMAIN.key" -out "$abs_path_folder_conf/$DOMAIN.crt" fail_if_error $? # Remove docker ps & image docker stop "$(docker ps -a)" || true docker rm -f "$(docker ps -aq)" || true docker rmi nginx_alb:latest || true docker rmi "$(docker image list | grep webpage)" || true # Remove the network docker network rm "$(docker network list | grep my_network)" || true # Move on the src folder and after that execute the docker script # Solution 1: Using the mv but not working if don't move absolute path # mv $(ls $abs_path_folder_script --ignore=run_setup.sh --ignore=try_catch.sh) "$abs_path_folder_docker/conf/" || throw $syspath_err # Solution 2: Move with name of Domain --> it work good # mv "$abs_path_folder_script/$DOMAIN.crt" "$abs_path_folder_docker/conf" || throw $syspath_err # mv "$abs_path_folder_script/$DOMAIN.key" "$abs_path_folder_docker/conf" || throw $syspath_err # mv "$abs_path_folder_script/$DOMAIN.csr" "$abs_path_folder_docker/conf" || throw $syspath_err # mv "$abs_path_folder_script/$DOMAIN.key.org" "$abs_path_folder_docker/conf" || throw $syspath_err # Solution 3: Create into conf and do not erase smt # cp -r "$PWD"/../src/ "$PWD"/../docker/ cp -r "$abs_path_folder_src" "$abs_path_folder_docker" || throw $syspath_err # cd "$PWD"/../docker/ || exit cd "$abs_path_folder_docker" || throw $syspath_err # Pull and create each website with specified name docker build -t webpage8001:latest -f Dockerfile.web . || throw $docker_err docker build -t webpage8002:latest -f Dockerfile.web . || throw $docker_err docker build -t webpage8003:latest -f Dockerfile.web . || throw $docker_err docker build -t webpage8004:latest -f Dockerfile.web . || throw $docker_err rm -rf src/ || throw $syspath_err docker build -t nginx_alb:latest --build-arg domain_key=$DOMAIN.key --build-arg domain_crt=$DOMAIN.crt -f Dockerfile.nginx . || throw $docker_err cd "$abs_path_folder_docker/conf/" || throw $syspath_err rm $(ls --ignore=nginx.conf) || throwErrors $syspath_err cd "$abs_path_folder_root" || throw $syspath_err docker-compose up -d || true ``` try_catch.sh ``` #!/bin/bash function try() { [[ $- = *e* ]]; SAVED_OPT_E=$? set +e } function throw() { exit $1 } function catch() { export ex_code=$? (( $SAVED_OPT_E )) && set +e return $ex_code } function throwErrors() { set -e } function ignoreErrors() { set +e } ``` Oh i missing the web part just use the source code from previous session --> but need to config env to see what dif between the webpage **index.js** ``` const http = require('http'); const port = process.env.PORT || 3000; const message = process.env.MESSAGE; const server = http.createServer((req, res) => { res.statusCode = 200; const msg = message res.end(msg); }); server.listen(port, () => { console.log(`Server running on http://localhost:${port}/`); }) ``` package.json ``` { "name": "node-hello", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "node index.js" }, "repository": { "type": "git", "url": "git+https://github.com/johnpapa/node-hello.git" }, "keywords": [], "author": "", "license": "ISC", "bugs": { "url": "https://github.com/johnpapa/node-hello/issues" }, "homepage": "https://github.com/johnpapa/node-hello#readme" } ``` Result ![](https://i.imgur.com/59AR1Fz.png) ![](https://i.imgur.com/3TAru7g.png) ![](https://i.imgur.com/ip0DgmA.png) ![](https://i.imgur.com/ZqkkPQf.png) ![](https://i.imgur.com/NKHXe4P.png) ## Conclusion - This is quite easy implement diagram but --> you will diggest into the nginx --> docker --> compose --> network --> nodejs - Note: don't touch everything about in conf if u don't know. I cost one morning to know wrong include --> ignore default configuration - So happy implement --> Session 5: Nginx end here --> Next session i will move on the cloud computing --> Azure i think so :smile: ## Reference [Multi-stage builds](https://docs.docker.com/build/building/multi-stage/) [Copy but ignore some file](https://unix.stackexchange.com/questions/41693/how-to-copy-some-but-not-all-files) [Config ssl](http://nginx.org/en/docs/http/configuring_https_servers.html) [Nginx configure example](https://www.nginx.com/resources/wiki/start/topics/examples/full) [Nginx --> config with digital ocean](https://www.digitalocean.com/community/tools/nginx) [Config env for nginx](https://www.baeldung.com/linux/nginx-config-environment-variables) [:coffee:](https://www.youtube.com/watch?v=ucRVDoFkcxc) [:thinking_face:](https://stackoverflow.com/questions/22009364/is-there-a-try-catch-command-in-bash)