Docker connect from a container to a service on the host

如何從 Docker 容器連到本機的 host port

情境

SSH Tunnel 連至遠端伺服器 (localhost:8888 -> remote:3306)

想透過 docker 啟動的 web service (LNMP) 操作 adminer/phpmyadmin 連至遠端的資料庫。

原本想更改 docker network mode 為 host , 讓容器直接使用同一張網卡,但 windows 和 Mac 環境不支援 (只支援 Linux),查了好久終於找到解法。

https://docs.docker.com/docker-for-windows/networking/#use-cases-and-workarounds

The host has a changing IP address (or none if you have no network access). From 18.03 onwards our recommendation is to connect to the special DNS name host.docker.internal, which resolves to the internal IP address used by the host. This is for development purpose and will not work in a production environment outside of Docker Desktop for Windows.

The gateway is also reachable as gateway.docker.internal.

解法

使用 host.docker.internal:8888

How to Deep Clone an Array in JavaScript

let array_A = [
    {'id': 1, 'type': true},
    {'id': 2, 'type': false},
    {'id': 3, 'type': true},
    {'id': 4, 'type': false},
    {'id': 5, 'type': true},
];

// Deep clone

    // 方法一: jQuery (若有使用 jQuery 可考慮)
        // let array_B = $.extend(true, {}, array_A);

        // Convert object to array
        // array_B = Object.values(array_B);

    // 方法二: JSON.parse(JSON.stringify())
    //         (純資料,可行;若遇 Function、Set、Map..等型態,失效)
        // let array_B = JSON.parse(JSON.stringify(array_A));

    // 方法三: 使用 lodash (library)
        // let array_B = _.cloneDeep(array_A);

    // 方法四: 國外網友提供的遞迴方法,感覺很不錯
        const clone = (items) => items.map(item => Array.isArray(item) ? clone(item) : {...item});
        let array_B = clone(array_A);

// Select type is true
array_B = array_B.filter( number => number.type );

// Set type to false
array_B.map( number => number.type = false );

console.log(array_A);
console.log(array_B);

https://dev.to/samanthaming/how-to-deep-clone-an-array-in-javascript-3cig

https://kanboo.github.io/2018/01/27/JS-ShallowCopy-DeepCopy/

AMP (Accelerated Mobile Pages)

<!doctype html>
<html amp lang="en">
<head>
    <meta charset="utf-8">
    <script async src="https://cdn.ampproject.org/v0.js"></script>
    <title>Hello, AMPs</title>
    <link rel="canonical" href="https://amp.dev/documentation/guides-and-tutorials/start/create/basic_markup/">
    <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1">
    <script type="application/ld+json">
        { "@context": "http://schema.org", "@type": "NewsArticle", "headline": "Open-source framework for publishing content", "datePublished": "2015-10-07T12:02:41Z", "image": [ "logo.jpg" ] }
    </script>
    <style amp-boilerplate>
        body {
            -webkit-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
            -moz-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
            -ms-animation: -amp-start 8s steps(1, end) 0s 1 normal both;
            animation: -amp-start 8s steps(1, end) 0s 1 normal both
        }

        @-webkit-keyframes -amp-start {
            from {
                visibility: hidden
            }
            to {
                visibility: visible
            }
        }

        @-moz-keyframes -amp-start {
            from {
                visibility: hidden
            }
            to {
                visibility: visible
            }
        }

        @-ms-keyframes -amp-start {
            from {
                visibility: hidden
            }
            to {
                visibility: visible
            }
        }

        @-o-keyframes -amp-start {
            from {
                visibility: hidden
            }
            to {
                visibility: visible
            }
        }

        @keyframes -amp-start {
            from {
                visibility: hidden
            }
            to {
                visibility: visible
            }
        }
    </style>
    <noscript>
        <style amp-boilerplate>
            body {
                -webkit-animation: none;
                -moz-animation: none;
                -ms-animation: none;
                animation: none
            }
        </style>
    </noscript>
</head>
<body>
    <h1>Welcome to the mobile web</h1>
    <script async custom-element="amp-analytics" src="https://cdn.ampproject.org/v0/amp-analytics-0.1.js"></script>
    <amp-analytics type="googleanalytics" id="analytics">
        <script type="application/json">
        {
            "vars": {
                "account": "UA-XXXXXXXX-Y"
            },
            "triggers": {
                "trackPageviewWithAmpdocUrl": {
                    "on": "visible",
                    "request": "pageview",
                    "vars": {
                        "title": "TITLE",
                        "ampdocUrl": "CANONICAL_URL"
                    }
                }
            }
        }
        </script>
    </amp-analytics>
</body>
</html>

https://amp.dev/documentation/guides-and-tutorials/start/create/basic_markup/

https://github.com/ampproject/amphtml/blob/master/spec/amp-var-substitutions.md

Nginx Config

nginx.conf
user nginx;
pid /var/run/nginx.pid;
worker_processes auto;
worker_rlimit_nofile 65535;

events {
    use epoll;
    multi_accept on;
    worker_connections 65535;
}

http {
    # DDoS Defense
    limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m;
    limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;
    limit_conn_status 429;
    limit_req_status 429;

    client_body_buffer_size  128k;
    client_header_buffer_size 3m;
    large_client_header_buffers 4 256k;
    client_body_timeout   5;
    client_header_timeout 5;

    reset_timedout_connection on;
    send_timeout 5;
    keepalive_timeout 5 5;
    keepalive_requests 100000;

    charset utf-8;
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    server_tokens off;
    log_not_found off;
    types_hash_max_size 2048;
    client_max_body_size 100M;

    # MIME
    include mime.types;
    default_type application/octet-stream;

    # logging
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log warn;

    # load configs
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*.conf;
}
default.conf
server {
    listen 80 default_server;
    server_name _;
    return 444; #Nginx No Response
}
general.conf
# security headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Content-Security-Policy "default-src * data: 'unsafe-eval' 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# . files
location ~ /\.(?!well-known) {
    deny all;
}
nginx/sites-available/your_domain_name.conf
server {
    listen 80;
    server_name www.domain.com;
    return 301 https://domain.com$request_uri;
}

server {
    listen 80;
    server_name domain.com;

    root /var/www/html/domain/public;

    if ($http_x_forwarded_proto = "http") {
        return 301 https://$server_name$request_uri;
    }

    index index.html index.htm index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri = 404;
        fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        include fastcgi_params;
        limit_conn conn_limit_per_ip 10;
        limit_req zone=req_limit_per_ip burst=10 nodelay;
    }

    include general.conf;
}