<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Heroku - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Heroku - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 12 May 2026 20:06:13 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/heroku/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ 如何使用 Dokku 构建自己的 Heroku ]]>
                </title>
                <description>
                    <![CDATA[ 原文：How to Build Your Own Heroku with Dokku [https://www.freecodecamp.org/news/how-to-build-your-on-heroku-with-dokku/]，作者： Nuno Bispo [https://www.freecodecamp.org/news/author/nunobispo/] Heroku是一个被开发者广泛使用的知名PaaS。而作为一个有趣和有用的项目，你可以用Dokku轻松地制作你自己的类似Heroku的PaaS。 什么是Heroku？ Heroku是一家成立于2007年的平台即服务（PaaS）公司。该平台在AWS上运行，其临时存储系统被称为“Dyno”。 Heroku是开发者使用最多的PaaS之一，这是有原因的——它很容易使用，有很好的文档，并支持多种编程语言。 但是，如果你可以通过一个简单易用的应用程序来部署你自己的类似Heroku的平台，包括CI/CD管道、数据库连接、HTTPS连接等等，会怎么样呢？ 嗯，这就是Dokku所提供的，甚至更多。让我们来看看。 什么是P ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-build-your-on-heroku-with-dokku/</link>
                <guid isPermaLink="false">624e592b99ec7406219e5cb6</guid>
                
                    <category>
                        <![CDATA[ Heroku ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ luojiyin ]]>
                </dc:creator>
                <pubDate>Thu, 07 Apr 2022 03:20:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/04/dokku.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/how-to-build-your-on-heroku-with-dokku/">How to Build Your Own Heroku with Dokku</a>，作者：<a href="https://www.freecodecamp.org/news/author/nunobispo/">Nuno Bispo</a></p><!--kg-card-begin: markdown--><p>Heroku是一个被开发者广泛使用的知名PaaS。而作为一个有趣和有用的项目，你可以用Dokku轻松地制作你自己的类似Heroku的PaaS。</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/dokku-logo-with-name5-1.png" alt="dokku-logo-with-name5-1" width="600" height="400" loading="lazy"></p>
<h2 id="heroku">什么是Heroku？</h2>
<p>Heroku是一家成立于2007年的平台即服务（PaaS）公司。该平台在AWS上运行，其临时存储系统被称为“Dyno”。</p>
<p>Heroku是开发者使用最多的PaaS之一，这是有原因的——它很容易使用，有很好的文档，并支持多种编程语言。</p>
<p>但是，如果你可以通过一个简单易用的应用程序来部署你自己的类似Heroku的平台，包括CI/CD管道、数据库连接、HTTPS连接等等，会怎么样呢？</p>
<p>嗯，这就是Dokku所提供的，甚至更多。让我们来看看。</p>
<h2 id="paas">什么是PaaS？</h2>
<p>平台即服务（PaaS）是一种软件架构风格，为部署你的应用程序的代码和管理它提供一个易于使用的抽象层。</p>
<p>这使你可以专注于编写业务逻辑，而不是担心平台本身。</p>
<p>PaaS供应商通常提供他们自己的数据库服务以及其他相关服务，这可以大大简化常见的开发任务。</p>
<p>PaaS的巨大优势在于，应用程序开发人员不需要执行任何系统管理工作。相反，你只需将你的代码和配置设置上传到一个中央服务器平台。</p>
<p>然后，该服务负责部署代码，根据需要进行扩展，备份数据，处理托管和正常运行时间问题，等等。</p>
<h2 id="dokku">什么是Dokku?</h2>
<p>Dokku是一个托管的平台即服务，使开发者能够轻松地部署他们的应用程序。</p>
<p>来自他们的网站：</p>
<blockquote>
<p>你见过的最小的PaaS实现</p>
</blockquote>
<p>Dokku基于Docker，使用Heroku的构建包来编译和打包你的应用程序。</p>
<p>Dokku最好的一点是，它非常轻量级，可以安装在一台服务器或虚拟机上。</p>
<p>它包括使用Docker容器的可扩展主机，使用Git的持续部署，以及其他流行的DevOps工具。</p>
<p>Dokku还提供各种功能，如支持多种语言、自定义域、自动部署等。</p>
<p>你可以轻松地将Postgres数据库甚至是文件存储连接到你的应用程序。</p>
<p>你可以在 <a href="https://dokku.com/">https://dokku.com/</a> 查看更多信息，或在文件中查看。<a href="https://dokku.com/docs/getting-started/installation/">https://dokku.com/docs/getting-started/installation/</a>。</p>
<p>你也可以对 <a href="https://github.com/dokku/dokku">这里的GitHub开源项目</a> 点个赞。</p>
<h2 id="dokku">如何安装Dokku</h2>
<p>为了安装Dokku，你将需要一个Linux VPS和一个域名。</p>
<p>你可以在没有域名的情况下安装和使用Dokku，但使用域名就简单多了。我推荐使用云VPS，因为它使访问和配置更容易。</p>
<p>连接域名时，可以将单个域名或通配符与服务器的IP联系起来。</p>
<p>我将使用托管在 <a href="https://hetzner.cloud/">Hetzner</a> 的VPS，安装了Ubuntu 20.04。</p>
<p>我们首先要确保我们的系统是最新的，有这些命令：</p>
<pre><code class="language-bash"># Update the linux installation
$ sudo apt update
$ sudo apt upgrade -y
</code></pre>
<p>然后我们可以下载并运行Dokku的安装脚本：</p>
<pre><code class="language-bash"># Install Dokku with the install script
$ wget https://raw.githubusercontent.com/dokku/dokku/v0.26.8/bootstrap.sh;
$ sudo DOKKU_TAG=v0.26.8 bash bootstrap.sh

--&gt; Ensuring we have the proper dependencies
--&gt; Note: Installing dokku for the first time will result in removal of
    files in the nginx 'sites-enabled' directory. Please manually
    restore any files that may be removed after the installation and
    web setup is complete.

    Installation will continue in 10 seconds.
    
    [...........]
    
    --&gt; Running post-install dependency installation

 ! Setup a user's ssh key for deployment by passing in the public ssh key as shown:

     echo 'CONTENTS_OF_ID_RSA_PUB_FILE' | dokku ssh-keys:add admin
</code></pre>
<p>安装脚本将安装Docker和所有必要的依赖项，同时也安装Dokku本身，如上面的代码所示。</p>
<p>安装完成后，我们需要分配SSH密钥来访问，同时配置我们的域名。</p>
<p>如果你已经设置了用SSH访问你的VPS（你应该这样做），那么你已经有了必要的密钥——你只需要把它们添加到Dokku中：</p>
<pre><code class="language-bash"># Assign SSH key to Dokku
$ cat ~/.ssh/authorized_keys | dokku ssh-keys:add admin

SHA256:6O1TLVOUkWV+zmTWXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
</code></pre>
<p>如果你在服务器中还没有SSH密钥，那么你需要生成一个密钥对：</p>
<pre><code class="language-bash"># Generate SSH key
$ ssh-keygen

Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:7T6BbRCVWjGtcSUXXXXXXXXXXXXXXXXXXXXXXXXXXXXX root@freeDokku
The key's randomart image is:
+---[RSA 3072]----+
[.................]
|     . oS*.o . . |
[.................]
+----[SHA256]-----+
</code></pre>
<p>然后你可以把它添加到Dokku：</p>
<pre><code class="language-bash"># Add SSH key to Dokku
$ dokku ssh-keys:add admin /root/.ssh/id_rsa.pub

SHA256:7T6BbRCVWjGtcSUXXXXXXXXXXXXXXXXXXXXXXXX
</code></pre>
<p>下一步，也是最后一步，是为你的Dokku安装分配域名。我们用以下命令来做这件事：</p>
<pre><code class="language-bash"># Set installation global domain
$ dokku domains:set-global domain.com

-----&gt; Set domain.com
</code></pre>
<p>确保你用你自己的域名替换domain.com，并且你的域名DNS指向服务器的IP地址。</p>
<p>这就是你安装和设置Dokku所需要做的一切。真的就这么简单。</p>
<p>你现在可以开始添加你的应用程序了。</p>
<p>让我们在下一节中通过添加一个标准的Django应用程序来看看这个例子。</p>
<h2 id="dokku">如何在Dokku中创建你的应用程序</h2>
<p>为了创建和部署我们的第一个应用程序，我们需要在Dokku上做一些准备工作。</p>
<p>要在Dokku上部署一个应用程序，请遵循以下步骤：</p>
<ul>
<li>在Dokku上创建应用程序，这意味着给它一个名字。</li>
<li>创建关联数据库（或其他插件，如果需要）。这将创建并提供一个数据库，以便使用自动添加到应用程序的DATABASE_URL，以方便部署。</li>
<li>推送必要的代码到Dokku的应用程序内部GitHub端点。这也可以包括必要的发布步骤（比如说，运行Django迁移</li>
</ul>
<p>代码推送后，Dokku将生成任何必要的Docker容器，并将运行我们的应用程序与任何相关的数据库（或其他插件）。</p>
<p>现在我们已经涵盖了必要的步骤，让我们在实践中进行。</p>
<p>让我们从创建我们的应用程序开始。在本教程中，我将创建一个非常简单的Django网站，其中包含我们测试Dokku的所有必要逻辑。</p>
<p>我们用这个命令在Dokku上创建一个应用程序（在我们安装Dokku的服务器上）：</p>
<pre><code class="language-bash"># Creating our application on Dokku
$ dokku apps:create djangotutorial

-----&gt; Creating djangotutorial...
</code></pre>
<p>默认情况下，数据存储（或数据库）在应用程序创建时不会被创建。</p>
<p>数据存储由一系列的插件来处理。你可以 <a href="https://dokku.com/docs/community/plugins/#official-plugins-beta">在这里查看所有可用的插件</a>。</p>
<p>对于我们的应用程序，我们将创建一个Postgres数据存储。由于默认情况下没有安装插件，我们首先需要安装Postgres插件：</p>
<pre><code class="language-bash"># install the postgres plugin
# plugin installation requires root, hence the user change
sudo dokku plugin:install https://github.com/dokku/dokku-postgres.git
</code></pre>
<p>然后我们可以创建我们的Postgres数据存储：</p>
<pre><code class="language-bash"># Create a Postgres datastore
$ dokku postgres:create djangotutorial_datastore

       Waiting for container to be ready
       Creating container database
       Securing connection to database
=====&gt; Postgres container created: djangotutorial_datastore
=====&gt; djangotutorial_datastore postgres service information
       Config dir:          /var/lib/dokku/services/postgres/djangotutorial_datastore/data
       Config options:
       Data dir:            /var/lib/dokku/services/postgres/djangotutorial_datastore/data
       Dsn:                 postgres://postgres:ea706cc108c805d5124d134d934024c5@dokku-postgres-djangotutorial-datastore:5432/djangotutorial_datastore
       Exposed ports:       -
       Id:                  782a04fe6bbd25958752c17c304358fd5ec1f3c54d6d53175b6481b3b957d94b
       Internal ip:         172.17.0.5
       Links:               -
       Service root:        /var/lib/dokku/services/postgres/djangotutorial_datastore
       Status:              running
       Version:             postgres:14.1
</code></pre>
<p>我们可以检查我们的数据存储的Docker容器是否已经启动并运行，方法是：</p>
<pre><code class="language-bash"># Check running containers
$ docker ps

CONTAINER ID   IMAGE                      COMMAND                  CREATED              STATUS              PORTS      NAMES
782a04fe6bbd   postgres:14.1              "docker-entrypoint.s…"   About a minute ago   Up About a minute   5432/tcp   dokku.postgres.djangotutorial_datastore
</code></pre>
<p>现在我们已经建立并运行了数据存储，我们需要把它与我们的应用程序联系起来：</p>
<pre><code class="language-bash"># Associate datastore with the application
$ dokku postgres:link djangotutorial_datastore djangotutorial

-----&gt; Setting config vars
       DATABASE_URL:  postgres://postgres:ea706cc108c805d5124d134d934024c5@dokku-postgres-djangotutorial-datastore:5432/djangotutorial_datastore
-----&gt; Restarting app djangotutorial
 !     App image (dokku/djangotutorial:latest) not found
</code></pre>
<p>你可以看到，一个DATABASE_URL被自动创建并与应用程序相关联。</p>
<p>上面的例子提到，我们的应用程序图像没有被发现，因为我们还没有向它推送任何代码。</p>
<p>我们可以检查应用程序的环境变量来确认我们的 <code>DATABASE\_URL</code> 是否存在：</p>
<pre><code class="language-bash"># Checking an application environment variables
$ dokku config:show djangotutorial

=====&gt; djangotutorial env vars
DATABASE_URL:  postgres://postgres:ea706cc108c805d5124d134d934024c5@dokku-postgres-djangotutorial-datastore:5432/djangotutorial_datastore
</code></pre>
<p>我们现在已经在Dokku方面完成了所有必要的配置，以支持我们应用程序的部署。</p>
<p>接下来，我们将为我们的应用程序创建代码，并将其部署到Dokku，以实现自动化的CI/CD管道。</p>
<h2 id="pycharm">如何在PyCharm上创建我们的应用代码</h2>
<p>在我们部署一个应用程序之前，我们需要有它的源代码来推送到Dokku。</p>
<p>在本教程中，我们将创建一个非常简单的 Django 应用程序，同时展示Postgres数据库的使用。</p>
<p>我们将使用 PyCharm 作为我们的 IDE 来创建和管理我们的项目。</p>
<p>我们在PyCharm中创建一个新的项目——让我们称之为 <code>DjangoTutorial</code>：</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/02/PyCharm-NewProject.png" alt="在PyCharm上创建一个新项目——作者截图" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>在PyCharm上创建一个新项目——作者截图</figcaption>
</figure>
<p>我个人更喜欢在已经有了虚拟环境的情况下创建新项目，这让生活变得更加简单。</p>
<p>如果你创建的项目有一个默认的main.py文件（就像我一样，因为我一直忘了去掉复选标记），你现在可以安全地删除它。我们不打算使用它了。</p>
<p>第一步当然是安装Django，以便我们能够构建我们的应用程序。我们使用pip进行安装：</p>
<pre><code class="language-bash">$ pip install django

Collecting django
  Downloading Django-4.0.2-py3-none-any.whl (8.0 MB)
     |████████████████████████████████| 8.0 MB 6.4 MB/s
Collecting sqlparse&gt;=0.2.2
  Using cached sqlparse-0.4.2-py3-none-any.whl (42 kB)
Collecting tzdata
  Using cached tzdata-2021.5-py2.py3-none-any.whl (339 kB)
Collecting asgiref&lt;4,&gt;=3.4.1
  Downloading asgiref-3.5.0-py3-none-any.whl (22 kB)
Installing collected packages: tzdata, sqlparse, asgiref, django
Successfully installed asgiref-3.5.0 django-4.0.2 sqlparse-0.4.2 tzdata-2021.5
</code></pre>
<p>然后，我们用以下命令创建我们的Django项目：</p>
<pre><code class="language-bash">django-admin startproject DjangoTutorial .
</code></pre>
<p>注意命令末尾的“.”。我喜欢用它，这样它就会在当前目录下创建项目，而不是创建一个额外的子目录。</p>
<p>现在你在PyCharm中应该有一个这样的项目结构：</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/02/PyCharm-Project.png" alt="我们的Django应用程序的PyCharm文件夹结构--作者的屏幕截图" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>我们的Django应用程序的PyCharm文件夹结构——作者的屏幕截图</figcaption>
</figure>
<p>我们可以用标准的Django运行方式来运行我们的项目：</p>
<pre><code class="language-bash">$ python manage.py runserver   

Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
February 02, 2022 - 16:49:27
Django version 4.0.2, using settings 'DjangoTutorial.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
</code></pre>
<blockquote>
<p>我们还没有应用我们的迁移，所以我们将在讨论了本地和Dokku访问的数据库配置之后再做这个。</p>
</blockquote>
<p>导航到链接 <a href="http://127.0.0.1:8000/">http://127.0.0.1:8000/</a>，我们现在可以访问我们标准的 Django 欢迎页面。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/02/Django.png" alt="Django欢迎页——作者的屏幕截图" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>Django欢迎页——作者的屏幕截图</figcaption>
</figure>
<p>我们已经完成了 Django 的安装并开始运行，所以现在我们可以开始构建项目的其他部分。</p>
<p>像大多数项目一样，我们将需要在数据库（或使用Dokku命名的数据库）中存储数据。</p>
<p>我们还希望能够在开发机器上本地调试和运行我们的应用程序（使用本地数据库，在这里是SQLite），并使用 Dokku 的 Postgres 数据库在云上运行它。</p>
<p>这意味着我们需要改变 settings.py 中的一些配置，以便能够支持两种使用情况，而不需要我们每次都改变任何标志或配置。</p>
<p>我们首先安装dj-database-url软件包：</p>
<pre><code class="language-bash"># Install packages for the database url
$ pip install dj-database-url
$ pip install psycopg2


# We also install this package to be able to use environment variables
$ pip install python-decouple
</code></pre>
<p>这个包使我们能够拥有一个Django数据库连接字典，通过简单地指定一个数据库URL来填充所有的数据。</p>
<p>安装好软件包后，让我们更新settings.py中的配置：</p>
<pre><code class="language-Python"># We need to add this import at the beginning to use environment variables
import dj_database_url
from decouple import config
from django.conf.global_settings import DATABASES

.....

# Let's also updated the allowed host so we can use it later on
ALLOWED_HOSTS = config('ALLOWED_HOSTS').split(',')

.....

# We replace the default database configuration from Django with this one
# Database
# https://docs.djangoproject.com/en/4.0/ref/settings/#databases

# DATABASE URL
DATABASES['default'] = dj_database_url.parse(config('DATABASE_URL'),conn_max_age=600)
</code></pre>
<p>settings.py</p>
<p>我们还需要在我们项目的根目录下创建 <code>.env</code> 文件：</p>
<pre><code class="language-yml">#HOST SETTINGS
ALLOWED_HOSTS = 127.0.0.1

#DATABASE SETTINGS
DATABASE_URL='sqlite:///db.sqlite3'
</code></pre>
<p>.env</p>
<p>正如你所看到的，通过这一改变，我们可以在本地开发机器上使用本地 <code>.env</code> 文件中的数据库 URL，然后在 Dokku 上会自动使用已经定义好的 DATABASE_URL，这个 URL 是我们在 Dokku 上链接数据存储和应用程序时创建的。</p>
<p>现在我们可以创建本教程的第一个（也是唯一）网页，一个简单的计数器，存储和读取数据库中的值。</p>
<p>让我们创建一个单独的应用程序来包含我们的逻辑：</p>
<pre><code class="language-bash">python manage.py startapp counter
</code></pre>
<p>现在我们的项目中应该有一个名为“counter”的新文件夹。让我们通过打开models.py文件添加一个新的模型：</p>
<pre><code class="language-Python">from django.db import models


class Counter(models.Model):
    count = models.IntegerField(default=0)

    def __str__(self):
        return self.count
</code></pre>
<p>counter/models.py</p>
<p>现在我们可以添加一个新的URL来加载我们的计数器页面。我们通过在counter文件夹中添加一个名为“urls.py”的新文件来做到这一点：</p>
<pre><code class="language-Python">from django.urls import path
from . import views

urlpatterns = [
    path('counter/', views.counter, name='counter'),
]
</code></pre>
<p>counter/urls.py</p>
<p>我们现在有了模型和URL来加载我们的测试页面。现在我们需要的是视图和HTML模板来渲染页面。</p>
<p>让我们通过编辑'views.py'文件来创建该视图（view）：</p>
<pre><code class="language-Python">from django.shortcuts import render
from .models import Counter


def counter(request):
    counter_value = Counter.objects.last()

    if counter_value is None:
        counter_value = Counter(count=0)
        counter_value.save()

    if request.method == 'POST':
        counter_value.count += 1
        counter_value.save()

    return render(request, 'counter.html', {'counter': counter_value.count})
</code></pre>
<p>counter/views.py</p>
<p>现在我们可以创建我们的HTML模板，在页面上显示计数器的值。我们在一个新的“templates”文件夹中创建一个名为“counter.html”的新文件：</p>
<pre><code class="language-HTML">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Counter&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;form method="post"&gt;
      {%csrf_token%}
    &lt;h4&gt;Counter value is: {{ counter }}&lt;/h4&gt;
    &lt;input type="submit" name="submit" value="Increase Counter"&gt;
  &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>counter/templates/counter.html</p>
<p>最后一步是将我们新创建的应用程序添加到settings.py文件中，以便Django能够识别它：</p>
<pre><code class="language-python">.....

INSTALLED_APPS = [
    'counter',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

.....
</code></pre>
<p>settings.py</p>
<p>而我们的主URLs文件的URL：</p>
<pre><code class="language-Python">from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('', include('counter.urls')),
    path('admin/', admin.site.urls),
]
</code></pre>
<p>urls.py</p>
<p>有了所有必要的代码和HTML，我们现在可以创建并运行我们的迁移，在数据库中创建我们的新模型。我们首先在本地服务器上通过运行：</p>
<pre><code class="language-bash"># Create and run migrations
$ python manage.py makemigrations
$ python manage.py migrate

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, counter, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying counter.0001_initial... OK
  Applying sessions.0001_initial... OK
</code></pre>
<p>正如你所看到的，我们不仅为我们的新应用程序应用了迁移（migrations），而且还为其他Django应用程序运行了初始迁移，因为这是我们第一次运行迁移（migrations）。</p>
<p>我们可以再次在本地运行我们的服务器，我们应该能够访问URL <a href="http://127.0.0.1:8000/counter/">http://127.0.0.1:8000/counter/</a> 并增加计数器：</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/CounterPage_Local.gif" alt="CounterPage_Local" width="600" height="400" loading="lazy"></p>
<p>运行我们的计数器应用程序 - 作者的GIF图</p>
<p>正如你所看到的，重新加载页面可以保持我们的计数器值，这意味着该值已经和我们的模型一起存储在数据库中。</p>
<h2 id="dokku">如何将我们的应用程序部署到Dokku上</h2>
<p>现在我们有一个非常简单的应用程序正在运行，并与数据库集成以存储我们的计数器值。</p>
<p>我们准备把它部署到云端，这样我们就可以在那里进行测试，并确保我们的数据库也能在云端工作。</p>
<p>在我们用Git推送将代码部署到Dokku之前，我们需要做一些准备。</p>
<ul>
<li>安装我们的网络服务器（gunicorn）</li>
<li>创建我们的需求文件（为我们的软件包）。</li>
<li>创建我们的Procfile（用于我们的部署命令）</li>
</ul>
<p>让我们从安装我们的网络服务器开始，以便在云中使用:</p>
<pre><code class="language-bash"># Install our web server
$ pip install gunicorn
</code></pre>
<p>我们现在可以用以下方法创建我们的 <code>requirements.txt</code> 文件，获得包的依赖:</p>
<pre><code class="language-bash"># Create requirements file
$ pip freeze &gt; requirements.txt
</code></pre>
<p>现在我们需要创建 <code>Procfile</code>。这个文件被 Dokku 用来决定在部署时和部署后运行哪些命令。</p>
<p>因此，让我们在根目录下创建一个名为 "Procfile "的新文件，其内容如下:</p>
<pre><code class="language-python">web: gunicorn DjangoTutorial.wsgi
release: python manage.py migrate
</code></pre>
<p>Procfile</p>
<p>我们创建了两个命令供Dokku运行:</p>
<ul>
<li>release - 这个命令是在我们的应用程序在Dokku的部署上执行的。我们用它来迁移我们的数据库。</li>
<li>web - 这个命令允许Dokku知道运行哪个webserver以允许访问该应用程序。</li>
</ul>
<p>最后，为了确保我们的代码被部署到Dokku时能收集到任何静态文件，我们需要在根目录上创建一个名为'static'的新目录。在里面我们创建一个名为'.gitkeep'的空文件（这将使我们以后能够将该目录添加到Git仓库中）。</p>
<p>我们还需要在'settings.py'文件中为静态文件添加这个路径:</p>
<pre><code class="language-Python"># Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/4.0/howto/static-files/

STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / "static"
</code></pre>
<p>settings.py</p>
<p>现在所有的文件和逻辑都到位了，我们可以用标准的Git推送方式部署到Dokku。让我们检查一下我们当前的文件结构:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/02/PyCharm-FolderStrcuture-1.png" alt="PyCharm-FolderStrcuture-1" width="600" height="400" loading="lazy"></p>
<p>PyCharm文件夹结构--作者的截图</p>
<p>为了能够将我们的代码推送到Dokku，我们需要将我们的项目添加到一个Git仓库。</p>
<p>由于我们不想把文件夹结构中的所有文件都推送到Dokku的git仓库，所以我们创建一个".gitignore "来排除某些文件和目录。我使用这个优秀的Gist的内容来填充这个文件:</p>
<p>[python pycharm gitignore</p>
<p>python pycharm gitignore. GitHub Gist: instantly share code, notes, and snippets.</p>
<p><img src="https://github.githubassets.com/favicons/favicon.svg" alt="favicon" width="32" height="32" loading="lazy">262588213843476Gist<br>
<img src="https://github.githubassets.com/images/modules/gists/gist-og-image.png" alt="gist-og-image" width="1280" height="640" loading="lazy"><br>
](<a href="https://gist.github.com/MOOOWOOO/3cf91616c9f3bbc3d1339adfc707b08a">https://gist.github.com/MOOOWOOO/3cf91616c9f3bbc3d1339adfc707b08a</a>)</p>
<p>We can now initialize and commit our code to a Git repository locally:</p>
<pre><code class="language-bash"># Initialize repository
$ git init -b main

# Add and commit our files
$ git add . &amp;&amp; git commit -m "initial commit"

[main (root-commit) e77a16a] initial commit
 20 files changed, 438 insertions(+)       
 create mode 100644 .gitignore
 create mode 100644 DjangoTutorial/__init__.py
 create mode 100644 counter/tests.py
 create mode 100644 counter/urls.py
 create mode 100644 counter/views.py
 create mode 100644 db.sqlite3
 create mode 100644 manage.py
 create mode 100644 requirements.txt
</code></pre>
<p>在提交了我们的仓库后，我们现在可以把它推送到远程仓库，也就是我们应用程序的Dokku Git仓库:</p>
<pre><code class="language-bash"># Adding our remote repository (replace domain.com with your domain name)
$ git remote add dokku dokku@domain.com:djangotutorial

# Time to push our code to the remote repository
$ git push dokku main

Enumerating objects: 34, done.
Counting objects: 100% (34/34), done.
Delta compression using up to 8 threads
Compressing objects: 100% (31/31), done.
Writing objects: 100% (34/34), 11.41 KiB | 402.00 KiB/s, done.
Total 34 (delta 7), reused 0 (delta 0)
-----&gt; Set main to DOKKU_DEPLOY_BRANCH.
-----&gt; Cleaning up...
-----&gt; Building djangotutorial from herokuish
-----&gt; Adding BUILD_ENV to build environment...
       BUILD_ENV added successfully
-----&gt; Python app detected
-----&gt; No Python version was specified. Using the buildpack default: python-3.9.9
       To use a different version, see: https://devcenter.heroku.com/articles/python-runtimes
-----&gt; No change in requirements detected, installing from cache
-----&gt; Installing python-3.9.9
-----&gt; Installing pip 21.3.1, setuptools 57.5.0 and wheel 0.37.0
-----&gt; Installing SQLite3
-----&gt; Installing requirements with pip
       Collecting asgiref==3.5.0
       Downloading asgiref-3.5.0-py3-none-any.whl (22 kB)
       Collecting dj-database-url==0.5.0
       Downloading dj_database_url-0.5.0-py2.py3-none-any.whl (5.5 kB)
       Collecting Django==4.0.2
       Downloading Django-4.0.2-py3-none-any.whl (8.0 MB)
       Collecting gunicorn==20.1.0
       Downloading gunicorn-20.1.0-py3-none-any.whl (79 kB)
       Collecting psycopg2==2.9.3
       Downloading psycopg2-2.9.3.tar.gz (380 kB)
       Preparing metadata (setup.py): started
       Preparing metadata (setup.py): finished with status 'done'
       Collecting python-decouple==3.5
       Downloading python_decouple-3.5-py3-none-any.whl (9.6 kB)
       Collecting sqlparse==0.4.2
       Downloading sqlparse-0.4.2-py3-none-any.whl (42 kB)
       Collecting tzdata==2021.5
       Downloading tzdata-2021.5-py2.py3-none-any.whl (339 kB)
       Building wheels for collected packages: psycopg2
       Building wheel for psycopg2 (setup.py): started
       Building wheel for psycopg2 (setup.py): finished with status 'done'
       Created wheel for psycopg2: filename=psycopg2-2.9.3-cp39-cp39-linux_x86_64.whl size=579484 sha256=9d6a2810a5d766738526d6f411e5e9ce514cce882b6c80a47a13c02dc7529e02
       Stored in directory: /tmp/pip-ephem-wheel-cache-8k0chg5g/wheels/b3/a1/6e/5a0e26314b15eb96a36263b80529ce0d64382540ac7b9544a9
       Successfully built psycopg2
       Installing collected packages: sqlparse, asgiref, tzdata, python-decouple, psycopg2, gunicorn, Django, dj-database-url
       Successfully installed Django-4.0.2 asgiref-3.5.0 dj-database-url-0.5.0 gunicorn-20.1.0 psycopg2-2.9.3 python-decouple-3.5 sqlparse-0.4.2 tzdata-2021.5
-----&gt; $ python manage.py collectstatic --noinput
       128 static files copied to '/tmp/build/static'.

-----&gt; Discovering process types
       Procfile declares types -&gt; release, web
-----&gt; Releasing djangotutorial...
-----&gt; Checking for predeploy task
       No predeploy task found, skipping
-----&gt; Checking for release task
-----&gt; Executing release task from Procfile: python manage.py migrate
=====&gt; Start of djangotutorial release task (a602cab30) output
       Operations to perform:
         Apply all migrations: admin, auth, contenttypes, counter, sessions
       Running migrations:
         Applying contenttypes.0001_initial... OK
         Applying auth.0001_initial... OK
         Applying admin.0001_initial... OK
         Applying admin.0002_logentry_remove_auto_add... OK
         Applying admin.0003_logentry_add_action_flag_choices... OK
         Applying contenttypes.0002_remove_content_type_name... OK
         Applying auth.0002_alter_permission_name_max_length... OK
         Applying auth.0003_alter_user_email_max_length... OK
         Applying auth.0004_alter_user_username_opts... OK
         Applying auth.0005_alter_user_last_login_null... OK
         Applying auth.0006_require_contenttypes_0002... OK
         Applying auth.0007_alter_validators_add_error_messages... OK
         Applying auth.0008_alter_user_username_max_length... OK
         Applying auth.0009_alter_user_last_name_max_length... OK
         Applying auth.0010_alter_group_name_max_length... OK
         Applying auth.0011_update_proxy_permissions... OK
         Applying auth.0012_alter_user_first_name_max_length... OK
         Applying counter.0001_initial... OK
         Applying sessions.0001_initial... OK
=====&gt; End of djangotutorial release task (a602cab30) output
-----&gt; App Procfile file found
=====&gt; Processing deployment checks
       No CHECKS file found. Simple container checks will be performed.
       For more efficient zero downtime deployments, create a CHECKS file. See https://dokku.com/docs/deployment/zero-downtime-deploys/ for examples
-----&gt; Deploying djangotutorial via the docker-local scheduler...
-----&gt; Deploying web (count=1)
       Attempting pre-flight checks (web.1)
       Waiting for 10 seconds (web.1)
       Default container check successful (web.1)
-----&gt; Deploying release (count=0)
-----&gt; Running post-deploy
-----&gt; Creating new app virtual host file...
-----&gt; Configuring djangotutorial.domain.com...(using built-in template)
-----&gt; Creating http nginx.conf
       Reloading nginx
-----&gt; Renaming containers
       Renaming container djangotutorial.web.1.upcoming-7101 (f8d229ebd8bc) to djangotutorial.web.1
-----&gt; Checking for postdeploy task
       No postdeploy task found, skipping
-----&gt; Updated schedule file
=====&gt; Application deployed:
       http://djangotutorial.domain.com

To domain.com:djangotutorial
 * [new branch]      main -&gt; main
</code></pre>
<p>我们刚刚将我们的应用程序部署到Dokku。</p>
<p>刚刚发生了什么？嗯，Dokku为我们做了很多工作:</p>
<ul>
<li>安装 Python</li>
<li>根据 requirements 文件安装Python的包</li>
<li>收集静态文件</li>
<li>执行migrations</li>
<li>最后启动gunicorn服务器来部署我们的应用程序</li>
</ul>
<p>如果你有一个权限错误，那么你的私钥应该在你的本地开发环境中注册。如果你在推送时得到一个 "拒绝许可 "的错误，你可以按以下方式注册你的私钥。<code>ssh-add -k ~/&lt;your private key&gt;</code>。</p>
<p>你也可能在访问应用程序时看到关于 ALLOWED_HOSTS 的错误。在这种情况下，你需要做的就是在Dokku服务器上运行以下命令，将环境变量设置为正确值:</p>
<pre><code class="language-shell"># Set ALLOWED_HOSTS environment variable (make sure to use your domain name)
$ dokku config:set djangotutorial ALLOWED_HOSTS=djangotutorial.domain.com
</code></pre>
<p>现在我们可以在上述网址上访问和测试我们的应用程序：</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/02/PageCounter_Server.gif" alt="在Dokku上运行我们的计数器应用程序——作者的GIF" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>在Dokku上运行我们的计数器应用程序——作者的GIF</figcaption>
</figure>
<p>恭喜你，你刚刚在Dokku上部署了你的应用程序。</p>
<h2 id="letsencryptssl">如何使用Let's Encrypt 加上 SSL</h2>
<p>我们可以做的最后一项配置是通过安装Let's Encrypt SSL证书为我们的应用程序添加SSL安全。</p>
<p>我们可以通过Let's Encrypt插件在Dokku上非常容易地做到这一点：</p>
<pre><code class="language-bash"># Install the Let's Encrypt plugin
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

# Configure the plugin (make sure to replace to your email)
dokku config:set --global DOKKU_LETSENCRYPT_EMAIL=email@domain.com

# set a custom domain that you own for your application
dokku domains:set djangotutorial djangotutorial.your.domain.com

# Enable Let's Encrypt
dokku letsencrypt:enable djangotutorial

# Enable Let's Encrypt auto-renewal
dokku letsencrypt:cron-job --add
</code></pre>
<p>现在我们有一个更安全的应用程序。毕竟，我们的计数器是非常重要的。</p>
<h2 id="">结语</h2>
<p>使用PaaS使开发者在构建网络应用时更容易。</p>
<p>你可以使用像Heroku这样的托管PaaS，还有很多其他的，所以选择是有的。</p>
<p>但也有一些主要的缺点：</p>
<ul>
<li>价格——托管解决方案可能在数据库存储或文件存储等方面有限制</li>
<li>你不能控制部署PaaS的主机，最近AWS的例子表明，即使是最大的云服务商也不是没有问题的。</li>
</ul>
<p>你可以通过自我托管你的PaaS来解决这些问题。</p>
<p>这允许在定价方面有更多的控制。你可以使用像 <a href="https://www.digitalocean.com/">Digital Ocean</a>、<a href="https://hetzner.cloud/">Hetzner</a> 和其他有相当便宜的VPS的主机供应商，它们可以完美地与 Dokku 一起工作。</p>
<p>没有数据库限制。你可能有的唯一限制是内存和磁盘空间，但你可以随时升级你的VPS，价格比在Heroku获得一个新的数据库要低。</p>
<p>Dokku很容易安装，就像我们看到的那样。创建和部署一个应用程序是一个3步过程：</p>
<ul>
<li>在Dokku上创建一个应用程序</li>
<li>在Dokku上创建一个数据存储（如果需要，如Postgres）并链接到应用程序</li>
<li>用Git将你的代码部署到Dokku上</li>
</ul>
<p>此外，你可能需要配置一些环境变量和SSL证书，但这就是全部。</p>
<p>Dokku确实是最小的PaaS实现。</p>
<p>可在<a href="https://github.com/nunombispo/DjangoTutorial">这里</a>获得Django应用程序的完整源代码。</p>
<p>在推特上关注我：<a href="https://twitter.com/DevAsService">https://twitter.com/DevAsService</a></p>
<p>查看我的网站：<a href="https://developer-service.io/">https://developer-service.io/</a></p>
<p>或在我的博客上查看：<a href="https://blog.developer-service.io/">https://blog.developer-service.io/</a></p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 用 Express.js 和 Heroku 部署 Web 应用 ]]>
                </title>
                <description>
                    <![CDATA[ 前言 假如你不熟悉 Web 开发，你会花很多时间学习如何用 HTML、CSS 和 JavaScript 来构建静态站点。 随后，你就可以开始了解如何使用诸如 React、VueJS 或 Angular 等流行框架了。 然而，在尝试了一些新的想法并在本地运行一些网站后，你可能想知道如何真正地部署网站或应用程序。结果是，有时候要知道从哪里开始可能会很困难。 我觉得，使用 Heroku 和 Express 是一种最容易的方式。 Heroku 是一种云平台，支持多种编程语言和框架。 解决方案很多，下面罗列一些（不是我的赞助商）：  * Digital Ocean [https://www.digitalocean.com/]  * Amazon Web Services [https://aws.amazon.com/]  * Azure [https://azure.microsoft.com/en-gb/]  * Google Cloud Platform [https://cloud.google.com/]  * Netlify [https://www.netlify.c ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/how-to-deploy-your-site-using-express-and-heroku/</link>
                <guid isPermaLink="false">5f76b0da027c3105323f58ac</guid>
                
                    <category>
                        <![CDATA[ Heroku ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Express.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Thu, 01 Apr 2021 05:10:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/10/domenico-loia-EhTcC9sYXsw-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <h2 id="-">前言</h2><p>假如你不熟悉 Web 开发，你会花很多时间学习如何用 HTML、CSS 和 JavaScript 来构建静态站点。</p><p>随后，你就可以开始了解如何使用诸如 React、VueJS 或 Angular 等流行框架了。</p><p>然而，在尝试了一些新的想法并在本地运行一些网站后，你可能想知道如何真正地部署网站或应用程序。结果是，有时候要知道从哪里开始可能会很困难。</p><p>我觉得，使用 Heroku 和 Express 是一种最容易的方式。</p><p>Heroku 是一种云平台，支持多种编程语言和框架。</p><p>解决方案很多，下面罗列一些（不是我的赞助商）：</p><ul><li><a href="https://www.digitalocean.com/">Digital Ocean</a></li><li><a href="https://aws.amazon.com/">Amazon Web Services</a></li><li><a href="https://azure.microsoft.com/en-gb/">Azure</a></li><li><a href="https://cloud.google.com/">Google Cloud Platform</a></li><li><a href="https://www.netlify.com/">Netlify</a></li><li><a href="https://zeit.co/">ZEIT Now</a></li></ul><p>搜索这些服务，看看哪个最适合你的需求。</p><p>我个人觉得 Heroku “开箱即用”最快也最容易。免费服务可能对资源有限制，不过，我建议可以用它进行测试。</p><p>这个例子使用 Express 服务器来管理一个简单的网站，下面是概括的步骤：</p><ul><li>用 Heroku、Git、npm 来设置</li><li>创建 Express.js 服务器</li><li>生成静态文件</li><li>部署到 Heroku</li></ul><p>总计约需要 25 分钟（如果想在静态文件上多花点时间，那就需要更长时间）。</p><p>假设你在阅读这篇文章时已经了解：</p><ul><li>基础的 HTML、CSS 和 JavaScript 知识</li><li>基本的命令行的用法</li><li>Git 版本控制的基础知识</li></ul><p>代码在<a href="https://github.com/pg0408/lorem-ipsum-demo">这个仓库</a>中。</p><h2 id="--1">设置</h2><p>对任何项目来说，第一步都是配置你所需要的工具。</p><p>你必须准备好：</p><ul><li>本地安装好 Node 和 npm（<a href="https://nodejs.org/en/download/">指南</a>）</li><li>Git 已安装（<a href="https://www.atlassian.com/git/tutorials/install-git">指南</a>）</li><li>CLI 安装（<a href="https://devcenter.heroku.com/articles/heroku-cli#download-and-install">指南</a>）</li></ul><h3 id="-git-">创建一个新目录，初始化 Git 仓库</h3><p>用命令行新建项目目录并访问该目录。</p><pre><code>$ mkdir lorem-ipsum-demo
$ cd lorem-ipsum-demo</code></pre><pre><code>$ git init</code></pre><p>⚠️ &nbsp;这个步骤非常重要，因为 Heroku 依赖于 Git 把本地机器上的代码部署到它的云服务器上。⚠️</p><p>你还可以创建一个 README.md 文件，稍后编辑。</p><pre><code>$ echo "Edit me later" &gt; README.md</code></pre><h3 id="-heroku-cli-">登录 Heroku CLI，创建一个新项目</h3><p>你可以通过 HerokuCLI（命令行界面）登录 Heroku。你需要一个免费的 Heroku 账户。</p><p>以下是两种选择。默认情况下，Heroku 允许通过 Web 浏览器登录。你可以使用 <code>-i</code> 通过命令行登录。</p><pre><code>$ heroku login -i</code></pre><p>你现在可以新建一个 Heroku 项目了。我的项目名字是 <code>lorem-ipsum-demo</code>。</p><pre><code>$ heroku create lorem-ipsum-demo</code></pre><p>为项目命名：</p><ul><li>如果在命令中没有指定名字，Heroku 会随机生成一个项目名</li><li>这个名字将成为项目 URL 的一部分，所以你可以选择自己喜欢的名字</li><li>它还意味着你需要选择一个唯一的项目名，而其他人不会使用它</li><li>你可以稍后重命名项目（所以不必担心现在就要获得一个完美的名称）</li></ul><h3 id="-npm-express-js">初始化新的 npm 项目并安装 Express.js</h3><p>下一步，可以通过创建 package.json 文件对新 npm 项目进行初始化。用下面的命令来完成它。</p><p>⚠️ &nbsp;这个步骤非常关键，在构建应用程序时，Heroku 依赖于你提供的 package.json 文件，以了解这是一个 Node.js 项目⚠️</p><pre><code>$ npm init -y</code></pre><p>然后，<a href="https://expressjs.com/en/starter/installing.html">安装 Express</a>。Express 是 NodeJS 中广泛使用的服务器框架。</p><pre><code>$ npm install express --save</code></pre><p>终于可以开始写代码了！</p><h2 id="-express-">写一个简单的 Express 服务器</h2><p>接下来，我们将创建一个名为 app.js 的文件，它在本地运行 Express 服务器。</p><pre><code>$ touch app.js</code></pre><p>这个文件将成为应用程序的入口点。也就是说，启动应用程序需要使用以下命令：</p><pre><code>$ node app.js</code></pre><p>但首先，你需要在你的文件里写一些代码。</p><h3 id="-app-js-">编辑 app.js 的内容</h3><p>用你喜欢的编辑器打开 app.js，编写下面的代码，然后保存。</p><pre><code class="language-javascript">// create an express app
const express = require("express")
const app = express()

// use the express-static middleware
app.use(express.static("public"))

// define the first route
app.get("/", function (req, res) {
  res.send("&lt;h1&gt;Hello World!&lt;/h1&gt;")
})

// start the server listening for requests
app.listen(process.env.PORT || 3000, 
	() =&gt; console.log("Server is running..."));</code></pre><p>我们快速分解代码来进一步了解它：</p><ul><li>头两行只需要 Express 模块​​，然后创建一个 Express 应用实例</li><li>接下来的一行需要使用 <code>express.static</code> 中间件。通过这种方式，可以服务于指定目录的静态文件（例如 HTML、CSS 和 JavaScript）。本例中，服务于 <code>public</code> 文件夹中的文件。</li><li>接下来的一行使用 <code>app.get()</code> 定义 URL 路径。任何发给根 URL 的 URL 请求都会得到一个简单的 HTML 消息响应。</li><li>最后一部分是启动服务器，查看 Heroku 使用哪个端口，如果在本地运行，则默认为 3000。</li></ul><p>⚠️ 在最后一行使用 <code>process.env.PORT || 3000</code> 对成功部署应用程序非常重要。⚠️</p><p>如果你保存 <code>app.js</code>，使用以下命令启动服务器：</p><pre><code>$ node app.js</code></pre><p>你就可以通过浏览器访问 localhost:3000，看看服务器是否正常运行。</p><h2 id="--2">创建静态文件</h2><p>接下来要创建一个静态文件。当用户访问项目时，他们会提供 HTML、CSS 和 JavaScript 文件。</p><p>在 <code>app.js</code> 中，你曾经告诉 <code>express.static</code> 中间件服务于 <code>public</code> 文件夹中的静态文件。</p><p>当然，首先要创建这样一个文件夹和其中包含的文件。</p><pre><code>$ mkdir public
$ cd public
$ touch index.html styles.css script.js</code></pre><h3 id="-html-">编辑 HTML 文档</h3><p>用你喜欢的文本编辑器打开 <code>index.html</code>，为页面提供基本的结构。</p><p>以下示例为 LoremIpsum 生成器创建了一个简单的登录页面，你可以自由修改。</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;head&gt;
	&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"&gt;&lt;/script&gt;
	&lt;link href="https://fonts.googleapis.com/css?family=Alegreya|Source+Sans+Pro&amp;display=swap" rel="stylesheet"&gt;
	&lt;link rel="stylesheet" type="text/css" href="styles.css"&gt;
&lt;/head&gt;
&lt;html&gt;
&lt;body&gt;
&lt;h1&gt;Lorem Ipsum generator&lt;/h1&gt;
  &lt;p&gt;How many paragraphs do you want to generate?&lt;/p&gt;
  &lt;input type="number" id="quantity" min="1" max="20" value="1"&gt;
  &lt;button id="generate"&gt;Generate&lt;/button&gt;
  &lt;button id="copy"&gt;Copy!&lt;/button&gt;
&lt;div id="lorem"&gt;
&lt;/div&gt;
&lt;script type="text/javascript" src="script.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><h3 id="-css-">编辑 CSS 文件</h3><p>然后，编辑 CSS 文件 <code>styles.css</code>。请确认在 HTML 文件中链接这个文件。</p><p>Lorem Ipsum 示例使用了下面的 CSS。同样，你可以自由发挥修改它。</p><pre><code class="language-css">h1 {
	font-family: 'Alegreya' ;
}

body {
	font-family: 'Source Sans Pro' ;
	width: 50%;
	margin-left: 25%;
	text-align: justify;
	line-height: 1.7;
	font-size: 18px;
}

input {
	font-size: 18px;
	text-align: center;
}

button {
	font-size: 18px;
	color: #fff;
}

#generate {
	background-color: #09f;
}

#copy {
	background-color: #0c6;
}</code></pre><h3 id="-javascript-">编辑 JavaScript 文件</h3><p>最后，你需要编辑 JavaScript 文件 <code>script.js</code>，让你的网页更具有交互性。</p><p>下面的代码为 Lorem Ipsum 定义了两个基本功能。我用的是 <a href="https://jquery.com/">JQuery</a>，操作起来简单快捷。</p><pre><code class="language-javascript">$("#generate").click(function(){
	var lorem = $("#lorem");
	lorem.html("");
	var quantity = $("#quantity")[0].valueAsNumber;
	var data = ["Lorem ipsum", "quia dolor sit", "amet", "consectetur"];
	for(var i = 0; i &lt; quantity; i++){
		lorem.append("&lt;p&gt;"+data[i]+"&lt;/p&gt;");
	}
})

$("#copy").click(function() {
	var range = document.createRange();
	range.selectNode($("#lorem")[0]);
	window.getSelection().removeAllRanges();
	window.getSelection().addRange(range);
	document.execCommand("copy");
	window.getSelection().removeAllRanges();
	}
)</code></pre><p>注意，这里的 <code>data</code> 列表被截断，以便更容易显示。在实际的应用里，这是一个较长的完整段落列表。你可以在仓库里看到全部的文件，或者在<a href="http://www.thelatinlibrary.com/cicero/fin1.shtml">这里</a>找到原始的来源。</p><h2 id="--3">部署你的应用程序</h2><p>写好静态代码，检查之后，就可以部署到 Heroku 了。但还需要做些事情。</p><h3 id="-procfile">创建 Procfile</h3><p>Heroku 需要一个 Procfile 才能知道如何运行应用程序。</p><p>Procfile 是一个“进程文件”，用于告诉 Heroku 运行哪个命令来管理给定的进程。本例中，命令将告诉 Heroku 如何在 Web 上启动服务器进行监听。</p><p>用以下命令创建一个文件：</p><p>⚠️ &nbsp;这个步骤很重要，因为没有 Procfile，Heroku 就不能让服务器在线。⚠️</p><pre><code>$ echo "web: node app.js" &gt; Procfile</code></pre><p>注意 Procfile 没有文件扩展名（例如 “txt”、“jason”)。</p><p>使用命令 node app.js 在本地运行服务器。</p><h3 id="-git--1">向 Git 添加和提交文件</h3><p>还记得在设置时初始化了一个 Git 仓库，或许你已经向其中添加并提交了一些文件。</p><p>在部署到 Heroku 之前，需要添加所有文件并 commit。</p><pre><code>$ git add .
$ git commit -m "ready to deploy"</code></pre><p><br>最后一步是 push 到 Heroku 的 master 分支。</p><pre><code>$ git push heroku master</code></pre><p>在 Heroku 构建和部署应用程序的过程中，应该可以看到命令行输出了大量信息。</p><p>如果看到 <code>Verifying deploy... done</code>，就说明构建成功了。<br><br>你现在可以打开浏览器，访问 xxx（你定义的项目名）.herokuapp.com，可以看到你的应用程序将被托管在网络上，大家都可以访问了！</p><h2 id="--4">回顾</h2><p>下面是把一个简单的 Express 应用程序部署到 Heroku 的步骤：</p><ul><li>新建目录，初始化一个 Git 仓库</li><li>登录到 Heroku CLI，创建一个新项目</li><li>初始化一个新的 npm 项目，并安装 Express.js</li><li>编辑 app.js 的内容</li><li>修改静态 HTML、CSS 和 JavaScript 文件</li><li>创建一个 Procfile</li><li>添加并 commit 文件到 Git 仓库，然后将其 push 到 Heroku 的 master 分支</li></ul><h2 id="--5">如果应用程序不能正常运行？</h2><p>有时候，即便网络上的教程已经比较全面，你实际做的项目仍然可能不能正常运行。</p><p>下列的步骤可以帮助你调试一些可能遇到的常见错误：</p><ul><li>你是否已经初始化项目文件夹中的 Git 仓库？检查是否已运行 <code>git init</code></li><li>你创建了 <code>package.json</code> 文件吗？检查是否已运行 <code>npm init -y</code></li><li>服务器是否运行？请确保 Procfile 使用正确的文件名启动服务器，确认有 <code>web: node app.js</code> ，而不是 <code>web: node index.js</code></li><li>Heroku 知道要监听的端口吗？确认你在 <code>app.js</code> 文件使用了 <code>app.listen(process.env.PORT || 3000)</code></li><li>静态文件中是否包含错误信息？在本地运行，检查是否有 bug</li></ul><p>谢谢阅读！<a href="http://lorem-ipsum-demo.herokuapp.com/">这是完整的 demo</a>。</p><p>原文：<a href="https://www.freecodecamp.org/news/how-to-deploy-your-site-using-express-and-heroku/">How to deploy your app to the web using Express.js and Heroku</a>，作者：Peter Gleeson</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
