为初学者构建一个包含 LXD 的网站/Web 服务器网络¶
简介¶
好的,我们已经有了一份在 Rocky Linux 上安装 LXD/LXC 的指南,但那是出自一位了解自己在做什么的人之手,他想在他本地网络上的物理机上构建一个容器化的服务器和/或应用程序网络。这很棒,我将直接借鉴其中的一些内容,这样就不用写太多了。
但是,如果您刚刚听说 Linux 容器,并且不太了解它们的工作原理,但又想托管一些网站,那么本指南就是为您准备的。本教程将教您如何在任何系统上使用 LXD 和 LXC 托管基本网站,包括虚拟专用服务器和云托管。
那么,什么是 Linux 容器?对于完全的初学者来说,它是一种让一台计算机假装成多台计算机的方式。这些“容器”各自包含一个您选择的操作系统的基本—通常是精简—版本。您可以将每个容器用作独立的服务器;在一个容器上放nginx,在另一个容器上放Apache,甚至使用第三个容器作为数据库服务器。
主要优点是,如果一个容器内的应用程序或网站出现严重错误、被黑客攻击或其他问题,不太可能影响您的其余服务器以及其他应用程序和网站。此外,容器非常容易快照、备份和还原。
在本例中,我们将在我们的“主机”系统(也是 Rocky Linux)之上运行容器化的 Rocky Linux。
从概念上讲,它类似于这样
如果您曾经玩过 VirtualBox 来运行一些 Windows 应用程序,那就像那样,但又不是。与虚拟机不同,Linux 容器不会为每个容器模拟整个硬件环境。相反,它们默认共享一些虚拟设备用于网络和存储,但您可以添加更多虚拟设备。因此,与虚拟机相比,它们需要的开销(处理能力和 RAM)少得多。
对于那些 Docker 用户来说(Docker 是另一个基于容器的系统,不是虚拟机系统),Linux 容器不像您习惯的那样短暂。每个容器实例中的所有数据都是持久的,并且您所做的任何更改都是永久性的,除非您恢复到备份。总之,关闭容器不会擦除您可能引入的任何问题。
LXD 具体来说,是一个命令行应用程序,可帮助您设置和管理 Linux 容器。今天我们将在我们的 Rocky Linux 主机服务器上安装它。我将经常写 LXC/LXD,因为有很多旧文档只提及 LXC,我正在努力让人们更容易找到此类更新的指南。
注意
在 LXD 之前有一个名为“LXC”的前身应用程序。今天,LXC 是技术,LXD 是应用程序。
我们将同时使用它们来创建一个大致如下的环境
具体来说,我将向您展示如何在服务器容器内设置简单的 Nginx 和 Apache Web 服务器,并使用另一个 Nginx 容器作为反向代理。同样,这种设置应该可以在任何环境中工作:从本地网络到虚拟专用服务器。
注意
反向代理是一种程序,它接收来自互联网(或您的本地网络)的传入连接,并将它们路由到正确的服务器、容器或应用程序。也有专门用于此任务的工具,如 HaProxy...但我发现 Nginx 更易于使用。
先决条件和假设¶
- 对 Linux 命令行界面有基本的了解。如果您在远程服务器上安装 LXC/LXD,您应该知道如何使用 SSH。
- 一台已连接互联网的服务器,物理的或虚拟的,上面已运行 Rocky Linux。
- 两个指向您的服务器的域名,并带有 A 记录。
- 两个子域名也可以。一个带通配符子域名记录的域名也可以,或者自定义的 LAN 域名。
- 一个命令行文本编辑器。nano 也可以,micro 是我的最爱,但使用任何您觉得舒适的。
- 您可以作为 root 用户完成整个教程,但这并非明智之举。在初始安装 LXC/LXD 后,我们将指导您创建一个非特权用户,专门用于操作 LXD 命令。
- 基于 Rocky Linux 的容器镜像现已可用。
- 如果您对 Nginx 或 Apache 不太熟悉,如果您想搭建一个完整的生产服务器,您将需要查看我们的一些其他指南。别担心,我会在下面链接它们。
设置主机服务器环境¶
安装 EPEL 仓库¶
LXD 需要 EPEL(企业 Linux 的额外软件包)仓库,可以使用以下命令轻松安装:
dnf install epel-release
安装完成后,检查更新:
dnf update
如果在上面的更新过程中有内核更新,请重新启动您的服务器:
安装 snapd¶
LXD 必须从 Rocky Linux 的 snap* 包安装。为此,我们需要使用以下命令安装 snapd:
dnf install snapd
现在,启用 snapd 服务以在服务器重启时自动启动,并立即启动它:
systemctl enable snapd
然后运行:
systemctl start snapd
在此之前重启服务器。您可以使用 reboot
命令或通过您的 VPS/云托管管理面板进行操作。
* snap 是一种打包应用程序的方法,它们会携带所有必需的依赖项,并且几乎可以在任何 Linux 系统上运行。
安装 LXD¶
安装 LXD 需要使用 snap 命令。此时,我们只是安装它,不做任何设置:
snap install lxd
如果您在物理(即“裸机”)服务器上运行 LXD,您最好回到另一篇指南并阅读其中的“环境设置”部分。那里有很多关于内核、文件系统等的精彩内容。
如果您在虚拟环境中运行 LXD,只需重启并继续阅读。
LXD 初始化¶
现在环境已经全部设置好,我们准备初始化 LXD。这是一个自动化脚本,会提出一系列问题以启动并运行您的 LXD 实例:
lxd init
以下是脚本的问题和我们的答案,并附有一些解释:
Would you like to use LXD clustering? (yes/no) [default=no]:
如果您对集群感兴趣,请在此处进行更多研究。否则,只需按“Enter”键接受默认选项。
Do you want to configure a new storage pool? (yes/no) [default=yes]:
接受默认值。
Name of the new storage pool [default=default]: server-storage
为您的存储池选择一个名称。我喜欢将其命名为 LXD 运行所在服务器的名称。(存储池基本上是一定量的硬盘空间,专门用于您的容器。)
Name of the storage backend to use (btrfs, dir, lvm, zfs, ceph) [default=zfs]: lvm
上面的问题是关于您想使用哪种文件系统进行存储,默认值可能因您系统上可用的内容而异。如果您使用的是裸机服务器,并且想使用 ZFS,请再次参考上面链接的指南。
在虚拟环境中,我发现“LVM”工作正常,而且通常是我使用的。您可以接受下一个问题的默认值。
Create a new LVM pool? (yes/no) [default=yes]:
如果您有一个特定的硬盘或分区希望用于整个存储池,请在下一个问题中回答“yes”。如果您正在 VPS 上执行所有这些操作,您可能必须选择“no”。
Would you like to use an existing empty block device (e.g., a disk or partition)? (yes/no) [default=no]:
Metal As A Service (MAAS) 超出了本文档的范围。接受这些默认值。
Would you like to connect to a MAAS server? (yes/no) [default=no]:
以及更多默认值。一切都很好。
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]: `
What IPv4 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
如果您想在 LXD 容器中使用 IPv6,可以启用下一个选项。这取决于您,但通常您不需要。
What IPv6 address should be used? (CIDR subnet notation, “auto” or “none”) [default=auto]:
这对于轻松备份服务器是必需的,并且可以允许您从其他计算机管理您的 LXD 安装。如果这一切听起来都不错,请在此处回答“yes”。
Would you like the LXD server to be available over the network? (yes/no) [default=no]: yes
如果您对最后一个问题回答了“yes”,请在此处接受默认值。
Address to bind LXD to (not including port) [default=all]:
Port to bind LXD to [default=8443]:
现在会询问您一个信任密码。这是您将如何从其他计算机和服务器连接到 LXC 主机服务器,因此请将其设置为您环境中合理的内容。将此密码保存在安全的位置,例如密码管理器。
Trust password for new clients:
Again:
然后继续接受后续的所有默认值。
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:
设置用户权限¶
在继续之前,我们需要创建我们的“lxdadmin”用户,并确保它具有所需的权限。我们需要“lxdadmin”用户能够使用 sudo 来访问 root 命令,并且需要它是“lxd”组的成员。要添加用户并确保它是这两个组的成员,请运行:
useradd -G wheel,lxd lxdadmin
然后设置密码:
passwd lxdadmin
与之前的密码一样,将此密码保存在安全的位置。
设置防火墙¶
在对容器做任何其他事情之前,您需要能够从外部访问您的代理服务器。如果您的防火墙阻止了端口 80(HTTP/Web 流量的默认端口)或端口 443(用于 HTTPS/安全Web 流量),那么您将无法做任何服务器相关的事情。
另一个 LXD 指南将向您展示如何使用 iptables 防火墙执行此操作,如果您想这样做的话。我倾向于使用 CentOS 的默认防火墙:firewalld。所以这次我们要这样做。
firewalld
通过 firewall-cmd
命令进行配置。我们要做的第一件事,在开放任何端口之前,是确保您的容器可以自动分配 IP 地址:
firewall-cmd --zone=trusted --permanent --change-interface=lxdbr0
警告
如果您不执行最后一个步骤,您的容器将无法正常访问互联网或彼此。这是至关重要的,了解这一点将为您节省大量的挫败感。
现在,要添加一个新端口,只需运行此命令:
firewall-cmd --permanent --zone=public --add-port=80/tcp
我们来分解一下:
--permanent
标志告诉防火墙确保在每次防火墙重启以及服务器本身重启时都使用此配置。--zone=public
告诉防火墙对所有人开放此端口的传入连接。- 最后,
--add-port=80/tcp
告诉防火墙接受端口 80 上的传入连接,只要它们使用 TCP(传输控制协议),这就是您在这种情况下需要的。
要对 HTTPS 流量重复此过程,只需再次运行该命令,然后更改数字。
firewall-cmd --permanent --zone=public --add-port=443/tcp
这些配置在您强制执行之前不会生效。要做到这一点,请让 firewalld 重新加载其配置,如下所示:
firewall-cmd --reload
现在,极小的可能性是这不起作用。在那些罕见情况下,让 firewalld 通过经典的“关机再开机”来按您的意愿执行。
systemctl restart firewalld
要确保端口已正确添加,请运行 firewall-cmd --list-all
。一个配置正确的防火墙看起来会有点像这样(我在本地服务器上打开了几个额外的端口,请忽略它们):
public (active)
target: default
icmp-block-inversion: no
interfaces: enp9s0
sources:
services: cockpit dhcpv6-client ssh
ports: 81/tcp 444/tcp 15151/tcp 80/tcp 443/tcp
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
这样应该就是防火墙方面的所有内容了。
设置容器¶
实际上管理容器非常简单。将其想象成能够随时召唤一台完整的计算机,并按需启动或停止。您还可以登录到上述“计算机”并运行任何您喜欢的命令,就像在主机服务器上一样。
注意
从现在开始,所有命令都应该以 lxdadmin
用户(或您选择的任何名称)的身份运行,尽管其中一些需要使用 sudo 来临时获得 root 权限。
在本教程中,您需要三个容器:反向代理服务器、测试 Nginx 服务器和测试 Apache 服务器,所有这些都运行在基于 Rocky 的容器上。
如果出于某种原因您需要一个完全特权的容器(您通常不需要),您可以以 root 身份运行所有这些命令。
在本教程中,您需要三个容器:
我们将它们命名为“proxy-server”(用于将 Web 流量路由到另外两个容器的容器)、“nginx-server”和“apache-server”。是的,我将向您展示如何反向代理到基于 nginx 和 apache 的服务器。
我们将从确定要基于哪个镜像创建容器开始。在本教程中,我们只使用 Rocky Linux。例如,使用 Alpine Linux 可以创建更小的容器(如果存储是关注点),但这超出了本文档的范围。
查找您想要的镜像¶
以下是使用 Rocky Linux 快速启动容器的方法:
lxc launch images:rockylinux/8/amd64 my-container
当然,“my-container”部分应该重命名为您想要的容器名称,例如“proxy-server”。如果您在 Raspberry Pi 之类的东西上执行所有这些操作,则“/amd64”部分应更改为“arm64”。
现在是详细版本:要查找您想要的镜像,您可以使用此命令列出 LXC 主存储库中的所有可用镜像:
lxc image list images: | more
然后只需按“Enter”键向下滚动大量的镜像列表,然后按“Control-C”退出列表视图模式。
或者,您可以简化您的生活,并指定您想要的 Linux 类型,如下所示:
lxc image list images: | grep rockylinux
这应该会打印出一个更短的列表,看起来像这样:
| rockylinux/8 (3 more) | 4e6beda70200 | yes | Rockylinux 8 amd64 (20220129_03:44) | x86_64 | VIRTUAL-MACHINE | 612.19MB | Jan 29, 2022 at 12:00am (UTC) |
| rockylinux/8 (3 more) | c04dd2bcf20b | yes | Rockylinux 8 amd64 (20220129_03:44) | x86_64 | CONTAINER | 127.34MB | Jan 29, 2022 at 12:00am (UTC) |
| rockylinux/8/arm64 (1 more) | adc0561d6330 | yes | Rockylinux 8 arm64 (20220129_03:44) | aarch64 | CONTAINER | 124.03MB | Jan 29, 2022 at 12:00am (UTC) |
| rockylinux/8/cloud (1 more) | 2591d9716b04 | yes | Rockylinux 8 amd64 (20220129_03:43) | x86_64 | CONTAINER | 147.04MB | Jan 29, 2022 at 12:00am (UTC) |
| rockylinux/8/cloud (1 more) | c963253fcea9 | yes | Rockylinux 8 amd64 (20220129_03:43) | x86_64 | VIRTUAL-MACHINE | 630.56MB | Jan 29, 2022 at 12:00am (UTC) |
| rockylinux/8/cloud/arm64 | 9f49e80afa5b | yes | Rockylinux 8 arm64 (20220129_03:44) | aarch64 | CONTAINER | 143.15MB | Jan 29, 2022 at 12:00am (UTC) |
创建容器¶
注意
下面是创建所有这些容器的快捷方法。您可能想在创建 proxy-server 容器之前稍作等待。下面我将向您展示一个技巧,可以节省您一些时间。
找到您想要的镜像后,使用上面显示的 lxc launch
命令。要创建本教程所需的容器,请按顺序运行以下命令(根据需要进行修改):
lxc launch images:rockylinux/8/amd64 proxy-server
lxc launch images:rockylinux/8/amd64 nginx-server
lxc launch images:rockylinux/8/amd64 apache-server
当您运行每个命令时,您应该会收到通知,表明您的容器已创建甚至启动。然后,您需要检查所有容器。
运行此命令以查看它们是否都已启动并正在运行:
lxc list
这应该会给您类似以下的输出(尽管如果您选择了使用 IPv6,它会显示更多文本):
+---------------+---------+-----------------------+------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+---------------+---------+-----------------------+------+-----------+-----------+
| proxy-server | RUNNING | 10.199.182.231 (eth0) | | CONTAINER | 0 |
+---------------+---------+-----------------------+------+-----------+-----------+
| nginx-server | RUNNING | 10.199.182.232 (eth0) | | CONTAINER | 0 |
+---------------+---------+-----------------------+------+-----------+-----------+
| apache-server | RUNNING | 10.199.182.233 (eth0) | | CONTAINER | 0 |
+---------------+---------+-----------------------+------+-----------+-----------+
关于容器网络的一点说明¶
因此,本指南开头链接的另一个指南有一个关于如何设置 LXC/LXD 以便与 Macvlan 配合使用的完整教程。如果您正在运行本地服务器,并且希望每个容器都有一个在本地网络上可见的 IP 地址,这将特别有用。
在 VPS 上运行时,您通常没有该选项。实际上,您可能只有一个允许您使用的 IP 地址。默认网络配置旨在适应这种限制;按照我上面指定的回答 lxd init
问题应该能解决所有问题。
基本上,LXD 创建一个名为桥(通常命名为“lxdbr0”)的虚拟网络设备,并且默认情况下所有容器都连接到该桥。通过它,它们可以通过您的主机的默认网络设备(以太网、Wi-Fi 或 VPS 提供的虚拟网络设备)连接到互联网。更重要的是,所有容器都可以相互连接。
为了确保这种容器间连接,每个容器都会获得一个内部域名。默认情况下,它只是容器的名称加上“.lxd”。因此,“proxy-server”容器对所有其他容器都可通过“proxy-server.lxd”访问。但这里有一个真正重要的知识点:默认情况下,“.lxd”域仅在容器内部可用。
如果您在主机操作系统(或其他任何地方)上运行 ping proxy-server.lxd
,您将得不到任何响应。不过,这些内部域名稍后会非常有用。
您实际上可以更改此设置,使容器的内部域名在主机上可用……但我从未真正弄清楚。将反向代理服务器放在容器中通常是最好的,这样您可以轻松地对其进行快照和备份。
管理您的容器¶
在继续之前,您应该了解的一些事项:
启动与停止¶
所有容器都可以根据需要使用以下命令进行启动、停止和重启:
lxc start mycontainer
lxc stop mycontainer
lxc restart mycontainer
即使是 Linux 有时也需要重启。您实际上可以一次性启动、停止和重启所有容器,使用以下命令:
lxc start --all
lxc stop --all
lxc restart --all
restart --all
选项对于某些更晦涩的临时 bug 非常有用。
在您的容器中执行操作¶
您可以通过两种方式控制容器内的操作系统:您可以直接从主机操作系统在容器中运行命令,或者您可以打开一个 shell。
我的意思是,要运行容器内的命令,例如安装 Apache,只需使用 lxc exec
,如下所示:
lxc exec my-container dnf install httpd -y
这将安装 Apache,您将在主机的终端上看到命令的输出。
要打开一个 shell(您可以在其中像 root 用户一样运行所有您想要的命令),请使用此命令:
lxc exec my-container bash
如果您像我一样,重视便利性而不是存储空间,并且在所有容器中都安装了像 fish 这样的备用 shell,只需更改命令,如下所示:
lxc exec my-container fish
几乎在所有情况下,您都会自动进入 root 账户,并位于 /root
目录。
最后,如果您打开了容器的 shell,您可以像退出任何 shell 一样退出它:使用简单的 exit
命令。
复制容器¶
现在,如果您有一个想要轻松复制的容器,则无需启动一个全新的容器并重新安装所有基础应用程序。这需要不必要的额外工作。只需运行:
lxc copy my-container my-other-container
将创建“my-container”的精确副本,名为“my-other-container”。它可能不会自动启动,因此请对新容器的配置进行任何您可能想要的更改,然后运行:
lxc start my-other-container
此时,您可能想进行一些更改,例如更改容器的内部主机名或其他内容。
配置存储和 CPU 限制¶
LXC/LXD 通常定义容器获得多少存储空间,并通常管理资源,但您可能希望对其进行控制。如果您担心保持容器体积小巧,可以使用 lxc config
命令按需进行收缩和扩展。
以下命令将为容器设置 2GB 的“软”限制。软限制实际上更像“最小存储”,并且如果可用,容器将使用更多存储。一如既往,请将“my-container”更改为您实际容器的名称。
lxc config set my-container limits.memory 2GB
您可以这样做来设置硬限制:
lxc config set my-container limits.memory.enforce 2GB
如果您想确保任何给定容器都无法占用您服务器的所有可用处理能力,可以使用此命令限制其可访问的 CPU 核心数量。只需根据您的需要更改末尾的 CPU 核心数量。
lxc config set my-container limits.cpu 2
删除容器(以及如何防止其发生)¶
最后,您可以通过运行此命令来删除容器:
lxc delete my-container
如果容器正在运行,您将无法删除它,因此您可以先停止它,或者使用 --force
标志来跳过这一步。
lxc delete my-container --force
现在,由于Tab 键的命令补全功能、用户错误以及大多数键盘上D 键紧挨着S 键的事实,您可能会不小心删除容器。
为了防止这种情况发生,您可以将任何容器设置为“受保护”(使其删除过程需要额外的步骤),方法是运行此命令:
lxc config set my-container security.protection.delete true
要取消保护容器,只需再次运行该命令,但将“true”更改为“false”。
设置服务器¶
好的,现在您的容器已启动并运行,是时候安装您需要的东西了。首先,确保所有容器都已更新,运行以下命令(如果您尚未创建“proxy-server”容器,请跳过它):
lxc exec proxy-server dnf update -y
lxc exec nginx-server dnf update -y
lxc exec apache-server dnf update -y
然后,进入每个容器并开始工作。
您还需要为每个容器准备一个文本编辑器。默认情况下,Rocky Linux 附带 vi,但如果您想简化生活,nano 也可以。您可以在打开容器之前在每个容器中安装它。
lxc exec proxy-server dnf install nano -y
lxc exec nginx-server dnf install nano -y
lxc exec apache-server dnf install nano -y
在接下来的所有文本编辑器相关命令中,我将使用 nano,但您随意使用。
Apache 网站服务器¶
出于学习和测试目的,我们将保持简短。有关完整的 Apache 指南,请参阅下面的链接。
首先,打开容器的 shell。请注意,默认情况下,容器会直接进入 root 账户。对我们来说没问题,尽管您可能希望为实际生产目的创建一个特定的 Web 服务器用户。
lxc exec apache-server bash
登录后,只需以简单的方式安装 Apache:
dnf install httpd
现在,您可以从这里开始遵循我们的Apache Web 服务器多站点设置指南,但这实际上对于我们的目的来说是过度的。在这样的容器化环境中,我们通常不想设置 Apache 来托管多个网站。毕竟,容器的整个目的是分离关注点。
另外,SSL 证书将放在代理服务器上,所以我们将保持简单。
安装 Apache 后,请确保它正在运行,并且可以在重启后继续运行:
systemctl enable --now httpd
--now
标志可以让您跳过启动实际服务器的命令。供参考,这将是:
systemctl start httpd
如果您在服务器主机上安装了 curl
,您可以使用以下命令确保默认网页已启动并运行:
curl [container-ip-address]
请记住,您可以使用 lxc list
查看所有容器的 IP 地址。如果您在所有容器中都安装了 curl,您可以直接运行:
curl localhost
从代理服务器获取真实用户 IP¶
现在,您需要执行此步骤来准备 Apache 使用反向代理。默认情况下,Web 服务器容器中的实际用户 IP 地址不会被记录。您希望这些 IP 地址能够通过,因为某些 Web 应用程序需要用户 IP 来进行审核、屏蔽和故障排除。
要让您的访问者 IP 地址通过代理服务器,您需要两部分:代理服务器中的正确设置(我们稍后会介绍),以及 Apache 服务器的一个简单配置文件。
非常感谢 Linode 和他们自己的 LXD 指南提供了这些配置文件模板。
创建一个新的配置文件:
nano /etc/httpd/conf.d/real-ip.conf
并将以下文本添加到其中:
RemoteIPHeader X-Real-IP
RemoteIPTrustedProxy proxy-server.lxd
请记住,如果必要,请将 proxy-server.lxd
替换为您实际代理容器的名称。现在,暂时不要重启 Apache 服务器。 我们添加的配置文件可能会产生问题,直到我们设置好代理服务器。
暂时退出 shell,然后开始处理 Nginx 服务器。
注意
虽然此技术确实有效(您的 Web 应用程序和网站将获得用户的真实 IP),但 Apache 本身的访问日志不会显示正确的 IP。它们通常会显示您的反向代理所在的容器的 IP。这显然是 Apache 日志记录方式的问题。
如果您需要自行查看 IP 地址,可以检查代理服务器的访问日志,或检查您要安装的任何 Web 应用程序的日志。
Nginx 网站服务器¶
同样,我们将保持简短。如果您想在生产中使用最新(且推荐)版本的 Nginx,请查看我们安装 Nginx 的初学者指南。该指南涵盖了完整的安装过程以及配置服务器的一些最佳实践。
首先,登录到容器的 shell:
lxc exec nginx-server bash
使用默认命令安装 Nginx:
dnf install nginx
然后,启用并启动 Nginx:
dnf enable --now nginx
注意
还记得我说要等一下再创建代理容器吗?原因如下:此时,您可以通过复制“nginx-server”容器来创建“proxy-server”容器,从而节省一些时间。
lxc copy nginx-server proxy-server
请确保使用 lxc start proxy-server
启动代理容器,并将代理端口添加到容器中,如下所述。
同样,您可以从主机上检查容器是否正常工作:
curl [your-container-ip]
再次从代理服务器获取真实用户 IP¶
日志应该这次能正常工作。应该。为此,我们在 /etc/nginx/conf.d
中放置一个非常相似的文件:
nano /etc/nginx/conf.d/real-ip.conf
然后将以下文本放入其中:
real_ip_header X-Real-IP;
set_real_ip_from proxy-server.lxd;
最后,暂时不要重启服务器。同样,该配置文件在代理服务器设置好之前可能会导致问题。
反向代理服务器¶
还记得我说您需要两个域名或子域名吗?这就是您需要它们的地方。本教程中使用的子域名是:
- apache.server.test
- nginx.server.test
根据需要更改所有文件和说明中的名称。
如果您从“nginx-server”容器复制了“proxy-server”容器,并且已将其添加了代理设备,请直接进入 shell。如果您之前创建了容器,则需要在“proxy-server”容器中重复安装 Nginx 的所有步骤。
安装完成后,并且您知道它运行正常,您只需要设置几个配置文件来将流量从您选择的域名路由到实际的网站服务器。
在此之前,请确保您可以通过内部域名访问这两个服务器:
curl apache-server.lxd
curl nginx-server.lxd
如果这两个命令在您的终端中加载了默认服务器欢迎页面的 HTML,那么一切都已正确设置。
关键步骤:配置“proxy-server”容器以接收所有传入的服务器流量¶
同样,您可能想在实际创建代理服务器时稍后执行此操作,但以下是您需要的说明:
还记得我们打开了防火墙中的端口 80 和 443 吗?这里我们让“proxy-server”容器监听这些端口,并接收所有指向它们的流量。
只需连续运行这两个命令:
lxc config device add proxy-server myproxy80 proxy listen=tcp:0.0.0.0:80 connect=tcp:127.0.0.1:80
lxc config device add proxy-server myproxy443 proxy listen=tcp:0.0.0.0:443 connect=tcp:127.0.0.1:443
我们来分解一下。每个命令都在 proxy-server 容器中添加一个虚拟“设备”。这些设备设置为监听主机操作系统上的端口 80 和端口 443,并将它们绑定到容器的端口 80 和端口 443。每个设备都需要一个名称,因此我选择了“myproxy80”和“myproxy443”。
listen
选项是主机操作系统上的端口,如果我没记错的话,0.0.0.0 是“lxdbr0”桥上的主机的 IP 地址。connect
选项是正在连接的本地 IP 地址和端口。
注意
设置好这些设备后,您应该重启所有容器,以确保一切正常。
这些虚拟设备理想情况下应该是唯一的。通常最好不要将“myport80”设备添加到另一个正在运行的容器中;它需要有另一个名称。
同样,一次只有一个容器可以监听任何特定的主机操作系统端口。
将流量导向 Apache 服务器¶
在“proxy-server”容器中,在 /etc/nginx/conf.d/
中创建一个名为 apache-server.conf
的配置文件。
nano /etc/nginx/conf.d/apache-server.conf
然后粘贴此文本,根据需要更改域名,然后保存:
upstream apache-server {
server apache-server.lxd:80;
}
server {
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
server_name apache.server.test; #< Your domain goes here
location / {
proxy_pass http://apache-server;
proxy_redirect off;
proxy_set_header Host $host;
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;
}
}
我们来稍微分解一下:
upstream
部分确切定义了反向代理将发送所有流量的位置。具体来说,它将流量发送到“apache-server”容器的内部域名:apache-server.lxd
。- 以
listen
开头的两条线指示服务器使用代理协议监听端口 80 上的流量。第一条通过 IPv4,第二条通过 IPv6。 server_name
功能负责处理所有专门指向“apache.server.test”的流量,并通过反向代理进行路由。proxy-pass
功能是实际将server_name
变量捕获的所有流量定向并发送到upstream
部分定义的服务器的部分。proxy_redirect
功能可能与反向代理产生干扰,因此我们确保将其关闭。- 所有
proxy-set-header
选项都在将用户 IP 等信息发送到 Web 服务器。
警告
listen
变量中的 proxy_protocol
部分对于代理服务器正常工作是*至关重要*的。切勿省略。
对于每个 LXD/网站配置文件,您都需要相应地更改 upstream
、server
、server_name
和 proxy_pass
设置。proxy-pass
中“http://”之后的文本必须与 upstream
文本之后的文本匹配。
使用 systemctl restart nginx
重新加载服务器,然后将浏览器指向您使用的任何域名,而不是 apache.server.test
。如果您的页面看起来像这样,那么您就成功了:
注意
您可以随意命名配置文件。我在这里的教程中使用的是简化名称,但一些系统管理员建议使用与实际域名相关的名称,但倒序。这是一种基于字母顺序的组织方式。
例如,“apache.server.test”将获得一个名为 test.server.apache.conf
的配置文件。
将流量导向 Nginx 服务器¶
基本上重复这个过程。像以前一样创建一个文件:
nano /etc/nginx/conf.d/nginx-server.conf
添加适当的文本:
upstream nginx-server {
server rocky-nginx.lxd:80;
}
server {
listen 80 proxy_protocol;
listen [::]:80 proxy_protocol;
server_name nginx.server.test; #< Your domain goes here
location / {
proxy_pass http://nginx-server;
proxy_redirect off;
proxy_set_header Host $host;
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;
}
}
同样,重新加载代理服务器,将浏览器指向相应的地址,并希望您看到这个:
重启您的 Web 服务器容器中的服务器¶
退出“proxy-server”容器,然后使用一个简单的命令重启另外两个容器中的服务器:
lxc exec apache-server systemctl restart httpd && lxc exec nginx-server restart nginx
这将把我们制作的“real-ip.conf”文件应用到它们各自的服务器配置中。
为您的网站获取 SSL 证书¶
使用 Let's Encrypt 和一个名为 certbot 的小应用程序可以最轻松地获取官方、正规的 SSL 证书。certbot 将自动检测您的网站,获取它们的 SSL 证书,并配置网站本身。它甚至会大约每 30 天自动续订一次证书,无需您或 cron 作业的任何干预。
所有这些都必须在“proxy-server”容器中完成,所以登录到该 shell。进入后,像在主机上一样安装 EPEL 存储库。确保容器首先更新:
dnf update
然后,添加 EPEL 存储库:
dnf install epel-release
然后您只需要安装 certbot 及其 Nginx 模块:
dnf install certbot python3-certbot-nginx
安装后,只要您已经配置了几个网站,只需运行:
certbot --nginx
Certbot 将读取您的 Nginx 配置,并找出您有多少网站以及它们是否需要 SSL 证书。此时,您会被问到几个问题。您是否接受服务条款,您是否想要电子邮件等?
最重要的几个问题如下。看到这个时输入您的电子邮件地址:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Enter email address (used for urgent renewal and security notices)
(Enter 'c' to cancel):
在这里,您可以选择哪些网站获得证书。只需按 Enter 即可为所有网站获取证书。
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: apache.server.test
2: nginx.server.test
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):
您将看到大量确认文本,然后就完成了。但如果您访问您的网站,您可能会发现它们无法工作。这是因为当 certbot 创建更新的配置时,它会忘记一件非常重要的事情。
进入您的 apache-server.conf
和 nginx-server.conf
文件,找到以下两行:
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
是的,它们缺少 proxy_protocol
设置,这很糟糕。自己添加。
listen proxy_protocol [::]:443 ssl ipv6only=on; # managed by Certbot
listen proxy_protocol 443 ssl; # managed by Certbot
保存文件,重启服务器,您的网站应该可以正常加载。
备注¶
- 在本教程中,我没有过多提及实际 Web 服务器的配置。在生产环境中,您至少应该做的是更改实际 Web 服务器容器中的服务器配置文件中的域名,而不仅仅是代理容器。也许在每个容器中设置一个 Web 服务器用户。
- 如果您想了解更多关于手动管理 SSL 证书和 SSL 服务器配置的信息,请查看我们关于安装 certbot 和生成 SSL 证书的指南。
- 像 Nextcloud 这样的应用程序(出于安全原因)需要一些额外的配置,如果您将它们放在 LXD 容器中并在代理后面,则需要。
结论¶
关于 LXC/LXD、容器化、Web 服务器和运行网站还有很多要学,但这应该能为您打下良好的基础。一旦您了解了所有内容应如何设置以及如何按您喜欢的方式进行配置,您甚至可以开始自动化该过程。
您可以使用 Ansible,或者像我一样,拥有一套自定义脚本来运行以加快一切速度。您甚至可以创建小型“模板容器”,其中预先安装了您所有喜欢的软件,然后只需复制它们并根据需要扩展它们的存储容量。
好了。完成了。我要去玩电子游戏了。玩得开心!
作者:Ezequiel Bruni
贡献者:Steven Spencer, Ganna Zhyrnova