生活点点

  • 使用 Docker 搭建 MySQL、WordPress、Nginx 和 Certbot 环境


    在现代网站架构中,使用容器化技术来部署应用程序已经成为一种常见的做法。Docker 是一个非常强大的工具,它允许我们将应用程序及其依赖打包到一个容器中,从而实现轻量级的虚拟化部署。本篇文章将展示如何使用 Docker 来搭建一个包含 MySQLWordPressNginxCertbot 环境的完整网站。

    我们将实现以下目标:

    • MySQL:用于存储 WordPress 数据。
    • WordPress:提供内容管理系统(CMS)功能。
    • Nginx:作为反向代理和 Web 服务器,负责处理 HTTPS 请求并提供 SSL 证书支持。
    • Certbot:用于自动申请和续期 SSL 证书,确保网站通过 HTTPS 安全访问。

    如果不想一步步学习,可以直接使用下面的一键部署,适合ubuntu server

    Github一键部署项目:Github/Ushiao/docker-compose-wordpress-nginx-mysql

    环境概述

    我们将使用 Docker 和 Docker Compose 来创建多个容器:

    • MySQL 容器:运行 MySQL 数据库。
    • WordPress 容器:运行 WordPress 内容管理系统。
    • Nginx 容器:作为反向代理和 Web 服务器。
    • Certbot 容器:自动获取和管理 SSL 证书。
    (更多…)
  • 快速处理ChatGPT发不出消息

    3月头,ChatGPT莫名无法发出消息,大部分是因为加入了多语言Alpha测试的用户有这个问题。处理方法如下:

    在账号->设置->语言->设置为英文

  • 稳定性加权运营指数得分法

    “稳定性加权运营指数得分法”(Stability-Weighted Operational Index Scoring, SWOIS)。这个名字体现了该方法的核心特点:通过加权稳定性(波动性的低度)来增强对运营指数高度的评价。

    如果您希望有一个得分,既反映运营指数的高度又反映其稳定性,那么我们需要综合考虑运营指数的均值(或总值)和其变异系数或标准差。以下是一种可能的计算方法:

    先,标准化运营指数:使得其均值为0,标准差为1。

    \( z_{index} = \frac{x – \bar{x}}{\sigma}\) 

    其中,xx 是特定月份的运营指数,xˉxˉ 是所有月份的平均运营指数,σσ 是运营指数的标准差。

    计算变异系数:这是一个表示波动性的指标。

    \( CV = \frac{\sigma}{\bar{x}}\) 

    为了使得分又高又稳定,我们可以将标准化的运营指数与变异系数的逆数(或某种函数)结合

    \( score = z_{index} \times f(CV)\) 

    其中,f(CV)f(CV) 是一个函数,其值随着CV的增加而减小,表示越稳定(CV越小),得分的权重越大。

    例如,一个简单的选择是:

    \( f(CV) = \frac{1}{1 + CV}\) 

    这样,当CV增加(也就是运营不稳定)时,得分的权重会降低,但当CV减少(运营更稳定)时,权重会增加。

    这种方法将运营指数的高度和稳定性结合在一个得分中,使得得分又高又稳定时最大。您可以根据实际需求对此方法进行调整或改进。

  • 使用 Gunicorn 进行 Python Web 应用部署的基础配置

    Gunicorn(Green Unicorn)是一个用于部署 Python Web 应用的 WSGI HTTP 服务器。它以高效、稳定和易用而著称。在这篇博客中,我们将介绍如何进行基础的 Gunicorn 配置,并展示一个示例配置文件。

    安装 Gunicorn

    首先,确保你已经安装了 Gunicorn。可以使用 pip 进行安装:

    pip install gunicorn

    基础配置示例

    以下是一个简单的 Gunicorn 配置文件示例 conf.py,用于启动一个 Web 应用:

    #conf.py
    
    import gevent.monkey
    import multiprocessing
    
    gevent.monkey.patch_all()
    
    bind = '0.0.0.0:5000'
    preload_app = True
    loglevel = 'error'
    logfile = 'log/debug.log'
    accesslog = 'log/access.log'
    access_log_format = '%(h)s %(t)s %(U)s %(q)s'
    errorlog = 'log/error.log'
    proc_name = 'vservice'
    pidfile = 'log/gunicorn.pid'
    daemon = True
    workers = multiprocessing.cpu_count() * 2 + 1
    threads = multiprocessing.cpu_count() * 2
    worker_class = 'gevent'


    这个配置文件设置了 Gunicorn 的基本参数,包括绑定地址、日志路径、进程和线程数量等。现在,让我们一行一行地解释这个配置。

    1. import gevent.monkey 和 gevent.monkey.patch_all():引入并启用 gevent monkey patch,以使 Gunicorn 与 gevent 协同工作。
    2. import multiprocessing:引入 multiprocessing 模块,用于获取 CPU 核心数量。
    3. bind = ‘0.0.0.0:8002’:设置 Gunicorn 的绑定地址和端口,允许通过所有网络接口访问,端口为 8002。
    4. preload_app = True:在主进程启动时预加载应用程序,适用于一些需要共享资源或者在启动时执行初始化代码的情况。
    5. loglevel = ‘error’:设置日志级别为 ‘error’,只记录错误信息。
    6. logfile = ‘log/debug.log’:设置日志文件路径。
    7. accesslog = ‘log/access.log’:设置访问日志文件路径。
    8. access_log_format = ‘%(h)s %(t)s %(U)s %(q)s’:设置访问日志的格式。
    9. errorlog = ‘log/error.log’:设置错误日志文件路径。
    10. proc_name = ‘vservice’:设置 Gunicorn 进程的名称。
    11. pidfile = ‘log/gunicorn.pid’:设置 Gunicorn 进程的 PID 文件路径。
    12. daemon = True:将 Gunicorn 进程设置为守护进程,即在后台运行。
    13. workers = multiprocessing.cpu_count() * 2 + 1:设置工作进程的数量,通常为 CPU 核心数的两倍加一。
    14. threads = multiprocessing.cpu_count() * 2:设置每个工作进程的线程数,通常为 CPU 核心数的两倍。
    15. worker_class = ‘gevent’:设置工作进程的类别为 gevent,表示使用 gevent 模块提供的协程支持。

    启动 Gunicorn 服务器

    使用以下命令启动 Gunicorn 服务器:

    gunicorn -c conf.py your_app:app

    这里的 your_app:app 是你的应用的模块和应用实例。通过这个简单的配置文件,你可以轻松地启动一个 Gunicorn 服务器,并根据实际需要进行配置。

    希望这篇博客对你理解和配置 Gunicorn 服务器有所帮助!如果有任何问题或疑问,请随时留言。

  • 避免Python中的递归调用问题:如何正确使用__getattr__和__setattr__方法

    递归调用是指一个函数或方法在执行的过程中,直接或间接地调用了自身,从而形成了无限循环的调用关系,导致程序崩溃或陷入死循环。在 Python 中,由于方法和属性的调用方式不同,很容易出现递归调用的问题,特别是在使用 __setattr__ 和 __getattr__ 等特殊方法时。

    RecursionError: maximum recursion depth exceeded 

    在相关开发的项目中,为了便于数据库和业务的交互,定义了一些Model来处理任务,为了简便完成Model的开发,采用了 __setattr__ 和 __getattr__ ,但却因此产生了递归调用的问题。以下是出错的代码:

    class Person(object):
        def __init__(self, *args, **kwargs):
           self.document = {"genre": "XXX", "age": "XXX"}
        def __getattr__(self, name):
            if name in self.document:
                return self.document[name]
            else:
                raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
        def __setattr__(self, name, value):
            # 这里的self.document会触发__getattr__方法
            # 从而在__getattr__里面的self.document又继续
            # 触发__getattr__,从而产生递归调用问题
            if name in self.document: 
                self.document[name] = value
            else:
                super().__setattr__(name, value)
    person = Person()
    person.age = 18 

    为了解决这个问题,我们可以在类中使用 self.__dict__.setdefault() 方法或者在 init 方法中使用 self._document = {} 来初始化实例属性。这样做的好处是,实例属性和类属性的作用域得到了清晰的界定,避免了递归调用的问题。此外,如果要修改实例属性,我们可以直接使用 setattr() 方法,而不是直接赋值,这样也可以避免递归调用的问题。

    下面是一个示例代码,演示了如何使用 getattrsetattr 方法,避免递归调用的问题:

    class Person(object):
        def __init__(self, *args, **kwargs):
           # 初始化实例下的__dict__
           self.__dict__.setdefault('document', {})
           self.document = {"genre": "XXX", "age": "XXX"}
        def __getattr__(self, name):
            if name in self.document:
                return self.document[name]
            else:
                raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
        def __setattr__(self, name, value):
            if name in self.document: 
                self.document[name] = value
            else:
                super().__setattr__(name, value)
    

    在这个示例代码中,我们使用了 self.__dict__.setdefault() 方法来初始化实例属性。这样,就可以避免递归调用的问题,确保程序能够正确地运行。

    另外在类属性这里初始化一个document = {}也能解决问题,但是需要注意类属性和实例属性的作用域,避免产生混淆,导致程序出错。

    class Person(object):
        document = {"genre": "XXX", "age": "XXX"}
        def __init__(self, *args, **kwargs):
            pass
        def __getattr__(self, name):
            if name in self.document:
                return self.document[name]
            else:
                raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
    
        def __setattr__(self, name, value):
            if name in self.document: 
                self.document[name] = value
            else:
                super().__setattr__(name, value)

    Python的__getattr__和__setattr__是在开发中很好用的方法,能大大提高开发效率,但是递归调用的问题不能忽视,以上便是针对这个问题的解决方案。

  • pyright的type hints提示

    大概很久没更新过vim的插件系统,最近重装了一下coc.nvim,发现最新的coc-pyright版本,增加了inlay hints,他的效果是在代码的变量边上显示变量类型,函数返回类型,如下所示:

    这个如果习惯没关系,在debug的时候会很好用,如果在写代码,甚至复制代码的时候,可能会有影响,总之不是很习惯。可以在vim里面通过:CocConfig打开coc-settings.json,在里面增加下面两个配置就可以了

    {
      # 返回类型不显示
      "pyright.inlayHints.functionReturnTypes": false,  
      # 变量类型不显示
      "pyright.inlayHints.variableTypes": false  
    }

    具体参考:

    https://github.com/fannheyward/coc-pyright#Configurations

  • coc-pyright安装失败

    在Vim中安装coc.nvim插件的扩展coc-pyright出现了code 1失败,无法正常安装,尝试了多种办法都没用,最后尝试使用管理员权限解决问题

    通过管理员模式打开vim的编辑界面

    sudo vim

    之后在Vim窗口输入指令

    :CocInstall coc-pyright

    这样就正常安装了

  • 如何在pypiserver中启用密钥保护保护你的Python包仓库

    作为一名专业的Python程序员,你可能经常需要管理自己的Python包仓库。而pypiserver就是一个简单易用的工具,可以让你快速搭建自己的Python包仓库。但是,为了保护你的Python包仓库的安全,你可能需要在pypiserver中启用密钥保护。本文将为你介绍如何在pypiserver中启用密钥保护。

    一、密码文件

    pypiserver默认不支持密钥,但是可以通过设置密码文件来限制访问pypiserver。在pypiserver的根目录下创建一个名为.htaccess的文件,并在其中添加以下内容:

    username:password

    其中,username和password分别是你要设置的用户名和密码。请注意,密码需要使用htpasswd工具生成,否则会造成安全风险。htpasswd工具可以通过以下命令安装:

    $ sudo apt-get install apache2-utils

    使用htpasswd生成密码:

    $ htpasswd -c .htpasswd username

    输入密码后,将在当前目录下生成一个名为.htpasswd的文件,其中包含加密后的密码。你可以使用以下命令验证密码是否设置成功:

    $ htpasswd -v .htpasswd username

    二、HTTPS

    HTTPS可以通过在pypiserver的配置文件中设置来启用。在pypiserver的根目录下创建一个名为config.py的文件,并在其中添加以下内容:

    [server:main]
    use = egg:gunicorn
    host = 0.0.0.0
    port = 80
    certfile = /path/to/cert.pem
    keyfile = /path/to/key.pem

    其中,certfile和keyfile分别是SSL证书和密钥文件的路径。你可以使用Let’s Encrypt等工具来生成证书和密钥文件。

    请注意,启用HTTPS会增加服务器的安全性,但也会增加服务器的负担。如果你的服务器配置较低,可能会影响pypiserver的性能。

    总结:

    本文介绍了如何在pypiserver中启用密钥保护,包括密码文件和HTTPS加密通信。通过设置密码文件或启用HTTPS,可以提高你的Python包仓库的安全性,保护你的Python包不受非法访问。

  • 如何使用 pip 配置文件配置 PyPI 私有服务器

    在 Python 开发过程中,我们经常需要使用 pip 命令来安装各种依赖包。默认情况下,pip 会从公共 PyPI 服务器中下载相应的文件。但是,有时候我们需要使用私有 PyPI 服务器来管理和分发私有的 Python 包和依赖。这时候,我们可以使用 pip 配置文件来配置私有服务器的 URL。

    配置私有 PyPI 服务器的 URL

    使用 pip 配置文件来配置私有 PyPI 服务器的 URL,可以让我们在使用 pip 安装包和依赖时,自动判断要从哪个服务器下载相应的文件。下面是配置文件的步骤:

    创建 ~/.pip 目录:

    mkdir -p ~/.pip

    创建 pip.conf 文件,并编辑文件:

    touch ~/.pip/pip.conf nano ~/.pip/pip.conf

    pip.conf 文件中添加以下内容:

    [global]
    index-url = http://localhost:8080/simple/ 
    #指定可信任的主机名,用于避免 SSL 证书验证失败的问题
    trusted-host = localhost

    这里的 index-url 参数指定了私有 PyPI 服务器的 URL,可以根据实际情况进行修改。

    配置完成后,我们就可以在使用 pip 安装包和依赖时,从私有 PyPI 服务器中下载相应的文件。如果需要从公共 PyPI 服务器中下载,可以在 pip 命令中使用 -i--index-url 参数指定相应的 URL。

    其他配置选项

    除了配置私有 PyPI 服务器的 URL,我们还可以在 pip 配置文件中指定认证信息、缓存设置等。以下是一些常用的配置选项:

    • index-url:指定 PyPI 服务器的 URL。
    • trusted-host:指定可信任的主机名,用于避免 SSL 证书验证失败的问题。
    • proxy:指定 HTTP/HTTPS 代理服务器的 URL。
    • timeout:指定连接超时的时间,单位为秒。
    • no-cache-dir:禁用缓存,每次都从服务器下载最新的包和依赖。

    可以在 pip 官方文档中查看完整的配置选项。

  • 如何配置和使用pypiserver搭建 PyPI 私有服务器

    PyPI 是 Python 包索引,可以方便地搜索、安装和管理 Python 包和依赖。但有时候我们希望在内部环境中使用自己的私有包和依赖,这时候就需要搭建 PyPI 私有服务器。

    pypiserver 是一个轻量级的 PyPI 服务器,可以方便地搭建 PyPI 私有服务器。下面将介绍如何安装和配置 pypiserver,以及如何上传和管理私有包和依赖。

    安装和配置 pypiserver

    首先,安装 pypiserver:

    pip install pypiserver

    接着,在需要搭建 PyPI 私有服务器的目录下,创建一个名为 packages 的文件夹,这里将存放私有包和依赖:

    mkdir packages

    然后,在该目录下创建一个名为 htpasswd 的文件,用于存放用户名和密码,用于访问私有服务器:

    htpasswd -c htpasswd username

    接着,启动 pypiserver:

    pypi-server -p 8080 -P htpasswd packages/

    其中,-p 参数指定端口号,-P 参数指定存放用户名和密码的文件,packages/ 是包和依赖的存放目录。

    现在,可以通过浏览器访问 http://localhost:8080/simple/,应该能够看到空的包列表。

    上传和管理私有包和依赖

    接下来,将介绍如何上传和管理私有包和依赖。

    首先,使用 pip 安装 twine

    pip install twine

    然后,创建一个私有包,假设为 mypackage,并在该包目录下执行:

    python setup.py sdist

    这将生成一个名为 dist/mypackage-0.0.1.tar.gz 的包文件。

    接着,使用 twine 上传包文件:

    twine upload --repository-url http://localhost:8080/ --user=username --password=password dist/*

    其中,--repository-url 参数指定私有服务器的 URL,--user--password 参数指定访问私有服务器的用户名和密码,dist/* 表示上传 dist 目录下的所有包文件,上传成功后,可以在私有服务器的包列表中看到新上传的包。

    如果需要管理私有包和依赖,可以在私有服务器的 packages 目录下手动添加或删除包文件。当添加或删除包文件后,需要重新启动 pypiserver:

    pypi-server -p 8080 -P htpasswd packages/
    

    使用私有服务器的包和依赖

    最后,将介绍如何使用私有服务器的包和依赖。

    首先,需要将私有服务器的 URL 添加到 pip 的配置中:

    pip config set global.index-url http://localhost:8080/simple/
    

    然后,可以使用 pip 安装私有包和依赖:

    pip install mypackage
    

    这将从私有服务器中安装 mypackage 包。

    如果需要安装私有依赖,可以在 requirements.txt 中指定私有服务器的 URL:

    -i http://localhost:8080/simple/
    mypackage==0.0.1

    然后,使用 pip 安装依赖:

    pip install -r requirements.txt
    

    这将从私有服务器中安装 mypackage 包和其他依赖。

    至此,本文介绍了如何安装和配置 pypiserver,以及如何上传和管理私有包和依赖,以及如何使用私有服务器的包和依赖。希望本文对大家有所帮助。