前言
本文主要讲解服务器端如何修改SSH端口、密钥方式登录服务器,安装Docker环境,最主要是通过nginx代理其他容器,让docker容器能通过https的方式访问到。
准备
一台初始化的Ubuntu系统(24.04 64位)
一个备案好的域名
一个cloudflare账号
服务器配置
修改SSH端口号
连接服务器:
ssh root@you ip
修改端口,编辑sshd_config
文件:
vi /etc/ssh/sshd_config
输入 i 编辑,把#去掉,把22改为想要的端口,最后:wq保存:
Port 10024
用编辑器打开 /lib/systemd/system/ssh.socket
文件
sudo vim /lib/systemd/system/ssh.socket
将 ListenStream=22
中的 22 端口号修改为你刚才设置的端口号
ListenStream=10024
重启服务
sudo systemctl daemon-reload
sudo systemctl restart ssh.socket
免密登录
在本地电脑生成SSH Key,一直回车就可以:
ssh-keygen
在本地路径C:\Users\你的用户\.ssh下创建config
文件:
Host Test
Port #端口号
HostName #IP地址
User root
IdentityFile #本地id_rsa文件
IdentitiesOnly yes
服务器cd ~/.ssh/
目录,(一定要CD到这个目录,切勿直接在根目录直接使用下面命令,会导致这个文件不生效)编辑文件,到本地C:\Users\你的用户名\.ssh 找到公钥文件,把本地电脑的公钥文件id_rsa.pub
复制进去,:wq
保存:
vi authorized_keys
如果之前连接过服务器,格式化后再连接可能报错,可以先删除本地电脑这两个文件,这两个文件是历史连接的记录
至此,完成服务器的端口修改和使用密钥登录的操作
安装Docker和Compose插件
阿里云安装Docke文档:https://help.aliyun.com/zh/ecs/use-cases/install-and-use-docker-on-a-linux-ecs-instance
安装:
执行以下命令安装Docker社区版本:
#更新包管理工具
sudo apt-get update
#添加Docker软件包源
sudo apt-get -y install apt-transport-https ca-certificates curl software-properties-common
sudo curl -fsSL http://mirrors.cloud.aliyuncs.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository -y "deb [arch=$(dpkg --print-architecture)] http://mirrors.cloud.aliyuncs.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
#安装Docker社区版本,容器运行时containerd.io,以及Docker构建和Compose插件
sudo apt-get -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
#启动Docker
sudo systemctl start docker
#设置Docker守护进程在系统启动时自动启动
sudo systemctl enable docker
通过查看Docker版本命令,验证Docker是否安装成功。
sudo docker -v
通过这种方式已经安装了dockercompose插件,无需再独立安装,使用命令sudo docker compose version可以查看版本,docker compose up -d可以使用该指令安装compose 文件,中间不用加横杠
配置镜像源:
这里介绍的是 使用cloudflare代理docker站点,相当于自建docker镜像站,稳定快速。
注册登录
cloudflare
,选择Workers 和 Pages,这两个部署方式都是可以的;Pages方式:连接
github
仓库,选择github
仓库(Fork过来的开源仓库),直接开始默认设置就可以Workers :复制 _worker.js 代码,
保存并部署
即可修改文件
/etc/docker/daemon.json
(如果不存在则创建)
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://docker.fxxk.dedyn.io"] # 请替换为您自己的Worker自定义域名
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
安装acme&生成证书
安装acme
acme官网Github
:https://github.com/acmesh-official/acme.sh
安装:(这里一定要带上自己的邮箱,否则后面会报错,会有记录报错,需要多试几次)
curl https://get.acme.sh | sh -s email="[email protected]"
这个命令会安装acme并且创建了一个 cronjob
, 每天 0:00
点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书.
“
注意:安装好之后建议重新连接服务器,如果这个时候直接使用
acme.sh
可能有问题
生成证书
关于如何使用DNS APi生成证书,官方有详细文档说明,包括阿里云的DNS、腾讯云的DNS等DNS 服务器,并详细介绍了如何获取DNS服务器的令牌
DNS APi
的安装方式:https://github.com/acmesh-official/acme.sh/wiki/dnsapi
以下是cloudflare
的生成证书方式:
export CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
export CF_Email="[email protected]"
acme.sh --issue --dns dns_cf -d domain.com -d *.domain.com
安装Nginx
容器
流程梳理
创建
home/keys
文件夹,存放Https
证书文件创建随机的密钥
创建容器的局域网段https
创建
/home/keys/nginx/conf.d
文件夹,存放nginx
的配置文件创建
nginx.conf
文件,并上传到服务器home/nginx
文件夹下通过
docker-cpmpose
文件安装Nginx
最后执行
acme.sh
命令
“
Tip:把所有的配置文件都放在home文件夹下,方便以后管理,目录使用英文并具有一定意义
Https文件存放
按照上面的流程,我们需要把https
证书放到一个可以让nginx
容器访问到的地方,这是一个官方的示例:
acme.sh --install-cert -d example.top \
--key-file /path/to/keyfile/in/nginx/key.pem \
--fullchain-file /path/to/fullchain/nginx/cert.pem \
--reloadcmd "service nginx force-reload"
(一个小提醒, 这里用的是 service nginx force-reload
, 不是 service nginx reload
, 据测试, reload
并不会重新加载证书, 所以用的 force-reload
)
因为我们使用的是Docker
的方式安装Nginx
,所以我们需要修改一下,把目录都放到home
目录的key
文件夹下(记得域名改为自己的)
创建文件夹:mkdir /home/keys
,存放Https
证书文件,这一步只需要创建文件夹,无需执行命令,最后再执行。
acme.sh --install-cert -d example.top \
--key-file /home/keys/key.pem \
--fullchain-file /home/keys/cert.pem \
--reloadcmd "docker restart some-nginx"
这句命令主要为域名创建了两个证书文件,并放在key指定文件夹下,最后重启some-nginx
容器
创建随机的密钥
创建随机的
https
证书密钥:openssl dhparam -out /home/keys/dhparam.pem 2048
创建容器的局域网段
创建容器的局域网段https:
# 创建容器的局域网段https
docker network create https
#这是查询network有哪些网段
docker network ls
#这是查询network里面https网段里面有哪些容器加入进来
docker network inspect https
nginx
的配置文件存放
创建文件夹:
mkdir /home/nginx mkdir /home/nginx/conf.d
创建nginx.conf
文件
创建
nginx.conf
文件,并上传到服务器home/nginx
文件夹下,这是一个通用的文件配置user nginx; worker_processes auto; pid /run/nginx.pid; worker_rlimit_nofile 65535; events { # 设置事件驱动模型,是内核2.6以上支持 use epoll; worker_connections 65535; accept_mutex off; multi_accept off; } http { # Basic Settings sendfile on; tcp_nopush on; tcp_nodelay on; send_timeout 120; keepalive_timeout 300; client_body_timeout 300; client_header_timeout 120; proxy_read_timeout 300; proxy_send_timeout 300; #tcp_nopush on; types_hash_max_size 4096; client_header_buffer_size 16m; client_max_body_size 4096m; include /etc/nginx/mime.types; include /etc/nginx/conf.d/*.conf; # include /usr/share/nginx/modules/*.conf; default_type application/octet-stream; # Logging Settings access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; # 开启gzip gzip on; # 启用gzip压缩的最小文件,小于设置值的文件将不会压缩 gzip_min_length 1k; # gzip 压缩级别,1-10,数字越大压缩的越好,也越占用CPU时间,后面会有详细说明 gzip_comp_level 2; # 进行压缩的文件类型。javascript有多种形式。其中的值可以在 mime.types 文件中找到。 gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml; # 是否在http header中添加Vary: Accept-Encoding,建议开启 gzip_vary on; # 禁用IE 6 gzip gzip_disable "MSIE [1-6]\."; }
安装Nginx
接下来是
Nginx
容器安装,编写docker-compose
文件:
services:
web:
image: nginx:latest
container_name: "some-nginx"
restart: always
volumes:
- /home/nginx/nginx.conf:/etc/nginx/nginx.conf
- /home/nginx/conf.d:/etc/nginx/conf.d
- /home/keys:/home/keys
# blog
- /home/blog:/var/www
ports:
- "80:80"
- "443:443"
# docker network create https
networks:
https:
external: true
解释:创建了一个some-nginx
的容器,把容器文件nginx.conf
、conf.d
和keys文件夹挂载出来。暴露端口是80和443;把容器加入到https
的网段里面,让这个网段里面的容器可以被nginx
容器代理到。
编写好后放在home/nginx文件夹下就可以直接使用一下命令安装:
docker compose up -d
执行acme.sh
命令
最后我们就可以运行之前acem
的安装命令:
acme.sh --install-cert -d example.top \
--key-file /home/keys/key.pem \
--fullchain-file /home/keys/cert.pem \
--reloadcmd "docker restart some-nginx"
正常的话,这里运行着一个nginx
容器了,这里的步骤稍微复杂但是细心一点还是没有难度的,特别需要注意的是域名、文件夹和文件名这些内容不要写错。
截止到这里,基本已经完成基本的架构,只需要其他docker容器加入到https这个网段内,通过conf文件,让nginx这个容器可以访问到就可以了。
最佳实践
安装Halo
编写docker-compose.yml
文件
services:
halo:
image: registry.fit2cloud.com/halo/halo:2.20
container_name: "halo2"
restart: on-failure:3
depends_on:
halodb:
condition: service_healthy
networks:
https:
volumes:
- /home/halo2:/root/.halo2
ports:
- "8090:8090"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8090/actuator/health/readiness"]
interval: 30s
timeout: 5s
retries: 5
start_period: 30s
environment:
# JVM 参数,默认为 -Xmx256m -Xms256m,可以根据实际情况做调整,置空表示不添加 JVM 参数
- JVM_OPTS=-Xmx256m -Xms256m
command:
- --spring.r2dbc.url=r2dbc:pool:mysql://halodb:3306/halo
- --spring.r2dbc.username=root
# MySQL 的密码,请保证与下方 MYSQL_ROOT_PASSWORD 的变量值一致。
- --spring.r2dbc.password=o#DwN&JSa56
- --spring.sql.init.platform=mysql
# 外部访问地址,请根据实际需要修改
- --halo.external-url=http://localhost:8090/
halodb:
image: mysql:8.1.0
container_name: "halo2mysql"
restart: on-failure:3
networks:
https:
command:
- --default-authentication-plugin=caching_sha2_password
- --character-set-server=utf8mb4
- --collation-server=utf8mb4_general_ci
- --explicit_defaults_for_timestamp=true
volumes:
- /home/mysql:/var/lib/mysql
- /home/mysqlBackup:/data/mysqlBackup
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
interval: 3s
retries: 5
start_period: 30s
environment:
# 请修改此密码,并对应修改上方 Halo 服务的 SPRING_R2DBC_PASSWORD 变量值
- MYSQL_ROOT_PASSWORD=o#DwN&JSa56
- MYSQL_DATABASE=halo
networks:
https:
external: true
增加 container_name 自定义容器名称
修改 networks 为自定义的https
修改 MYSQL_ROOT_PASSWORD 数据库密码
修改 volumes 外挂目录
修改 halo.external 外部访问连接
编写halo.conf
文件
upstream halo-server {
server halo2:8090 fail_timeout=0;
}
# listen on HTTP2/SSL
server {
listen 443 ssl http2;
server_name www.domian.top;
# ssl certs from letsencrypt
ssl_certificate /home/keys/cert.pem;
ssl_certificate_key /home/keys/key.pem;
# dhparam.pem
ssl_dhparam /home/keys/dhparam.pem;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
ssl_prefer_server_ciphers on;
location / {
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect off;
proxy_set_header Host $host:$server_port;
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;
proxy_pass http://halo-server;
}
}
# redirect HTTP and handle let's encrypt requests
server {
listen 80;
server_name www.domian.top;
# send everything else to HTTPS
location / {
return 302 https://www.domian.top;
proxy_set_header Host $host:$server_port;
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;
proxy_pass http://halo-server;
}
}
halo-server 可以自定义名称,每个conf文件不要一样
server halo2:8090 是自定义容器名称+端口号
server_name 为访问halo应用的域名
可能用到的工具
这里列举了我常用的开发工具和连接服务器工具链接
VsCode:https://code.visualstudio.com/
Git:https://git-scm.com/
PicGo:https://picgo.github.io/PicGo-Doc/zh/
Snipaste:https://zh.snipaste.com/
FileZilla Client: https://www.filezilla.cn/
可能用到的指令
给文件夹赋予权限:
chmod 777 /home/nginx
查看容器日志:(在容器启动失败的情况下使用非常有效能定位错误)
docker logs -f some-nginx
进入容器内部
docker exec -it some-nginx bash
一些踩过的坑
cloudflare代理SSL证书重定向问题
在部署的时候遇到一个巨坑,因为使用的是cloudflare
进行·解析,但是有一个端到端的加密过程,看下面图片就知道了,用户访问域名会被cloudflare
先代理,走https
,但是cloudflare
跟服务器也要走https
,不能走http
,不然就会出现前端重定向问题!这里一般选择完全的SSL
加密
halo看不到应用市场&cloudflare缓存问题
如果是使用cloudflare代理的网站,在安装halo后可能会遇到插件和应用商店看不到的问题,这需要在cloudflare后台缓存->配置->缓存级别改为标准,这也是一个巨坑!
Halo上传单文件大小不得超过100Mb
使用cloudflare代理的网站,单文件大小不得超过100mb,除了付费升级,就是不使用cloudflare代理,直接DNS到服务器,但是服务器受到的威胁性会提高
评论区