Wednesday, August 12, 2020

Setup Postfix MTA to send email on Centos 8 using gmail account

Reference: http://souptonuts.sourceforge.net/postfix_tutorial.html

 # 1. install postfix
[root@thermalite ~]# yum install postfix cyrus-sasl cyrus-sasl-plain
Last metadata expiration check: 2:46:54 ago on Mon 10 Aug 2020 03:13:19 PM EDT.
Package postfix-2:3.3.1-12.el8.x86_64 is already installed.
Package cyrus-sasl-2.1.27-1.el8.x86_64 is already installed.
Package cyrus-sasl-plain-2.1.27-1.el8.x86_64 is already installed.
Dependencies resolved.
Nothing to do.
Complete!

# 2. Next, edit the main Postfix configuration file @ /etc/postfix/main.cf to include the following:
[root@thermalite siteconfig]# cat /etc/postfix/main.cf | grep -v "^#" |  sed -e '/^$/d'
compatibility_level = 2
queue_directory = /var/spool/postfix
command_directory = /usr/sbin
daemon_directory = /usr/libexec/postfix
data_directory = /var/lib/postfix
mail_owner = postfix
mydomain = wezzle.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = all
mydestination = wezzle.com, $myhostname, localhost.$mydomain, localhost
unknown_local_recipient_reject_code = 550
mynetworks = 192.0.0.0/8
relayhost = [smtp.gmail.com]:587
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
home_mailbox = Maildir/
mailbox_command = /usr/bin/procmail -a "$EXTENSION"
mailbox_size_limit = 0
debug_peer_level = 2
debugger_command =
         PATH=/bin:/usr/bin:/usr/local/bin:/usr/X11R6/bin
         ddd $daemon_directory/$process_name $process_id & sleep 5
newaliases_path = /usr/bin/newaliases.postfix
mailq_path = /usr/bin/mailq.postfix
setgid_group = postdrop
html_directory = no
manpage_directory = /usr/share/man
sample_directory = /usr/share/doc/postfix/samples
readme_directory = /usr/share/doc/postfix/README_FILES
smtpd_tls_cert_file = /etc/ssl/certs/thermalite.crt
smtpd_tls_key_file = /etc/ssl/private/thermalite.key
smtpd_tls_security_level = may
smtp_tls_CApath = /etc/pki/tls/certs
smtp_tls_security_level = may
meta_directory = /etc/postfix
shlib_directory = /usr/lib64/postfix
smtp_use_tls = yes
smtp_tls_loglevel=1
smtp_tls_security_level = encrypt
smtp_sasl_auth_enable = yes
smtp_sasl_path = smtpd
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_tls_policy_maps = hash:/etc/postfix/tls_policy
smtp_sasl_security_options = noanonymous
smtp_sasl_mechanism_filter = login, plain
smtp_tls_security_level = verify
smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt
smtp_sasl_tls_security_options = noanonymous
message_size_limit = 1024000000
smtpd_tls_auth_only = no
smtpd_use_tls = yes
smtp_tls_note_starttls_offer = yes
smtpd_tls_CAfile = /etc/ssl/certs/cacert.pem
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_sasl_auth_enable = yes
[root@thermalite siteconfig]#


# 3. configure the .mailrc for a user bills
[bills@thermalite ~]$ cat .mailrc
set smtp-use-starttls
set ssl-verify=ignore
set smtp=smtp://smtp.gmail.com:587
set smtp-auth=login
set smtp-auth-user=bills.smith@gmail.com
set smtp-auth-password=dfdyhukigkssosbxv
set from="bills.smith@gmail.com"
[malex@thermalite ~]$


# 4. send a test mail_owner
[malex@thermalite ~]$ echo "This is a test email from my server" |\
 /usr/bin/mailx -v -s "Postfix Newsletter Update for `TZ="Asia/Manila" date '+%A, %B %d %Y %H:%M:%S'`" bills.smith@gmail.com


Generating Certificate for your Centos 8 Postfix Server

 # 1. generate a private key
[root@thermalite ~]# openssl genrsa -des3 -out thermalite.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
....................+++++
............+++++
e is 65537 (0x010001)
Enter pass phrase for thermalite.key:
Verifying - Enter pass phrase for thermalite.key:
[root@thermalite ~]#

# 2. generate a certicate sign request using the private key and output a certicate sign request (.csr)
[root@thermalite ~]# openssl req -new -key thermalite.key -out thermalite.csr
Enter pass phrase for thermalite.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:New Jersey
Locality Name (eg, city) [Default City]:Cherry Hill
Organization Name (eg, company) [Default Company Ltd]:O2bot LLC
Organizational Unit Name (eg, section) []:IT Department
Common Name (eg, your name or your server's hostname) []:thermalite
Email Address []:donot-reply@gmail.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

# 3. generate and actual certificate using the certicate sign request (.csr)
[root@thermalite ~]# openssl x509 -req -days 365 -in thermalite.csr -signkey thermalite.key -out thermalite.crt
Signature ok
subject=C = US, ST = New Jersey, L = Cherry Hill, O = O2bot LLC, OU = IT Department, CN = thermalite, emailAddress = donot-reply@gmail.com
Getting Private key
Enter pass phrase for thermalite.key:
[root@thermalite ~]#

# 4. generate a nopass
[root@thermalite ~]# openssl rsa -in thermalite.key -out thermalite.key.nopass
Enter pass phrase for thermalite.key:
writing RSA key
[root@thermalite ~]#

# 5. overwrite the private key with nopass
[root@thermalite ~]# mv thermalite.key.nopass thermalite.key
mv: overwrite 'thermalite.key'? y
[root@thermalite ~]#

# 6. creata a new certificate authority
[root@thermalite ~]# openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.pem -days 365
Generating a RSA private key
.+++++
.......................................+++++
writing new private key to 'cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:New Jersey
Locality Name (eg, city) [Default City]:Cherry Hill
Organization Name (eg, company) [Default Company Ltd]:O2bot LLC
Organizational Unit Name (eg, section) []:IT Department
Common Name (eg, your name or your server's hostname) []:thermalite
Email Address []:donot-reply@gmail.com

# 7. chmod all files
[root@thermalite ~]# chmod 600 thermalite.key cakey.pem

# 8. move to proper directories
[root@thermalite ~]# mv thermalite.crt /etc/ssl/certs/.
[root@thermalite ~]# mv cacert.pem /etc/ssl/certs/.
[root@thermalite ~]# update-ca-trust

[root@thermalite ~]# mkdir -p /etc/ssl/private
[root@thermalite ~]# mv thermalite.key /etc/ssl/private/.
[root@thermalite ~]# mv cakey.pem /etc/ssl/private/.

Testing if Postfix MTA on Centos 8 is working on localhost

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[root@thermalite siteconfig]# telnet localhost 25
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 thermalite.localdomain ESMTP Postfix
ehlo thermalite.localdomain
250-thermalite.localdomain
250-PIPELINING
250-SIZE 1024000000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 SMTPUTF8
MAIL FROM: bills@thermalite.localdomain
250 2.1.0 Ok
RCPT TO: o2bot@thermalite.localdomain
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: Hello postfix

This is a test email using postfix MTA
.
250 2.0.0 Ok: queued as 47A074112F1B
quit
221 2.0.0 Bye
Connection closed by foreign host.

[root@thermalite siteconfig]# ls -l /var/mail/
bills  malex  o2bot  root   rpc
[root@thermalite siteconfig]# ls -l /var/mail/o2bot
-rw-rw----. 1 o2bot mail 600 Aug 12 17:03 /var/mail/o2bot
[root@thermalite siteconfig]# cat /var/mail/o2bot
From bills@thermalite.localdomain  Wed Aug 12 17:03:39 2020
Return-Path: <bills@thermalite.localdomain>
X-Original-To: o2bot@thermalite.localdomain
Delivered-To: o2bot@thermalite.localdomain
Received: from thermalite.localdomain (thermalite [IPv6:::1])
        by thermalite.localdomain (Postfix) with ESMTP id 47A074112F1B
        for <o2bot@thermalite.localdomain>; Wed, 12 Aug 2020 17:01:56 -0400 (EDT)
Subject: Hello postfix
Message-Id: <20200812210233.47A074112F1B@thermalite.localdomain>
Date: Wed, 12 Aug 2020 17:01:56 -0400 (EDT)
From: bills@thermalite.localdomain

This is a test email using postfix MTA

[root@thermalite siteconfig]# 

Centos 8 yum History

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
[root@thermalite ~]# yum history
ID     | Command line             | Date and time    | Action(s)      | Altered
-------------------------------------------------------------------------------
    59 | erase subscription-manag | 2020-08-12 11:16 | Removed        |   63 EE
    58 | update                   | 2020-08-12 11:13 | Upgrade        |    1
    57 | update                   | 2020-08-11 18:54 | Upgrade        |   49
    56 |                          | 2020-08-10 16:58 | Install        |    2
    55 | install procmail         | 2020-08-10 09:43 | Install        |    1
    54 |                          | 2020-08-09 17:51 | Install        |    1
    53 | install fetchmail        | 2020-08-09 17:19 | Install        |    1
    52 | remove stunnel-5.48-5.el | 2020-08-09 06:01 | Removed        |    1
    51 | remove sendmail-8.15.2-3 | 2020-08-09 05:44 | Removed        |    3 EE
    50 | install telnet           | 2020-08-09 03:36 | Install        |    1
    49 | autoremove               | 2020-08-09 03:31 | Removed        |    7
    48 | install stunnel          | 2020-08-09 02:12 | Install        |    1
    47 | install mailx            | 2020-08-09 01:31 | Install        |    1
    46 | install sendmail sendmai | 2020-08-09 01:08 | Install        |    3
    45 | distro-sync              | 2020-08-09 01:03 | E, I, R, U     |   52 EE
    44 | erase docker-ce          | 2020-06-26 15:07 | Removed        |    3 EE
    43 | distro-sync --nobest     | 2020-06-26 15:06 | D, I           |    6
    42 | autoremove               | 2020-06-26 15:02 | Removed        |   12
    41 | update                   | 2020-06-26 14:41 | E, I, O, U     |  647 EE
    40 | update                   | 2020-06-10 09:20 | Upgrade        |    4 EE
    39 | install -y mariadb-serve | 2020-05-27 21:37 | Install        |   11
    38 | update -y                | 2020-05-27 15:35 | Upgrade        |    1 EE
    37 | install perl             | 2020-05-24 13:22 | Install        |   99
    36 | autoremove               | 2020-05-24 13:19 | Removed        |    3
    35 | install docker-ce -y     | 2020-05-24 12:58 | Install        |    3
    34 | install https://download | 2020-05-24 12:58 | I, O           |    2
    33 | remove docker-ce-cli-19. | 2020-05-24 12:57 | Removed        |    1
    32 | install docker-ce-cli    | 2020-05-24 12:57 | Install        |    1
    31 | remove docker-ce-cli-19. | 2020-05-24 12:56 | Removed        |    4 EE
    30 | install docker-ce-18.09. | 2020-05-24 12:55 | Install        |    4
    29 | remove docker-ce-cli-19. | 2020-05-24 12:55 | Removed        |    4 EE
    28 | install docker-ce --nobe | 2020-05-24 12:35 | Install        |    4
    27 | erase perl-DBD-SQLite pe | 2020-05-24 12:22 | Removed        |    5
    26 | erase gitlab-ee          | 2020-05-24 12:19 | Removed        |    1
    25 | update                   | 2020-05-24 12:12 | I, U           |  112 ##
    24 | erase mysql-server       | 2020-05-24 12:11 | Removed        |    7
    23 | erase mssql-server       | 2020-05-24 12:11 | Removed        |    1
    22 | install mysql-server     | 2020-05-24 12:03 | Install        |    7 EE
    21 | install jenkins          | 2020-04-24 23:55 | Install        |    1
    20 | install java-1.8.0-openj | 2020-04-24 23:50 | I, U           |    5 EE
    19 | install nmap             | 2020-04-23 12:52 | Install        |    1
    18 | install -y gitlab-ee     | 2020-04-23 12:49 | Install        |    1
    17 | install -y yum-utils --d | 2020-04-23 12:39 | Install        |    1
    16 | install postfix          | 2020-04-23 12:38 | Install        |    1
    15 | update                   | 2020-03-28 16:37 | Upgrade        |   15
    14 | -y install mssql-tools u | 2020-03-22 17:50 | Install        |    2  <
    13 | -y install mssql-tools u | 2020-03-22 17:44 | Install        |    4 ><
    12 | -y install python2 compa | 2020-03-22 17:43 | Install        |    1 >
    11 | install -y nginx         | 2020-03-17 15:22 | Install        |    8
    10 | install httpd            | 2020-03-17 14:31 | Install        |    9
     9 | autoremove               | 2020-03-08 14:10 | Removed        |    2
     8 | update                   | 2020-03-08 14:05 | I, U           |  140 EE
     7 | -y install postgresql12  | 2020-02-15 16:55 | Install        |    3
     6 | -y install https://downl | 2020-02-15 16:52 | Install        |    1
     5 | install -y nodejs        | 2020-02-15 16:39 | Install        |    7  <
     4 | groupinstall -y Developm | 2020-02-15 16:37 | I, U           |   87 >
     3 | install gcc              | 2020-02-09 09:40 | Install        |    7  <
     2 | install openssh-server o | 2020-02-09 09:01 | Upgrade        |    3 >
     1 |                          | 2020-02-09 08:36 | Install        | 1347 EE
[root@thermalite ~]#

Tuesday, August 11, 2020

How to Fix Internet Connection on Centos 8

When you suddenly can ping www.yahoo.com but can ping its ip address 98.137.11.163. You may have a DNS issue.

Use this sample configuration from my Centos 8 Server.


Thermalite Network configuration

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
[root@thermalite ~]# cat /etc/sysconfig/network-scripts/ifcfg-enp2s0
TYPE="Ethernet"
PROXY_METHOD="none"
BROWSER_ONLY="no"
BOOTPROTO="none"
DEFROUTE="yes"
IPV4_FAILURE_FATAL="no"
IPV6INIT="yes"
IPV6_AUTOCONF="yes"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="enp2s0"
UUID="fc6f7668-2012-4473-9037-56296cb3aff7"
DEVICE="enp2s0"
ONBOOT="yes"
IPADDR=192.168.1.100
PREFIX=24
GATEWAY=192.168.1.1
[root@thermalite ~]#


[root@thermalite ~]# cat /etc/resolv.conf
# Generated by NetworkManager
search fios-router.home
nameserver 192.168.1.1 
[root@thermalite ~]#

[root@thermalite ~]# cat /etc/networks
default 0.0.0.0
loopback 127.0.0.0
link-local 169.254.0.0
[root@thermalite ~]#
[root@thermalite ~]# cat /etc/sysconfig/network

# Created by anaconda
#NETWORKING=yes
#NETWORKING_IPV6=no
#HOSTNAME=thermalite.localdomain
[root@thermalite ~]#
 

Monday, August 10, 2020

Configure Fetchmail to retrieve Gmail Account on Centos 8 using a local user

Overview:

These steps will try to configure the CentOs server to fetch the emails from gmail
and store it to the mail inbox of the local linux user malex. The mailbox can
be read using the program mailx.

CentOs 8 hostname: thermalite.localdomain
Linux user: malex
Gmail Accout: mygmail@gmail.com

1
2
3
4
5
6
7
[root@thermalite ~]# yum install fetchmail
Last metadata expiration check: 2:55:51 ago on Mon 10 Aug 2020 12:13:12 PM EDT.
Package fetchmail-6.3.26-19.el8.x86_64 is already installed.
Dependencies resolved.
Nothing to do.
Complete!
[root@thermalite ~]#
 

# 1. create a ~/.fetchmailrc to set the user account config

1
2
[malex@thermalite ~]$ ls -l ~/.fetchmailrc
-rw-------. 1 malex malex 222 Aug 10 13:22 /home/malex/.fetchmailrc


# 2. View content of the ~/.fetchmailrc file, chmod to 600
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[malex@thermalite ~]$ cat /home/malex/.fetchmailrc
# set username
set postmaster "malex"
# set polling time (5 minutes)
set daemon 300

poll imap.gmail.com with proto IMAP
    user 'mygmail@gmail.com' there with password 'passfromapppasswords' is malex here options ssl

[malex@thermalite ~]$


# 3. configuration for the fetchmail in /etc
Note: The password is not the actual password but the app password to by-pass 2-Factor authentication. See https://support.google.com/accounts/answer/185833?hl=en
1
2
3
4
5
6
7
8
9
[root@thermalite ~]# cat /etc/fetchmailrc.example
# set username
set postmaster "malex"
# set polling time (5 minutes)
set daemon 300

poll imap.gmail.com with proto IMAP
    user 'mygmail@gmail.com' there with password 'passfromapppasswords' is malex here options ssl
[root@thermalite ~]#


# 4. restart fetchmail service
1
[root@thermalite ~]# systemctl restart fetchmail


# 5. check status of fetchmail service
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
[root@thermalite ~]# systemctl status fetchmail
● fetchmail.service - A remote-mail retrieval utility
   Loaded: loaded (/usr/lib/systemd/system/fetchmail.service; enabled; vendor preset: disabled)
   Active: active (running) since Mon 2020-08-10 14:12:03 EDT; 25min ago
 Main PID: 326506 (fetchmail)
    Tasks: 1 (limit: 48942)
   Memory: 2.7M
   CGroup: /system.slice/fetchmail.service
           └─326506 /usr/bin/fetchmail -d 300 --fetchmailrc /etc/fetchmailrc.example

Aug 10 14:12:03 thermalite.localdomain systemd[1]: Started A remote-mail retrieval utility.
[root@thermalite ~]#


# 6. location of mail for mailex
1
2
3
[root@thermalite ~]# ls -l /var/mail/malex
-rw-rw----. 1 malex mail 281355833 Aug 10 14:34 /var/mail/malex
[root@thermalite ~]#

# 7. view mails using mailx

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[malex@thermalite ~]$ mail
Heirloom Mail version 12.5 7/5/10.  Type ? for help.
"/var/spool/mail/malex": 4764 messages 2 new 4755 unread
 U4741 eBay                  Mon Aug 10 14:26 1696/120756 "Save big at The Brand Outlet 👟🎧️"
 U4745 Macy's                Mon Aug 10 14:26 1182/67493 "Wknd fun: 40-60% off Deals of the Day!"
 U4748 JCPenney              Mon Aug 10 14:26 1423/71443 "This EXTRA 30% OFF is yours, just in time for back to school!"
 U4758 Kohl’s                Mon Aug 10 14:31 774/72915 "Save $10 + shop gotta-have gifts for every budget 🎁🎁🎁"
 U4759 Walgreens Photo       Mon Aug 10 14:31 889/40013 "40% off Everything Photo! Create and pick up gifts all in the same day!"
>N4760 Walgreens Photo       Mon Aug 10 14:31 852/38092 "Get up to 50% off gifts + create & pick up SAME DAY = last-minute gifts that don’t fee"
&


Saturday, July 4, 2020

How to create Node JS Basic Routing

1. Reference: https://github.com/acad1. Create project folder
------------------------
malex@WINDOWS-1J3BS7A MINGW64 /
$ cd ~

malex@WINDOWS-1J3BS7A MINGW64 ~
$ cd node-tutorial/

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial
$ ls -l
total 8
drwxr-xr-x 1 malex 197121 0 Jul  4 11:56 node-pgsql/
drwxr-xr-x 1 malex 197121 0 Jul  4 12:35 node-rest-shop/

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial
$ mkdir -p node-rest-shop-basic-router/api/routes

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial
$ cd node-rest-shop-basic-router/

2. Initialize the project
-------------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install ` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (rest-shop-basic-router)
version: (1.0.0)
description: A Node.js RESTful API Tutorial Project (Build a simple shop API)
entry point: (index.js) server.js
test command:
git repository:
keywords:
author: Alex Madriaga
license: (ISC)
About to write to C:\Users\malex\node-tutorial\node-rest-shop-basic-router\packa
ge.json:

{
  "name": "rest-shop-basic-router",
  "version": "1.0.0",
  "description": "A Node.js RESTful API Tutorial Project (Build a simple shop API)",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Alex Madriaga",
  "license": "ISC"
}


Is this OK? (yes) yes

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$

3. Create the server.js
-----------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ touch server.js

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ vi server.js

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ cat server.js

const app = require('./app');
const port = process.env.PORT || 3700;

// 0. default root
app.get("/",async (req,res, next) => {
    try{
      res.send("Welcome to Node REST Shop Basic Router Application");
    } catch(error){
       console.error(error.message);
    }
});

app.listen(port,()=> {
    console.log("Server is listening on port :",port);
});

4. Create the app.js
-----------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ touch app.js

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ vi app.js

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ cat app.js

const express = require("express");
const app = express();
const productRoutes = require('./api/routes/products');
const orderRoutes = require('./api/routes/orders.js');

app.use('/products', productRoutes);
app.use('/orders', orderRoutes);

module.exports = app;

5. Create orders routes
-----------------------

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ touch api/routes/orders.js

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ vi api/routes/orders.js

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ cat api/routes/orders.js

const express = require('express');
const router = express.Router();

router.get('/', (req, res, next) => {
    res.status(200).json({
        message: 'Orders were fetched'
    });
});

router.post('/', (req, res, next) => {
    res.status(201).json({
        message: 'Order was created'
    });
});

router.get('/:orderId', (req, res, next) => {
    res.status(200).json({
        message: 'Order details',
        orderId: req.params.orderId
    });
});

router.delete('/:orderId', (req, res, next) => {
    res.status(200).json({
        message: 'Order deleted',
        orderId: req.params.orderId
    });
});

module.exports = router;

6. Create products routes
-------------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ touch api/routes/products.js

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ vi api/routes/products.js

malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ cat api/routes/products.js

const express = require('express');
const router = express.Router();

router.get('/', (req, res, next) => {
    res.status(200).json({
        message: 'Handling GET requests to /products'
    });
});

router.post('/', (req, res, next) => {
    res.status(201).json({
        message: 'Handling POST requests to /products'
    });
});

router.get('/:productId', (req, res, next) => {
    const id = req.params.productId;
    if (id === 'special') {
        res.status(200).json({
            message: 'You discovered the special ID',
            id: id
        });
    } else {
        res.status(200).json({
            message: 'You passed an ID'
        });
    }
});

router.patch('/:productId', (req, res, next) => {
    res.status(200).json({
        message: 'Updated product!'
    });
});

router.delete('/:productId', (req, res, next) => {
    res.status(200).json({
        message: 'Deleted product!'
    });
});

module.exports = router;

7. Install express module
-------------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ npm i express -s
+ express@4.17.1
added 50 packages from 37 contributors and audited 50 packages in 2.131s
found 0 vulnerabilities

8. Install morgan module
-------------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ npm i morgan -s
+ morgan@1.10.0
added 4 packages from 2 contributors and audited 54 packages in 1.286s
found 0 vulnerabilities

9. Install nodemon module
-------------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ npm i nodemon -s
+ nodemon@2.0.4
added 118 packages from 54 contributors and audited 173 packages in 7.435s

8 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities


10. View updated package.json
----------------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-router
$ cat package.json

{
  "name": "rest-shop-basic-router",
  "version": "1.0.0",
  "description": "A Node.js RESTful API Tutorial Project (Build a simple shop API)",
  "main": "server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Alex Madriaga",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1",
    "morgan": "^1.10.0",
    "nodemon": "^2.0.4"
  }
}


11. Run the node js application
-------------------------------
malex@WINDOWS-1J3BS7A MINGW64 ~/node-tutorial/node-rest-shop-basic-rc-router
$ nodemon index.js

12. Open browser at htpp://localhost:3700
-----------------------------------------

Friday, July 3, 2020

How to allow access Angular outside localhost:4200

How to allow access outside localhost

1. view open port
[root@thermalite ~]# firewall-cmd --list-ports
9000/tcp 9001/tcp 1433/tcp 8080/tcp 5000/tcp

[root@thermalite ~]# firewall-cmd --permanent --add-port 4200/tcp
success

[root@thermalite ~]# systemctl restart firewalld

[root@thermalite ~]# firewall-cmd --list-ports
9000/tcp 9001/tcp 1433/tcp 8080/tcp 5000/tcp 4200/tcp

[malex@thermalite hello-world]$ ng serve --host 0.0.0.0
Your global Angular CLI version (10.0.1) is greater than your local
version (10.0.0). The local Angular CLI version is used.

To disable this warning use "ng config -g cli.warnings.versionMismatch false".
WARNING: This is a simple server for use in testing or debugging Angular applications
locally. It hasn't been reviewed for security issues.

Binding this server to an open connection can result in compromising your application or
computer. Using a different host than the one passed to the "--host" flag might result in
websocket connection issues. You might need to use "--disableHostCheck" if that's the
case.

chunk {main} main.js, main.js.map (main) 57.7 kB [initial] [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 141 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 6.15 kB [entry] [rendered]
chunk {styles} styles.js, styles.js.map (styles) 12.4 kB [initial] [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 2.41 MB [initial] [rendered]
Date: 2020-07-03T18:38:33.009Z - Hash: 1c609b822fe9cba12387 - Time: 6023ms
** Angular Live Development Server is listening on 0.0.0.0:4200, open your browser on http://localhost:4200/ **
: Compiled successfully.



Open browser: http://192.168.1.100:4200

How to create a basic PostgreSQL and Node JS Application

1. Create the project folder
--------------------------------
[malex@thermalite node-pgsql]$ mkdir node-pgsql

[malex@thermalite node-pgsql]$ cd node-pgsql

[malex@thermalite node-pgsql]$ npm init -y

2. create the database and table on PostgreSQL
--------------------------------------------------------
[malex@thermalite node-pgsql]$ cat database.sql
-- 1. create database
CREATE DATABASE todo_database;

-- 2. connect to database
\c todo_database

-- 3. create table
CREATE TABLE todo(
  todo_id SERIAL PRIMARY KEY,
  description VARCHAR(255)
);


3. Add npm libraries
-------------------------
[malex@thermalite node-pgsql]$ npm i express -s

[malex@thermalite node-pgsql]$ npm i pg -s

[malex@thermalite node-pgsql]$ npm i nodemon -s

4. create connection configuration
------------------------------------------
[malex@thermalite node-pgsql]$ cat dbpgsql.js
const Pool = require("pg").Pool;

const pool = new Pool({
    user: "postgres",
    password: "pfa_user",
    database: "todo_database",
    host: "192.168.1.100",
    port: 5432
});

module.exports = pool;

5. create the index.js
--------------------------
[malex@thermalite node-pgsql]$ cat index.js
const express = require("express");
const app = express();
const pool = require("./dbpgsql");
const port = 5000;

app.use(express.json()) // -> req.body

// ROUTES//

// 0. default root
app.get("/",async (req,res) => {
try{
  res.send("Welcome to PostgreSQL Node Application");
} catch(error){
   console.error(error.message);
}

});

// 1. get all todos
app.get("/todos",async (req,res) => {
    try {
        const allTodos = await pool.query("SELECT * FROM todo");
        res.json(allTodos.rows);
    } catch (error) {
        console.error(error.message);
    }
});

// 2. get a todo
app.get("/todos/:id",async (req,res) => {
    const { id } = req.params;
    try {
        const todo = await pool.query("SELECT * FROM todo WHERE todo_id = $1", [id]);
        res.json(todo.rows[0]);
    } catch (error) {
        console.error(error.message);
    }
});

// 3. create a todo
app.post("/todos",async (req,res) => {
    try {
        const { description } = req.body;
        const newTodo = await pool.query("INSERT INTO todo (description) VALUES ($1) RETURNING *",
        [description]
        );
        res.json(newTodo);
    } catch (error) {
        console.error(error.message);
    }
});

// 4. update a todo
app.put("/todos/:id",async (req,res) => {
    try {
        const { id } = req.params; // WHERE
        const { description } = req.body; //SET

        const updateTodo = await pool.query("UPDATE todo SET description=$1 WHERE todo_id=$2",
        [description, id]
        );
        res.json("Todo was successfully updated.");
    } catch (error) {
        console.error(error.message);
    }
});

// 5. delete a todo
app.delete("/todos/:id",async (req,res) => {
    try {
        const { id } = req.params; // WHERE

        const deleteTodo = await pool.query("DELETE FROM todo WHERE todo_id=$1",
        [id]
        );
        res.json("Todo was successfully deleted.");
    } catch (error) {
        console.error(error.message);
    }
});

app.listen(port,()=> {
    console.log("Server is listening on port: ", port);
});

6. run the application
[malex@thermalite node-pgsql]$ nodemon index


7. open browser and got to http://192.168.1.100:5000/todos

How to open port 5000 for use by Node JS Application

How to open port 5000 for use by Node JS Application
Reference: https://www.cyberciti.biz/faq/howto-rhel-linux-open-port-using-iptables/

[root@thermalite ~]# firewall-cmd --list-ports
9000/tcp 9001/tcp 1433/tcp 8080/tcp

[root@thermalite ~]# firewall-cmd --get-zones
block dmz drop external home internal libvirt public trusted work

[root@thermalite ~]# ip a
1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp2s0: mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 90:2b:34:38:27:51 brd ff:ff:ff:ff:ff:ff
    inet 192.168.1.100/24 brd 192.168.1.255 scope global noprefixroute enp2s0
       valid_lft forever preferred_lft forever
    inet6 fe80::3033:b8ea:8652:3d3/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: virbr0: mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether 52:54:00:41:41:60 brd ff:ff:ff:ff:ff:ff
    inet 192.168.122.1/24 brd 192.168.122.255 scope global virbr0
       valid_lft forever preferred_lft forever
4: virbr0-nic: mtu 1500 qdisc fq_codel master virbr0 state DOWN group default qlen 1000
    link/ether 52:54:00:41:41:60 brd ff:ff:ff:ff:ff:ff
5: docker0: mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:82:0e:78:5f brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:82ff:fe0e:785f/64 scope link
       valid_lft forever preferred_lft forever

[root@thermalite ~]# firewall-cmd --get-zone-of-interface=enp2s0
public

[root@thermalite ~]# firewall-cmd --permanent --add-port 5000/tcp
success

[root@thermalite ~]# firewall-cmd --list-ports
9000/tcp 9001/tcp 1433/tcp 8080/tcp

[root@thermalite ~]# systemctl restart firewalld

[root@thermalite ~]# firewall-cmd --list-ports
9000/tcp 9001/tcp 1433/tcp 8080/tcp 5000/tcp
[root@thermalite ~]#

Connect to a MongoDB Database Using Node.js

1. Reference: https://www.mongodb.com/blog/post/quick-start-nodejs-mongodb--how-to-get-connected-to-your-database

2. Session
[malex@thermalite mongodb-atlas-client]$ ls -l
total 0
[malex@thermalite mongodb-atlas-client]$ npm init -y
Wrote to /home/malex/nodejs/mongodb-atlas-client/package.json:

{
  "name": "mongodb-atlas-client",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}


[malex@thermalite mongodb-atlas-client]$ npm i mongodb -s
+ mongodb@3.5.9
added 20 packages from 11 contributors and audited 20 packages in 1.204s

1 package is looking for funding
  run `npm fund` for details

found 0 vulnerabilities

[malex@thermalite mongodb-atlas-client]$ vi connection.js

[malex@thermalite mongodb-atlas-client]$ cat connection.js

const { MongoClient } = require('mongodb');

async function main() {
    /**
     * Connection URI. Update , , and to reflect your cluster.
     * See https://docs.mongodb.com/ecosystem/drivers/node/ for more details
     */
    const uri = "mongodb+srv://node_user:pass123@cluster101.n7nqjv.mongodb.net/test?retryWrites=true&w=majority";


    /**
     * The Mongo Client you will use to interact with your database
     * See https://mongodb.github.io/node-mongodb-native/3.3/api/MongoClient.html for more details
     */
    const client = new MongoClient(uri);

    try {
        // Connect to the MongoDB cluster
        await client.connect();

        // Make the appropriate DB calls
        await listDatabases(client);

    } catch (e) {
        console.error(e);
    } finally {
        // Close the connection to the MongoDB cluster
        await client.close();
    }
}

main().catch(console.error);

/**
 * Print the names of all available databases
 * @param {MongoClient} client A MongoClient that is connected to a cluster
 */
async function listDatabases(client) {
    databasesList = await client.db().admin().listDatabases();

    console.log("Databases:");
    databasesList.databases.forEach(db => console.log(` - ${db.name}`));
};


[malex@thermalite mongodb-atlas-client]$ node connection
(node:351200) DeprecationWarning: current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
Databases:
 - sample_airbnb
 - sample_analytics
 - sample_geospatial
 - sample_mflix
 - sample_restaurants
 - sample_supplies
 - sample_training
 - sample_weatherdata
 - admin
 - local
[malex@thermalite mongodb-atlas-client]$