Compare commits

...

19 Commits

Author SHA1 Message Date
henry.chen
b75f7d6a96 chore(release): 3.0.10 2025-11-12 09:43:51 +08:00
henry.chen
5aa8152802 fix: default RUN_MODE=prod 2025-11-12 09:43:48 +08:00
henry.chen
1a9628a5dc chore(release): 3.0.9 2025-11-12 09:34:03 +08:00
henry.chen
71c02266bc fix: image RUN_MODE 2025-11-12 09:33:49 +08:00
henry.chen
4b71e288f3 chore(release): 3.0.8 2025-10-14 10:03:04 +08:00
henry.chen
523ee64931 fix: upload file path 2025-10-14 10:02:36 +08:00
henry.chen
422aacdc09 chore: update 2025-08-05 14:33:28 +08:00
henry.chen
07fc49db5c chore: update docs 2025-08-05 14:26:17 +08:00
henry.chen
666161d37e chore(release): 3.0.7 2025-07-26 09:52:30 +08:00
henry.chen
11b22da339 fix: feed not generate 2025-07-26 09:52:18 +08:00
henry.chen
bd9a45078b chore(release): 3.0.6 2025-07-25 18:05:33 +08:00
henry.chen
629ad782c4 fix: feed & sitemap not generate 2025-07-25 18:05:23 +08:00
henry.chen
5e63f5e69d chore(release): 3.0.5 2025-07-25 17:55:44 +08:00
henry.chen
33afbd351d fix: mongodb uri error 2025-07-25 17:55:14 +08:00
henry.chen
eaeeaaafb9 fix: RUN_MODE error 2025-07-25 17:21:02 +08:00
henry.chen
ae3fb35435 chore: update 2025-07-25 13:37:49 +08:00
henry.chen
c1d73f1a45 fix: admin login session 2025-07-25 13:35:06 +08:00
henry.chen
fd7981b4f9 chore(release): 3.0.4 2025-07-25 10:59:04 +08:00
henry.chen
9f77fb7b3f fix(ci): golang version 2025-07-25 10:59:02 +08:00
19 changed files with 247 additions and 166 deletions

View File

@@ -2,6 +2,57 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [3.0.10](https://github.com/eiblog/eiblog/compare/v3.0.9...v3.0.10) (2025-11-12)
### Bug Fixes
* default RUN_MODE=prod ([5aa8152](https://github.com/eiblog/eiblog/commit/5aa81528027eca648e430503a1f5a04118ca650e))
### [3.0.9](https://github.com/eiblog/eiblog/compare/v3.0.8...v3.0.9) (2025-11-12)
### Bug Fixes
* image RUN_MODE ([71c0226](https://github.com/eiblog/eiblog/commit/71c02266bc0173a4af1ffc876dc36051377e1af0))
### [3.0.8](https://github.com/eiblog/eiblog/compare/v3.0.7...v3.0.8) (2025-10-14)
### Bug Fixes
* upload file path ([523ee64](https://github.com/eiblog/eiblog/commit/523ee64931a0dc1f9f743682fe84b1a1f250686c))
### [3.0.7](https://github.com/eiblog/eiblog/compare/v3.0.6...v3.0.7) (2025-07-26)
### Bug Fixes
* feed not generate ([11b22da](https://github.com/eiblog/eiblog/commit/11b22da339c542eb6d697cb3ac7bc78a401c6420))
### [3.0.6](https://github.com/eiblog/eiblog/compare/v3.0.5...v3.0.6) (2025-07-25)
### Bug Fixes
* feed & sitemap not generate ([629ad78](https://github.com/eiblog/eiblog/commit/629ad782c45fae7af9efdf99513bafdf87e7758c))
### [3.0.5](https://github.com/eiblog/eiblog/compare/v3.0.4...v3.0.5) (2025-07-25)
### Bug Fixes
* admin login session ([c1d73f1](https://github.com/eiblog/eiblog/commit/c1d73f1a453af62d15c25a79c382d9cefd8a3d2e))
* mongodb uri error ([33afbd3](https://github.com/eiblog/eiblog/commit/33afbd351d2b41f9edf36959908c3f183745d903))
* RUN_MODE error ([eaeeaaa](https://github.com/eiblog/eiblog/commit/eaeeaaafb98a4aa0a42dba74b411b1d361faf1d5))
### [3.0.4](https://github.com/eiblog/eiblog/compare/v3.0.3...v3.0.4) (2025-07-25)
### Bug Fixes
* **ci:** golang version ([9f77fb7](https://github.com/eiblog/eiblog/commit/9f77fb7b3f283aacb9d9c2a0e2f79c8a6c412edb))
### [3.0.2](https://github.com/eiblog/eiblog/compare/v3.0.1...v3.0.2) (2025-07-25)

View File

@@ -1,8 +1,6 @@
# EiBlog [![License](https://img.shields.io/badge/license-MIT-brightgreen.svg)](LICENSE.md) [![Versuib](https://img.shields.io/github/tag/eiblog/eiblog.svg)](https://github.com/eiblog/eiblog/releases)
> 博客项目结构参考模版https://github.com/deepzz0/appdemo
用过其它博客系统,不喜欢,不够轻,不够快!这是我开发的第二款博客系统,也实在不想再在这件事情上过多纠结了。`EiBlog` 是一个比较稳定的博客系统,现已迭代至 `2.0` 版本,稳定性和维护你是不用担心的。
用过其它博客系统,不喜欢,不够轻,不够快!这是我开发的第二款博客系统,也实在不想再在这件事情上过多纠结了。`EiBlog` 是一个比较稳定的博客系统,博主已稳定使用多年。这里是 `3.0` 版本,如果仍在使用 `2.0` [请点击这里](https://github.com/eiblog/eiblog/tree/v2)。
但它有着部署简单(上线复杂!)的特点,不推荐没有计算机知识的朋友搭建,欢迎咨询。该博客的个中优点(简洁、轻快,安全),等你体验。
@@ -12,6 +10,13 @@ Docker镜像地址
* 博客搜索:[deepzz0/elasticsearch](https://hub.docker.com/r/deepzz0/elasticsearch)
* 数据备份:[deepzz0/backup](https://hub.docker.com/r/deepzz0/backup)
### 功能变化
- [x] 增对 **TOTP 双因素认证** 的支持,配置开启后后台绑定
- [x] 新增 **自定义页面**,支持独立页面和内嵌页面
- [x] 优化项目结构,更加清晰,各个 app 之间配置独立
- [ ] 支持多搜索引擎,如数据库原生、[zincsearch](https://github.com/zincsearch/zincsearch)、bleve 等
### 快速体验
**二进制**
@@ -33,8 +38,6 @@ $ docker run --name eiblog \
参考项目根目录下的 [docker-compose.yml](https://github.com/eiblog/eiblog/blob/v2/docker-compose.yml),修改相关配置:
```
$ docker compose up -d
$ docker-compose up -d
```
@@ -46,7 +49,7 @@ $ docker-compose up -d
| 类型driver | 地址source示例 |
| -------------- | ------------------------------------------------------------ |
| mongodb | mongodb://localhost:27017 |
| mongodb | mongodb://localhost:27017/eiblog |
| mysql | user:password@tcp(localhost:3306)/eiblog?charset=utf8mb4&parseTime=True&loc=Local |
| postgres | host=localhost port=5432 user=user password=password dbname=eiblog sslmode=disable |
| sqlite | /path/eiblog.db |

View File

@@ -1,4 +1,4 @@
FROM golang:1.20 AS builder
FROM golang:1.23 AS builder
WORKDIR /eiblog
COPY . .

View File

@@ -1,4 +1,4 @@
FROM golang:1.20 AS builder
FROM golang:1.23 AS builder
WORKDIR /eiblog
COPY . .

View File

@@ -28,9 +28,12 @@ var Conf Config
// load config file
func init() {
// run mode
mode := config.RunMode(os.Getenv("RUN_MODE"))
if !mode.IsRunMode() {
panic("config: unsupported env RUN_MODE: " + mode)
mode := config.RunModeProd
if m := os.Getenv("RUN_MODE"); m != "" {
mode = config.RunMode(m)
if !mode.IsRunMode() {
panic("config: unsupported env RUN_MODE: " + mode)
}
}
logrus.Infof("Run mode:%s", mode)

View File

@@ -3,7 +3,7 @@ apimode:
listen: 0.0.0.0:9000
database: # 数据库配置
driver: mongodb
source: mongodb://localhost:27017
source: mongodb://localhost:27017/eiblog
backupto: qiniu # 备份到, default: qiniu
interval: 7d # 备份周期, default: 7d
validity: 60 # 备份保留时间, default: 60

View File

@@ -8,7 +8,7 @@ import (
"time"
"github.com/eiblog/eiblog/cmd/backup/config"
"github.com/eiblog/eiblog/pkg/connector/db"
pdb "github.com/eiblog/eiblog/pkg/connector/db"
)
// MongoStorage 备份恢复器
@@ -24,14 +24,17 @@ func (r MongoStorage) Backup(name string) (string, error) {
if err != nil {
return "", err
}
arg := fmt.Sprintf("mongodump -h %s -d eiblog -o /tmp", u.Host)
if u.Path == "" {
return "", fmt.Errorf("no database specified")
}
arg := fmt.Sprintf("mongodump -h %s -d %s -o /tmp", u.Host, u.Path)
cmd := exec.CommandContext(ctx, "sh", "-c", arg)
err = cmd.Run()
if err != nil {
return "", err
}
// tar
arg = fmt.Sprintf("tar czf /tmp/%s -C /tmp eiblog", name)
arg = fmt.Sprintf("tar czf /tmp/%s -C /tmp %s", name, u.Path)
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
err = cmd.Run()
if err != nil {
@@ -46,11 +49,11 @@ func (r MongoStorage) Restore(path string) error {
defer cancel()
// drop database
mdb, err := db.NewMDB(config.Conf.Database)
database, err := pdb.NewMDB(ctx, config.Conf.Database)
if err != nil {
return err
}
err = mdb.Drop(ctx)
err = database.Drop(ctx)
if err != nil {
return err
}
@@ -66,7 +69,7 @@ func (r MongoStorage) Restore(path string) error {
if err != nil {
return err
}
arg = fmt.Sprintf("mongorestore -h %s -d eiblog /tmp/eiblog", u.Host)
arg = fmt.Sprintf("mongorestore -h %s -d %s /tmp/%s", u.Host, u.Path, u.Path)
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
return cmd.Run()
}

View File

@@ -1,5 +0,0 @@
# Changelog
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [3.0.3](https://github.com/eiblog/eiblog/compare/v3.0.2...v3.0.3) (2025-07-25)

View File

@@ -43,9 +43,12 @@ type Config struct {
// init 初始化配置
func init() {
// run mode
mode := config.RunMode(os.Getenv("RUN_MODE"))
if !mode.IsRunMode() {
panic("config: unsupported env RUN_MODE: " + mode)
mode := config.RunModeProd
if rm := os.Getenv("RUN_MODE"); rm != "" {
mode = config.RunMode(rm)
if !mode.IsRunMode() {
panic("config: unsupported env RUN_MODE: " + mode)
}
}
logrus.Infof("Run mode:%s", mode)

View File

@@ -6,17 +6,18 @@ import (
"sort"
"time"
"github.com/eiblog/eiblog/cmd/eiblog/config"
pdb "github.com/eiblog/eiblog/pkg/connector/db"
"github.com/eiblog/eiblog/pkg/model"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
// example:
// driver: mongodb
// source: mongodb://localhost:27017
// source: mongodb://localhost:27017/eiblog
const (
mongoDBName = "eiblog"
@@ -31,44 +32,39 @@ const (
)
type mongodb struct {
*mongo.Client
*mongo.Database
}
// Init init mongodb client
func (db *mongodb) Init(name, source string) (Store, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*20)
defer cancel()
opts := options.Client().ApplyURI(source)
client, err := mongo.Connect(ctx, opts)
database, err := pdb.NewMDB(ctx, config.Conf.Database)
if err != nil {
return nil, err
}
err = client.Ping(ctx, readpref.Primary())
if err != nil {
return nil, err
}
db.Client = client
db.Database = database
// create index
indexModel := mongo.IndexModel{
Keys: bson.D{bson.E{Key: "username", Value: 1}},
Options: options.Index().SetUnique(true).SetSparse(true),
}
db.Database(mongoDBName).Collection(collectionAccount).
db.Database.Collection(collectionAccount).
Indexes().
CreateOne(context.Background(), indexModel)
indexModel = mongo.IndexModel{
Keys: bson.D{bson.E{Key: "slug", Value: 1}},
Options: options.Index().SetUnique(true).SetSparse(true),
}
db.Database(mongoDBName).Collection(collectionArticle).
db.Database.Collection(collectionArticle).
Indexes().
CreateOne(context.Background(), indexModel)
indexModel = mongo.IndexModel{
Keys: bson.D{bson.E{Key: "slug", Value: 1}},
Options: options.Index().SetUnique(true).SetSparse(true),
}
db.Database(mongoDBName).Collection(collectionSerie).
db.Database.Collection(collectionSerie).
Indexes().
CreateOne(context.Background(), indexModel)
return db, nil
@@ -78,7 +74,7 @@ func (db *mongodb) Init(name, source string) (Store, error) {
func (db *mongodb) LoadInsertBlogger(ctx context.Context,
blogger *model.Blogger) (created bool, err error) {
collection := db.Database(mongoDBName).Collection(collectionBlogger)
collection := db.Database.Collection(collectionBlogger)
filter := bson.M{}
result := collection.FindOne(ctx, filter)
@@ -99,7 +95,7 @@ func (db *mongodb) LoadInsertBlogger(ctx context.Context,
func (db *mongodb) UpdateBlogger(ctx context.Context,
fields map[string]interface{}) error {
collection := db.Database(mongoDBName).Collection(collectionBlogger)
collection := db.Database.Collection(collectionBlogger)
filter := bson.M{}
params := bson.M{}
@@ -115,7 +111,7 @@ func (db *mongodb) UpdateBlogger(ctx context.Context,
func (db *mongodb) LoadInsertAccount(ctx context.Context,
acct *model.Account) (created bool, err error) {
collection := db.Database(mongoDBName).Collection(collectionAccount)
collection := db.Database.Collection(collectionAccount)
filter := bson.M{"username": acct.Username}
result := collection.FindOne(ctx, filter)
@@ -136,7 +132,7 @@ func (db *mongodb) LoadInsertAccount(ctx context.Context,
func (db *mongodb) UpdateAccount(ctx context.Context, name string,
fields map[string]interface{}) error {
collection := db.Database(mongoDBName).Collection(collectionAccount)
collection := db.Database.Collection(collectionAccount)
filter := bson.M{"username": name}
params := bson.M{}
@@ -150,7 +146,7 @@ func (db *mongodb) UpdateAccount(ctx context.Context, name string,
// InsertSerie 创建专题
func (db *mongodb) InsertSerie(ctx context.Context, serie *model.Serie) error {
collection := db.Database(mongoDBName).Collection(collectionSerie)
collection := db.Database.Collection(collectionSerie)
serie.ID = db.nextValue(ctx, counterNameSerie)
_, err := collection.InsertOne(ctx, serie)
@@ -159,7 +155,7 @@ func (db *mongodb) InsertSerie(ctx context.Context, serie *model.Serie) error {
// RemoveSerie 删除专题
func (db *mongodb) RemoveSerie(ctx context.Context, id int) error {
collection := db.Database(mongoDBName).Collection(collectionSerie)
collection := db.Database.Collection(collectionSerie)
filter := bson.M{"id": id}
_, err := collection.DeleteOne(ctx, filter)
@@ -170,7 +166,7 @@ func (db *mongodb) RemoveSerie(ctx context.Context, id int) error {
func (db *mongodb) UpdateSerie(ctx context.Context, id int,
fields map[string]interface{}) error {
collection := db.Database(mongoDBName).Collection(collectionSerie)
collection := db.Database.Collection(collectionSerie)
filter := bson.M{"id": id}
params := bson.M{}
@@ -184,7 +180,7 @@ func (db *mongodb) UpdateSerie(ctx context.Context, id int,
// LoadAllSerie 查询所有专题
func (db *mongodb) LoadAllSerie(ctx context.Context) (model.SortedSeries, error) {
collection := db.Database(mongoDBName).Collection(collectionSerie)
collection := db.Database.Collection(collectionSerie)
opts := options.Find().SetSort(bson.M{"id": -1})
filter := bson.M{}
@@ -218,14 +214,14 @@ func (db *mongodb) InsertArticle(ctx context.Context, article *model.Article, st
}
}
collection := db.Database(mongoDBName).Collection(collectionArticle)
collection := db.Database.Collection(collectionArticle)
_, err := collection.InsertOne(ctx, article)
return err
}
// RemoveArticle 硬删除文章
func (db *mongodb) RemoveArticle(ctx context.Context, id int) error {
collection := db.Database(mongoDBName).Collection(collectionArticle)
collection := db.Database.Collection(collectionArticle)
filter := bson.M{"id": id}
_, err := collection.DeleteOne(ctx, filter)
@@ -234,7 +230,7 @@ func (db *mongodb) RemoveArticle(ctx context.Context, id int) error {
// CleanArticles 清理回收站文章
func (db *mongodb) CleanArticles(ctx context.Context, exp time.Time) error {
collection := db.Database(mongoDBName).Collection(collectionArticle)
collection := db.Database.Collection(collectionArticle)
// 超过两天自动删除
filter := bson.M{"deleted_at": bson.M{"$gt": time.Time{}, "$lt": exp}}
@@ -246,7 +242,7 @@ func (db *mongodb) CleanArticles(ctx context.Context, exp time.Time) error {
func (db *mongodb) UpdateArticle(ctx context.Context, id int,
fields map[string]interface{}) error {
collection := db.Database(mongoDBName).Collection(collectionArticle)
collection := db.Database.Collection(collectionArticle)
filter := bson.M{"id": id}
params := bson.M{}
@@ -260,7 +256,7 @@ func (db *mongodb) UpdateArticle(ctx context.Context, id int,
// LoadArticle 查找文章
func (db *mongodb) LoadArticle(ctx context.Context, id int) (*model.Article, error) {
collection := db.Database(mongoDBName).Collection(collectionArticle)
collection := db.Database.Collection(collectionArticle)
filter := bson.M{"id": id}
result := collection.FindOne(ctx, filter)
@@ -276,7 +272,7 @@ func (db *mongodb) LoadArticle(ctx context.Context, id int) (*model.Article, err
// LoadArticleList 获取文章列表
func (db *mongodb) LoadArticleList(ctx context.Context, search SearchArticles) (
model.SortedArticles, int, error) {
collection := db.Database(mongoDBName).Collection(collectionArticle)
collection := db.Database.Collection(collectionArticle)
filter := bson.M{}
for k, v := range search.Fields {
@@ -334,7 +330,7 @@ type counter struct {
// nextValue counter value
func (db *mongodb) nextValue(ctx context.Context, name string) int {
collection := db.Database(mongoDBName).Collection(collectionCounter)
collection := db.Database.Collection(collectionCounter)
opts := options.FindOneAndUpdate().SetUpsert(true).
SetReturnDocument(options.After)

View File

@@ -25,79 +25,8 @@ func startTimer() {
if err != nil {
logrus.Error("startTimer.generateCrossdomain: ", err)
}
ticker := time.NewTicker(time.Hour)
for now := range ticker.C {
// generate feed & sitemap
if now.Hour()%4 == 0 {
err = generateFeed()
if err != nil {
logrus.Error("startTimer.generateFeed: ", err)
}
err = generateSitemap()
if err != nil {
logrus.Error("startTimer.generateSitemap: ", err)
}
}
// clean expired articles
exp := now.Add(-48 * time.Hour)
err := Store.CleanArticles(context.Background(), exp)
if err != nil {
logrus.Error("startTimer.CleanArticles: ", err)
}
// fetch disqus count
if now.Hour()%5 == 0 {
err = DisqusClient.PostsCount(Ei.ArticlesMap)
if err != nil {
logrus.Error("startTimer.PostsCount: ", err)
}
}
}
}
// generateFeed 定时刷新feed
func generateFeed() error {
tpl := XMLTemplate.Lookup("feedTpl.xml")
if tpl == nil {
return errors.New("not found: feedTpl.xml")
}
_, _, articles := Ei.PageArticleFE(1, 20)
params := map[string]interface{}{
"Title": Ei.Blogger.BTitle,
"SubTitle": Ei.Blogger.SubTitle,
"Host": config.Conf.Host,
"FeedrURL": config.Conf.FeedRPC.FeedrURL,
"BuildDate": time.Now().Format(time.RFC1123Z),
"Articles": articles,
}
path := filepath.Join(config.EtcDir, "assets", "feed.xml")
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer f.Close()
return tpl.Execute(f, params)
}
// generateSitemap 定时刷新sitemap
func generateSitemap() error {
tpl := XMLTemplate.Lookup("sitemapTpl.xml")
if tpl == nil {
return errors.New("not found: sitemapTpl.xml")
}
params := map[string]interface{}{
"Articles": Ei.Articles,
"Host": config.Conf.Host,
}
path := filepath.Join(config.EtcDir, "assets", "sitemap.xml")
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer f.Close()
return tpl.Execute(f, params)
// 定时刷新
refreshFeedAndSitemap()
}
// generateOpensearch 生成opensearch.xml
@@ -158,3 +87,75 @@ func generateCrossdomain() error {
defer f.Close()
return tpl.Execute(f, params)
}
// refreshFeedAndSitemap 定时刷新feed和sitemap
func refreshFeedAndSitemap() {
defer time.AfterFunc(time.Hour*4, refreshFeedAndSitemap)
now := time.Now()
// generate feed & sitemap
err := generateFeed()
if err != nil {
logrus.Error("startTimer.generateFeed: ", err)
}
err = generateSitemap()
if err != nil {
logrus.Error("startTimer.generateSitemap: ", err)
}
// clean expired articles
exp := now.Add(-48 * time.Hour)
err = Store.CleanArticles(context.Background(), exp)
if err != nil {
logrus.Error("startTimer.CleanArticles: ", err)
}
// fetch disqus count
err = DisqusClient.PostsCount(Ei.ArticlesMap)
if err != nil {
logrus.Error("startTimer.PostsCount: ", err)
}
}
// generateFeed 定时刷新feed
func generateFeed() error {
tpl := XMLTemplate.Lookup("feedTpl.xml")
if tpl == nil {
return errors.New("not found: feedTpl.xml")
}
_, _, articles := Ei.PageArticleFE(1, 20)
params := map[string]interface{}{
"Title": Ei.Blogger.BTitle,
"SubTitle": Ei.Blogger.SubTitle,
"Host": config.Conf.Host,
"FeedrURL": config.Conf.FeedRPC.FeedrURL,
"BuildDate": time.Now().Format(time.RFC1123Z),
"Articles": articles,
}
path := filepath.Join(config.EtcDir, "assets", "feed.xml")
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer f.Close()
return tpl.Execute(f, params)
}
// generateSitemap 定时刷新sitemap
func generateSitemap() error {
tpl := XMLTemplate.Lookup("sitemapTpl.xml")
if tpl == nil {
return errors.New("not found: sitemapTpl.xml")
}
params := map[string]interface{}{
"Articles": Ei.Articles,
"Host": config.Conf.Host,
}
path := filepath.Join(config.EtcDir, "assets", "sitemap.xml")
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer f.Close()
return tpl.Execute(f, params)
}

View File

@@ -9,8 +9,8 @@ import (
"github.com/eiblog/eiblog/cmd/eiblog/handler/file"
"github.com/eiblog/eiblog/cmd/eiblog/handler/pages"
"github.com/eiblog/eiblog/cmd/eiblog/handler/swag"
"github.com/eiblog/eiblog/pkg/middleware"
"github.com/eiblog/eiblog/tools"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
@@ -36,7 +36,7 @@ func runHTTPServer(endRun chan error) {
middleware.SessionOpts{
Name: "su",
Secure: config.Conf.RunMode.IsReleaseMode(),
Secret: []byte("ZGlzvcmUoMTAsICI="),
Secret: tools.CryptoRand(16),
}))
// swag

View File

@@ -1,6 +1,6 @@
services:
mongodb:
image: mongo:3.2
image: mongo:3.6
volumes:
- ${PWD}/mgodb:/data/db
restart: always
@@ -13,7 +13,7 @@ services:
eiblog:
image: deepzz0/eiblog:latest
volumes:
- ${PWD}/eiblog/etc:/app/etc
- ${PWD}/eiblog/etc/app.yml:/app/etc/app.yml
extra_hosts:
- "disqus.com:151.101.192.134"
- "deepzz.disqus.com:151.101.192.134"
@@ -30,7 +30,9 @@ services:
image: deepzz0/backup:latest
#command: ./backend --restore true
volumes:
- ${PWD}/backup/etc:/app/etc
- ${PWD}/backup/etc/app.yml:/app/etc/app.yml
links:
- mongodb
environment:
- RUN_MODE=prod
restart: always

View File

@@ -7,19 +7,20 @@ EiBlog 镜像仓库地址https://hub.docker.com/u/deepzz0备份镜像为
目前仅支持同步 mongodb 数据到七牛云,参考 `app.yml`
```
backupapp:
mode:
name: cmd-backup
enablehttp: true
httpport: 9001
backupto: qiniu # 备份到七牛云
interval: 7d # 多久备份一次
validity: 60 # 保存时长days
qiniu: # 七牛OSS
bucket: backup
domain: st.deepzz.com
accesskey: MB6AXl_Sj_mmFsL-Lt59Dml2Vmy2o8XMmiCbbSeC
secretkey: BIrMy0fsZ0_SHNceNXk3eDuo7WmVYzj2-zrmd5Tf
apimode:
name: cmd-backup
listen: 0.0.0.0:9000
database: # 数据库配置
driver: mongodb
source: mongodb://localhost:27017/eiblog
backupto: qiniu # 备份到, default: qiniu
interval: 7d # 备份周期, default: 7d
validity: 60 # 备份保留时间, default: 60
qiniu: # 七牛OSS
bucket: eiblog
domain: st.deepzz.cn
accesskey: MB6AXl_Sj_mmFsL-Lt59Dml2Vmy2o8XMmiCbbSeC
secretkey: BIrMy0fsZ0_SHNceNXk3eDuo7WmVYzj2-zrmd5Tf
```
@@ -36,7 +37,7 @@ $ docker pull deepzz0/backup
```
$ docker run --name backup \
-v ${PWD}/conf:/app/conf
-v ${PWD}/etc/app.yml:/app/etc/app.yml
```
Docker-compose 请参考项目根目录下的 `docker-compose.yml` 文件。

View File

@@ -5,7 +5,7 @@
* [准备工作](#准备工作)
* [开始部署](#开始部署)
博主提供了下面将要用到的镜像,可到这里查看:[https://hub.docker.com/u/deepzz0](https://hub.docker.com/u/deepzz0)。由于所有配置均在 `app/conf.yml` 下,所以在通过 docker 部署时建议将配置映射出来方便调试。
博主提供了下面将要用到的镜像,可到这里查看:[https://hub.docker.com/u/deepzz0](https://hub.docker.com/u/deepzz0)。在通过 docker 部署时建议将配置映射出来方便调试。
### 存储后端
@@ -13,7 +13,7 @@
```
# driver # source
mongodb mongodb://localhost:27017
mongodb mongodb://localhost:27017/eiblog
postgres host=localhost port=5432 user=user dbname=eiblog sslmode=disable password=password
mysql user:password@tcp(127.0.0.1:3306)/eiblog?charset=utf8mb4&parseTime=True&loc=Local
sqlite /path/eiblog.db
@@ -74,8 +74,8 @@ eshost: http://localhost:9200
| favicon.ico | st.example.com/static/img/favicon.ico | cdn 名为 `static/img/favicon.ico`。你也可以在代理服务器自行配置,只要通过 example.com/favicon.ico 也是能够访问到。 |
| bg04.jpg | st.example.com/static/img/bg04.jpg | cdn 名为 `static/img/bg04.jpg`,首页左侧的大背景图,需要更名请到 website/st_blog.css 修改。 |
| avatar.png | st.example.com/static/img/avatar.png | cdn 名为 `static/img/avatar.png`,个人博客头像 |
| blank.gif | st.example.com/static/img/blank.gif | cdn 名为 `static/img/blank.gif`,空白图片,复制链接下载 https://st.deepzz.com/static/img/blank.gif。 |
| default_avatar.png | st.example.com/static/img/default_avatar.png | cdn 名为 `static/img/default_avatar.png`disqus 默认头像图片,复制链接下载 https://st.deepzz.com/static/img/default_avatar.png |
| blank.gif | st.example.com/static/img/blank.gif | cdn 名为 `static/img/blank.gif`,空白图片,复制链接下载 https://st.deepzz.cn/static/img/blank.gif。 |
| default_avatar.png | st.example.com/static/img/default_avatar.png | cdn 名为 `static/img/default_avatar.png`disqus 默认头像图片,复制链接下载 https://st.deepzz.cn/static/img/default_avatar.png |
> 注意:
>
@@ -85,21 +85,27 @@ eshost: http://localhost:9200
#### 配置说明
走到这里,我相信只走到 `80%` 的路程。放弃还来得及。这里会对 `eiblog/conf` 下的所有文件做说明,希望你做好准备。
走到这里,我相信只走到 `80%` 的路程。这里会对 `cmd/eiblog/etc` 下的所有文件做说明
具体的配置内容已经在 `app.yml` 中进行说明了。
```
cmd/eiblog/etc
├── app.yml # 博客配置文件
├── assets # 后台所需的资源文件
├── page # 自定义的页面文件
├── template # 前台渲染的模板
└── xml # xml 渲染模板,如 sitemap
```
如果用 nginx 作为代理服务器,博主提供了一份示例配置 `eiblog/eiblog.conf`,该配置涉及到 `ssl` 相关配置建议存放于 `/etc/nginx/ssl` 下。其中关于 `ssl_dhparam`、站点认证均提供了相关配置。
具体的配置内容已经在 `app.yml` 中进行说明了。如果用 nginx 作为代理服务器,博主提供了一份示例配置 `eiblog/eiblog.conf`,该配置涉及到 `ssl` 相关配置建议存放于 `/etc/nginx/ssl` 下。其中关于 `ssl_dhparam`、站点认证均提供了相关配置。
### 开始部署
下面是博主通过 `docker-compose` 一键部署的文件内容,仅供参考:
```
version: '3'
services:
mongodb:
image: mongo:3.2
image: mongo:3.6
volumes:
- ${PWD}/mgodb:/data/db
restart: always
@@ -108,24 +114,32 @@ services:
volumes:
- ${PWD}/esdata:/usr/share/elasticsearch/data
restart: always
eiblog:
iamge: deepzz0/eiblog:latest
image: deepzz0/eiblog:latest
volumes:
- ${PWD}/conf:/app/conf
- ${PWD}/eiblog/etc/app.yml:/app/etc/app.yml
extra_hosts:
- "disqus.com:151.101.192.134"
- "deepzz.disqus.com:151.101.192.134"
links:
- elasticsearch
- mongodb
environment:
- RUN_MODE=prod
ports:
- 9000:9000
- 127.0.0.1:9000:9000
restart: always
backup:
image: deepzz0/backup:latest
#command: ./backend --restore true
volumes:
- ${PWD}/conf:/app/conf
- ${PWD}/backup/etc/app.yml:/app/etc/app.yml
links:
- mongodb
environment:
- RUN_MODE=prod
restart: always
```

View File

@@ -10,7 +10,7 @@ import (
const (
RunModeLocal RunMode = "local" // 本地环境
RunModeDev RunMode = "dev" // 开发环境
RunModeProd RunMode = "pro" // 生产环境
RunModeProd RunMode = "prod" // 生产环境
)
// RunMode 运行模式

View File

@@ -4,7 +4,6 @@ import (
"context"
"errors"
"net/url"
"time"
"github.com/eiblog/eiblog/pkg/config"
@@ -16,7 +15,7 @@ import (
// NewMDB new mongodb
// https://docs.mongodb.com/manual/reference/connection-string/
// mongodb://db0.example.com,db1.example.com,db2.example.com/dbname?replicaSet=myRepl&w=majority&wtimeoutMS=5000
func NewMDB(opts config.Database) (*mongo.Database, error) {
func NewMDB(ctx context.Context, opts config.Database) (*mongo.Database, error) {
if opts.Driver != "mongodb" {
return nil, errors.New("db: driver must be mongodb, but " + opts.Driver)
}
@@ -29,8 +28,6 @@ func NewMDB(opts config.Database) (*mongo.Database, error) {
return nil, errors.New("db: please specify a database")
}
database = database[1:]
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
// remove database
u.Path = ""

View File

@@ -42,7 +42,7 @@ type UploadParams struct {
func (cli *QiniuClient) Upload(params UploadParams) (string, error) {
key := params.Name
if !params.NoCompletePath {
key = filepath.Base(params.Name)
key = completeQiniuKey(params.Name)
}
mac := qbox.NewMac(cli.Conf.AccessKey,

View File

@@ -2,6 +2,7 @@
package tools
import (
"crypto/rand"
"crypto/sha256"
"fmt"
"io"
@@ -128,3 +129,14 @@ func IgnoreHTMLTag(src string) string {
// 去除换行符
return regexpEnter.ReplaceAllString(src, "")
}
// CryptoRand random with crypto/rand
func CryptoRand(byteLen int) []byte {
buf := make([]byte, byteLen)
_, err := rand.Read(buf)
if err != nil {
panic(fmt.Sprintf("rand: error reading random bytes: %s", err))
}
return buf
}