Setup Fediverse Blog: WriteFreely
《使用 WriteFreely 搭建聯邦宇宙博客站點》
WriteFreely 是一個能通過 ActivityPub 協議接入聯邦宇宙的博客實例框架,使用 Go 進行實現(沒想到啊沒想到)。實話説搭建起來基本上沒有難度,最簡單的實現就是裝個 MySQL 然後直接作爲服務啓動,完事。但是由於太久沒折騰服務器了,再加上又想挂反代又想搞 Docker,結果折騰了將近一天(中間睡了一覺)才把這玩意建立起來。
WriteFreely 自身是不支持上傳圖片的,想要在 blog 中插入圖片就需要一個外部的圖床。一不做二不休,乾脆也在服務器上部署了 Piwigo 來進行支持。
簡述
Nginx
+ WriteFreely
+ Piwigo
+ MySQL
,支持 http
和 https
,最終域名為 blog.penguinsoup.me
。
MySQL in Docker
首先要先把服務器設置起來。考慮到其他的應用也可能用這個 MySQL,因此最後沒有選擇將其合并到 Docker Compose 中,而是作爲一個單獨的容器,通過 3306 端口暴露自身的服務。另外,還考慮使用 Docker Secrets 來傳遞用戶密碼。
--- working_directory
|--- docker-compose.yaml
|--- config
| |--- my.cnf
|--- secrets
| |--- mysql-root
由於 MySQL 某個(某個)版本加入的改變驗證方式的默認設置(*企鵝粗口*),因此需要修改一下默認設置來使通過密碼登入賬戶成爲可能:
# config/my.cnf
[mysqld]
mysql_native_password=ON
default-time-zone='+00:00' # writefreely required
再就是在 secrets/mysql-root
中放入管理員賬戶的密碼,並準備好 docker-compose.yaml
:
version: "3"
services:
mysql:
image: mysql:8.4.2
container_name: mysql
ports:
- 3306:3306
networks:
- mysql-bridge
volumes:
- /path/to/working_directory/config:/etc/mysql/conf.d/
- /path/to/working_directory/logs:/var/log/mysql
- /path/to/working_directory/secrets:/run/secrets
environment:
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql-root
restart: unless-stopped
networks:
mysql-bridge:
external: true
配置 Docker Network 並啓動:
$ docker network create --driver bridge mysql-bridge
$ docker compose up -d
$ docker inspect mysql-bridge
...
Container {
"hash code": {
"Name": "mysql",
"IPv4Address": "172.xx.xx.xx" # that's mysql host addr in other containers
}
}
...
從外部連入(即便 client 就在服務器,的也需要手動指定爲 remote):
mysql -u root -h localhost -P 3306 --protocol=tcp -p # client on server
最後按照 WriteFreely 和 Piwigo 的指引設置好相關的數據庫,並創建一個給外部連入用的賬戶即可:
CREATE DATABASE writefreely CHARACTER SET latin1 COLLATE latin1_swedish_ci;
CREATE DATABASE pwigo;
CREATE USER '${USER}'@'%' IDENTIFIED WITH mysql_native_password BY 'y0Ur_p^sswD';
GRANT ALL PRIVILEGES ON writefreely.* TO '${User}'@'%';
GRANT ALL PRIVILEGES ON piwigo.* TO '${User}'@'%';
FLUSH PRIVILEGES;
由於其他容器訪問 MySQL 都是通過 Docker
Nginx
接下來要設置好反向代理(如果服務器只提供一個網頁服務就不用,但一般不會有人租個服務器就單單搭一個 blog 吧,嗯?),這樣就可以把通過不同域名映射到同一 IP 的同端口請求轉發到不同的實際應用上進行處理。
--- working_directory
|--- {blog,img}.penguinsoup.me.conf
|--- includes
| |--- {proxy,ssl,gzip}.conf
|--- ssl
| |--- yourdomain.{crt,key} # use acme.sh or something to issue
|--- logs
| |--- {blog,img}.penguinsoup.me
| |--- {access,error}.log # created by nginx
配置文件如下:
# proxy.conf
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_http_version 1.1;ssl_session_timeout 1d;
# ssl.conf
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
# gzip.conf
gzip on;
gzip_types
application/javascript
application/x-javascript
application/json
application/rss+xml
application/xml
image/svg+xml
image/x-icon
application/vnd.ms-fontobject
application/font-sfnt
text/css
text/plain;
gzip_min_length 256;
gzip_comp_level 5;
gzip_http_version 1.1;
gzip_vary on;
# blog.penguinsoup.me.conf
server {
# listening server:port
listen 80;
listen [::]:80;
listen 443 ssl; # optional: https
listen [::]:443 ssl; # optional: https
server_name blog.penguinsoup.me;
# optional: logs
access_log /path/to/working_directory/logs/access.log;
error_log /path/to/working_directory/logs/error.log warn;
# optional: enable compression
include /path/to/working_directory/includes/gzip.conf;
# optional: https certificate
ssl_certificate /path/to/working_directory/ssl/blogpenguinsoup.crt;
ssl_certificate_key /path/to/working_directory/ssl/blogpenguinsoup.key;
include /etc/nginx/includes/ssl.conf;
# webfinger proxy
location ~ ^/.well-known/(webfinger|nodeinfo|host-meta)/ {
include /path/to/working_directory/includes/proxy.conf;
proxy_pass http://localhost:8080; # default port of writefreely
proxy_redirect off;
}
# static files
location ~ ^/(css|img|js|fonts)/ {
root /path/to/your/static;
expires 12M;
}
# main proxy
location / {
include /path/to/working_directory/includes/proxy.conf;
proxy_pass http://localhost:8080; # default port of writefreely
proxy_redirect off;
}
}
# img.penguinsoup.me
server {
# listening server:port
listen 80;
listen [::]:80;
listen 443 ssl;
listen [::]:443 ssl;
server_name img.penguinsoup.me;
# logs
access_log /path/to/working_directory/logs/img.penguinsoup.me/access.log;
error_log /path/to/working_directory/logs/img.penguinsoup.me/error.log warn;
# enable compression
include /path/to/working_directory/includes/gzip.conf;
# https certificate
ssl_certificate /path/to/working_directory/ssl/imgpenguinsoup.crt;
ssl_certificate_key /path/to/working_directory/ssl/imgpenguinsoup.key;
include /path/to/working_directory/includes/ssl.conf;
# main proxy
location / {
include /path/to/working_directory/includes/proxy.conf;
proxy_pass http://localhost:7999;
proxy_redirect off;
}
}
別忘了生成域名對應的 HTTPS
證書並安裝到 ssl/
下面,具體的操作方式可以參照 這篇文章。
Nginx 就不扔進容器了,這個還是放在 host 上比較方便一點。通過包管理器或者別的方式安裝之後,在 /etc/nginx/site-enabled
下面創造 blog 和 img 配置文件的軟鏈接,最後記得重新啓動 service
。
Piwigo in Docker
直接上 docker-compose.yaml
:
version: "3"
services:
piwigo:
image: lscr.io/linuxserver/piwigo:14.5.0
container_name: piwigo
environment:
- PUID=1000
- PGID=1000
- TZ=Asia/Shanghai
volumes:
- /path/to/photos:/gallery
ports:
- 7999:80
networks:
- mysql-bridge
restart: unless-stopped
networks:
mysql-bridge:
external: true
啓動后訪問一下,設置好就可以了。別忘了 MySQL 的地址是上面 inspect mysql-bridge
的時候的地址。
WriteFreely in Docker
最開始的時候我是想把這個丟進 Docker 裏面的,然而因爲預編譯版本扔進容器會缺依賴跑不起來,然後又懶得在容器裏編譯了,最後就直接用預編譯文件跑在 host 上了。後面因爲某個(某個)圖床把整個 Docker 搞崩潰了,想著就弄一下吧,結果在官方倉庫的 docker-compose.yaml
裏面發現了這麽一行
image: writeas/writefreely:latest
好啊!原來你們有鏡像啊!那就老規矩,docker-compose.yaml
:
version: "3"
services:
writefreely:
image: writeas/writefreely:latest
container_name: writefreely
volumes:
- /path/to/working_directory/config.ini:/go/config.ini
- /path/to/working_directory/keys:/go/keys
- /path/to/working_directory/static:/go/static
ports:
- 8080:8080
networks:
- mysql-bridge
user: "0:0"
restart: unless-stopped
networks:
mysql-bridge:
external: true
目錄結構:
--- working_directory
|--- docker-compose.yaml
|--- config.ini # created by wf
|--- keys
| |--- # files created by wf
|--- static # copy from binary package
接下來要進行設置,然而問題來了:沒有 config.ini
與 keys
就不能啓動,但是不啓動就沒有這些配置文件()。所以,此時要先直接啓動容器來進行配置:
$ docker container run -it --rm \
> -v mount config.ini \
> -u "0:0" \ # start up as root
> writeas/writefreely:latest --config
# don't forget: database host is the addr found in `inspect mysql-bridge`
$ docker container run -it --rm \
> -v mount keys \
> -u "0:0" \ # start up as root
> writeas/writefreely:latest --gen-keys
接下來要修改一項 config.ini
中的設置,否則無法在容器中運行:
bind = localhost
->
bind = 0.0.0.0
最後 compose up
,然後就可以愉快地使用啦!