Reverse proxy with NGINX (AMZ Linux 2) + NAT instance

Install nginx

sudo amazon-linux-extras install nginx1

nginx -v

sudo systemctl start nginx
sudo systemctl enable nginx

sudo systemctl status nginx
sudo systemctl is-enabled nginx

Configure reverse proxy

Reverse proxy for EC2:

HTTP:

cd /etc/nginx/conf.d
nano reverse-proxy.conf

Add following lines:

server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
         proxy_pass <http://172.31.18.252>;
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Check configure syntax and restart nginx:

nginx -t
systemctl restart nginx

HTTPS:

Generate key

openssl genrsa -aes128 2048 > server.key

openssl rsa -in server.key -out server.key

openssl req -new -key server.key > server.csr
※以下入力(このあたりは自由です。)
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]:Tokyo
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

# 証明書作成
openssl x509 -req -days 3650 -signkey server.key < server.csr > server.crt
mkdir /etc/nginx/ssl/
cp server.key server.crt /etc/nginx/ssl/
chmod 400 /etc/nginx/ssl/server.*

cd /etc/nginx/conf.d
nano proxy-ssl.conf

Add the following lines:

server {
    listen       443 ssl http2;
    listen       [::]:443 ssl http2;
    server_name  _;
    root         /usr/share/nginx/html;

    ssl_certificate "ssl/server.crt";
    ssl_certificate_key "ssl/server.key";
    ssl_session_cache shared:SSL:1m;
    ssl_session_timeout  10m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    #ssl_ciphers PROFILE=SYSTEM;
    ssl_prefer_server_ciphers on;

    proxy_redirect      off;
    proxy_set_header    X-Real-IP $remote_addr;
    proxy_set_header    X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header    Host $http_host;

    location / {
        proxy_pass <http://172.31.18.252;
    }
}
nginx -t
systemctl restart nginx

Testing:

  • Create a private instance an

  • Install apache httpd and edit index

  • Connect to the private instance by public IP of reverse instance:

Before:

After:

Reference: https://www.server-world.info/en/note?os=CentOS_8&p=nginx&f=8

https://www.howtoforge.com/how-to-configure-nginx-as-a-web-server-and-reverse-proxy-for-apache-on-centos-8/

Stream for RDS

Reference: https://docs.nginx.com/nginx/admin-guide/load-balancer/tcp-udp-load-balancer/

Install stream modules:

yum install nginx-mod-stream

Get IP of the RDS instance:

dig <name>.cluster-ro-xxxxxxxxxxxx.ap-northeast-1.rds.amazonaws.com

For eg:

 dig database-2.cluster-ro-cfvulhssfv2n.ap-northeast-1.rds.amazonaws.com

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.amzn2.5.2 <<>> database-2.cluster-ro-cfvulhssfv2n.ap-northeast-1.rds.amazonaws.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7564
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;database-2.cluster-ro-cfvulhssfv2n.ap-northeast-1.rds.amazonaws.com. IN        A

;; ANSWER SECTION:
database-2.cluster-ro-cfvulhssfv2n.ap-northeast-1.rds.amazonaws.com. 5 IN CNAME database-2-instance-1.cfvulhssfv2n.ap-northeast-1.rds.amazonaws.com.
database-2-instance-1.cfvulhssfv2n.ap-northeast-1.rds.amazonaws.com. 5 IN A 172.31.5.49

;; Query time: 4 msec
;; SERVER: 172.31.0.2#53(172.31.0.2)
;; WHEN: Tue Nov 22 08:58:46 UTC 2022
;; MSG SIZE  rcvd: 161

\=> IP of the DB instance: 172.31.5.49

Add following into nginx.conf file: (note that steam block has equal incident with http block):

stream {
  upstream rds {
    server  172.31.5.49:5432;
  }

  server {
    listen 5432;
    proxy_pass rds;
  }
}
nginx -t
systemctl restart nginx

You can access the rds instance by the public IP of the proxy instnance

Reference: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_ConnectToPostgreSQLInstance.html

Stream for Elasticache:

dig test-proxy-001.ndzcu2.ng.0001.apne1.cache.amazonaws.com

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.amzn2.5.2 <<>> test-proxy-001.ndzcu2.ng.0001.apne1.cache.amazonaws.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 50
;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;test-proxy-001.ndzcu2.ng.0001.apne1.cache.amazonaws.com. IN A

;; ANSWER SECTION:
test-proxy-001.ndzcu2.ng.0001.apne1.cache.amazonaws.com. 15 IN CNAME test-proxy-001-001.ndzcu2.0001.apne1.cache.amazonaws.com.
test-proxy-001-001.ndzcu2.0001.apne1.cache.amazonaws.com. 15 IN A 172.31.32.145

;; Query time: 4 msec
;; SERVER: 172.31.0.2#53(172.31.0.2)
;; WHEN: Tue Nov 22 09:52:46 UTC 2022
;; MSG SIZE  rcvd: 140

→ IP = 172.31.32.145

stream {
  upstream elasticache {
    server  172.31.32.145:6379;
  }

  server {
    listen 6379;
    proxy_pass elasticache;
  }
}
nginx -t 
systemctl restart nginx

Reference: https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/GettingStarted.ConnectToCacheNode.html

Testing:

Download the CLI: https://github.com/microsoftarchive/redis/releases/download/…

Extract, and open terminal:

C:\Users\trinhthihaiyen\Downloads\Redis-x64-3.0.504>redis-cli.exe -h 52.197.101.143 -p 6379
Could not connect to Redis at 52.197.101.143:6379: Unknown error
not connected> ^C
C:\Users\trinhthihaiyen\Downloads\Redis-x64-3.0.504>redis-cli.exe -h 52.197.101.143 -p 6379
52.197.101.143:6379> set a "hello"
OK
52.197.101.143:6379> get a
"hello"
52.197.101.143:6379>

File configure:

# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }

# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2;
#        listen       [::]:443 ssl http2;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers PROFILE=SYSTEM;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }

}

# update IP in the stream configuration to your IP
stream {
  upstream elasticache {
    server  172.31.32.145:6379;
  }

  server {
    listen 6379;
    proxy_pass elasticache;
  }

  upstream rds {
    server  172.31.5.49:5432;
  }

  server {
    listen 5432;
    proxy_pass rds;
  }
}

Reverse proxy for Elasticsearch

cd /etc/nginx/conf.d
nano es-proxy.conf

Add the following lines:

server {
    listen 443 ssl;
    server_name $host;
    rewrite ^/$ https://$host/_dashboards redirect;

    ssl_certificate           "ssl/server.crt";
      ssl_certificate_key       "ssl/server.key";

    #ssl on;
    ssl_session_cache  builtin:1000  shared:SSL:10m;
    ssl_protocols  TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;
    ssl_prefer_server_ciphers on;

    location ^~ /_dashboards {
        # Forward requests to Dashboards
        # proxy_pass https://vpc-workshop-domain-vpc-sanhsxgdhgmlm3ipovjzmbivse.us-east-1.es.amazonaws.com/_dashboards;
        proxy_pass https://<os_domain_url>/_dashboards;


        # Update cookie domain and path
        # proxy_cookie_domain vpc-workshop-domain-vpc-sanhsxgdhgmlm3ipovjzmbivse.us-east-1.es.amazonaws.com $host;
        proxy_cookie_domain <os_domain_url> $host;

        proxy_set_header Accept-Encoding "";
        sub_filter_types *;
        sub_filter DOMAIN_ENDPOINT $host;
        sub_filter_once off;

        # Response buffer settings
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
    }

    location ~ \/(log|sign|fav|forgot|change|saml|oauth2) {

        # Handle redirects to Dashboards
        # proxy_redirect https://vpc-workshop-domain-vpc-sanhsxgdhgmlm3ipovjzmbivse.us-east-1.es.amazonaws.com https://$host;
        proxy_redirect https://<os_domain_url> https://$host;
    }
}
  1. Use this command to restart NGINX.
$ sudo systemctl restart nginx.service

Testing:

Locate to the url:

https://<public-ip-of-reverse-proxy-instance>/_dashboards

You can now login and go to OpenSearch dashboard

Note:
AWS OpenSearch: tại Access policy, phần Domain access policy, Nếu sử dụng “Do not set domain level access policy” mà không thiết định JSON policy cho phần access control thì sẽ gặp lỗi

"{"Message":"User: anonymous is not authorized to perform: es:ESHttpGet"}"

khi truy cập OpenSearch Dashboards URL thông qua reverse proxy → Chọn ● Only use fine-grained access control

Reference: https://aws.amazon.com/premiumsupport/knowledge-center/opensearch-outside-vpc-nginx/

SG cho con NAT + reverse proxy:

You have to allow HTTP, HTTPS, SSH and PostgreSQL, Custom TCP port 6379 inbound traffic. Also, you have to allow HTTP and HTTPS traffic from your private subnets’ CIDR block.

Configure NAT Instance

sysctl -w net.ipv4.ip_forward=1
yum install iptables-services -y
/sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
service iptables save
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
systemctl start iptables
chkconfig iptables on

Reference: docs.aws.amazon.com/vpc/latest/userguide/VP..