使用 DigitalOcean 上的 Dokku 创建你自己的 Heroku
介绍
介绍
那么,您希望拥有自己的基础设施,同时拥有最好的商品来将您的代码推向生产,对吗?
那么你已经找到了你的指南。我们会仔细检查你所需的一切。
我们将在 DigitalOcean 上设置服务器,配置您的应用程序以便与 Dokku 一起使用,学习如何将您的代码直接推送到生产环境,并通过向您的应用程序添加 TLS/SSL 来完成指南。
最棒的是?这一切都是免费的。(*)
(*)如果您是 DigitalOcean 的新用户并通过推荐链接注册。
0. 开始之前
Dokku 是什么
您可能想知道 Dokku 是什么。
Dokku是一个由 docker 提供支持的平台即服务(PaaS),可帮助您构建和管理应用程序的生命周期。
这意味着它与 Heroku 有很多相似之处,所以如果你以前使用过 Heroku,你会觉得它很熟悉。例如,你可以推送代码进行部署、使用构建包、扩展流程等等。
前言
对于本指南,我将使用带有Git Bash
终端的 Windows 10,但在任何 GNU/Linux 系统上一切都应该是相同的。
该服务器将是 DigitalOcean 的 Ubuntu 20.04 映像,其中已设置 Dokku。
作为示例应用程序,我们将使用Heroku 的这个NodeJS 入门项目。
要求
- 一个 DigitalOcean 帐户
- 域名
- 终端
- SSH 密钥对
要求信息
如果您还没有 DigitalOcean 帐户,不妨创建一个,免费!而且,如果您使用我的推荐链接,还能免费获得 100 美元的积分!
如果您没有 SSH 密钥对,请按照本教程了解如何生成并将其添加到您的 DigitalOcean 帐户。
1. Droplet 的创建
这可能是最简单的步骤,因为 DigitalOcean 提供了已设置 Dokku 的 Ubuntu 20.04 映像,只需按照该链接并创建一个 droplet。
然后只需选择满足您需求的任何选项即可。
⚠ 您应该选择靠近您或您的客户的数据中心。⚠
创建完成后,转到新 droplet 的“网络”选项卡并分配一个浮动 IP。
在浏览器上访问该 IP,您将发现已设置 Dokku。
只需填写您的公共 SSH 密钥和您将要使用的域名即可。我建议启用virtualhost naming
,因为它比使用端口更简单、更常用。
提示:如果您之前已将公共 SSH 密钥添加到您的 DigitalOcean,
Public SSH Key
则表单应该已经自动填写!
为了本指南的目的,我将使用dokku
我自己的域名akbal.dev上的子域名。
2. 域名管理
我目前的域名管理器是 CloudFlare,但您可以使用任何其他域名注册商或管理器,说明应该是相同的。😊
DNS 记录
我们必须配置我们的 DNS 设置以指向我们的新 droplet 的浮动 IP。
首先添加一个A
类型记录,其中包含您之前在 Dokku 设置中分配的主机名和浮动 IP。
您还应该添加一条catch-all规则,以便在子域上部署的任何内容都会自动转发到 droplet。
如果您正在使用 CloudFlare 并且在接下来的步骤中遇到连接问题,请尝试将 DNS 记录代理设置为
DNS only
而不是Proxied
,因为它似乎会导致麻烦。
3. 本地配置
在我们开始之前,我们应该在我们这边配置一些东西。
💻这些步骤都是在我们的本地机器上完成的。
添加 SSH 密钥
我们必须将我们的私人 SSH 密钥添加到我们的本地终端,以便我们可以进行身份验证并连接到 droplet。
eval `ssh-agent -s` # Start the agent that holds on to our keys
ssh-add '~/path/to/ssh/private.key' # Add our private SSH key
⚠ 这是一个重要的步骤,如果您不将私有 SSH 密钥添加到终端,您将无法稍后将代码推送到 Dokku!
我们应该检查密钥是否已成功添加。如果输出为空,则表示密钥未添加。
ssh-add -l
然后让我们尝试以 root 用户身份通过 SSH 连接到我们的 droplet。
ssh root@<domain>
# E.g.
ssh root@dokku.akbal.dev
瞧,我们进来了!
4. 应用程序设置
我们需要一个在 Dokku 上运行的应用程序,不是吗?
💻这些步骤都是在我们的本地机器上完成的。
克隆存储库
让我们克隆示例应用程序。
git clone https://github.com/heroku/node-js-getting-started.git
cd node-js-getting-started
请注意,如果您以前使用过 Heroku,那么您应该熟悉一个文件,即Procfile
。我们将在下一步中讨论它。
熟悉起来
现在我们已经克隆了存储库,我们可以安装依赖项并根据需要使用该应用程序。
npm install # Install dependencies
npm run start # Start the application
现在如果我们访问http://localhost:5000
浏览器,我们应该会看到应用程序正在运行。
5. 应用程序配置
我们应该配置我们的应用程序,以便 Dokku 能够运行它。
如果您使用示例应用程序,则可以跳过此步骤,因为它已经配置好了。
💻这些步骤都是在我们的本地机器上完成的。
Buildpacks 琐事
Dokku 使用 Heroku 自己的 Buildpacks 来构建您的应用程序并检测它正在使用的语言。
在本指南中,我们使用NodeJS 应用程序,因此 Dokku 将检测并使用 Heroku 的 NodeJS Buildpack。
进程文件
Dokku 需要Procfile
识别process types
我们的应用程序使用什么和命令,例如启动 Web 服务器。
如果你还没有创建这个文件,那么你需要创建它。一个常见的 NodeJS 文件Procfile
如下所示:
web: node index.js
# Or like this
web: npm run start
节点版本
engines
Dokku 将下载并使用我们的部分中指定的 NodeJS 版本package.json
。
// ...
"engines": {
"node": "12.x"
},
您应该添加这部分,否则 Dokku 将选择一个可能适合您的应用程序的 NodeJS 版本。
进一步配置
您应该查看您正在使用的语言的Buildpack 文档来进一步配置!
6.服务器配置
现在我们可以连接到 droplet 并设置了我们的应用程序,让我们稍微配置一下服务器。
🖥 这些步骤是在Dokku droplet上完成的。
内存交换
您很可能会在低内存(<2GB)的 droplet 上使用 Dokku。
为了修复可能因内存不足而导致的故障,我们应该创建一个更大的交换文件。阅读本教程来了解如何操作。
7.服务器安全
虽然保护服务器安全并非易事,但以下说明将解决最常见的问题。
🖥 这些步骤是在Dokku droplet上完成的。
根用户
我们一直在使用这个root
用户,但这存在安全风险。我们不应该用它来做所有事情,而应该使用我们自己拥有root
权限的用户。
按照本指南了解如何创建具有 sudo 权限的新用户。
完成后,我们应该将公共 SSH 密钥从root
用户复制到我们自己的用户。
USER=<user> # Set the user variable
mkdir -p /home/$USER/.ssh # Create ssh directory
chmod 700 /home/$USER/.ssh # Apply directory permissions
cp /root/.ssh/authorized_keys /home/$USER/.ssh/authorized_keys # Copy the ssh authorized key
chown -R $USER:$USER /home/$USER/.ssh # Apply user and group permissions
sudo chmod 600 /home/$USER/.ssh/authorized_keys # Apply file permissions
# As a one-liner
USER=<user>; mkdir -p /home/$USER/.ssh && chmod 700 /home/$USER/.ssh && cp /root/.ssh/authorized_keys /home/$USER/.ssh/authorized_keys && chown -R $USER:$USER /home/$USER/.ssh && sudo chmod 600 /home/$USER/.ssh/authorized_keys
# E.g.
USER=alejandro; mkdir -p /home/$USER/.ssh && chmod 700 /home/$USER/.ssh && cp /root/.ssh/authorized_keys /home/$USER/.ssh/authorized_keys && chown -R $USER:$USER /home/$USER/.ssh && sudo chmod 600 /home/$USER/.ssh/authorized_keys
现在尝试使用新用户重新连接到 droplet。
ssh <user>@<domain>
# E.g.
ssh alejandro@dokku.akbal.dev
完美!效果非常好。
固态混合硬盘
默认的 droplet 配置允许任何人以用户身份登录root
,这应该被禁用,因为这是一个安全风险。
查看本指南的第一步,了解如何配置 SSHD 并禁用用户登录。root
Docker 端口
防火墙默认打开 Docker 端口,我们应该关闭它们,因为这可能存在安全隐患。
sudo ufw status # Optional, check the current rules on the firewall
# Delete Docker rules
sudo ufw delete allow 2375/tcp
sudo ufw delete allow 2376/tcp
sudo ufw status # Optional, check that Docker's ports are deleted
UFW 是 Ubuntu 的防火墙管理器,了解更多。
失败2Ban
Fail2Ban 是一款保护您的服务器免受暴力破解和自动攻击的实用程序。它可以阻止重复的连接尝试,并暂时禁止它们。
这是有关如何安装、配置和使用它的简单指南。
8. 多库
现在,配置的每个步骤都已完成,我们可以进入真正有趣的步骤:实际使用 Dokku!
🖥 这些步骤是在Dokku droplet上完成的。
Dokku 命令行界面
Dokku 是通过终端使用的,它没有界面或 Web 视图,这是它的优势,因为它消耗的系统资源比应用程序所需的要少。
要开始使用 Dokku,只需dokku
在终端上输入。
dokku
常见的 Dokku 命令
这些是您肯定要使用的命令,因此请访问文档链接并熟悉它们。
应用程序创建
第一步是创建一个应用程序。
dokku apps:create <app>
# E.g.
dokku apps:create my-app
应用外壳现已创建,但为空。在我们推送代码之前,它不会执行任何操作。
但在这样做之前,我们应该配置其他方面,比如它将要使用的域。
域配置
让我们添加一个域,以便在部署后我们可以从浏览器轻松访问我们的应用程序。
dokku domains:add <app> <domain>
# E.g.
dokku domains:add my-app my-app.dokku.akbal.dev
环境配置
如果我们的应用程序使用任何环境变量,例如.env
文件,您应该通过 Dokku 添加它们。
dokku config:set <app> <variables>
# E.g.
dokku config:set my-app NODE_ENV=production
# You can add multiple environment variables.
dokku config:set my-app NODE_ENV=production SECURITY_KEY=XXX
请记住,执行此命令将重新启动应用程序。
部署代码
现在是真正交易的时候了,我们已经在本地机器和服务器上配置了所有内容,所以让我们部署吧!
💻这些步骤都是在我们的本地机器上完成的。
让我们将 Dokku 添加为 git 远程,以便我们可以将代码推送到它。
git remote add <remote-name> dokku@<remote>:<application>
# E.g.
git remote add dokku dokku@dokku.akbal.dev:my-app
剩下唯一要做的事情就是推送代码,让我们尝试一下!
git push <remote-name> <local-branch>:master
# E.g.
git push dokku main
# Or if your branch is already master
git push dokku master
就这样!代码推送后,你就能看到 Dokku 正在检测并构建你的应用程序!🥰
如果此步骤给您带来麻烦,则可能是您没有将您的私有 SSH 密钥添加到当前终端,请在添加 SSH 密钥步骤中了解更多信息。
Dokku 完成后,它将输出一个链接以在浏览器中访问您的应用程序,请执行此操作!
由于 Dokku 强制启用HSTS,而我们尚未配置 TLS/SSL,网站可能无法正常运行。了解如何禁用 HSTS。
TLS/SSL 配置
我们将向Dokku添加lets encrypt 插件,以便应用程序可以通过HTTPS提供服务。
首先将letsencrypt
插件添加到 Dokku。
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git
然后通过环境变量添加所需的联系电子邮件。 letsencrypt
dokku config:set <app> DOKKU_LETSENCRYPT_EMAIL=<email>
# E.g.
dokku config:set my-app DOKKU_LETSENCRYPT_EMAIL=contact@akbal.dev
# We can set the contact email globally too, so it works for any application.
dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=<email>
现在是时候为我们的应用程序生成证书了。
dokku letsencrypt <app>
# E.g.
dokku letsencrypt my-app
添加HTTPS就是这么简单。
查看我们超级安全的网站!
规模流程
扩展流程非常简单,您只需告诉 Dokku,它就会处理一切。
🖥 这些步骤是在Dokku droplet上完成的。
dokku ps:scale <app> <process-type>=<count>
# E.g.
dokku ps:scale my-app web=1
# Even multiple types
dokku ps:scale my-app web=1 worker=2
9. 其他
更多知识
我鼓励你去阅读Dokku 文档,并尝试一下你现在已完成的Dokku 设置。你将学到很多很棒的知识,比如如何读取应用程序的日志。
故障排除
无法将代码推送到 Dokku 远程
这可能是因为您尚未将私有 SSH 密钥添加到您的终端,请尝试添加它!
Dokku 远程 Git 分支提前
我遇到过这种情况:我提交到 Dokku 后,在本地又回退到之前的提交,这在尝试再次推送时造成了许多问题,因为 Dokku 自己的 git 仓库位于未来版本。好在,有一个非常简单的解决方案:强制推送!💪
git push --force dokku <branch>
# E.g.
git push --force dokku main
代理返回不同的签名类型 ssh-rsa(预期为 rsa-sha2-512)(Windows 10)
看来 Windows 10 上的 ssh 二进制文件已经过时,并且服务器拒绝连接,解决方案是使用Git Bash
或任何其他具有更新二进制文件的终端,有关此问题的更多信息,请参见此处
10.结束
我希望您喜欢我的完整指南并发现它很有用,我花了很多天才给您带来这些知识。
有用的链接
这些资源在您的 Dokku 旅程中非常有用。
自我推销
如果你觉得本教程有用,那么你应该关注我,我会发布更多有趣的内容!🥰
或者在经济上支持我。💸
如果您想继续学习,请查看我撰写的这篇“如何完全保护 Ubuntu 服务器”文章。
信用
本指南的完成要感谢许多出色的人。
- Linux化
- DigitalOcean 及其社区
- 向 Ubuntu 寻求故障排除帮助