前言 / Intro

最近终于下定决心,把原来一直在用的 Windows Server 2016 备份过后,宣布彻底弃用了。之所以之前用 Windows Server,是因为最开始部署博客的时候我还玩不明白满是命令行的 Linux。随着时间的推移,慢慢地变得能够上手了,同时也发现 Linux 有不少优点,比如系统占用小啦,开源社区生态越来越完善啦等等等等。于是的现在,我全面投入了 Linux 的拥抱。因为感觉一众发行版之中 Ubuntu 的生态相对更完善,上手操作简单方便,且通常云服务器提供商也必定会提供 Ubuntu 的镜像,所以光速重装了系统。本以为会花很长时间,结果是几秒钟的时间迅速重装好了。想想也是,毕竟是托管主机,内部更换镜像秒秒钟的事。选择的也是目前我用的云服务商(腾讯云)能够安装到的最新长期维护稳定发行版:Ubuntu Server 22.04 LTS.

其实一开始挣扎了好久,到底要不要安装桌面环境,毕竟 GUI 操作直观流畅,全敲命令行实在是有点恼人。一番纠结过后,还是没有选择安装桌面环境。考虑到我的服务器性能本来就不高,安装桌面环境之后怕不是又跟原来 Windows Server 一样动不动飙升高占用了,而且也想稍微逼自己一把用一用终端,也能巩固一下常用命令的记忆。

敬请注意 / WARNING

这篇折腾日志可能包含先部署再 排错 / 升级 / 修改 等非一次性部署好的情况,几乎只是用来记录我走过的路程的,所以算不上一份标准的教程。你可以先向后阅读,根据潜在的说明或者自行分析,尽可能避免复现不必要的步骤。

前置准备

重装系统!

访问云服务器管理商,通常都会有预制好的镜像,不论是新装还是重装都是即点即用。就不过多赘述啦。

一键重装
一键重装

端口放行

如果你是第一次购买服务器,记得去放行端口,常用的有80、8080、443 (HTTP / HTTPS)、22、1022 (SSH)、3389 (RDP远程桌面) 等,其他的根据你自己的需要灵活调节。主流云服务商都很贴心地在面板里给出了一键放行,直接点就可以。

一键放行端口
一键放行端口

解析域名

如果你已经拥有了域名并且要绑定,接下来转到 DNS 面板,依旧是大快人心的一键添加解析记录。

DNS 云解析
DNS 云解析

要是暂时还没有域名,只用 IP 地址来访问的话也不是不可以,但向公网暴露真实 IP 地址有很多弊端,很容易被攻击 ( 虽说一般我们这种小站几乎是无人在意吧,但也正巧是容易被什么恶意爬虫当成下手的对象 ( 所以建议还是准备一个域名。

做完了这些前置工作,就可以连接到我们的 Ubuntu 主机啦~

配置环境

连接到终端

使用任意 SSH 工具,连接到我们主机的命令终端。这里我是用习惯了 XShell,因为操作简单而且重要的是很美观 (颜狗上线

美丽的 XShell 面板
美丽的 XShell 面板

全新启动 & 安装 Docker

Linux 启动第一步,当然是先更新一下。


sudo apt update
sudo apt upgrade

因为我个人喜欢用容器对每个程序进行隔离化管理,所以接下来安装 Docker。

内容可能有时效性。
参阅:Docker 官方文档 - https://docs.docker.com/engine/install/ubuntu

首先执行一下完全卸载命令,确保服务器内没有安装过旧版本,防止引起冲突。


sudo apt remove $(dpkg --get-selections docker.io docker-compose docker-compose-v2 docker-doc podman-docker containerd runc | cut -f1)

如果是新装,机器里什么都没有,那大概可以跳过这一步。当然以防万一也可以运行一下。

此时直接执行安装命令大概是无效的。要先设置一下 Docker 的仓库


# 添加 Docker 官方 GPG key:
sudo apt update
sudo apt install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

# 将仓库写入 Apt 源:
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF

# 添加完仓库地址,再次执行更新来获取仓库源
sudo apt update

现在可以执行安装命令了。


sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

查看一下 Docker 状态,确认是否安装完成并运行:


sudo systemctl status docker

如果没有运行,手动启动一下。


sudo systemctl start docker

安装 Portainer

现在我们已经拥有了 Docker 容器环境,可以拉取并部署各种程序了。虽然直接就这么用也不是不行,但对于我个人而言,我更喜欢可视化一点的操作,而且日后有想要修改的内容不用一遍遍敲命令去操作(比如搜索、停用以及删除)容器,也不用大费周章地改动之前的命令再去完整输入新命令,所以我还要再安装一个 Portainer。

内容可能有时效性。
参阅:Portainer 官方文档 - https://docs.portainer.io/start/install-ce/server/docker/linux

直接执行部署命令,系统识别到本地没有镜像会先自动拉取:


docker run -d -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:lts

如果你要部署为 HTTPS 或自行导入 SSL 证书,将其中的端口更换为 -p 8000:8000 -p 9443:9443 即可。

使用你的 IP 地址或域名加你的访问端口来访问 Portainer 面板。能成功登入即可。

安装 Typecho 和 数据库

TIPS

插一句,其实这里一开始我想使用 Portainer 内置的 Stacks 来部署 docker-compose 的,但是部署时发现,Stacks 指定文件夹必须使用绝对路径,但是我又想用较为优雅的 ./ 相对路径,如果强制使用相对路径在 Stacks 内部署,就会自动部署到 /data/compose/1/typecho 类似这样的主机根目录,所以我还是选择了官方 docker-compose 手段。

综上所述,那么我们还是按照传统的方式:

首先创建文件夹:


mkdir -p my_blog && cd $_

启动编辑器:


nano docker-compose.yml

编辑 docker-compose:


services:
  typecho:
    image: joyqi/typecho:1.3.0-php8.2-apache
    container_name: typecho
    restart: always
    environment:
      - TIMEZONE=Asia/Shanghai
    volumes:
      - ./typecho/usr:/app/usr
    depends_on:
      - db

  db:
    image: mariadb:10.6
    container_name: typecho-db
    restart: always
    environment:
      - MYSQL_ROOT_PASSWORD=Root-Pwd-1234
      - MYSQL_DATABASE=my_blog
      - MYSQL_USER=username
      - MYSQL_PASSWORD=Pwd-1234    # 用户名密码按需修改
      - TZ=Asia/Shanghai
    volumes:
      - ./db:/var/lib/mysql

两个愿望 一次满足 嘿嘿 docker-compose 真好用 (

这里一定要记好我们设置的所有名称、用户名和密码。最后会用到。

  • 此外,如果你不想使用独立的数据库容器,想用 Typecho 内置的 SQLite,那么可以把 depends_on: 之后有关独立数据库容器的部署内容全部删除。

写好配置文件,然后部署镜像:


docker compose up -d

这里我拉取镜像使用 typecho:1.3.0-php8.2-apache 指定了具体版本。因为有一些国内镜像源可能包含的不是最新镜像仓库,指定具体版本后如果报错,可以帮助我们具体定位问题,从而考虑尝试换源解决。

另外,Typecho 时区我使用了完整参数名 - TIMEZONE=Asia/Shanghai 。这是因为第一次我用的简写 - TZ=Asia/Shanghai 居然对我的 Typecho 不生效,不知是不是版本原因。如果你用完整参数反而无效了,可以考虑进 Portainer 更换这一项,亦或者重新 docker-compose 部署。

部署好之后,我再加了一条映射:


- ./typecho/config.inc.php:/app/config.inc.php

这是因为 config.inc.php 是一个日后可能频繁修改的配置文件,所以我们要挂载出来。

姑且以防万一有萌新第一次操作写个提醒,冒号前相对路径是宿主机真实路径 (host),而后者是容器内路径 (container)。通过 Portainer 添加可能会用到。

TIPS

或许有的小伙伴要问,为什么还要大费周折在部署好之后才添加这条路径映射呢?有两个原因:

  1. 如果我们一开始就挂载这个文件,有可能会因为系统找不到这个路径,就会默认优先使用该名称自动创建成一个空文件夹,从而导致 Typecho 找不到这个文件;
  2. 我第一次尝试先手动创建空文件,再进行挂载时,发现 Typecho 无法进入欢迎界面,也无法显示正常的博客页面。排查发现是因为系统检测到有这个配置文件了,所以以为我们的博客已经部署好了,就直接进入博客页面。但实际上又没有被部署,所以就会出现 bug。

所以,我会让程序先自行创建初始 config.inc.php 配置文件,而后再给它挂载出来。

  • 以上单纯是我发现的一些小问题。如果你发现我的步骤是不必要,或者还有更好的办法,欢迎留言告诉我。

注意,此时我们还暂时不能访问博客页面。因为我们还没有放行 80 端口投放在公网访问。同样地,如果你选择直接将容器 80 端口映射到宿主机也不是不行 —— 还是请先不要着急添加端口映射,因为我们要使用一项更为优秀的方案:添加 Nginx 反代理。

安装 Nginx (NPM)

NPM,全称 Nginx Proxy Manager,是一项可视化 Nginx 反代理面板。

创建并进入文件夹:


mkdir -p npm && cd $_

启动编辑器:


nano docker-compose.yml

还是 docker-compose:


version: '3.8'
services:
  app:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: nginx-proxy-manager
    restart: unless-stopped
    ports:
      - '80:80'
      - '81:81'
      - '443:443'
    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
    networks:
      - default
      - my_blog_net     # 按需自定义这里和后面的 Docker 网络名称

networks:
  my_blog_net:
    external: true
    name: my_blog_default

部署镜像:


docker compose up -d

访问 IP地址 / 域名:81 进入我们的 NPM 面板。

如图,新建一个代理服务,域名处填写我们的域名(废话)。

因为我们是在 Docker 内网环境下部署的,所以要转发的主机按照 Docker 内的地址写

协议 https转发主机名建议填写你设置的容器名称,例如 typecho ,这样如果我们日后对容器有修改、更新时,不受内网 IP 地址变动的影响。端口填写 Typecho 内网端口 80 .

可以打开下面的两项常用功能,“缓存资源”“阻止常见攻击”

NPM 配置示例
NPM 配置示例

如果你不需要使用自定义 SSL 证书,还可以转到 SSL 选项卡,为我们的域名申请一个免费的 LetsEncrypt,再打开“强制使用 SSL”。操作很简单,就不放图了。

设置完毕,点击“保存”

配置并访问博客

前置工作都准备完毕,接下来终于可以访问我们的博客页面了。

博客初始化界面
博客初始化界面

输入域名,第一次会启动欢迎页面引导向导。输入用户名、邮箱,以及我们之前设置过的数据库信息即可。如果忘了,回头看看我们刚才设置过的 Typecho 的 docker-compose.yml 文件。

注意“数据库地址”不要填 IP,填你在 yaml 中定义的数据库服务名(例如我们刚才设置的 db)即可,Docker 内网的 DNS 会自动寻址。

  • 如果你选择的是没有单独部署 SQL 数据库,欲使用 Typecho 内置的 SQLite,那么我们直接下拉菜单,选择 “Pdo 驱动 SQLite 适配器” 即可只需输入数据库名称和路径,完成简化设置。

转到下一步,设置我们的邮箱(会和 Gravatar 头像服务相关联)、用户名密码。再一路继续。

成功访问博客
成功访问博客

大功告成!

博客的部署就到这里结束了。如果你想个性化你的博客,安装主题、插件等等,可以在互联网上搜索,款式各种各样。至于我自己在用的一些设置,留到日后看情况写吧。