Enabling SSL with Let’s Encrypt, NGINX and Docker

Recently, I read a lot of articles on how to enable ssl with certbot, nginx and docker, but all the methods I read did not work for me untill I found this methods listed below. Thanks to all the authories who wrote the articles in the references.

Steps

  • Setting up Nginx and Certbot on your host server
  • Obtaining an SSL Certificate on your hose server
  • Map your host letsencrypt folder to nginx in docker

Detail

Step 1 Setting up Nginx and Certbot on your host server

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx certbot nginx

Setting up Nginx

$ sudo vim /etc/nginx/sites-available/default

find the following line:

server_name localhost;

change to your domain name

server_name example.com www.example.com;

reload your nginx new configuration

$ sudo nginx -t
$ sudo service nginx reload

Step 2 Obtaining an SSL Certificate

$ sudo certbot --nginx -d example.com -d www.example.com

You need to configure your HTTPS settings according to certbot.

After you configure your HTTPS, stop the nginx

$ sudo service nginx stop

Step 3 Map your host letsencrypt folder to nginx in docker

You’d like to modify your nignx config file first.

server {
  listen 443 ssl http2;
  server_name app1;

  ssl_certificate /etc/letsencrypt/live/app1.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/app1.com/privkey.pem;

  # ... The rest of your NGINX configuration.
}

server {
  listen 80;
  server_name app1.com;
  return 301 https://$host$uri; # redirect http to https
}

Then you need to open 443 port and map folders to docker.

Here is a sample.

version: '2'
services:
   nginx:
    image: nginx:latest
    ports:
        - '80:80'
        - '443:443'  # don't forget to open 443 port
    volumes:
        - ./nginx:/etc/nginx/conf.d
        - ./logs/nginx:/var/log/nginx
        - ./wordpress:/var/www/html
        - /etc/letsencrypt:/etc/letsencrypt # you need to map this folder
        - /etc/ssl:/etc/ssl # you need to map this folder as well
    links:
        - wordpress
    restart: always
    container_name: qinjingfei_nginx

Conclusion

I knew this approach is not elegant, but it works.

References

如何免费的让网站启用HTTPS

How To Secure Nginx with Let’s Encrypt on Ubuntu 14.04

Enabling SSL with Let’s Encrypt, NGINX and Docker

stackoverflow

apache 换成 nginx

https://www.howtoforge.com/tutorial/dockerizing-wordpress-with-nginx-and-php-fpm/

之前在DO的VPS上搭建的博客(LAMP),如果不开swap space 有时会因为内存不过杀掉mysql,导致网站无法打开。虽然最近打开了swap space, 情况大幅度好转,但从网上看到说nginx比apache 省内存。所以,动手试试:). 这篇文章根据网上教程写的(链接在最上面), 内容非原创. 因为,网上已经有教程了。所以,我也就只把配置文件贴出来就好了,具体请看教程.

docker-compose.yml

version: '2'

services:

   nginx:
    image: nginx:latest
    ports:
        - '80:80'
    volumes:
        - ./nginx:/etc/nginx/conf.d
        - ./logs/nginx:/var/log/nginx
        - ./wordpress:/var/www/html
    links:
        - wordpress
    restart: always

   db:
     image: mariadb:latest
     ports:
       - '3306:3306'
     volumes:
       - ./db-data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: qinjingfei
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
     container_name: qinjingfei_db

   wordpress:
     depends_on:
       - db
     image: wordpress:4.7.1-php7.0-fpm
     volumes:
       - ./wordpress:/var/www/html
     restart: always
     ports:
       - "9000:9000"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
     container_name: qinjingfei_wp

效果:比apache省100MB内存

安装mysql

mysql

安装

docker pull mysql:latest
latest: Pulling from library/mysql
Digest: sha256:96edf37370df96d2a4ee1715cc5c7820a0ec6286551a927981ed50f0273d9b43
Status: Image is up to date for mysql:latest

现在运行mysql服务器

$ docker run  -d --name=test-mysql --env="MYSQL_ROOT_PASSWORD=mypassword" mysql

docker inspect test-mysql 来查看ip地址和端口

现在用mysql客户端连接服务器

$ mysql -uroot -pqinjingfei -h 172.17.0.2 -P 3306
  • -u

user

  • -p

password

  • -P

port

  • -h

host

基本命令

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)


mysql> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+---------------------------+
| Tables_in_mysql           |
+---------------------------+
| columns_priv              |
| db                        |
| engine_cost               |
| event                     |
| func                      |
| general_log               |
| gtid_executed             |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| innodb_index_stats        |
| innodb_table_stats        |
| ndb_binlog_index          |
| plugin                    |
| proc                      |
| procs_priv                |
| proxies_priv              |
| server_cost               |
| servers                   |
| slave_master_info         |
| slave_relay_log_info      |
| slave_worker_info         |
| slow_log                  |
| tables_priv               |
| time_zone                 |
| time_zone_leap_second     |
| time_zone_name            |
| time_zone_transition      |
| time_zone_transition_type |
| user                      |
+---------------------------+
31 rows in set (0.01 sec)

mysql> select * from db;
...

PHP

PHP 是什么

PHP(“Hypertext Preprocessor”, 超文本预处理器)是一种被广泛应用的开放源代码的多用途脚本语言。

PHP能做什么

  • 收集表单数据
  • 生成动态网页
  • 发送/接受cookies

安装

sudo apt install php php-mysql

用PHP 连接 mysql

demo.php

<?php
        $dbhost = '172.17.0.2:3306';
        $dbuser = 'root';
        $dbpass = 'mypassword';
        $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
        if(! $conn ) {
           die('Could not connect: ' . mysql_error());
        }
        echo 'Connected successfully';
        mysqli_close($conn);
?>

执行

$ php demo.php
Connected successfully⏎   

使用VPS搭建自己的WordPress

准备

  • 一个运行linux的VPS
  • 一个 non-root 用户
  • 域名

租用VPS

  • 请自己google

下面的图片是我刚创建的vps

申请域名

域名申请

  • 略过(请Google)

我自己用的是namecheap

配备域名解析

Digital Ocean

Namecheap

-配置成功的话后,打开terminal, ping 自己的域名


现在,你就成功的将你的网址解析到你的ip地址了。

用Docker 来搭建wordpress

第一步 安装Docker

Ubuntu

$ sudo apt install docker docker.io

第二步 测试Docker是否安装成功(可略过)

$ sudo docker run hello-world

第三部 安装后的配置

  • 安装docker-compse
$ sudo -i
$ curl -L https://github.com/docker/compose/releases/download/1.13.0/docker-compose-Linux-x86_64 > /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose

  • 开机重启docker
$ sudo systemctl enable docker

  • Non-root access

如果,你没有创建普通用户的话。执行下面的命令

# adduser jing
# usermod -aG sudo jing

如果,你有普通用户,请执行下面的命令

$ sudo groupadd docker      # 创建docker组
$ sudo usermod -aG docker jing  # 把user加入到docker组

第四步 用LAMP来测试Docker

  • 什么是LAMP
    • Linux
    • Apache
    • MySQL
    • PHP/Python/Perl

    在non-root 用户执行下面的指令

    $ mkdir $HOME/apache && cd $HOME/apache
    $ printf '<?php\n  phpinfo(); \n?>' > info.php
    $ docker run -d --name=apache -p 8080:80 -v $HOME/apache:/var/www/html php:apache
    
    

docker run

  • 创建和开始一个容器

-d

  • “detach” from it, 跟我们连ssh和tmux 一样

--name=apache

  • 给容器一个名字apache

-p 8080:80

  • 把本机的端口8080和容器的端口80连在一起

-v $HOME/apache:/var/www/html

  • map 以上的文件夹
  • $HOME/apache 的文件map到 /var/www/html

现在你可以看到容器在运行

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                  NAMES
d1fbdb7e0c5f        php:apache          "docker-php-entryp..."   3 seconds ago       Up 3 seconds        0.0.0.0:8080->80/tcp   apache

现在,你应该可以访问http://YOUR-SERVER-IP:8080/info.php

现在关掉并且删掉容器

$ docker stop apache
$ docker rm apache
$ docker rmi php:apache

第五步 搭建wordpress

$ mkdir wp_test && cd wp_test # 创建文件夹

创建docker-compose.yml

version: '2'

services:
   db:
     image: mariadb:latest
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: somewordpress
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
     container_name: wp_test_db

   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     volumes:
       -db_app:/var/www/html
     ports:
       - "8080:80"
     restart: always
     environment:
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
     container_name: wp_test

mariadb 比mysql 省内存
第一次运行容器

$ docker-compose up -d

docker ps 查看容器

$ docker ps
20570a5eb798        wordpress:latest    "docker-entrypoint..."   3 seconds ago       Up 2 seconds        0.0.0.0:8080->80/tcp   wp_test
c1872cb1443d        mysql:5.7           "docker-entrypoint..."   3 seconds ago       Up 3 seconds        3306/tcp               wp_test_db

http://YOUR-SERVER-IP:8080 安装WordPress, 用docker-compose down停止运行容器

在安装完WordPress后,你就可以用http://YOUR-SERVER-IP:8080 访问你的WordPress网站了。

Docker 教程系列 二

使用Dockerfile 定制镜像

  • Dockerfile

镜像的定制实际上是定制每一层所添加的配置、文件。我们可以吧每一层修改、安装、构建、操作的命令写在一个脚本,用这个脚本来构建、定制镜像。 这个脚本叫做Dockerfile。

$ mkdir mynginx
$ cd mynginx
$ touch Dockerfile

Dockerfile 内容

FROM nginx
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html

FROM 指定基础镜像

所谓定制镜像,那一定是以一个基础镜像为基础,在其上定制。

FROM 就是制订基础镜像

在Dockerfile中FROM 是必备的指令,并且是第一个指令。

FROM scratch # 空白镜像
...

RUN 执行指令

  • shell格式: RUN <命令>
RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.htm
  • exec 格式: RUN [“可执行文件”,“参数1”,“参数2”]

错误的写法

FROM debian:jessie

RUN apt-get update
RUN apt-get install -y gcc libc6-dev make
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"
RUN mkdir -p /usr/src/redis
RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1
RUN make -C /usr/src/redis
RUN make -C /usr/src/redis install

Dockerfile 中每一个指令都会建立一层

上面的写法创建了7层镜像

正确的写法

FROM debian:jessie

RUN buildDeps='gcc libc6-dev make' \
    && apt-get update \
    && apt-get install -y $buildDeps \
    && wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \
    && mkdir -p /usr/src/redis \
    && tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \
    && make -C /usr/src/redis \
    && make -C /usr/src/redis install \
    && rm -rf /var/lib/apt/lists/* \
    && rm redis.tar.gz \
    && rm -r /usr/src/redis \
    && apt-get purge -y --auto-remove $buildDeps

&&将各个所需命令串联起来,将7层,简化为1层。

\换行

#注释

构建镜像

Dockerfile 文件所在目录执行:

$ docker build -t nginx:v3 .
Step 1/2 : FROM nginx
 ---> b8efb18f159b
Step 2/2 : RUN echo '<h1>Hello, Docker!</h1>' > /usr/share/nginx/html/index.html
 ---> Running in 23d1b8a55e02
 ---> 2c1c0dc5e64e
Removing intermediate container 23d1b8a55e02
Successfully built 2c1c0dc5e64e
Successfully tagged nginx:v3

RUN指令启动了一个容器23d1b8a55e02,执行命令,并提交了最后一层2c1c0dc5e64e, 随后删掉了23d1b8a55e02

dokcer build指令

docker build [选项] <上下文路径/URL/->
  • -t

tag list — Name and optionally a tag in the name:tag format

其它docker build 的用法

直接用Git repo

$ docker build https://github.com/twang2218/gitlab-ce-zh.git#:8.14

用tar压缩包构建

$ docker build http://server/context.tar.gz

从标准输入中读取 Dockerfile 进行构建

$ docker build - < Dockerfile

从标准输入中读取上下文压缩包进行构建

$ docker build - < context.tar.gz

Docker 教程系列 一

介绍

准备

在学习docker之前,你应该对这些概念熟悉:

  • IP Addresses and Ports
  • Virtual Machines
  • Editing configuration files
  • Basic familiarity with the ideas of code dependencies and building
  • Machine resource usage terms, like CPU percentages, RAM use in bytes, etc.
容器
  • 镜像

An image is a lightweight, stand-alone, executable package that includes everything needed to run a piece of software, including the code, a runtime, libraries, environment variables, and config files.

跟虚拟机中的镜像概念相同

  • 容器

A container is a runtime instance of an image—what the image becomes in memory when actually executed. It runs completely isolated from the host environment by default, only accessing host files and ports if configured to do so.

安装Docker

Ubuntu

sudo apt install docker docker.io 

Mac

下载安装包

https://docs.docker.com/docker-for-mac/install/

打开docker app

安装 docker 二进制文件

brew install docker

测试是否安装成功

$ docker info
containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 17.06.0-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host ipvlan macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: cfb82a876ecc11b5ca0977d1733adbe58599088a
runc version: 2d41c047c83e09a6d61d464906feb2a2f3c52aa4
init version: 949e6fa
Security Options:
 seccomp
  Profile: default
Kernel Version: 4.9.36-moby
Operating System: Alpine Linux v3.5
OSType: linux
Architecture: x86_64
CPUs: 2
Total Memory: 1.952GiB
Name: moby
ID: 7TJ4:K4SP:PRQR:UP3P:EDRA:V5X7:6EFS:DSIT:FGTI:U4HI:QDUY:GDQL
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): true
 File Descriptors: 17
 Goroutines: 28
 System Time: 2017-08-18T00:29:23.364592786Z
 EventsListeners: 1
Registry: https://index.docker.io/v1/
Experimental: true
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

如果以上都正常的话,可以运行一个Nginx服务器:

$ docker run -d -p 80:80 --name webserver nginx
  • -d

detach — Run container in background and print container ID

跟ssh和tmux的detach 一样

  • -p

publish list — Publish all exposed ports to the host

感觉跟virtualbox里的portforwarding 很像, 不太确定

跟ngrok里的很像

  • --name webserver

把这个容器命名为webserver

如果成功的话,会显示以下的画面

要停止Nginx服务器并且删除

$ docker stop webserver
$ docker rm webserver