🐳 如何使用 Nginx 将静态网站容器化,通过 Certbot 自动续订域名 SSL 证书,并将其部署到 DigitalOcean?
介绍
欢迎回来,朋友们!👋 我们今天的议程非常重大……但别担心,它会很有趣,也很有启发性!
📌本文目标:
- 快速了解 Docker Compose(不“深入”,但接近了);
- 配置 Nginx、Certbot 和前端的 Docker 容器;
- 编写简单的静态网站(使用
Parcel.js打包工具); - 将完成的项目推送到git仓库;
- 将项目部署到DigitalOcean服务器;
毫不谦虚地说,我建议您将这篇文章添加到您的书签中,因为您在其他任何地方都找不到如此详细的部署过程描述。
……我们开始!🔥
什么是 Docker Compose?
请遵循 Docker 官方文档:
Compose 是一个用于定义和运行多容器 Docker 应用程序的工具。使用 Compose,您可以通过 YAML 文件配置应用程序的服务。然后,只需一条命令,即可根据配置创建并启动所有服务。
特征:
- 单个主机上的多个独立环境;
- 创建容器时保留卷数据;
- 仅重新创建已更改的容器;
- 变量以及在不同环境之间移动作品;
它是如何运作的?🙄
- 使用以下方式定义应用程序的环境
Dockerfile: - 明确定义构成应用程序的各项服务
docker-compose.yml,以便它们能够在隔离的环境中一起运行; - 运行
docker-compose up和组合功能会启动并运行您的整个应用程序;
项目结构
$ tree .
.
├── .editorconfig
├── .gitignore
├── .prettierignore
├── Makefile
├── docker-compose.prod.yml
├── docker-compose.yml
├── frontend
│ ├── .dockerignore
│ ├── Dockerfile
│ ├── package.json
│ └── src
│ ├── common
│ │ ├── robots.txt
│ │ └── sitemap.xml
│ ├── css
│ │ ├── reset.css
│ │ └── style.css
│ ├── html
│ │ └── index.html
│ ├── images
│ │ └── logo.png
│ └── js
│ └── index.js
└── webserver
├── nginx
│ ├── default.conf
│ ├── nginx.conf
│ └── site.com.conf
└── register_ssl.sh
没时间看文章,但又想马上找到答案?🤔
没问题!我特意在我的 GitHub 上创建了一个仓库,其中包含了本文将要讨论的项目结构:
koddr / example-static-website-docker-nginx-certbot
使用 Docker、Nginx 和 Certbot 的示例静态网站
只需git clone阅读说明即可README。
Docker Compose 配置
我们来看一下docker-compose.yml这个文件。这是主文件,其中包含容器的基本配置:
# ./docker-compose.yml
version: "3.7"
services:
nginx:
container_name: nginx
image: nginx:alpine
networks:
- nginx_net
volumes: # 💡
- ./webserver/nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./webserver/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./webserver/certbot/conf:/etc/letsencrypt
- ./webserver/certbot/www:/var/www/certbot
ports:
- 80:80
restart: unless-stopped
command: /bin/sh -c "while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g 'daemon off;'" # 💡
certbot:
container_name: certbot
image: certbot/certbot
networks:
- nginx_net
volumes:
- ./webserver/certbot/conf:/etc/letsencrypt
- ./webserver/certbot/www:/var/www/certbot
restart: unless-stopped
entrypoint: /bin/sh -c "trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;" # 💡
depends_on:
- nginx
networks:
nginx_net:
name: nginx_net
💡了解这一点很有用:
- 指令中的项目
volumes应按如下方式编写:
<local dir|file>:<container dir|file>
例如,./webserver/nginx/nginx.conf:/etc/nginx/nginx.conf意思是:将nginx.conf文件从本地文件夹复制./webserver/nginx到容器文件夹/etc/nginx。
如果要复制包含所有文件的文件夹,只需指定卷,如下所示:
./my-project/folder:/var/www/folder
command容器指令nginx帮助我们每 6 小时重启一次 Nginx,并下载新的 SSL 证书(如果有的话);entrypoint容器指令certbot帮助我们每 12 小时检查一次是否需要新的 SSL 证书;
生产环境配置
好的!是时候docker-compose.prod.yml👌了
这是一个覆盖生产环境的文件(可能存储在不同的 git 仓库中或由不同的团队管理)[...] 运行时
docker-compose up会自动读取覆盖文件。
# ./docker-compose.prod.yml
version: "3.7"
services:
frontend:
container_name: frontend
build:
context: ./frontend
volumes:
- static:/frontend/build
nginx:
volumes:
- static:/usr/share/nginx/html # 💡
- ./webserver/nginx/default.conf:/etc/nginx/conf.d/default.conf
- ./webserver/nginx/site.com.conf:/etc/nginx/sites-enabled/site.com.conf # ⚠️
- ./webserver/nginx/nginx.conf:/etc/nginx/nginx.conf
- ./webserver/certbot/conf:/etc/letsencrypt
- ./webserver/certbot/www:/var/www/certbot
ports:
- 80:80
- 443:443
depends_on:
- frontend # 💡
volumes:
static:
💡了解这一点很有用:
- 我们已将所有构建文件放入其中
/usr/share/nginx/html/,但您可以选择容器上的任何文件夹; - 最佳实践是在构建完所有前端文件后启动 Nginx,因此我们设置了
depends_on一个指令,指定要等待创建的容器名称;
⚠️别忘了:
- 改为
site.com您的域名(或项目名称);
Nginx 和 Certbot
$ tree ./webserver
.
├── nginx
│ ├── default.conf
│ ├── nginx.conf
│ └── site.com.conf
└── register_ssl.sh
获取和更新 SSL 证书的脚本(register_ssl.sh)最有意思。不过,我把它留给你们自己研究(作为作业)。
为了更好地理解,我将 Nginx 配置分为三个文件:main(nginx.conf)、get SSL(default.conf)和生产域(site.com.conf)。
为了避免文章篇幅过长,我建议您只阅读最后两个配置。Nginx 主配置请参见此处。
- 配置获取 SSL 证书并将 HTTP 重定向到 HTTPS(
default.conf):
# ./webserver/nginx/default.conf
# Config for get SSL and redirect to HTTPS
server {
listen 80;
server_name .site.com;
# Allow only for register SSL (Certbot)
location ^~ /.well-known/acme-challenge { root /var/www/certbot; }
# Redirect to HTTPS
location / { return 301 https://site.com$request_uri; }
}
- 生产域的配置(
site.com.conf):
# ./webserver/nginx/site.com.conf
# Redirect to non-WWW
server {
listen 443 ssl http2;
server_name www.site.com;
# SSL
ssl_certificate /etc/letsencrypt/live/site.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/site.com/privkey.pem;
# Additional Nginx options
include /etc/letsencrypt/options-ssl-nginx.conf;
# Diffie-Hellman parameter for DHE ciphersuites
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# Redirect to HTTPS
location / { return 301 https://site.com$request_uri; }
}
# Config for HTTPS
server {
listen 443 ssl http2;
server_name site.com;
# Root & index.html
root /usr/share/nginx/html;
index index.html;
# SSL
ssl_certificate /etc/letsencrypt/live/site.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/site.com/privkey.pem;
# Additional Nginx options
include /etc/letsencrypt/options-ssl-nginx.conf;
# Diffie-Hellman parameter for DHE ciphersuites
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# 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 'self' http: https: data: blob: 'unsafe-inline'" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# dot files
location ~ /\.(?!well-known) { deny all; }
# SEO files
location = /robots.txt { log_not_found off; }
location = /sitemap.xml { log_not_found off; }
location = /favicon.ico { log_not_found off; }
# Assets, media
location ~* \.(?:css(\.map)?|js(\.map)?|jpe?g|png|gif|ico|cur|heic|webp|tiff?|mp3|m4a|aac|ogg|midi?|wav|mp4|mov|webm|mpe?g|avi|ogv|flv|wmv)$ {
expires 7d;
}
# SVG, fonts
location ~* \.(?:svgz?|ttf|ttc|otf|eot|woff2?)$ {
add_header Access-Control-Allow-Origin "*";
expires 7d;
}
# Frontend files
location / {
try_files $uri $uri/ /index.html;
}
}
⚠️别忘了:
- 更改
site.com为您的域名;
前端(静态网站)
$ tree ./frontend
.
├── .dockerignore
├── Dockerfile
├── package.json
└── src
├── common
│ ├── robots.txt
│ └── sitemap.xml
├── css
│ ├── reset.css
│ └── style.css
├── html
│ └── index.html
├── images
│ └── logo.png
└── js
└── index.js
让我们更详细地探讨一些文件。
- 要从容器中排除的忽略文件和文件夹列表(
.dockerignore):
# ./frontend/.dockerignore
# Files
.dockerignore
Dockerfile
*.log
# Folders
.cache/
node_modules/
build/
- Docker 容器指令(
Dockerfile):
# ./frontend/Dockerfile
FROM node:alpine
LABEL maintainer="Your Name"
WORKDIR /frontend
COPY package*.json ./
RUN npm install --only=production
COPY . .
RUN npm run build:prod
- 最后,Node.js 指令和依赖项(
package.json):
// ./frontend/package.json
{
"name": "frontend",
"version": "1.0.0",
"description": "Your project description.",
"main": "./src/js/index.js",
"scripts": {
"build": "parcel build ./src/html/*.html -d ./build",
"copy": "cp -R ./src/common/* ./build", // 💡
"build:prod": "npm run build && npm run copy"
},
"author": "Your Name",
"dependencies": {
"parcel-bundler": "^1.12.4"
}
}
💡了解这一点很有用:
copy该命令帮助我们将文件(这些文件不会包含在最终的软件包中,但也很重要)从文件夹复制./src/common到./build目标文件夹;
将项目推送到 Git
将代码存储在版本控制系统 (VCS) 中被认为是一种良好的做法,例如 GitHub/Bitbucket 等版本控制系统,或者您自己的版本控制系统,例如Gitea。
因此,遵循以上最佳实践:
✅ 在版本控制系统中创建代码仓库;
✅ 将所有更改添加到提交中;
✅ 将提交推送到代码仓库;
部署到 DigitalOcean
- 登录您的 DO 帐户;
还没有账号?通过我的推荐链接加入 DigitalOcean 吧(你赚100 美元,我赚 25 美元)。这是我给你的奖励!😉
- 点击顶部的绿色按钮“创建”,然后选择“水滴”:
- 选择“市场”选项卡,然后选择“ Docker ”:
- 向下滚动,选择方案、存储、附加选项和数据中心区域(根据您的意愿选择任意区域);
- 好的,滚动到“身份验证”部分,然后单击“新建 SSH 密钥”:
☝️提示:我建议为每个新服务器创建一个新的 SSH 密钥,因为这样比所有服务器使用同一个密钥更安全!
- 按照右侧说明操作,生成新的 SSH 密钥并填写表格:
- 重新检查 Droplet 的选项,然后点击底部的“创建 Droplet ”👍
- 接下来,转到“ Droplets ”列表并添加您的域名:
- 输入域名并选择服务器:
- 为域名添加两条“ A ”记录(“ @ ”和“ www ”):
- 通过 SSH 连接到您的服务器:
$ ssh root@<droplet IP>
- 克隆你的仓库并进入项目文件夹:
$ git clone https://github.com/user/project-name.git
$ cd project-name
- 请通过启动获取 SSL 证书的过程来检查 Certbot 的配置
test mode:
$ make certbot-test DOMAINS="site.com www.site.com" EMAIL=mail@site.com
DOMAINS请使用您的域名(WWW 和非 WWW)指定变量。
- 如果看到
Congratulations!以下内容,请开始获取 SSL 证书的流程production mode:
$ make certbot-prod DOMAINS="site.com www.site.com" EMAIL=mail@site.com
- 现在,检查 Nginx 和前端配置:
$ make deploy-test
- 控制台没有错误?您的静态网站已准备好上线:
$ make deploy-prod
搞定!我们已经用 Nginx 和 Certbot 构建了容器化的静态网站,并部署到了 DigitalOcean!🎉
照片由
[标题] chuttersnap https://unsplash.com/photos/9cCeS9Sg6nU
[1] Jeffrey Blum https://unsplash.com/photos/FQ06bmigBqg
[2] John Barkiple https://unsplash.com/photos/l090uFWoPaI
PS
如果你想在这个博客上看到更多类似的文章,请在下方留言并订阅我。谢谢!😻
❗️您可以通过Boosty平台支持我,既可以长期支持,也可以一次性支持。所有收益都将用于支持我的开源软件项目,并激励我为社区创作新的产品和文章。
当然,您也可以帮助我让开发者的工作变得更好!只需以贡献者的身份加入我的项目即可。很简单!
我最需要你帮助(和点赞)的项目👇
- 🔥 gowebly:一款新一代 CLI 工具,可轻松使用 Go 在后端创建出色的 Web 应用程序,使用 htmx、hyperscript 或 Alpine.js 以及最流行的 CSS 框架在前端进行开发。
- ✨ create-go-app:通过运行一条 CLI 命令,创建一个包含 Go 后端、前端和部署自动化功能的新生产就绪项目。
我的其他一些小项目:yatr、gosl、json2csv、csv2api。
文章来源:https://dev.to/koddr/how-to-dockerize-your-static-website-with-nginx-automatic-renew-ssl-for-domain-by-certbot-and-deploy-it-to-digitalocean-4cjc








