目录:

最近尝试用Apache搭建个人网站,记录一下过程。本文中所有需要替换的内容都用<>括起来,读者可以搜索>'>"来查找需要替换的内容。

由于完整代码包含私钥等敏感信息,恕不提供。

sed命令

替换文件中的字符串

支持正则表达式

sed --in-place 's/old/new/[option]' file
sed -i 's/old/new/[option]' file

option:

  • g:全局替换
  • i:忽略大小写
  • p:打印替换的行

范围替换

sed --in-place '/start/,/end/s/old/new/g' file
sed --in-place '10,20s/old/new/g' file

删除文件中的字符串

sed --in-place '/pattern/d' file

查看文件中的字符串

sed --quiet '/pattern/p' file

过滤输出

替换输出内容

echo "hello world" | sed 's/hello/hi/'

删除包含pattern的行

echo -e "hello\nworld" | sed '/hello/d'

只输出包含pattern的行

echo -e "hello\nworld" | sed --quiet '/hello/p'

更新并安装应用

由于PHP依赖Apache2和Git(?),所以第三行命令事实上可以改为sudo apt-get install php mysql-server --assume-yes --quiet

sudo apt-get update
sudo apt-get upgrade --assume-yes --quiet
# 安装Apache2、PHP、MySQL、Git
sudo apt-get install apache2 php mysql-server git --assume-yes --quiet
# 安装php插件
sudo apt-get install php-mysql php-mbstring php-gd --assume-yes --quiet

配置HTTP服务器

修改PHP配置文件

short_open_tag配置项默认为Off,修改为On,以便支持<?标签作为<?php的简写。 详见PHP配置文件

打开配置项short_open_tag(位于/etc/php/8.1/apache2/php.ini文件)

sudo sed --in-place 's/^short_open_tag = Off$/short_open_tag = On/g' /etc/php/8.1/apache2/php.ini

查看配置项short_open_tag是否修改成功

sed --quiet '/^short_open_tag/p' /etc/php/8.1/apache2/php.ini

修改APACHE2配置文件

启用rewrite模块

rewrite模块用来配置伪静态规则,详见Apaceh RewriteRule。 更详细的介绍请见mod_rewrite参考手册mod_rewrite入门

启用rewrite模块。使用--relative选项创建相对路径的软链接。

sudo ln --symbolic --relative /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/rewrite.load

或者使用a2enmod命令:

sudo a2enmod rewrite

修改apache2.conf文件

修改apache2.conf文件,允许/var/www/html目录下的.htaccess文件覆盖默认配置,并禁止列出目录内容。

原来的配置文件长这样:

<Directory /var/www/>
	Options Indexes FollowSymLinks
	AllowOverride None
	Require all granted
</Directory>

修改后的配置文件长这样:

<Directory /var/www/>
	Options FollowSymLinks
	AllowOverride All
	Require all granted
</Directory>

修改apache2.conf文件

sudo sed --in-place '/<Directory \/var\/www\/>/,/<\/Directory>/s/Options Indexes FollowSymLinks/Options FollowSymLinks/' /etc/apache2/apache2.conf
sudo sed --in-place '/<Directory \/var\/www\/>/,/<\/Directory>/s/AllowOverride None/AllowOverride All/' /etc/apache2/apache2.conf

这里使用/pattern1/,/pattern2/表示只替换pattern1pattern2之间的内容(局部替换)。

查看修改后的配置文件(<Directory /var/www/>部分)

sed --quiet '/<Directory \/var\/www\/>/,/<\/Directory>/p' /etc/apache2/apache2.conf

修改000-default.conf文件(可选)

修改000-default.conf文件,将DocumentRoot修改为/var/www/html/subdir

sudo sed --in-place 's/DocumentRoot \/var\/www\/html/DocumentRoot \/var\/www\/html\/subdir/' /etc/apache2/sites-enabled/000-default.conf

查看配置文件中的DocumentRoot配置项

sed --quiet '/DocumentRoot/p' /etc/apache2/sites-enabled/000-default.conf

重启Apache

sudo /etc/init.d/apache2 restart

配置伪静态规则

因为允许.htaccess文件覆盖默认配置,所以可以在/var/www/html目录下创建.htaccess文件,添加伪静态规则,无需重启Apache。

RewriteEngine on
RewriteRule ^(Ue|app|config|install)/ - [F]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php?s=$1 [L,QSA]

解释:

  • 如果请求的URL是Ueappconfiginstall目录时,返回403错误;
  • 如果请求的URL对应的文件或目录不存在,将请求重写到index.php文件。

另一种伪静态规则:

RewriteEngine on
RewriteBase "/"
RewriteRule ^(admin.php|index.php|assets)/ - [L]
RewriteRule ^(.*)$ /index.php?s=$1 [L,QSA]

解释:

  • 如果请求的URL是admin.php/index.php,则直接返回该文件或目录;
  • 如果请求的URL是assets目录,直接返回该文件或目录;
  • 否则,将请求重写到index.php文件(无论该URL对应的文件或目录是否存在)

修改/var/www/html目录权限

默认情况下,/var/www/html目录的所有者是root,这是为了保护网站的安全性,防止用户修改网站文件。

如果需要修改/var/www/html目录下的文件,有几种方法(越靠前越不推荐):

  • 将网站的用户改为root,这样就可以直接修改网站文件。因为root有权访问修改所有文件,如果网站以root身份访问文件系统,那么一旦Web服务器被破坏,它就能访问您的整个系统。本质上,我们通过指定身份是www-data而不是root,以保证即使Web服务器被破坏,它也只能完全访问其自己的文件,而不是整个服务器。
  • /var/www/html修改为777权限,这样所有用户都可以访问修改网站文件。这样做会导致网站不安全,任何用户都可以访问修改网站文件。
  • /var/www/html所有者改为网站用户,这样网站用户就可以访问修改网站文件,但是网站用户对该文件夹有完全的所有权,仍然可以任意访问修改网站文件,没有起到权限控制的作用。
  • 将我本人加入www-data组,将/var/www/html的所有者改为我本人,所有组改为www-data,这样我本人就可以访问修改网站文件,但是www-data组对该文件夹有完全的所有权,通过权限管理可以控制www-data允许查看和修改的文件。

我现在选择最后一种方案,但是权限管理上暂且偷懒了:除去部分文件设置了600权限(U=RW, G=, O=),其他文件设置了664权限(U=RW, G=RW, O=R),文件夹设置了775权限(U=RWX, G=RWX, O=RX)。

sudo usermod --append --groups www-data $USER # 将当前用户加入www-data组
sudo chown --verbose --recursive --from=root:root $USER:www-data /var/www/html # 将/var/www/html的所有者改为$USER, 所有组改为www-data
chmod --recursive g+w /var/www/html # 将/var/www/html的组权限改为可写。因为本来就是文件644,文件夹755,所以只需要加上组可写权限
ln --symbolic /var/www/html ~/html # 创建软链接~/html -> /var/www/html,方便平时访问

配置MySQL

创建数据库和用户

创建数据库web,创建用户web和当前用户,授权web和当前用户访问web数据库。

这里分开web用户和当前用户,是为了区分网站用户和和我本人,以便权限管理,并且也可以区分SQL命令来源。至于我本人为什么不用root用户,是因为root用户拥有最高权限,不适合用于日常操作。

sudo mysqladmin create web
sudo mysql -vvv --execute="CREATE USER 'web'@'localhost' IDENTIFIED BY '<password1>';"
sudo mysql -vvv --execute="CREATE USER '$USER'@'localhost' IDENTIFIED BY '<password2>';"
sudo mysql -vvv --execute="GRANT ALL PRIVILEGES ON web.* TO 'web'@'localhost';"
sudo mysql -vvv --execute="GRANT ALL PRIVILEGES ON web.* TO '$USER'@'localhost';"
sudo mysql -vvv --execute="FLUSH PRIVILEGES;"

命令解释:

  • -v: 显示输入的sql语句
  • -vv: 显示输入的sql语句和执行的结果(Query OK, 0 rows affected
  • -vvv: 像交互式一样显示结果(
    Query OK, 0 rows affected (0.05 sec)
    Records: 0  Duplicates: 0  Warnings: 0
    

配置~/.my.cnf

配置~/.my.cnf文件,以便在命令行中不用输入密码就可以访问数据库。这里不配置user,这样默认使用当前用户访问数据库,并且使用sudo mysql命令访问数据库时,用户自动切换为root用户(反正root用户没有密码,设置password并不影响访问)。

一定要配置600权限,你也不想别人看到你的数据库密码吧。尤其这个“别人”还是一般网站访客。

echo "配置~/.my.cnf"
echo -e "[client]\npassword=<password2>" | tee ~/.my.cnf
echo -e "[mysql]\ndatabase = web\nshow-warnings\nsafe-updates\nbinary-as-hex" | tee --append ~/.my.cnf
# 设置权限
chmod 600 ~/.my.cnf

命令解释:

  • echo命令用于输出内容,-e选项用于解析转义字符(比如\n),以便输出多行内容
  • tee命令用于将标准输入的内容写入文件,--append选项用于追加内容到文件末尾
  • show-warnings: 显示警告信息
  • safe-updates: 禁止不带WHERE子句的UPDATEDELETE语句
  • binary-as-hex: 以十六进制显示二进制数据

临时关闭safe-updates选项

mysql --safe-updates=0

配置Git

因为我选择使用SSH访问Git服务器,所以需要配置SSH密钥。别忘了设置600权限。

git config --global user.email "<email>"
git config --global user.name "<name>"
mkdir --parents ~/.ssh
cp --verbose "/mnt/d/install/git_ed25519" ~/.ssh/id_ed25519
find ~/.ssh -type f -exec chmod 600 {} \; -o -type d -exec chmod 700 {} \;

如果是远程服务器,可以使用scp命令上传密钥。

scp .\git_ed25519 <user>@<host>:~/.ssh/id_ed25519