如何在Linux服务器上后台持久运行Gunicorn
- **问题概述**
- **解决方案一:使用`nohup`命令**
- **解决方案二:使用`systemd`服务**
- **创建`systemd`服务文件**
- **修改`systemd`服务文件以使用虚拟环境**
- 日志管理
- **激活并启动服务:**
- 如何设置用户和组
- **确认用户和组存在**
- 如何赋予用户和组对应用程序目录和所需资源有正确的权限
- 如何查看我的目前系统中的用户和组
- **结论**
问题概述
在使用SSH远程连接到服务器并在终端启动**gunicorn
时,关闭SSH窗口后常常导致gunicorn
**进程终止,这导致无法访问API接口,尽管端口侦听似乎仍在进行。
解决方案一:使用nohup
命令
nohup
命令可用于在退出登录或关闭终端后继续运行进程。要使用nohup
,您可以在命令前加上**nohup
,并在命令最后添加&
**,将进程放入后台运行。
nohup gunicorn -w 4 --bind 0.0.0.0:6666 --reload run:app --timeout 120 --access-logfile - --error-logfile - &
这个命令将**gunicorn
的输出重定向到一个名为nohup.out
的文件中,即使SSH会话关闭,gunicorn
**进程也会继续运行。
解决方案二:使用systemd
服务
创建systemd
服务文件
创建一个新的服务文件**/etc/systemd/system/gunicorn.service
(服务文件名你可以自己定义,例如answerai.service
)**,文件内容如下:
[Unit]
Description=gunicorn daemon for my web application
After=network.target
[Service]
User=myuser
Group=mygroup
WorkingDirectory=/path/to/your/app
ExecStart=/path/to/your/virtualenv/bin/gunicorn --workers 4 --bind 0.0.0.0:6666 run:app
StandardOutput=append:/path/to/your/logs/gunicorn.out
StandardError=append:/path/to/your/logs/gunicorn.err
[Install]
WantedBy=multi-user.target
替换**myuser
、mygroup
、/path/to/your/app
和/path/to/your/virtualenv/bin/gunicorn
**为您的实际信息。
在这个文件中:
-
我们设定了描述和在网络服务启动之后启动**
gunicorn
**。 -
在**
[Service]
**部分,我们定义了运行服务的用户(myuser
)和组(mygroup
),服务的工作目录(/path/to/your/app
),以及启动命令。 -
**
ExecStart
行指定了启动服务时要执行的命令。在这里,我们告诉gunicorn
**使用4个工作进程ExecStart
中的命令实际上定义了如何启动gunicorn
以及它将如何与您的应用程序进行通信。这里有两种常见的绑定方式:-
绑定到一个 UNIX 套接字:
ExecStart=/var/www/myapp/venv/bin/gunicorn --workers 4 --bind unix:/var/www/myapp/myapp.sock myapp.wsgi:application
这条命令将
gunicorn
绑定到一个 UNIX 套接字文件myapp.sock
。这种方式在与 Nginx 等 Web 服务器配合时很常见,因为它们可以直接通过 UNIX 套接字与gunicorn
通信,这比 TCP 套接字更高效,因为它们不需要进行网络堆栈的额外处理。 -
绑定到 TCP 端口:
ExecStart=/path/to/your/virtualenv/bin/gunicorn --workers 4 --bind 0.0.0.0:6666 run:app
这条命令将
gunicorn
绑定到所有接口的6666
端口。这种方式在您直接通过 HTTP 访问gunicorn
时很有用,或者在测试环境中很常见,因为它允许从任何 IP 地址通过指定端口访问应用程序。选择哪种方式取决于您的部署需求和安全考虑。UNIX 套接字通常更安全,因为它们在文件系统中作为文件存在,不对外暴露端口,而且通常会配合 Web 服务器一起使用。如果您直接使用 TCP 端口绑定,那么可能需要考虑使用防火墙规则来限制对该端口的访问。
-
-
最后,在**
[Install]
**部分,我们定义了这个服务将如何被安装和启动,这里是在多用户目标下。在**
systemd
服务文件中的[Install]
部分,WantedBy
是一个指令,它定义了当该服务被enable
时应该被哪个“目标”(target)所拉起。目标是systemd
**中用于定义系统启动过程中的不同阶段的一个单位。**
multi-user.target
是一个目标,它相当于传统的运行级别(runlevel)。它通常用于设置一个多用户的文本模式环境,没有图形界面,但网络服务已启动并可以使用。当您设置一个服务WantedBy=multi-user.target
并启用它(使用systemctl enable
命令)时,您告诉systemd
**在达到多用户文本模式时,也就是系统启动过程中达到相应的点时,应该启动这个服务。简单来说,**
WantedBy=multi-user.target
**确保了您的服务会在系统启动到多用户运行级别时自动启动。这是大多数后台服务的标准配置,使得在系统启动时无需手动启动服务。
修改systemd
服务文件以使用虚拟环境
如果您需要在Python虚拟环境中运行**gunicorn
,您应该在systemd
服务文件的ExecStart
命令中指定虚拟环境中的gunicorn
**可执行文件的完整路径。这样,服务在启动时会使用虚拟环境中的Python和依赖包。
您的服务文件中的**ExecStart
**部分应该看起来像这样:
[Service]
...
ExecStart=/path/to/your/virtualenv/bin/gunicorn --workers 4 --bind 0.0.0.0:6666 run:app
...
在这里,**/path/to/your/virtualenv/bin/gunicorn
是您虚拟环境中gunicorn
的完整路径。您需要将/path/to/your/virtualenv
**替换为您的虚拟环境实际所在的路径。
举例说明:
假设您的虚拟环境位于**/home/myuser/myappenv
,并且您的应用程序目录是/home/myuser/myapp
**。服务文件可能会是这样的:
[Unit]
Description=gunicorn daemon for myapp web application
After=network.target
[Service]
User=myuser
Group=myuser
WorkingDirectory=/home/myuser/myapp
ExecStart=/home/myuser/myappenv/bin/gunicorn --access-logfile - --workers 4 --bind 0.0.0.0:6666 myapp.wsgi:application
[Install]
WantedBy=multi-user.target
这里的关键是确保**ExecStart
指向了虚拟环境中的gunicorn
**。
日志管理
使用**systemd
来管理gunicorn
服务时,systemd
本身提供了日志管理功能,它会自动处理服务的输出,并存储在系统的日志中,可以通过journalctl
命令来访问。因此,如果您使用systemd
,通常不需要nohup
来重定向输出到文件中,systemd
**会更好地为您服务。
不过,如果您仍然想要将**gunicorn
的输出重定向到特定的文件,您可以在systemd
服务文件的[Service]
部分使用StandardOutput
和StandardError
**指令来指定输出和错误日志的路径。
例如:
[Service]
...
ExecStart=/path/to/your/virtualenv/bin/gunicorn --workers 4 --bind 0.0.0.0:6666 run:app
StandardOutput=append:/path/to/your/logs/gunicorn.out
StandardError=append:/path/to/your/logs/gunicorn.err
...
这里,StandardOutput=append:/path/to/your/logs/gunicorn.out
指令将会把stdout
输出追加到指定的文件中,StandardError=append:/path/to/your/logs/gunicorn.err
则将错误信息追加到另一个文件。您需要确保这些文件是可写的,并且gunicorn
运行的用户(在[Service]
部分指定的User
)具有写入这些文件的权限。
请注意,使用**append
是在systemd
较新版本中引入的选项,如果您的系统中的systemd
版本不支持,您可能需要去掉append:
**并直接写文件路径。
此外,如果您想保留使用**nohup
的原始方法并重定向输出到文件,那么您就不需要systemd
服务。您只需在命令行中启动gunicorn
**,如下所示:
nohup /path/to/your/virtualenv/bin/gunicorn --workers 4 --bind 0.0.0.0:6666 run:app > /path/to/your/logs/gunicorn.out 2>&1 &
在这里,>
是将标准输出(stdout
)重定向到文件,2>&1
是将标准错误(stderr
)也重定向到同一个文件中。结尾的**&
是将进程放到后台运行。这样做,即使SSH会话关闭,gunicorn
进程也会继续运行,并且它的输出会被记录到/path/to/your/logs/gunicorn.out
**文件中。
激活并启动服务:
在创建和配置好服务文件之后,以下命令将帮助您管理服务:
# 重新加载systemd以识别新的服务
sudo systemctl daemon-reload
# 启动gunicorn服务
sudo systemctl start gunicorn.service
# 设置gunicorn服务开机启动
sudo systemctl enable gunicorn.service
# 检查gunicorn服务的状态
sudo systemctl status gunicorn.service
# 查看gunicorn服务的日志
journalctl -u gunicorn.service
这样一来,您的**gunicorn
**进程就会在指定的Python虚拟环境中运行,而且即使在SSH会话关闭后也能持续运行。
如何设置用户和组
确认用户和组存在
在您的**systemd
服务文件中指定的用户(User
)和组(Group
**)应该是系统中已存在的。使用以下命令查看系统中的用户和组:
- 查看所有用户:
cat /etc/passwd
或getent passwd
- 查看所有组:
cat /etc/group
或getent group
如果需要,您可以创建一个新的用户和组:
sudo adduser myuser
sudo addgroup mygroup
sudo adduser myuser mygroup
确保这个用户和组对应用程序目录和所需资源有正确的权限。
在Linux系统中,当您创建一个新用户时,默认情况下,系统会为该用户创建一个同名的用户组,并且这个用户会自动成为那个组的成员。这个默认组被称为用户的"主组"(primary group)。每个文件都有一个所有者和一个组,且新文件的默认组设置通常是其所有者的主组。
然而,如果您需要让用户属于额外的组,您需要手动将用户添加到这些组中。这就是**
sudo adduser myuser mygroup
命令的作用。它将用户myuser
添加到组mygroup
**,作为它的附加组(secondary group)。这样做的原因可能是:
- 权限共享:如果您希望**
myuser
能够访问由mygroup
**组拥有的文件或目录,您需要将该用户添加到该组。- 应用需求:某些应用程序可能要求用户必须属于特定的组才能运行。
- 安全控制:通过将用户分配给特定的组,您可以更细粒度地控制用户的权限,而不是给予他们更广泛的权限。
所以,最后这步**
sudo adduser myuser mygroup
是为了确保myuser
不仅拥有其主组的权限,还能够获取其他组如mygroup
的组权限。如果mygroup
**是您创建的特定目的的组,您需要执行这个命令来实现这一点。如果不需要额外的组权限,这一步则不是必需的。
如何赋予用户和组对应用程序目录和所需资源有正确的权限
-
更改所有者: 使用
chown
命令将您的应用目录的所有权更改为正确的用户和组。sudo chown -R 用户名:组名 /应用目录路径
替换
用户名
和组名
为实际的用户名和组名,/应用目录路径
为您的应用实际所在的路径。 -
设置权限: 使用
chmod
命令为目录设置权限。-
让用户有完全的权限:
sudo chmod -R 700 /应用目录路径
-
让组有读取和执行权限:
sudo chmod -R 750 /应用目录路径
-
验证权限:
使用**ls -l
**命令来验证权限和所有权是否正确设置。ls -l /path/to/your/app
-
测试权限:
切换到您的**gunicorn
**用户,尝试读取和写入应用程序目录中的文件。sudo -u myuser -g mygroup touch /path/to/your/app/testfile
如果命令执行没有错误,表示权限设置正确。
确保在设置权限时,您明白每个权限的含义,以及为什么要分配它们。不恰当的权限设置可能会导致安全风险,特别是在生产环境中。通常,最佳实践是赋予最小必要权限,以避免潜在的安全问题。
需要注意的是:
root
用户在Linux系统中具有最高权限。root
能够访问和操作系统上的所有文件和命令,无论这些文件的权限设置是什么。这意味着即使一个文件的权限被设置为只允许特定用户访问,root
用户仍然可以操作这个文件。当您使用
root
用户时,您需要特别小心,因为具有这样的权限也意味着您能够执行任何可能对系统造成损害的操作。所以通常建议对于日常操作使用普通用户,并仅在需要进行系统级更改时使用root
权限。 -
如何查看我的目前系统中的用户和组
您可以通过几个不同的命令在Linux系统中查看存在的用户和组。
查看用户列表:
-
查看**
/etc/passwd
**文件,这个文件包含了系统上每个用户的信息:cat /etc/passwd
-
使用**
getent
**命令:getent passwd
这些命令会列出所有用户,其中每一行代表一个用户,行中的第一个字段是用户名。
查看组列表:
-
查看**
/etc/group
**文件,这个文件包含了系统上每个组的信息:cat /etc/group
-
使用**
getent
**命令:getent group
这些命令会列出所有组,其中每一行代表一个组,行中的第一个字段是组名。
结论
无论您选择**nohup
还是systemd
,关键是确保您的gunicorn
进程在后台稳定运行,并且能够在系统重启后自动启动。systemd
提供了一个更强大和可配置的解决方案,适合生产环境。而nohup
**是一个快速且简单的临时解决方案,适合开发或测试环境。请确保使用正确的用户和组,并为服务和日志文件设置适当的权限。