博客

  • 从零自建个人博客(1):从空服务器到跑起来的 WordPress

    0. 前言:我为什么要自己搭博客

    (1)动机说明
    我想在实践中学习 Linux / 建站 / 运维,而不是先看完一堆理论。

    (2)整体路线
    从腾讯云租赁云服务器 → 配 SSH 安全 → 装 Nginx + PHP + MariaDB → 部署 WordPress → 用 IP 正常访问博客 → 将 IP 解析成个人注册的域名。

    (3)适合看这篇博客的人
    只会一点点 Linux 命令,想边做边学,不要求一步到位的生产级方案。


    1. 环境说明与最终目标

    (1)当前环境
    服务商:腾讯云;服务器地域:广州;配置:4 核 4G、3M 带宽、40G 系统盘;系统版本:Ubuntu 24.04 LTS;初始登录方式:密码登录。

    (2)想达到的效果
    用「域名」可以访问到 WordPress 博客首页和后台;
    SSH 只允许密钥登录,不再接受密码;
    域名已经解析到服务器(但因备案,暂时不能直接用域名访问真正网站)。


    2. 第一步:拿到云服务器之后,先把 SSH 安全搞清楚

    (1)使用密钥登录而不是密码

    SSH 的全称是 Secure Shell(直译过来是“安全外壳”),可以理解为一条“加密的远程命令通道”。

    需要使用 SSH 的原因是:云服务器的物理本体在服务商的机房,并且没有键盘和显示器,我碰不到。所以我要通过 SSH 连接上服务器,才能对其进行操控。当连接上去之后,看到的提示符就是那台服务器的命令行,在这个终端窗口输入的命令就会在那台机器上执行。

    服务器上有一个常驻进程叫 sshd,默认监听 22 端口,它负责处理所有 SSH 的登录请求。如果我在本地 cmd 里执行:

    ssh root@服务器IP
    

    就是在对本地的主机说:“我想通过 SSH 登录到这台机器的 root 账号”。

    一台在公网暴露的服务器,如果用密码登录,会有很大的风险。互联网上有无数扫描脚本,会不停尝试常见账号(root、admin 等)加上脚本密码库中的常见密码。密码只是一串字符串,只要被撞对或者泄露,对方就能直接登录;日志里经常能看到各种国家的 IP 在疯狂尝试 SSH 登录。因此,我们采用密钥登录,并且关闭 SSH 的密码登录验证方式。

    所谓密钥登录,核心是使用一对“非对称密钥”来证明“我是我”,而不是告诉服务器“我的密码是什么”。

    要通过密钥登录,首先要在本地生成一对 SSH 密钥(如果你原先没有的话)。在支持 OpenSSH 的环境里可以直接用命令:

    ssh-keygen -t ed25519
    

    一路回车,就会在本地生成两份文件:

    • id_ed25519:私钥,只保存在本机或者你信任的地方;
    • id_ed25519.pub:公钥,可以复制给服务器使用。

    有了一对密钥之后,你就可以登录到你的服务器(第一次可以暂时用密码,后面就不需要了),在目标用户(如 root)的 home 目录下创建 SSH 目录和授权文件。例如以 root 为例:

    mkdir -p /root/.ssh
    

    意思是创建 /root/.ssh 这个路径,-p 是 mkdir 的命令参数,作为 parents 的缩写,作用是如果找不到父级路径就一并创建。然后执行:

    chmod 700 /root/.ssh
    

    chmod 是 change mode 的缩写,用于修改文件/目录的权限位。这里的 700 这个参数涉及 Linux 的权限管理,对于此处篇幅来说过于复杂,因此不过多赘述。

    接下来使用 nano 编辑器,把本地生成的公钥内容粘贴到这个文件中去:

    nano /root/.ssh/authorized_keys
    

    保存后再执行:

    chmod 600 /root/.ssh/authorized_keys
    

    更改这个文件的权限位。如果不更改,sshd 会认为这个目录/文件“不够安全”,直接拒绝使用里面的公钥。

    完成以上几步之后,我们已经可以通过密钥登录服务器了。后面再配置 sshd_config 把“密码登录”关掉,做到真正只接受密钥。

    (2)修改 sshd_config,只允许密钥登录

    上一步只是“把钥匙放进了门口的锁孔里”,SSH 服务到底用不用这把钥匙、还允不允许用密码,其实是由一个配置文件控制的,这个文件就是:

    /etc/ssh/sshd_config
    

    sshd 就是前面提到的 SSH 服务进程,它启动时会读取这个配置文件,里面的每一行选项都会直接影响登录策略。因此我们需要进来把几个关键选项改一改,让服务器只接受密钥登录、彻底关掉密码登录。

    我做的步骤是这样的:

    (1)先备份一份原始配置(养成习惯)

    cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
    

    这样万一后面改坏了,还可以随时从 .bak 恢复。

    (2)用编辑器打开配置文件

    nano /etc/ssh/sshd_config
    

    在文件里找到或添加下面几行(如果原来有同名配置但前面有 # 注释号,去掉 # 并改成自己想要的值):

    PubkeyAuthentication yes
    PasswordAuthentication no
    PermitRootLogin prohibit-password
    PermitEmptyPasswords no
    

    它们的含义简单解释一下:

    • PubkeyAuthentication yes
      启用“公钥认证”,也就是允许我们用刚才配置好的密钥登录。如果这一项是 no,即使你把 authorized_keys 配好了,也用不上。
    • PasswordAuthentication no
      禁用密码登录。设成 no 之后,sshd 不再接受“输入账号密码”这种方式,只剩下公钥登录一种途径。
      这一步是安全性的关键:互联网上扫你 22 端口的脚本再多,也不可能撞到你的私钥。
    • PermitRootLogin prohibit-password
      控制 root 能不能通过 SSH 登录。这个参数有几个取值:yesnoprohibit-password 等。
      这里我选择 prohibit-password,意思是: root 允许登录,但不能用密码,只能用密钥
      这样既保留了 root 远程运维的便利,又避免了“root+弱密码被撞库”的风险。
    • PermitEmptyPasswords no
      禁止空密码账号登录(这一条一般默认就是 no,这里只是明确写出来)。

    改完之后,按 Ctrl+O 保存,回车确认,接着 Ctrl+X 退出 nano。

    (3)检查配置语法并重载 SSH 服务

    直接改完配置就重启服务是有风险的,一旦写错某个参数名或者多打了奇怪的字符,sshd 运行起不来,你会发现下一次完全连不进服务器。所以 OpenSSH 提供了一个语法检查命令:

    sshd -t
    
    • 如果没有任何输出,说明语法合法,可以放心重载;
    • 如果提示某一行有错误,就回去编辑 sshd_config 修正,直到 sshd -t 不再报错为止。

    语法检查通过后,再重载 SSH 服务让新配置生效:

    systemctl reload ssh
    

    这里用 reload 而不是 restart,是为了尽量平滑地应用新配置,不会中断当前已建立的会话。

    (4)开一个新的终端窗口测试登录

    这一步非常重要:
    不要先把当前唯一的 SSH 会话关掉,而是再开一个新终端,用密钥重新登录一遍,确认新配置没有把自己锁在门外。

    例如在本地再开一个命令行窗口,执行:

    ssh root@你的服务器IP
    

    正常情况下:

    • 用密钥登录:直接进到服务器,不再询问密码;
    • 如果强制指定“只用密码试试看”,比如: ssh -o PubkeyAuthentication=no root@你的服务器IP 这时候应该会提示 Permission denied (publickey).,说明密码登录确实被关掉了。

    等确认新会话可以用密钥正常登录之后,再把旧的会话关掉,这样就算哪里配置错了,你还有“备用门”可以进来修。

    做到这一步为止,我们就完成了 SSH 这道“入口”的加固:
    服务器上只有配置过密钥的客户端才能登录,任何不知道你私钥的人,即使猜到了账号名,也没办法通过密码暴力尝试进入。

    3. 第二步:安装 Nginx,让服务器开口说“你好世界”

    (1)Nginx 是什么,为什么要先装它

    完成 SSH 加固之后,下一步就是让这台服务器对外“开口说话”。从 Web 的角度看,真正站在最前面、接收浏览器 HTTP 请求的,是 Web 服务器软件。在这篇文章里我选择的是 Nginx。

    简单粗暴地理解:

    • Nginx 是一个高性能的 Web 服务器;
    • 它负责监听 80 端口(以后还有 443 端口的 HTTPS),接收来自浏览器的请求;
    • 对于静态文件(HTML/CSS/图片),它可以直接从磁盘读出来返回;
    • 对于动态请求(比如 .php),它可以转发给后端的 PHP-FPM 等程序处理。

    后面我们访问博客时,浏览器发出的每一个 HTTP 请求,第一站就是 Nginx。

    (2)安装并启动 Nginx

    在 Ubuntu 上安装 Nginx 非常简单,用 apt 即可。登录到服务器后执行:

    apt update
    apt install -y nginx
    

    安装完成后,系统会自动启动 Nginx 服务,可以用下面的命令查看状态:

    systemctl status nginx
    

    看到状态是 active (running),说明 Nginx 已经在后台运行,并且默认监听 80 端口。

    如果你的云服务商有安全组之类的配置,要确认已经放行 80 端口,这样外网浏览器才能访问到 Nginx。

    (3)创建站点目录 /var/www/blog

    Nginx 启动之后,还需要一个“网站根目录”来放网页文件。我这次选择把博客站点放在:

    /var/www/blog
    

    在服务器上先把这个目录建出来,并把属主改成 Nginx/PHP 运行的用户 www-data

    mkdir -p /var/www/blog
    chown -R www-data:www-data /var/www/blog
    

    随后在里面写一个最简单的首页 index.html,先确认 Nginx 能正常对外返回静态页面。示例:

    nano /var/www/blog/index.html
    

    内容可以非常朴素,例如:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <title>我的第一个自定义网页</title>
    </head>
    <body>
        <h1>你好,这是我的第一个自定义网页</h1>
        <p>现在只是一个静态首页,后面会换成真正的博客系统。</p>
    </body>
    </html>
    

    保存退出之后,站点目录和第一版首页就准备好了。

    (4)配置 Nginx 虚拟主机,指向这个目录

    接下来需要告诉 Nginx:“当有人访问这台服务器的 80 端口时,从 /var/www/blog 这个目录里找网页文件”。

    在 Ubuntu 的默认布局里,每一个站点都有一个独立的配置文件,放在:

    /etc/nginx/sites-available/
    

    我新建了一个叫 blog 的配置文件:

    nano /etc/nginx/sites-available/blog
    

    写入大致如下内容(先只配置最基础的静态站点):

    server {
        listen 80;
        listen [::]:80;
    
        server_name _;
    
        root /var/www/blog;
        index index.php index.html index.htm;
    
        access_log /var/log/nginx/blog_access.log;
        error_log  /var/log/nginx/blog_error.log;
    
        location / {
            try_files $uri $uri/ =404;
        }
    }
    

    这里几个关键点:

    • listen 80:监听 80 端口;
    • server_name _:先用 _ 占位,表示接收发到这台机器上的所有请求(后面备案通过后会换成域名);
    • root /var/www/blog:站点根目录就是刚才创建的 /var/www/blog
    • index index.php index.html index.htm:访问目录(例如 /)时,依次尝试这些文件名;
    • access_log / error_log:把访问日志和错误日志分开写到单独的文件里,方便后面排错。

    写好之后保存退出,再用一个软链接把这个站点“启用”起来:

    ln -s /etc/nginx/sites-available/blog /etc/nginx/sites-enabled/blog
    

    (5)检查配置并让 Nginx 重新加载

    和 sshd_config 一样,Nginx 也提供了语法检查命令。每次改完配置都应该先检查再重载:

    nginx -t
    

    如果输出类似:

    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    

    说明语法没有问题,可以让 Nginx 重新加载配置:

    systemctl reload nginx
    

    (6)用浏览器访问,看到第一句“你好世界”

    此时在本地浏览器里输入:

    http://你的服务器IP
    

    如果一切顺利,你应该能看到刚才写的 index.html 内容(“你好,这是我的第一个自定义网页……”)。这说明:

    • 云服务器的 80 端口已经对外开放;
    • Nginx 能收到请求,并正确把 / 映射到 /var/www/blog/index.html
    • 从浏览器到服务器,再到 Nginx、再到磁盘上的静态文件,这条最基础的链路已经打通。

    在进入 PHP、数据库、WordPress 之前,先把这一步确认清楚,可以大大减少后面排错的心智负担:
    只要以后出现问题,你知道“静态页面能不能正常打开”本身就是一个很重要的判据。

    3. 第三步:从静态到动态 —— MariaDB + PHP 环境

    前面 Nginx 已经能把一个静态的 index.html 正常丢给浏览器了,但博客系统不可能只靠静态页面。像 WordPress 这种博客程序,需要:

    • 有地方存数据(文章、用户、评论等)——这就是数据库 MariaDB;
    • 有东西来执行 .php 脚本,把数据库里的数据拼成 HTML 再返回——这就是 PHP-FPM。

    这一节的目标是:把数据库和 PHP 环境都装好,并和 Nginx 串起来,先跑一个简单的 info.php 进行自检。


    (1)安装 MariaDB 并做基础安全配置

    Ubuntu 24.04 默认源里已经带了 MariaDB,我直接用 apt 安装:

    apt update
    apt install -y mariadb-server mariadb-client
    

    安装完成后,检查一下服务状态:

    systemctl status mariadb
    

    状态显示为 active (running),说明数据库已经在后台跑起来了。

    接下来是非常重要的一步:跑官方提供的安全配置脚本 mysql_secure_installation。它的作用是用一组向导问题,帮我们把一些明显危险的默认配置关掉:

    mysql_secure_installation
    

    运行后会依次问一些问题,大致包括(不同版本提示可能略有差异):

    • 是否切换为 unix_socket 认证(我选择了 Y,这样 sudo mysql 可以直接以 root 身份进数据库);
    • 是否移除匿名用户(我选择 Y,匿名用户没什么必要,还增加攻击面);
    • 是否禁止 root 远程登录(我选择 Y,只允许本机用 root 管数据库即可);
    • 是否删除 test 测试库(我选择 Y);
    • 是否重新加载权限表(Y)。

    跑完这一轮之后,数据库的“默认大坑”基本都填了一遍,后面我们再自己建一个只给 WordPress 用的专用账号。


    (2)为博客创建独立数据库和账号

    数据库服务跑起来之后,需要先进去一趟,给 WordPress 准备一个专用的库和账号。因为刚刚在 mysql_secure_installation 里启用了 unix_socket 认证,所以我直接用:

    sudo mysql
    

    这条命令会以 root 系统用户的身份,直接进到 MariaDB 的 root 账户里(不需要再输一次数据库密码)。

    在 MariaDB 提示符下,我做了三件事:

    ① 创建一个专用的数据库(假设叫 blog_wp):

    CREATE DATABASE blog_wp
      DEFAULT CHARACTER SET utf8mb4
      COLLATE utf8mb4_unicode_ci;
    

    这里指定了字符集 utf8mb4 和排序规则 utf8mb4_unicode_ci,原因很简单:
    后面文章标题、正文、评论里可能会出现中文甚至 emoji,用 utf8mb4 可以一次性兼容好。

    ② 创建一个只给 WordPress 用的账号(我这里叫 wpuser,密码用一串强密码占位):

    CREATE USER 'wpuser'@'localhost'
      IDENTIFIED BY '这里换成你自己的强密码';
    

    'localhost' 的意思是:这个账号只能从本机连接数据库,不能远程连,这样被扫到的风险又少了一点。

    ③ 给这个用户授予对 blog_wp 这个库的全部权限:

    GRANT ALL PRIVILEGES ON blog_wp.* TO 'wpuser'@'localhost';
    FLUSH PRIVILEGES;
    

    这样,WordPress 以后就会用 wpuser 这个普通账号连数据库,而不是用 root。
    好处很明显:即便某天哪篇插件被攻破,攻击者拿到的也只是一个只能操作 blog_wp 的账号,权限范围比 root 小很多。

    做完这三步,数据库这一侧就准备好了:有了专用的库、有了专用账号、有了对应权限。


    (3)安装 PHP-FPM 及常用扩展

    接下来安装 PHP。Ubuntu 24.04 源里默认已经是 PHP 8.3,我直接用 apt 安装 PHP-FPM 以及 WordPress 常用的一些扩展:

    apt install -y php-fpm php-mysql php-xml php-mbstring php-gd php-curl php-zip
    

    安装完成后,先看一下 PHP-FPM 的服务状态:

    systemctl status php8.3-fpm
    

    状态显示为 active (running) 就说明 php-fpm 正常跑着,准备接收来自 Nginx 的 FastCGI 请求。

    PHP-FPM 其实可以简单理解为:

    一个专门负责执行 PHP 脚本的“后端工作进程池”。
    Nginx 收到 .php 请求以后,会把请求转发给 php-fpm,php-fpm 执行完脚本,再把结果(已经是 HTML)丢回给 Nginx。

    我还确认了一下 php-fpm 的 Unix Socket 路径,默认是在:

    ls /run/php
    

    可以看到类似:

    php8.3-fpm.sock
    

    后面 Nginx 配置里的 fastcgi_pass 就要写这个 sock。


    (4)让 Nginx 能正确转发 PHP 请求

    前面我们给站点 /etc/nginx/sites-available/blog 写的配置,只处理了静态文件,还没有告诉 Nginx:遇到 .php 文件应该怎么办。现在需要在这个站点配置里加上一段 PHP 专用的 location

    打开站点配置:

    nano /etc/nginx/sites-available/blog
    

    在原来的 server {} 里,补充这样一段(一般放在 location / {} 的后面):

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
    
    location ~ /\.ht {
        deny all;
    }
    

    这里的含义是:

    • location ~ \.php$:匹配以 .php 结尾的请求;
    • include snippets/fastcgi-php.conf:引入一份官方准备好的 FastCGI 参数模板(SCRIPT_FILENAME 等变量都会自动设好);
    • fastcgi_pass unix:/run/php/php8.3-fpm.sock:把这些请求通过 Unix Socket 转发给 php-fpm;
    • 下面那个 location ~ /\.ht { deny all; } 是一个小安全保护,禁止访问 .htaccess 之类的隐藏文件(虽然这是 Apache 风格,但顺手防一下问题不大)。

    改完之后,和之前一样先检查 Nginx 配置语法:

    nginx -t
    

    如果一切正常,再重载服务:

    systemctl reload nginx
    

    到这里为止,链路已经变成:

    浏览器 → Nginx → (静态文件 or 转发到 PHP-FPM)→ 返回给浏览器

    剩下的就是验证 PHP 这条支路真的能跑起来。


    (5)用 info.php 验证 PHP 是否正常工作

    为了确认 Nginx 和 php-fpm 的配合没有问题,我在站点根目录下写了一个非常简单的测试脚本 info.php

    echo "<?php phpinfo();" > /var/www/blog/info.php
    

    然后在浏览器里访问:

    http://服务器IP/info.php
    

    如果环境没问题,会弹出一个 PHP 信息页面,里面有版本号(例如 PHP 8.3.6)、编译选项、加载的扩展、配置文件位置等各种详细信息。这说明:

    • Nginx 正确地把 .php 请求转发给了 php-fpm;
    • php-fpm 成功执行了 phpinfo()
    • 结果又被 Nginx 原样返回到了浏览器。

    验证通过之后,这个文件千万不要长期留在服务器上,因为任何人打开这个页面,都能看到你 PHP 环境的各种详细信息,不利于安全。测试完,我把它删掉了:

    rm /var/www/blog/info.php
    

    到这一节结束为止,整条“动态请求链路”已经打通:

    浏览器发起 GET /info.php → Nginx 匹配到 location ~ \.php$
    把请求丢给 php-fpm → php-fpm 执行 PHP 代码 → 生成 HTML →
    Nginx 把 HTML 返回给浏览器。

    下一步就是把 WordPress 的代码放进 /var/www/blog,让它不再只是一个简陋的静态首页,而变成一个真正可用的博客系统。

    4. 第四步:部署 WordPress —— 让博客真正跑起来

    前面只是让 Nginx+PHP 环境跑起来,这一步才是真正把博客系统本体——WordPress——部署进去,让它接管整个站点。

    (1)下载并解压 WordPress 到站点目录

    我把 WordPress 临时下载到 /tmp 目录,然后再移动到真正的站点目录 /var/www/blog

    cd /tmp
    curl -O https://wordpress.org/latest.tar.gz
    tar -xzf latest.tar.gz
    

    解压之后,会出现一个 wordpress 目录,里面就是所有的程序文件。接下来把这些文件搬到 /var/www/blog 下面(注意是移动目录里的内容,而不是整个目录):

    mv /tmp/wordpress/* /var/www/blog/
    

    之前我在 /var/www/blog 里写过一个测试用的 index.html,它会和 WordPress 的 index.php 冲突,所以顺手把那个测试首页备份一下:

    mv /var/www/blog/index.html /var/www/blog/index.html.bak 2>/dev/null || true
    

    到这里,站点目录下就基本是 WordPress 的结构了,可以用下面命令看一下:

    ls /var/www/blog
    

    能看到 wp-admin/wp-content/wp-includes/index.php 等一堆文件,说明 WordPress 的代码已经就位。

    (2)设置 WordPress 文件权限

    因为我是用 root 把文件移动过来的,所以此时这些文件的属主还是 root。
    但真正访问这些文件的,是 Nginx 和 php-fpm,它们的运行用户是 www-data。如果属主不改,后面就会出现“权限不足”的错误。

    于是我把整个站点目录的属主和属组统一改成 www-data

    chown -R www-data:www-data /var/www/blog
    

    这里的 -R 表示递归,把 /var/www/blog 下面所有目录和文件都一起修改;冒号前面的 www-data 是属主用户,冒号后面的 www-data 是属组,这样做的效果是:整棵目录树都归 www-data 用户 / www-data 组所有。

    为了让权限更收敛一点,我还可以按“目录 750、文件 640”的习惯设一遍(这一条你可以根据需要选择写不写,我这里顺带提一下):

    find /var/www/blog -type d -exec chmod 750 {} \;
    find /var/www/blog -type f -exec chmod 640 {} \;
    

    这样既保证 www-data 有权限读取/执行这些文件,也避免其他系统用户随便翻看站点代码。

    (3)配置 wp-config.php 连接数据库

    WordPress 的数据库配置写在根目录下的 wp-config.php 里。
    官方自带了一个模板文件 wp-config-sample.php,可以先复制一份并改名:

    cd /var/www/blog
    cp wp-config-sample.php wp-config.php
    

    复制完之后,用编辑器打开:

    nano wp-config.php
    

    找到下面几行,把它们改成前面我们为 WordPress 专门创建的数据库信息:

    define( 'DB_NAME', 'blog_wp' );          // 数据库名
    define( 'DB_USER', 'wpuser' );           // 数据库用户名
    define( 'DB_PASSWORD', '你的强密码' );   // 数据库密码
    define( 'DB_HOST', 'localhost' );        // 数据库主机,一般本机就是 localhost
    

    这里的四个参数要和你在 MariaDB 里执行的那几条 SQL 对上号:

    • DB_NAME 对应 CREATE DATABASE blog_wp ...
    • DB_USER 对应 CREATE USER 'wpuser'@'localhost' ...
    • DB_PASSWORD 就是你给 wpuser 设的那串强密码
    • DB_HOSTlocalhost,表示只从本机连接数据库

    保存退出之后,按理说访问安装页面就可以进入 WordPress 的安装向导了。

    (4)一次关键踩坑:500 错误与权限问题

    实际操作中,我这里踩了一个比较典型的坑:访问安装页面报 500 错误。

    当我在浏览器里访问:

    http://服务器IP/wp-admin/install.php
    

    得到的是 HTTP ERROR 500。
    这时候不要瞎猜,第一件事就是看 Nginx 错误日志。我在站点配置里已经把错误日志单独指定到了 /var/log/nginx/blog_error.log,所以用:

    tail -n 40 /var/log/nginx/blog_error.log
    

    日志里出现了这样的关键信息(简化一下):

    PHP Warning:  require_once(/var/www/blog/wp-config.php): Failed to open stream: Permission denied
    PHP Fatal error:  Uncaught Error: Failed opening required '/var/www/blog/wp-config.php'
    

    这几句话基本就把问题点名了:

    • WordPress 在加载 wp-config.php 的时候,提示 Permission denied(权限被拒绝);
    • 然后因为配置文件读不到,抛出致命错误,Nginx 只好返回 500。

    原因其实很简单:我用 root 去 cp wp-config-sample.php wp-config.php 之后,这个新文件的属主变成了 root,而不是 www-data。前面虽然对整个目录做过一次 chown -R,但那是在复制之前,所以 wp-config.php 就“漏网了”。

    解决方式也很直接:把这个文件的属主改回 www-data,并设一个合适的权限位:

    chown www-data:www-data /var/www/blog/wp-config.php
    chmod 640 /var/www/blog/wp-config.php
    

    再次刷新安装页面,500 错误就消失了,正常出现了 WordPress 的安装向导。这一段经历刚好让“属主 + 权限”这些概念从抽象变成了实战里的具体问题。

    (5)通过安装向导完成初始化

    当一切准备妥当后,访问:

    http://服务器IP/wp-admin/install.php
    

    就会看到 WordPress 熟悉的安装向导页面。

    这里会让我填写一些基础信息:

    • 站点标题(比如“某某的个人博客”);
    • 管理员用户名(以后用来登录后台,不建议用 admin 这种太常见的名字);
    • 管理员密码(会有密码强度提示,建议用一串难以猜测的强密码);
    • 管理员邮箱(后续用于找回密码、接收通知等);
    • 是否允许搜索引擎索引(刚开始可以勾上,或者等内容多一点之后再打开)。

    点击“安装 WordPress”之后,程序会在数据库里自动创建各种表(文章、用户、选项等),几秒钟之后提示安装完成。
    接着就可以直接访问后台登录页:

    http://服务器IP/wp-admin
    

    用刚才设置的管理员用户名和密码登录,左侧就是完整的 WordPress 控制台:文章、媒体、页面、外观、插件……到这里,整个博客系统算是真正跑起来了。

    前台首页地址则是:

    http://服务器IP/
    

    现在用 IP 访问,你会看到的是 WordPress 默认的主题首页,而不再是之前那个 “你好,这是我的第一个自定义网页”。