I recently bought a NAS, and I don’t want to be limited to using it on the Intranet. I need to map my NAS to the public network. After analyzing various technical solutions, NAT penetration was selected according to the actual conditions, hence this article, which is for the record and to share your own implementation steps for those who may encounter the same type of requirements.

Intranet → Public Network

Before explaining this mapping process, we need to know what NAT is. In the 1980s, when people were designing network addresses, they did not consider the situation of 2 32 power terminal devices connecting to the Internet, and the computing, storage and transmission costs of increasing IP length (even from 4 bytes to 6 bytes) for the devices at that time were quite huge. Network Address Translation (NAT) is born when IP addresses are insufficient. The essence of NAT is that a group of machines share a public IP Address, that is, the requests sent by Intranet machines are translated into public IP addresses through NAT to hide the Intranet IP addresses. The response of the public network is mapped to the corresponding machine through NAT.

DDNS + Port mapping

The Dynamic Domain Name Server (DDNS) maps a user’s Dynamic IP address to a fixed Domain Name resolution service. Each time a user connects to the network, the client program sends the Dynamic IP address to the Server program on the host of the service provider. DDNS can ensure the correct pointing of domain names in the context that most home networks use dynamic IP addresses. Port mapping with DDNS can map services on Intranet machines.

NAT penetration

The principle of NAT penetration to expose services is different from that of DDNS+ port mapping. The prerequisite for NAT penetration is to deploy the Server on the Server that has a public IP address and the Client on the Server that needs to be exposed. After startup, the Client completes identity authentication and establishes a tunnel with the Server. Then the user access behavior is first transmitted to the Server. The Server allocates the corresponding Client according to the registration information of the Client during startup, and the Client transmits the response to the Server. The Server returns the Client response to the user. The whole invocation link is similar to a reverse proxy.

Ngrok

Ngrok is a specific implementation application of NAT penetration. The official website describes Ngrok as follows: Ngrok is a reverse proxy that creates a secure tunnel from a public endpoint to a locally running web service. ngrok captures and analyzes all traffic over the tunnel for later inspection and replay. Ngrok is a reverse proxy that can create a secure channel from a public network endpoint to a local Web service. Ngrok captures and analyzes all traffic passing through the tunnel for later inspection and replay.

The operation sequence diagram of Ngrok is as follows:

Set up process

Because the overall Ngrok server/client setup is cumbersome, the environment involved includes Go, Git, and make. In order to simplify the construction operation and ensure the consistency of the environment in multi-machine deployment, Docker was used to build the overall server and client.

The service side

At present, the server is deployed on Aliyun ECS and the system is CentOS 7.x. Dockerfile is as follows:

## Build based on the Golang-alpine image
FROM golang:alpine  

## Set Ngrok server domain name parameters
ARG DOMAIN_NAME   

Openssl make git
Clone Ngrok source code to git after installation
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories && \
    apk add --no-cache openssl make git && \
    cd / && \
    mkdir data && \
    cd data && \
    git clone https://github.com/inconshreveable/ngrok.git source

## Add Ngrok compile build script to image
ADD build.sh /data

WORKDIR /data

## Call the compiled build script
RUN sh build.sh $DOMAIN_NAME && \
    export PATH=$PATH:/data/source/bin

VOLUME ["/data"]

## Expose the Ngrok channel listening address
EXPOSE 4443

## Start Ngrok server
CMD ["/data/source/bin/ngrokd"]
Copy the code

build.sh

export NGROK_DOMAIN="$0"

cd /data/source

## Generate SSL certificate based on incoming Ngrok domain nameexport NGROK_DOMAIN="$DOMAIN_NAME" && \ openssl genrsa -out rootCA.key 2048 && \ openssl req -x509 -new -nodes -key rootCA.key -subj "/CN=$NGROK_DOMAIN" -days 5000 -out rootCA.pem && \ openssl genrsa -out device.key 2048 && \ openssl req -new -key device.key -subj "/CN=$NGROK_DOMAIN" -out device.csr && \ openssl x509 -req -in device.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out device.crt -days 5000 && \ cp -f rootCA.pem assets/client/tls/ngrokroot.crt && \ cp -f device.crt assets/server/tls/snakeoil.crt && \ cp -f device.key assets/server/tls/snakeoil.key echo "ready to make  server ->"
## build ngrok-server
make release-server

## compile ngrok-client
echo "ready to make client ->"
GOOS=linux GOARCH=amd64 make release-client
Copy the code

Ngrok supports the construction of multi-platform clients through the GOOS and GOARCH parameters. By default, the linux-AMD64 client is built. You can modify build.sh if you need to build clients of other platforms. The corresponding chart is as follows:

GOOS GOARCH platform
linux 386 Linux 32-bit system
linux amd64 Linux 64-bit system
windows 386 Windows 32-bit system
windows amd64 Windows 64-bit system
darwin 386 Macos 32-bit system
darwin amd64 Macos 64-bit system
linux arm Arm architecture Linux system

Docker build –tag [your image name: version] –build-arg DOMAIN_NAME=[your domain name] Build the image.

I used Docker-compose to start the image after the build was complete. Docker – compose. Yml as follows:

version: "3.1"

services:

   ngrok:
      image: shawjie/ngrok:latest ## Completed image
      command: "/data/source/bin/ ngrokd-domain ='[your domain name]' -httpaddr =':80'" # HTTP listener port
      ports:
         - "4443:4443"

## Before Ngrok there was an Nginx as a whole server gateway
## Configure Ngrok and Ngink in the same network environment
networks:
  default:
    external:
      name: bin_nginx_default
Copy the code

The configuration on Nginx is as follows

server { listen 80; server_name *.ngrok.xxx.com; Charset UTF-8; charset utF-8; location / { proxy_pass http://ngrok:80; Proxy_set_header x-real-ip $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; proxy_redirect off; }}Copy the code

At this point, the Server side configuration is complete. As for the client, you must first Copy the completed ngrok-client from the running image.

Docker cp [your container name]:/data/source/bin Then copy the corresponding client to the client based on your own system.

The client

The client is currently deployed on Synology 218+ DMS. Create a config.yml file in the same directory as ngrok-client to configure the ngrok-client connection to the server and related channel contents.

config.yml

server_addr: "ngrok.xxx.com:4443"  ## Your domain name: port number
trust_host_root_certs: false

tunnels:
   synology_nas:
      subdomain: nas  Remote_port = remote_port = remote_port = remote_port
      proto:
         http: 5000  ## Support HTTP TCP values for the corresponding address or port number
Copy the code

In order to facilitate the operation of the unified environment and convenient management, I still use Docker to deploy the client. First, the client runs on the basis of the image dockerfile:

FROM alpine:latest  ## Mirrors are built based on Alpine to reduce the image size

RUN cd /usr/local && \
    mkdir service

WORKDIR /usr/local/service

VOLUME ["/usr/local/service"]

Start the client configuration
CMD /usr/local/service/ngrok -config=config.yml -log=ngrok_access.log start-all
Copy the code

Then, links between volumes are established through Docker run to complete the construction and startup of the overall Ngrok server-client.

Docker run – name shawjie_ngrok_client – v/usr/local/data: / usr/local/service – net host – d [you build client-side image name]

At this point, you can directly access your Intranet services through the domain name.

The tail

Recently, I have been busy with my work. Because I have acquired a Nas and the router at home does not have public IP, the DDNS + port mapping scheme is not feasible, so I have to find another way. The author of nGROk2. x project does not intend to open source, but carries out commercial operation. But the simple function ngrok1. x has been able to fully cope with it. Ngrok can not only map my Nas out, but also complete many other things, such as wechat related development callback, or if you want to temporarily show an application to the outside, or even if you want to map SSH from the Intranet server through Ngrok. In a word, this function is completely limited to your imagination, tomorrow is my 22nd birthday, I will go to my birthday, I plan to finish an article before the end of this month, in a word… Come on.