网页网站您现在的位置是:首页 > 博客日志 > 网页网站

我在单个服务器上托管几十个网站

<a href='mailto:'>微wx笑</a>的头像微wx笑 2022-06-18网页网站 2 0关键字: 网站  服务器  

作者详细介绍,他如何在一个服务器上托管几十个网站,大部分是 API 调用。这里最大的难题还不是把服务架起来,而是如何同时维护和管理它们。

多年来,我积累了相当多的网站、Web 应用程序、API 和其他我构建并继续公开托管的服务。我已经为他们尝试了很多不同的托管方法,在几个不同的提供商之间切换,最终找到了我觉得可以满足我所有需求的东西。YYl无知

如今,托管软件有几乎无限的选择,而且每天都会出现更多。但是,您可以在网上找到许多关于此类事情的文章和指南,它们要么来自公共云提供商,要么来自拥有庞大基础设施、复杂应用程序需求和大量流量的公司。YYl无知

我想写这篇文章主要是为了分享我为架构做出的决定以及为什么我会以我的方式做事。虽然我的需求规模要小得多,而且我目前不为我正在运行的任何东西收取任何费用,但我仍然想为我的网站用户提供尽可能好的体验并保护我在项目中投入的所有工作.YYl无知

硬件

我在俄勒冈州希尔斯伯勒托管的 OVH 的单个专用服务器上运行所有内容。我选择了那个位置,因为我住在西雅图,从我的公寓可以很好地 ping 到它。来自美国东海岸的 Ping 通常小于 100 毫秒,我认为这是可以接受的。我在税后支付约 85 美元/月的费用。这是相当昂贵的,老实说,它比我需要的要多,但我非常关心我的网站以及我在那里建立和托管的其他东西,所以我很乐意花钱买一台好的服务器来托管它们。YYl无知

它具有以下规格:YYl无知

CPU: Intel Xeon E5-1650 v4, 6 cores/12 threads @ 3.6GhzMemory: 64GBNetwork: 500mbit upload / 1Gbit download, uncappedHD: 2x 420GB NVME in RAID 1, 420GB effective storageOS: Debian

过去,我使用各种虚拟服务器来托管我的服务。我和许多其他人一样,在我第一次学习编程和系统管理时使用他们的免费学生学分和每月 5 美元的 droplet 开始使用DigitalOcean 。YYl无知

几年后,我搬到了SSDNodes——一家提供极其便宜的服务器的“预算”托管公司。他们总是在进行某种形式的销售;目前,他们以每年 100 美元的价格提供具有 48GB RAM、12vCPU 和 760GB 存储的 KVM “2X-LARGE” VPS。这听起来好得令人难以置信,这是我的经验。在那里运行东西时,我遇到了很大的性能问题;我很确定他们的 CPU 非常超额认购,而且他们的 HD 非常慢。他们的服务器也有随机重启的问题。因此,对于严重的生产工作负载,我真的不能推荐它。话虽如此,当我在学校时,这对我来说是一个很好的选择,并且对我来说足够好几年了。YYl无知

虚拟与专用

我真的很想使用专用服务器而不是虚拟服务器。我没有很多技术原因。一个设置良好的、非过度使用的 VPS 和具有相同底层硬件的专用服务器之间的性能应该几乎相同。我也没有做任何花哨的自定义内核调整或类似的事情。我确实喜欢这样一个事实,即我是唯一一个使用硬盘驱动器的人,并且存在 IOPS 限制或奇怪的网络存储设置。YYl无知

我也非常喜欢我完全控制的 OVH 数据中心中真正的硬件设置盒的想法。它确实为我构建和维护的完全虚拟的构造带来了持久性和有形的感觉。YYl无知

容器 + 码头工人

我的服务没有像 Kubernetes 这样的“编排”层。我非常明确地做出了这个决定。我在多个工作中使用过 Kubernetes,包括我现在的工作,它带来的复杂性和问题的数量对于托管像我这样的东西所带来的好处来说太高了。如果我运行的服务数量大幅增长或者我需要添加额外的服务器,我可能会在未来重新考虑这个决定。YYl无知

作为替代方案,我使用普通的 Docker。每个服务器、数据库和其他服务都在自己的容器中运行。目前,我的服务器上有 67 个正在运行的容器。如果服务器重新启动,所有容器都配置为自动重新启动,但这种情况很少发生。从我的角度来看,与 K8s 相比的主要缺点是当我部署新版本的东西时会有一些小的停机时间,因为我没有任何负载平衡或滚动部署。对于我的应用程序和流量水平,几秒钟的停机时间是可以接受的,只需停止和重新创建容器就足够了。YYl无知

每当我添加新服务时,我都会记录我用来启动它的确切命令,并在我出于任何原因需要重新创建容器时引用它。我知道这是一个可以改进的领域;它现在非常手动。我很想听听人们为此提出的某种轻量级解决方案。docker runYYl无知

我仍然获得了我所依赖的容器化的所有重要好处。服务相互隔离,依赖关系和环境是确定性的,更易于管理,并且可以对单个服务进行更改和推理,而不会破坏其他应用程序。YYl无知

对于需要在文件系统上存储状态的任何容器,我使用映射到主机文件系统上专用目录中的文件夹的卷挂载。这确保了容器可以被销毁和重新创建而不会丢失数据。我还会自动备份这些数据,这将在后面的部分中详细介绍。YYl无知

对于绑定和侦听端口的服务,我从容器默认侦听的任何端口映射到单独的范围。我为每个不同的服务保留了 100 个端口块,并让它们的所有容器都在该范围内进行侦听;它帮助我保持井井有条。但是,我不会将这些端口中的任何一个直接暴露给互联网。我设置了一个防火墙,用于拒绝到服务器的所有流量,除了我特别选择的端口。ufwYYl无知

NGINX 反向代理

所有暴露在互联网上的使用 HTTPS 或 WebSocket 的东西都通过一个 NGINX 反向代理。这是我在容器外运行的极少数事情之一。我本可以把它放在一个容器中,但我发现我调整了它的配置并且需要经常重新加载配置更改,所以让它在本地运行对我来说最合适。过去,我使用 Apache2 作为我的主要网络服务器,但我发现 NGINX 更容易配置并且现在似乎更受欢迎。nginx -s reloadYYl无知

NGINX 使在同一台服务器上托管多个域变得容易。我只是为每个顶级域创建一个配置文件。由于租用多个域会随着时间的推移变得昂贵,我通常在子域上托管新项目或较小的东西。对于后端和 API,我使用指令将流量传递到服务从其 Docker 容器本地侦听的任何端口。使用纯 NGINX 配置,我可以为我的应用程序设置任何类型的路由、标头逻辑或其他自定义行为。这是我的一项服务的典型配置块示例:proxy_passYYl无知

    location / {
        proxy_pass http://localhost:4900/;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass_request_headers      on;
    }

我所有的 HTTPS 证书都通过letencrypt颁发和管理。这是一项了不起的服务;我所要做的就是每 3 个月运行一次,一切都会自动处理。尽管我有近 50 个不同的域 + 子域都由同一台服务器路由,但它或多或少完美无瑕,而且 100% 免费。snap run certonly --nginxYYl无知

现代 NGINX 功能

我不为 NGINX 使用容器的另一个原因是我有一些自定义模块和自定义项:YYl无知

  • 使用 Google 的开源ngx_brotli模块支持 brotli 压缩YYl无知

Brotli 压缩是 gzip 和 deflate 的现代替代方案,它显着提高了压缩率,同时在客户端上具有相似的解压缩速度。我为通过我的 NGINX 服务器的所有可压缩文件启用了它,它运行良好。YYl无知

HTTP3/QUIC 仍处于试验阶段,但我使用的所有浏览器都支持它,而且 Cloudflare 已将它部署在他们的整个网络中。按照博客文章中的指南,我能够应用补丁并轻松进行设置。我没有任何记录延迟或任何改进的指标,但我总是喜欢运行最新最好的东西,并且到目前为止没有遇到任何问题。YYl无知

  • 我用于一些复杂的重写逻辑以方便我的静态站点托管程序的模块(下面有更多详细信息)set-misc-nginx-modulephostYYl无知

我构建了一个脚本来自动化这个。我不能保证它会在没有修改的情况下工作;我可能对其中未反映的内容进行了一些手动编辑。YYl无知

phost静态站点主机

我广泛使用的一个独特工具是几年前我自己构建的一个项目:. 它的主要目的是使部署静态站点用于演示或开发变得非常快速和容易。如果您有兴趣,我写了一个更详细(但已过时)的工具描述。phostYYl无知

我在我的计算机上安装了一个小客户端,我可以运行它来将目录作为静态站点部署到我的一个域上的子目录。该命令处理:YYl无知

phost create subdir-name directory

这些文件将被发送到服务器,创建一个目录,并通过一些网络服务器路由魔法可以在https://somedir-name.ameo.design/访问。我有一些有用的附加功能,例如可选地重定向 404 以促进 SPA 和使用 部署新版本,但除此之外,该工具非常简单。index.htmlphost updateYYl无知

在新项目的开发或原型设计阶段,我会大量使用这个工具。如果项目需要,我仍然必须手动处理后端/API 的部署,但这使得部署 UI 更新变得非常容易。话虽如此,我不建议您尝试使用自己,除非您愿意投入大量精力来设置它 - 我真的只是为个人使用而构建它。老实说,可能有一些完善的开源替代品效果更好。phostYYl无知

网络 + DNS

我所有网站的 DNS 在 DigitalOcean 上免费管理。这完全是因为 DO 是我第一个托管网站或配置 DNS 的地方,而且我从不费心移动它,因为它运行良好。他们的网络用户界面也很容易使用。YYl无知

我的站点的 DigitalOcean DNS 概述页面的屏幕截图,显示站点名称和配置记录的数量及其类型YYl无知

我最近所做的一项更改是为我的服务器设置 IPv6 支持。OVH 提供了 /64 的 IPv6 地址以及我一直在使用的 IPv4,但我推迟了很长时间的设置,因为我过去在台式机和笔记本电脑上遇到过大量的 IPv6 问题。然而,当我真正去做的时候,它进行得相当顺利!我大部分时间都花在 NGINX 配置更改上,但现在我已经学会了正确的模式,一切都很好。DNS 更改只是包括使用我的服务器的 IPv6 地址为我现有的所有 A 记录创建重复的 AAAA 记录。YYl无知

外部 CDN

尽管在单个服务器上运行和托管所有内容很方便,但对于地理位置较远的用户来说,延迟可能会很高。对于我的一些网站,大部分流量来自美国以外。出于这个原因,我使用 CDN ( bunny.net ) 为我最大/访问量最大的网站托管静态网站。他们使用一个简单的模型,他们只是在他们的域上代理您的目标,因此我必须进行的大部分更改都在我的应用程序前端。我每月支付 1 美元(他们每月的最低账单),足以满足每月高达约 1TB 的出站流量。YYl无知

一张显示通过 Bunny CDN 到我的服务器的全球流量分布的地图YYl无知

我过去使用过 Cloudflare,它也可以正常工作。如果我想隐藏我的服务器的 IP 地址,那将是非常必要的。如果我将来遇到 DDOS 攻击或类似问题,这可能会变得很有必要,但 Bunny 目前是一个很棒且简单的选择。YYl无知

服务

既然我已经了解了我为支持它们而运行的所有基础架构,我觉得我应该对我部署的那种东西来证明它的合理性有所了解。这是一个非详尽的列表,但它为我托管的服务类型提供了一个好主意。YYl无知

网站

我为几个网站托管静态内容和 API 后端:YYl无知

数据库

我托管了几个不同的数据库来支持它们:YYl无知

  • 多个站点和服务使用的 MySQL/MariaDB 服务器YYl无知

  • Quavertrack 和 Sentry 的 Postgres 服务器YYl无知

  • Robintrack 使用的 MongoDB 服务器YYl无知

  • 适用于 Plausible 和 Sentry 的 Clickhouse 服务器YYl无知

通过似是而非的自托管分析

我使用Plausible为我的所有网站托管我自己的分析。它是我过去使用的 Google Analytics 的一种注重隐私的轻量级替代品。他们提供了一个开源的、可自我托管的版本,我将它与. 设置好后很容易添加到站点,我已经为我的大多数最大站点和我未来部署的新站点配置了它。docker-composeYYl无知

谷歌分析没有做的一些看似合理的事情是在一个仪表板上显示我所有网站的每日浏览量,以便于检查:YYl无知

我的似是而非的仪表板的屏幕截图,显示了我的一些网站的分析。YYl无知

通过 Sentry 进行自托管错误报告

与 Plausible 类似,我运行一个自托管的Sentry实例来记录我所有网站的 JS 错误和其他事件。YYl无知

我的自托管哨兵主页的屏幕截图,显示了来自我所有网站的 JS 错误和事件汇总到一个视图中" title="我的自托管哨兵主页的屏幕截图,显示了来自我所有网站的 JS 错误和事件汇总到一个视图中YYl无知

自从设置了这个,我发现它对于捕捉错误和查看用户如何使用我的网站非常有价值。它还能够将我所有站点的事件聚合到一个视图中,我觉得这非常有用。YYl无知

个人实用程序

我还为我的个人非公共用途运行各种实用程序和服务:YYl无知

  • httpbin用于测试 API 和东西YYl无知

  • Send,已停产的 Firefox Send 服务的自托管分支,用于轻松共享文件YYl无知

  • 我使用的个人屏幕截图托管程序和文件上传器与定制版的Flameshot一起用于即时捕获、上传和共享屏幕截图YYl无知

  • Owncast - 自包含的自托管 RTMP 直播YYl无知

安全

我自学了有关服务器和托管网站的所有知识,并且犯了很多错误。我在高中时不小心在 Github 上泄露了我的 AWS 凭证(很高兴 AWS 将我从加密矿工一夜之间积累的数千美元账单中拯救了出来),我有一个机器人的 VPS pwnd,它使用我运行未经身份验证的公共 Redis 服务器来覆盖我的 SSH 授权密钥文件,并且我已经清空了我的 MongoDB 并持有赎金(幸运的是我已经备份了这个)。我很幸运,这些事情在我编程生涯的早期就发生在我身上,并没有真正产生任何持久的影响。他们还教给我关于服务器和站点安全性的课程,这些课程我从未忘记。YYl无知

第一步是防火墙。我使用, 一个包装器,并且默认拒绝对端口 80、443 和我运行 SSH 服务器的非默认端口以外的所有内容的所有访问。正如我之前提到的,在进出服务器的过程中,一切都通过 NGINX 反向代理。由于一切都在同一台服务器上运行,我不必担心将数据库或类似的东西暴露在互联网上;即使某些东西意外绑定到 0.0.0.0 而不是 127.0.0.1,防火墙也会阻止从服务器外部访问它。ufwiptablesYYl无知

说到 SSH,我将我的配置设置为仅允许基于密钥的访问 - 不允许仅密码登录。我的 SSH 密钥也受密码保护。除此之外,我以非特权用户身份登录,并在服务器上配置了一个最终密码以进行 sudo 访问。sshdYYl无知

在服务级别,我小心翼翼地为数据库、云存储 API 以及其他任何需要经过身份验证的访问的事物创建和使用特定于应用程序的凭据。我的大多数数据库都启用了密码身份验证,即使它们位于同一台服务器上并且为每个服务使用不同的用户名/密码。这确保了即使在一个容器中存在某种可以访问其数据库的漏洞,其他应用程序的数据库仍将受到保护。YYl无知

对于运行时机密和配置,我根据服务和机密的敏感性混合使用环境变量、挂载的配置文件和内置机密。如果有人能够在主机上获得root权限,那就真的结束了。如果攻击者能够以某种方式从容器中逃脱,事情看起来也不是很好。YYl无知

不过,需要注意的一件重要事情是,我的网站目前都没有处理任何类型的敏感用户数据。正因为如此,我的服务器的安全需求与任何处理 PII 的东西完全不同。如果我构建了具有这些需求的东西,我可能最终会将其托管在自己的服务器上,或者转向公共云/无服务器替代方案。YYl无知

监控

我使用一个名为Munin的旧工具来监控我的服务器和一些服务。它的配置非常繁琐,很容易破解,但它会生成清晰有用的图表。如果有一天我感到无聊,我可能会将其换成 Prometheus + Grafana 或其他更现代的替代品。YYl无知

Munin 制作的示例图表显示了我的服务器在过去一个月的总内存利用率YYl无知

在容器中运行我的所有服务的一个优点是可以收集每个服务的资源使用情况。Munin 有插件可以自动处理这个问题,轮询 Docker 守护进程并为每个容器的内存和 CPU 使用情况构建区域图表。YYl无知

我还使用一个名为ccze的程序从我的 NGINX 服务器生成格式化的、彩色的日志。通过查看此日志,我可以查看我所有网站的实时流量,这对于衡量流量水平、识别行为模式、检查哪些机器人正在访问我的 API 以及类似的东西非常有用。YYl无知

使用 CCZE 格式化的 NGINX 服务器日志的屏幕截图,显示了我的各种站点、服务和 API 中的用户和机器人流量混合YYl无知

为了了解服务器上的实时资源利用率和活动,我使用了一个名为btm的程序。我过去使用过其他人,但我之所以使用它是因为它是用 Rust 编写的,而且我喜欢这种语言和社区。btmYYl无知

btm TUI 的屏幕截图,显示内存、CPU、网络利用率和进程列表以及每个核心 CPU 使用情况的历史图YYl无知

备份+灾难恢复

我的备份解决方案简单但有效。我有各种定期运行的 shell 脚本来备份数据库和其他东西,并将它们上传到谷歌云存储进行备份。YYl无知

我使用并行 xz 压缩(矫枉过正,但不妨使用这些核心)。我学到的一件事是,直接从管道或类似管道导入是一个坏主意。我遇到了我的数据库锁定和我的网站变得无响应的问题,所以我总是转储到一个普通文件,然后压缩并上传它。mysqldumpxz.sql/tmpYYl无知

我使用“存档”级存储存储我的备份。最低存储期限为 1 年,但成本为 0.11 美分/GB/月,老实说有点疯狂。我每天都上传新档案,并配置了一个生命周期规则,以便在 1 年存储期结束后删除所有旧备份。YYl无知

我在设置之前进行了数学计算,似乎作为存档存储 1 年与作为“冷线”存储 90 天(其最短存储期)的价格几乎相同。因此,我选择了存档。不过,这真的无关紧要。我每月花费 <5 美元来存储 >2TB 的备份。YYl无知

此外,我保留了服务器上所有内容的所有(好吧,尽可能多的)配置文件的副本,以及在本地存储的在其上运行的东西。我的 NGINX 配置特别复杂,需要花费大量时间才能做到正确,因此我确保定期保持同步。YYl无知

结论

正如您可能想象的那样,随着我学到东西并添加了更多站点+服务,这种设置随着时间的推移发生了巨大的变化。从某些方面来说,这对我的目的来说太过分了。主要因素是我真的很关心这台服务器以及它上面运行的一切。它托管的站点和服务代表了我一生中无数个小时的努力,并且是我最关心的一些事情。但最重要的是,我真的很喜欢设置并托管它。让所有不同的部分和谐地一起工作并真正拥有对我正在运行的软件的端到端可见性和控制是非常令人满意的。我也很喜欢使用公开可用的软件和工具来完成所有这些工作。除了租用硬件之外,几乎所有东西都是免费的,这很棒。YYl无知

我希望你发现这篇文章有用或至少很有趣。我确信我正在做的一些事情可以改进,我很想听听您对我可以做得更好或不同的想法!YYl无知


YYl无知

转自:https://cprimozic.net/blog/my-selfhosted-websites-architecture/YYl无知


YYl无知

本文为转载文章,版权归原作者所有,不代表本站立场和观点。

很赞哦! () 有话说 ()