本文由 Ficow Shen 首發於 Ficow Shen's Blog.
文章概覽
- 前言
- Sketch
- HTML, CSS, JavaScript
- Python & Flask & MySQL & SQLAlchemy
- Gunicorn & Terminal & Command
- Domain name
- Nginx & Certbot
前言
你是否曾經嘗試過搭建個人博客網站?
Hugo, Hexo,WordPress 這些耳熟能詳的產品,你是否也曾經試用過?
這些產品可以讓你極速搭建個人博客網站,而且你不需要了解太多技術細節。
如果你只是想有一個簡單的博客網站
,只是希望能夠進行內容創作、發表
,那么我建議你使用那些產品
並停止閱讀這篇文章
。
如果你想DIY你的博客
、想更深入地了解一個博客系統
、想學習一些Web和后端技術
,那么我建議你繼續閱讀,然后 自己搭建一個博客網站!
為何選擇 Python
和 Flask
進行后端開發?
- Python
簡單易學
- 對腳本語言感興趣,通過學習 Python 來熟悉
腳本語言
- Flask 是一個知名且
被廣泛應用
的后端開發框架,社區非常活躍
- Python 和 Flask 都有
豐富的第三方庫
當然,除了 Python,你也可以選擇 PHP, Golang 等作為后端開發語言。
在學習開始之前,我向你推薦一個網站:Learn X in Y minutes 。
正如網站名稱說的那樣,你可以在Y分鍾內學習X。該站可以加快你的學習進程,讓你盡快看到內容的全貌。
Sketch
使用 Sketch,主要是為了設計博客頁面
。
當然,也可以用 PhotoShop 這種類似的軟件。
然后,你就可以參考別人的個人博客頁面,然后設計自己的博客頁面的版式、配色等等。
也許有人會問,有很多現成的主題可以用,為什么還要自己設計呢?
如果你想學習和應用 Web技術
,尤其是 CSS 中的 Selector、Flexbox,那么自己寫就可以讓你的學習效果更好。
如果你不感興趣,可以跳過這一步,直接去用別人造好的輪子即可。
如果你覺得 Sketch 實在太貴,請看這里。
Sketch 是個很優秀的產品,請您支持正版
~
HTML, CSS, JavaScript
HTML 示例:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
CSS 示例:
body {
background-color: lightblue;
}
h1 {
color: white;
text-align: center;
}
p {
font-family: verdana;
font-size: 20px;
}
JavaScript 示例:
document.getElementById("demo").innerHTML = "Hello JavaScript";
在開始學習之前,我在知乎了解了 零基礎如何迅速學習前端?。
然后,在 菜鳥教程 看完了 HTML, CSS, JavaScript 的基礎內容。
相關的基礎知識必須過一遍
,甚至幾遍!
要確保自己知道這些技術包含哪些內容,然后你后面需要用到的時候,就可以很容易地找到它們並把它們用起來。
除此之外,還在 MDN 單獨學習了一些技術點,比如:Flexbox.
以及 阮一峰的網絡日志。
看了這些東西之后,就需要實操練習。你可以去找一些博客網站來模仿,通過模仿別人的網站來熟悉前端的布局技術。
其實,要點就是:看基礎知識,然后模仿着寫,鞏固學習效果
。
掌握了這些知識,你就可以寫出靜態的網頁了。
Python & Flask & MySQL & SQLAlchemy
Python 示例:
# -*- coding: UTF-8 -*-
# 該實例輸出 Hello World!
print('Hello World!')
讓靜態網頁“活”起來的關鍵是后端提供的數據支持。
學習 Python & Flask & MySQL
之后,你就可以自己定義后端接口,然后為前端提供數據支持。
學習 Python3,了解 Python 的基礎知識點。
掌握了 Python 基礎知識之后,就可以開始學習 Flask 了。
點開 Documentation,里面會有 Quickstart,也有 Tutorial。這兩個部分,不容錯過!
如果覺得閱讀英文文檔的難度太高,你可以看 Flask Web開發:基於Python的Web應用開發實戰。
這本書的資源僅供參考,請您支持正版
~
另外,Flask Tutorial 中使用的是SQLite,但是我建議你使用更好的關系型數據庫,比如:MySQL 或者 PostgreSQL。
如何安裝和使用這些數據庫,你可以參考官方文檔或者去搜索引擎找相關的文章來學習。
學完這些內容之后,你基本上就已經學會了:
定義后端接口
、執行數據庫CRUD操作
、返回網頁數據給前端
、單元測試
以及 基本的網絡安全知識
。
把前端和后端的內容結合在一起,網頁的內容就任由你來定義。
如果你覺得書寫 SQL 語句很煩人,那么我推薦你使用知名的ORM【對象關系映射(Object Relational Mapping)】 框架 SQLAlchemy。
你可以去官方網站找 Tutorial 來快速入門, 比如:SQLAlchemy tutorial
這里有兩個示例可供參考。
使用 SQL 語句的示例:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.sql import text
eng = create_engine("mysql://testuser:test623@localhost/testdb")
with eng.connect() as con:
con.execute(text('DROP TABLE IF EXISTS Cars'))
con.execute(text('''CREATE TABLE Cars(Id INTEGER PRIMARY KEY,
Name TEXT, Price INTEGER)'''))
data = ( { "Id": 1, "Name": "Audi", "Price": 52642 },
{ "Id": 2, "Name": "Mercedes", "Price": 57127 },
{ "Id": 3, "Name": "Skoda", "Price": 9000 },
{ "Id": 4, "Name": "Volvo", "Price": 29000 },
{ "Id": 5, "Name": "Bentley", "Price": 350000 },
{ "Id": 6, "Name": "Citroen", "Price": 21000 },
{ "Id": 7, "Name": "Hummer", "Price": 41400 },
{ "Id": 8, "Name": "Volkswagen", "Price": 21600 }
)
for line in data:
con.execute(text("""INSERT INTO Cars(Id, Name, Price)
VALUES(:Id, :Name, :Price)"""), **line)
使用 SQLAlchemy ORM 的示例:
#!/usr/bin/python
# -*- coding: utf-8 -*-
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
eng = create_engine('sqlite:///:memory:')
Base = declarative_base()
class Car(Base):
__tablename__ = "Cars"
Id = Column(Integer, primary_key=True)
Name = Column(String)
Price = Column(Integer)
Base.metadata.bind = eng
Base.metadata.create_all()
Session = sessionmaker(bind=eng)
ses = Session()
ses.add_all(
[Car(Id=1, Name='Audi', Price=52642),
Car(Id=2, Name='Mercedes', Price=57127),
Car(Id=3, Name='Skoda', Price=9000),
Car(Id=4, Name='Volvo', Price=29000),
Car(Id=5, Name='Bentley', Price=350000),
Car(Id=6, Name='Citroen', Price=21000),
Car(Id=7, Name='Hummer', Price=41400),
Car(Id=8, Name='Volkswagen', Price=21600)])
ses.commit()
觀察后可以發現,使用了 ORM 可以幫助我們專注於業務邏輯。
不用擔心 SQL 語句是否打錯字,也不用擔心它是否能正常執行並返回預期的結果。
Gunicorn & Terminal & Command
學習完 Flask 之后,你已經知道了開發服務器和生產服務器的區別。
為了更好的性能以及安全性,在部署博客系統的時候,你需要使用一個生產服務器。
我選擇了 Gunicorn,配置比較簡單(入門容易),而且用戶群也比較龐大(遇到問題更容易解決)。
參考 Gunicorn 的教程,你可以很容易地完成相關的配置。
Gunicorn 配置示例:
import multiprocessing
bind = '127.0.0.1:8000'
workers = multiprocessing.cpu_count() * 2 + 1
backlog = 2048
worker_class = "gevent"
worker_connections = 1000
daemon = False
debug = True
proc_name = 'gunicorn_demo'
pidfile = './log/gunicorn.pid'
errorlog = './log/gunicorn.log'
使用 Gunicorn 之后,你可以很容易地配置后端應用的訪問地址、進程數、日志路徑、運行模式等等。
在你打算部署服務器時,你會發現你必須使用 命令行工具
。
首先,啟動 Gunicorn 需要執行命令行指令,比如:gunicorn --paste development.ini -b :8080 --chdir /path/to/project
。
然后,連接遠程服務器需要使用 SSH, 比如: ssh root@127.0.0.1
。
推薦你學習 Linux 教程 和 Shell 教程 。在部署后台系統到遠程服務器的過程中,你會反復用到如 cd
, ls
, vim
等這些命令。所以,學習這些命令是必需的步驟。
如果你還沒有購買雲服務器,那我推薦你使用 Vultr 的服務器。
優點:便宜、不用備案、輕松部署強力愛國上網等等
缺點:延遲高、經常有黑客來訪等等
當然,你也可以購買知名的 AWS、阿里雲、騰訊雲、UCloud 等等廠商的雲服務器。
Domain name
擁有自己的博客的同時,你是不是也希望能夠擁有一個特別的網站域名
,比如自己的名字?
現在以 http://ficow.cn 為例來講解域名相關的知識。
你可以訪問 http://www.ficow.cn,也可以訪問 http://ficow.cn 。
但是,如果我訪問 http://123.ficow.cn 就無法看到正常的頁面。為什么呢?
因為我在域名解析頁面進行了相應的配置,http://ficow.cn 和 http://www.ficow.cn 都是我希望別人可以正常訪問的網頁。
我是在 阿里雲(原萬網) 購買了 ficow.cn
這個域名,當然你也可以選擇其他的域名提供商購買域名。
在購買了域名之后,就可以登錄控制台進行域名解析
。
在主機記錄這一列,我配置了 www
和 blog
。這兩個均指向了同一個IP,也就意味着目前我是依靠這一台服務器來處理個人首頁 和 博客。
關於域名配置的詳細內容,你可以參考域名提供商提供的幫助文檔,也可以直接通過搜索引擎尋找答案,這里就不贅述了。
但是,你是不是比較好奇,兩個不同的主機記錄竟然指向了同一台服務器。服務器是如何對不同的主機記錄進行解析的呢? 接下來,Nginx
會告訴你答案~
Nginx & Certbot
Nginx 是一個高性能反向代理服務器,它可以將遠程服務器上收到的數據轉發給你的后台程序。用它來處理靜態文件請求非常方便。
這是一個 Nginx server 的配置 Demo:
server
{
access_log /home/xxx/path/to/project custom_log;
server_name blog.ficow.cn;
charset utf-8;
root /home/xxx/path/to/project;
# Proxy connections to the application servers
location / {
proxy_pass http://0.0.0.0:5000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
client_max_body_size 10M;
}
}
你可以通過簡單地配置 Nginx 來監聽 80
端口,然后讓它根據域名來區分以及轉發數據給你的后台程序。
在上面的示例中,Nginx 會把指向 blog.ficow.cn
的訪問請求轉發給 http://0.0.0.0:5000
, 限制客戶端請求中body最大為 10M。
當然,你可以讓多個 server_name
都使用這同一套配置。你還可以定義多個 server
,然后對不同的 server_name
進行不同的定制化處理,比如:負載均衡
。
想了解更多關於如何配置 Nginx 的內容,請參考官網文檔。
如果你希望你的博客網站支持 HTTPS,我推薦你使用 Certbot。
Certbot 的最大優勢就是:免費、易用
,這對於一個個人博客系統來說,簡直完美~
在 Ubuntu 系統上安裝 Certbot 的示例:
sudo apt-get update
sudo apt-get install software-properties-common
sudo add-apt-repository ppa:certbot/certbot
sudo apt-get update
sudo apt-get install python-certbot-nginx
自動配置 Nginx 的 SSL 相關參數:
certbot --nginx
編輯定時任務,定期調起 Certbot 去更新 SSL 證書:
crontab -e
插入本行內容,並保存退出,定時任務即可生效
# 分 時 某月中的幾號 幾月 星期幾 *代表任何時候 ,分隔多個相同類型的參數
0 0,12 * * * python -c 'import random; import time; time.sleep(random.random() * 3600)' && certbot renew
如果系統默認打開的編輯器不是vim,可以修改環境變量
在~/.profile中加入以下內容,並保存退出
vim ~/.profile
export EDITOR="/usr/bin/vim";
加載更新的EDITOR配置:
source ~/.profile
然后再重新使用crontab -e添加定時更新 SSL 證書的任務即可。
然后,嘗試使用HTTPS來訪問你的博客吧!