随着CentOS7的终结日渐临近,升级或替换系统终于也被提上日程了。在虚拟机上测试过从CentOS7转换到AlmaLinux或RockyLinux,但情况并非很理想。
Oneinstack和LNMP的自动化脚本又频频传出挂马的消息,至于宝塔这种可视化界面又存在这样那样的问题(见《这次被宝塔面板给坑苦了——数据库被删除》、《宝塔面板不执行计划任务》)还对系统性能要求颇高,所以干脆学习一下如何手动安装服务器的应用程序。
本文中的安装方法主要参考自《How to Install LEMP Stack (Nginx, PHP and MariaDB) on Debian 12》一文。

准备工作

首先将系统及所有程序都升级到最新版

$ sudo apt update && sudo apt upgrade

安装一些必要程序

$ sudo apt install wget curl nano ufw software-properties-common dirmngr apt-transport-https gnupg2 ca-certificates lsb-release debian-archive-keyring unzip -y

有些程序已经默认安装在系统中,还有些可以根据自己的需要增添。

配置防火墙

在开始安装前,需对防火墙进行一下配置,如不需要可以跳过本步骤。
首先查看一下UFW的运行状况

$ sudo ufw status

你可能会看到如下的内容:

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

如果防火墙没有运行的话,会显示Status: inactive。因为是远程服务器,所以在开启UFW前要确保SSH已被允许,否则就无法远程连接到服务器了,运行以下命令:

$ sudo ufw allow ssh

然后运行:

$ sudo ufw enable

开启过程会提示可能会中断SSH操作并询问是否继续,输入Y即可。再次检验UFW运行状态,应该就能看到如上所示的信息了。
接下来添加HTTP和HTTPS的端口:

$ sudo ufw allow http
$ sudo ufw allow https

再次检验UFW状态,如下所示:

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443/tcp (v6)               ALLOW       Anywhere (v6)

安装PHP

默认情况下,Debian 12自带PHP 8.2,运行以下命令就可以安装:

$ sudo apt install php-fpm php-cli php-mysql php-mbstring php-xml php-gd

上述命令安装了PHP的MySQL、CLI、GD、Mbstring和XML扩展,也可以根据需要安装任何其他额外的扩展。
检验安装版本:

$ php --version
PHP 8.2.26 (cli) (built: Nov 25 2024 17:21:51) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.26, Copyright (c) Zend Technologies
    with Zend OPcache v8.2.26, Copyright (c), by Zend Technologies

如果想始终使用最新版本的PHP,或者如果想安装多个版本的PHP,可以添加Ondrej的PHP存储库。
首先,导入Sury的repo PHP GPG密钥:

$ sudo curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg

添加Ondrej Sury的PHP存储库:

$ sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'

更新系统存储库列表:

$ sudo apt update

现在就可以安装任何版本的PHP了,比如8.1:

$ sudo apt install php8.1-fpm php8.1-cli

安装数据库程序MariaDB或MySQL

Debian 12中并不包含MySQL软件包,其已经被MariaDB替换,所以可以通过以下命令进行安装:

$ sudo apt install mariadb-server

安装完毕后,检查一下版本:

$ mysql --version

mysql  Ver 15.1 Distrib 10.11.16-MariaDB, for debian-linux-gnu (x86_64) using  EditLine wrapper

运行MariaDB安全安装脚本

$ sudo mysql_secure_installation

系统将要求输入root密码。直接按回车键,因为之前并没有为它设置任何密码。

NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB
      SERVERS IN PRODUCTION USE!  PLEASE READ EACH STEP CAREFULLY!

In order to log into MariaDB to secure it, we'll need the current
password for the root user. If you've just installed MariaDB, and
haven't set the root password yet, you should just press enter here.

Enter current password for root (enter for none):

接下来,系统将询问你是否要切换到Unix套接字身份验证方法。unix套接字插件允许你使用操作系统凭据连接到MariaDB服务器。由于你已经有一个受保护的根帐户,请输入n继续(如果搞不清楚的话输入y也可以)。

OK, successfully used password, moving on...

Setting the root password or using the unix_socket ensures that nobody
can log into the MariaDB root user without the proper authorisation.

You already have your root account protected, so you can safely answer 'n'.

Switch to unix_socket authentication [Y/n] n

接下来,系统会询问您是否要更改root密码。 这里输入y,然后再输入想修改的新密码。

 ... skipping.

You already have your root account protected, so you can safely answer 'n'.

Change the root password? [Y/n] y

接下来,系统会问你一些问题,以提高MariaDB的安全性。 输入Y可删除匿名用户、禁止远程root登录、删除测试数据库并重新加载权限表。

 ... skipping.

By default, a MariaDB installation has an anonymous user, allowing anyone
to log into MariaDB without having to have a user account created for
them.  This is intended only for testing, and to make the installation
go a bit smoother.  You should remove them before moving into a
production environment.

Remove anonymous users? [Y/n] y
 ... Success!

Normally, root should only be allowed to connect from 'localhost'.  This
ensures that someone cannot guess at the root password from the network.

Disallow root login remotely? [Y/n] y
 ... Success!

By default, MariaDB comes with a database named 'test' that anyone can
access.  This is also intended only for testing, and should be removed
before moving into a production environment.

Remove test database and access to it? [Y/n] y
 - Dropping test database...
 ... Success!
 - Removing privileges on test database...
 ... Success!

Reloading the privilege tables will ensure that all changes made so far
will take effect immediately.

Reload privilege tables now? [Y/n] y
 ... Success!

Cleaning up...

All done!  If you've completed all of the above steps, your MariaDB
installation should now be secure.

Thanks for using MariaDB!

注意:MariaDB可能会因为出现缺少字符集的问题而出现导入错误(详见《Mariadb导入数据表时发生“Unknown collation: 'utf8mb4_0900_ai_ci'”错误》一文)而又懒得折腾,或者就是偏好使用MySQL,那么只能下载安装包进行安装了。
首选,进入MySQL存储库下载页面,下载最新软件包。也可以在命令界面下使用wget命令下载最新的发行包。

wget https://repo.mysql.com/mysql-apt-config_0.8.33-1_all.deb

其次,下载完成后,使用如下命令进行安装。

sudo dpkg -i mysql-apt-config_0.8.33-1_all.deb

执行如上命令后,你会看到如下的MySQL配置安装界面,默认为8.4长期维护版本,如果需要切换则按回车键进行选择(下图为Ubuntu在虚拟机中的演示效果,Debian 12同理)。
MySQL-Package_configuration.jpg
MySQL-Package_configuration-receive_version.jpg
MySQL-Package_configuration-version_8_0.jpg
使用以下命令更新软件包,并安装MySQL。

sudo apt update
sudo apt install mysql-server

安装过程中将会要求设置root密码,这一步先不设置,Tab键切换到 “OK” 继续,然后在后期通过安全安装脚本进行配置。最后同样检验一下版本以及测试数据库运行。
可以通过在命令行中输入sudo mysqlsudo MariaDB进入数据库控制台。

设置MariaDB

登录MariaDB shell:

$ sudo mysql

创建一个示例数据库:

MariaDB> CREATE DATABASE exampledb;

创建SQL用户帐户:

MariaDB> CREATE USER 'exampleuser'@'localhost' IDENTIFIED BY 'YourPassword2!';

将数据库上的所有权限授予该用户:

MariaDB> GRANT ALL PRIVILEGES ON exampledb.* TO 'exampleuser'@'localhost';

由于我们没有修改root用户,因此应该创建另一个SQL用户来执行采用密码身份验证的管理任务。为此选择一个强密码。

MariaDB> GRANT ALL ON *.* TO 'navjot'@'localhost' IDENTIFIED BY 'Yourpassword32!' WITH GRANT OPTION;

清空用户权限:

MariaDB> FLUSH PRIVILEGES;

退出shell:

MariaDB> exit

让我们使用新创建的用户再次登录到MySQL shell:

$ sudo mysql -u exampleuser -p

创建一个测试表:

MariaDB> CREATE TABLE exampledb.name_list ( sno INT AUTO_INCREMENT, content VARCHAR(255), PRIMARY KEY(sno) );

插入测试数据:

MariaDB> INSERT INTO exampledb.name_list (content) VALUES ("Navjot");

重复上述命令多次以添加更多条目。执行以下命令检查表的内容:

MariaDB> SELECT * FROM exampledb.name_list;

你将获得如下输出结果:

+-----+---------+
| sno | content |
+-----+---------+
|   1 | Navjot  |
|   2 | Adam    |
|   3 | Josh    |
|   4 | Peter   |
+-----+---------+
4 rows in set (0.00 sec)

退出shell:

MariaDB> exit

安装Nginx

Debian 12附带了一个旧版本的Nginx。如果要安装最新版本,则需要下载官方Nginx存储库。
首先,导入Nginx的签名密钥:

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

添加Nginx稳定版本的存储库:

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/debian `lsb_release -cs` nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list

更新系统存储库:

$ sudo apt update

安装Nginx:

$ sudo apt install nginx

验证安装:

$ sudo nginx -v
nginx version: nginx/1.26.2

启动Nginx:

$ sudo systemctl start nginx

验证服务状态:

$ systemctl status nginx
● nginx.service - nginx - high performance web server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Sat 2025-01-04 14:39:57 CST; 5s ago
       Docs: https://nginx.org/en/docs/
    Process: 18225 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
   Main PID: 18226 (nginx)
      Tasks: 3 (limit: 4420)
     Memory: 2.9M
        CPU: 15ms
     CGroup: /system.slice/nginx.service
             ├─18226 "nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf"
             ├─18227 "nginx: worker process"
             └─18228 "nginx: worker process"

配置PHP-FPM

打开配置文件php.ini进行编辑:

$ sudo nano /etc/php/8.2/fpm/php.ini

根据服务器资源和需求配置PHP的内存限制,比如:

memory_limit = 256M

还有上传文件的大小限制:

upload_max_filesize = 50M
...
post_max_size = 50M

保存并退出。
也可以不打开文件,而直接使用如下的命令:

$ sudo sed -i 's/post_max_size = 8M/post_max_size = 50M/' /etc/php/8.2/fpm/php.ini
$ sudo sed -i 's/upload_max_filesize = 2M/upload_max_filesize = 50M/' /etc/php/8.2/fpm/php.ini
$ sudo sed -i 's/memory_limit = 128M/memory_limit = 256M/' /etc/php/8.2/fpm/php.ini

打开文件/etc/php/8.0/fpm/pool.d/www.conf

$ sudo nano /etc/php/8.2/fpm/pool.d/www.conf

我们需要将UNIX用户/PHP流程组设置为NGINX。在文件中找到用户= www-data,group = www-data行,然后将其更改为nginx。

...
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
user = nginx
group = nginx
...

同时,找到listen.owner=www-datalisten.group=www-data行,并将它们改成nginx:

listen.owner = nginx
listen.group = nginx

保存并退出。
重启PHP-fpm进程:

$ sudo systemctl restart php8.2-fpm

如果希望修改上述的用户名(比如www用户)则需要先创建用户,否则重启进程会提示错误。

安装phpMyAdmin

下载phpMyAdmin的文件包。可从phpMyAdmin下载页面中获取最新版本。

$ wget https://files.phpmyadmin.net/phpMyAdmin/5.2.1/phpMyAdmin-5.2.1-all-languages.tar.gz

为网站创建一个目录:

$ sudo mkdir /var/www/html/example.com -p

解压缩文档到站点目录下:

$ sudo tar -xzf phpMyAdmin-5.2.1-all-languages.tar.gz -C /var/www/html/example.com

切换到站点目录:

$ cd /var/www/html/example.com

将提取的目录重命名为比较模糊的名称以提高安全性,比如:

$ sudo mv phpMyAdmin-5.2.1-all-languages ms175

设置phpMyAdmin

复制示例配置文件:

$ sudo cp ms175/config.sample.inc.php ms175/config.inc.php

打开配置文件并编辑:

$ sudo nano sm175/config.inc.php

查找$cfg['blowfish secret'] = ";并输入一个32个字符的随机字符串,用于基于cookie的认证。
你可以使用phpSolved的在线生成器,也可以通过命令行完成。
复制黏贴生成的值,如下所示:

$cfg['blowfish_secret'] = 'Tc/HfLPBOADxJ-rhQP}HJoZEK69c3j:m';

保存并退出。
删除phpMyAdmin的setup目录:

$ sudo rm -rf /var/www/html/example.com/ms175/setup

设置Opcache

Opcache是PHP的缓存系统。它的工作原理是将预编译的脚本字节码保存在内存中,这样用户每次访问页面时,加载速度都会加快。Opcache默认已安装(见PHP安装部分中检验版本的结果,其中带有with Zend OPcache字样)。
如果结果中没有,可以运行以下命令手动安装:

$ sudo apt install php-opcache

要更改Opcache设置,请打开配置文件/etc/php/8.2/fpm/conf.d/10-opcache.ini进行编辑。

$ sudo nano /etc/php/8.2/fpm/conf.d/10-opcache.ini

以下设置可以帮助你开始使用Opcache,通常建议使用这些设置以获得良好的性能。你可以通过在底部添加以下行来启用它:

opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60

保存并退出。
重新启动PHP-FPM:

$ sudo systemctl restart php8.2-fpm

安装SSL证书

如果只希望使用Let's Encrypt的证书,那么可以安装Certbot证书脚本工具,如果希望有多个证书选择可以使用acme脚本(具体见《使用acme脚本申请免费ssl证书》一文)。以下是Certbot的安装和使用过程。
你可以使用Debian的存储库安装Certbot,也可以使用Snapd工具(一种全新的软件包管理工具)获取最新版本。在本安装中,将使用Snapd版本。Debian 12并没有安装Snapd,命令如下:

$ sudo apt install snapd

运行以下命令以确保Snapd为最新版:

$ sudo snap install core
$ sudo snap refresh core

安装Certbot:

$ sudo snap install --classic certbot

使用以下命令,通过创建指向/usr/bin目录的软链接,确保Certbot命令可以运行:

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

验证Certbot是否正常运行:

$ certbot --version
certbot 2.6.0

示例网站测试

创建并打开一个测试页面:

$ sudo nano /var/www/html/example.com/index.php

将以下代码粘贴到其中:

<?php
$user = "exampleuser";
$password = "YourPassword2!";
$database = "exampledb";
$table = "name_list";

try {
    $db = new PDO("mysql:host=localhost;dbname=$database", $user, $password);
    echo "<h2>Members List</h2><ol>"; 
    foreach($db->query("SELECT content FROM $table") as $row) {
        echo "<li>" . $row['content'] . "</li>";
    }
    echo "</ol>";
}   catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "<br/>";
    die();
}

保存并退出。

生成SSL证书

执行如下命令生成SSL证书:

$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m name@example.com -d example.com

上面的命令会将证书下载到服务器上的/etc/letsencrypt/live/example.com目录中。
生成Diffie-Hellman组证书:

$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096

检查Certbot更新调度程序服务。

$ sudo systemctl list-timers

会发现snap.certbot.renew.service是计划运行的服务之一。

试运行流程,检查SSL更新是否正常:

$ sudo certbot renew --dry-run

如果没有出错,则一切就绪,那么证书将自动更新。

设置Nginx

创建并打开文件/etc/nginx/conf.d/example.conf,进行编辑:

$ sudo nano /etc/nginx/conf.d/example.conf

将以下代码粘贴到其中:

server {
    listen       443 ssl http2;
    listen       [::]:443 ssl http2;
    server_name  example.com;

    access_log  /var/log/nginx/example.com.access.log;
    error_log   /var/log/nginx/example.com.error.log;

    ssl_certificate      /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

    ssl_session_timeout  5m;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    root /var/www/html/example.com;

    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Pass PHP Scripts To FastCGI Server
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock; #depends on PHP versions
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

# enforce HTTPS
server {
    listen       80;
    listen       [::]:80;
    server_name  example.com;
    return 301   https://$host$request_uri;
}

保存并退出。
打开/etc/nginx/nginx.conf文件进行编辑:

$ sudo nano /etc/nginx/nginx.conf

include /etc/nginx/conf.d/*.conf; 这一行前添加以下内容:

server_names_hash_bucket_size  64;

保存并退出。
验证Nginx配置:

$ sudo nginx -t

如果没有错误,就说明可以开始了。启动Nginx服务器:

$ sudo systemctl start nginx

如果出现警告的话,比如:

nginx: [warn] the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/conf.d/example.conf:2

则可以将开头几行修改为:

server {
    listen       443 ssl;
    listen       [::]:443 ssl;
    http2 on;
    server_name  example.com;
    ……

在浏览器中访问https://example.com,加载网站后将看到以下页面。
lemp-site-output.png
你可以通过浏览器访问https://example.com/ms175来访问phpMyAdmin。输入管理用户或之前创建的用户进行登录。

其他参考资料

https://www.cnblogs.com/linux265/p/17974348
https://www.cyberciti.biz/faq/set-up-a-firewall-with-ufw-on-debian-12-linux/

最后修改:2025 年 01 月 06 日
如果觉得我的文章对你有用,请随意赞赏