引言
技术上来说,我的这个小站是个非法网站,备案是一概没有的,也不打算有。它整个都部署在外网VPS上,加载速度多少还是有点那个什么。坐下来认真写文章和评论的时候还好,但说说这种闲着没事记录想法的东西就很难容忍漫长的加载了。我考虑过使用电子邮件发布,但写电邮需要的行动力并没有低到哪里去。在打通大内网并且试用了一下Memos之后,使用docker在家里的服务器上部署一个web应用来做这件事就成了一个很自然的路线。
我在大概10个小时前还对docker、flask和html几乎没有了解——建站时学习的html知识早忘了,所以又要依赖强力的G老师了!
前置准备
需要Wordpress站点的应用密码,可以在用户选项里面创建。
需要开启Wordpress的REST API,默认一般是开启的,但是要修改固定链接模式为简单之外的任何模式。
需要测试一下REST API,链接大致是:
https://example.com/wp-json/wp/v2/posts
https://example.com/index.php/wp-json/wp/v2/posts
之类的,如果访问这种链接能够看到一大段类似rss订阅结果的文本就是成功了。
需要一台部署了docker的服务器,安装python和Flask。最好装个1Panel之类的面板,真的会方便很多,我们GUI时代成长起来的就是这样……
(可选)下载iziToast的css和js文件,用于显示发布成功或失败的提示信息。由于主站用了这个插件,所以就路径依赖了。
部署前端
在服务器上创建一个目录,比如/home/wp_post,作为docker打包的目录,整个目录结构如下,缺少的文件自己创建一下。
wp_post ├─ app.py ├─ Dockerfile ├─ templates │ └─ index.html └─ static ├─ logo.png ├─ iziToast.min.css └─ iziToast.min.js
其中app.py是后端逻辑,Dockerfile是docker镜像的构建文件,templates和static目录分别存放网页模板和静态资源。static其实是可有可无的,但为了美化还是加上去好。
创建完文件后,打开index.html,写入:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>网页标题</title>
<link rel="icon" href="{{ url_for('static', filename='logo.png') }}" type="image/png">
<!-- Argon CSS -->
<link href="{{ url_for('static', filename='argon.css') }}" rel="stylesheet">
<link rel="stylesheet" href="{{ url_for('static', filename='iziToast.min.css') }}">
<script src="{{ url_for('static', filename='iziToast.min.js') }}"></script>
<style>
body, html {
height: 100%;
margin: 0;
background-color: #f7f7f7;
font-family: 'Nunito', sans-serif;
}
.main-content {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
.form-group textarea {
width: 80%; /* Adjusted width */
height: 60vh; /* 70% of the viewport height */
margin: 0 auto; /* Centering the textarea */
border: 2px solid #5e72e4;
border-radius: 15px;
padding: 20px; /* Padding inside the textarea */
transition: border-color 0.3s ease;
resize: none; /* Prevent resizing */
}
.form-group textarea:focus {
border-color: #2dce89;
box-shadow: none;
}
.btn-submit {
background-color: #5e72e4;
color: white;
border-radius: 20px;
border: none;
padding: 10px 24px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
transition: background-color 0.3s ease;
margin-top: 20px; /* Space between textarea and button */
}
.btn-submit:hover {
background-color: #4b60d6;
}
</style>
</head>
<body>
<div class="main-content">
<h2>说句话吧</h2>
<form action="/post_article" method="post" style="width: 100%; max-width: 600px;">
<div class="form-group">
<textarea class="form-control" id="content" name="content" placeholder="文本框提示内容"></textarea>
</div>
<div>
<button type="submit" class="btn-submit">发布按钮文字</button>
</div>
</form>
</div>
<!-- Argon JS -->
<script src="{{ url_for('static', filename='argon.js') }}"></script>
<script>
document.querySelector('form').addEventListener('submit', function(e) {
e.preventDefault();
var formData = new FormData(this);
fetch('/post_article', {
method: 'post',
body: formData
}).then(response => response.json()).then(data => {
if(data.success) {
iziToast.success({
title: '发布成功',
message: data.message,
position: 'topCenter', // 设置通知位置为页面正上方
timeout: 3000 // 通知显示时间(毫秒)
});
} else {
iziToast.error({
title: '发布失败',
message: data.message,
position: 'topCenter', // 设置通知位置为页面正上方
timeout: 3000 // 通知显示时间(毫秒)
});
}
}).catch(error => {
iziToast.error({
title: '未知错误',
message: '未知错误提示信息',
position: 'topCenter', // 设置通知位置为页面正上方
timeout: 3000 // 通知显示时间(毫秒)
});
});
});
</script>
</body>
</html>
这个页面同时包含了发布功能和提示功能。由于我发布的想法不需要标题所以省略掉了。在head里面还包含了指定iziToast css和js文件以及网站logo的功能。这里的logo最好是一个32*32的png之类的文件,如果改成icon的话要同步更改type,这不是本文的重点,相关资料也可以轻易地搜索到,不再赘述。
至此完成了前端部署。
部署后端
首先修改Dockerfile:
# 使用Python官方镜像作为基础镜像 FROM python:3.8-alpine # 设置工作目录 WORKDIR /app # 复制当前目录下的所有文件到容器内的/app目录 COPY . /app # 安装Flask和requests RUN pip install Flask requests # 告诉Docker在容器启动时运行Python应用 CMD ["python", "./app.py"]
然后修改app.py:
from flask import Flask, render_template, request, redirect, url_for, jsonify
import requests
import base64
app = Flask(__name__)
# Home route
@app.route('/')
def home():
return render_template('index.html')
# Route to post an article
@app.route('/post_article', methods=['POST'])
def post_article():
#准备请求数据
content = request.form['content']
article_data = {'title': content, 'content': content, 'status': 'publish'}
# 登录信息
wp_url = "REST API请求链接"
username = "Wordpress登陆用户名"
app_password = "Wordpress应用密码"
# 编码登录信息
token = base64.b64encode(f"{username}:{app_password}".encode()).decode("utf-8")
headers = {'Authorization': 'Basic ' + token}
# 向WordPress REST API发送POST请求
response = requests.post(wp_url, headers=headers, json=article_data)
# 根据响应状态码判断是否成功
if response.status_code == 201:
# 成功
return jsonify({"success": True, "message": "发布成功提示信息"})
else:
# 失败
error_message = response.json().get('message', '发布失败提示信息')
return jsonify({"success": False, "message": error_message})
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
将REST API链接、登录用户名和应用密码填入相应的位置,即完成后端设置。
创建并运行docker
连接到服务器,使用sudo -i获得root权限,然后确认docker状态:
systemctl status docker
进入刚才的目录:
cd /home/wp_post
打包镜像:
docker build -t <image name> .
最后这个点还挺重要的,没他不行。
运行镜像:
docker run -d -p <对外端口号>:5000 <image name>
这里面当然省略了很多东西,比如指定内部端口号啊之类的,但是这样就能跑了,之后可以在GUI面板进行重命名啊之类的管理。现在访问服务器ip:port应该可以看到一个正常工作的页面了。
收工!又水了一篇!




