fix: mount config directory instead of file for Docker Compose
Build and Push to GHCR / build-and-push (push) Has been cancelled

- Add CONFIG_PATH env support to avoid Docker creating config.json as a directory
- Config Save() now auto-creates parent directories
- Update docker-compose.yml to mount ./config:/app/config
- Update README deployment docs accordingly
This commit is contained in:
Agent
2026-05-24 15:44:29 +08:00
parent 45da2d1d0c
commit 44c8ff6a6f
6 changed files with 42 additions and 14 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ RUN apk --no-cache add ca-certificates
WORKDIR /app WORKDIR /app
# 创建必要目录 # 创建必要目录
RUN mkdir -p web/static cache RUN mkdir -p web/static cache config
# 复制编译后的二进制文件和静态资源 # 复制编译后的二进制文件和静态资源
COPY --from=builder /app/mirror-proxy . COPY --from=builder /app/mirror-proxy .
+8 -3
View File
@@ -49,10 +49,11 @@ services:
ports: ports:
- "8080:8080" - "8080:8080"
volumes: volumes:
- ./config.json:/app/config.json - ./config:/app/config
- ./cache:/app/cache - ./cache:/app/cache
environment: environment:
- TZ=Asia/Shanghai - TZ=Asia/Shanghai
- CONFIG_PATH=/app/config/config.json
EOF EOF
``` ```
@@ -62,7 +63,7 @@ EOF
docker-compose up -d docker-compose up -d
``` ```
首次启动会自动创建 `config.json`(默认账号 `admin` / `admin123`)。 首次启动会自动在 `./config/` 目录下创建 `config.json`(默认账号 `admin` / `admin123`),无需手动提前创建配置文件。
**3. 常用命令** **3. 常用命令**
@@ -96,12 +97,16 @@ docker-compose pull && docker-compose up -d
### 使用 Docker 直接运行 ### 使用 Docker 直接运行
```bash ```bash
# 创建配置目录
mkdir -p config cache
# 拉取并运行(首次运行自动生成 config.json) # 拉取并运行(首次运行自动生成 config.json)
docker run -d \ docker run -d \
--name mirror-proxy \ --name mirror-proxy \
-p 8080:8080 \ -p 8080:8080 \
-v $(pwd)/config.json:/app/config.json \ -v $(pwd)/config:/app/config \
-v $(pwd)/cache:/app/cache \ -v $(pwd)/cache:/app/cache \
-e CONFIG_PATH=/app/config/config.json \
--restart unless-stopped \ --restart unless-stopped \
ghcr.io/arkylin/mirror-proxy:latest ghcr.io/arkylin/mirror-proxy:latest
``` ```
+5 -1
View File
@@ -15,7 +15,11 @@ import (
) )
func main() { func main() {
cfg, err := config.Load("config.json") configPath := os.Getenv("CONFIG_PATH")
if configPath == "" {
configPath = "config.json"
}
cfg, err := config.Load(configPath)
if err != nil { if err != nil {
log.Fatalf("Failed to load config: %v", err) log.Fatalf("Failed to load config: %v", err)
} }
+3 -4
View File
@@ -1,14 +1,13 @@
services: services:
mirror-proxy: mirror-proxy:
# 使用 GHCR 预构建镜像(推荐) image: ghcr.io/arkylin/mirror-proxy:latest
# image: ghcr.io/arkylin/mirror-proxy:latest
build: .
container_name: mirror-proxy container_name: mirror-proxy
restart: unless-stopped restart: unless-stopped
ports: ports:
- "8080:8080" - "8080:8080"
volumes: volumes:
- ./config.json:/app/config.json - ./config:/app/config
- ./cache:/app/cache - ./cache:/app/cache
environment: environment:
- TZ=Asia/Shanghai - TZ=Asia/Shanghai
- CONFIG_PATH=/app/config/config.json
+5 -5
View File
@@ -63,7 +63,7 @@ func (h *Handler) CreateLink(w http.ResponseWriter, r *http.Request) {
} }
h.cfg.SetLink(link) h.cfg.SetLink(link)
if err := h.cfg.Save("config.json"); err != nil { if err := h.cfg.Save(config.GetConfigFilePath()); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@@ -112,7 +112,7 @@ func (h *Handler) UpdateLink(w http.ResponseWriter, r *http.Request) {
} }
h.cfg.SetLink(link) h.cfg.SetLink(link)
if err := h.cfg.Save("config.json"); err != nil { if err := h.cfg.Save(config.GetConfigFilePath()); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@@ -132,7 +132,7 @@ func (h *Handler) DeleteLink(w http.ResponseWriter, r *http.Request) {
} }
h.cfg.DeleteLink(id) h.cfg.DeleteLink(id)
if err := h.cfg.Save("config.json"); err != nil { if err := h.cfg.Save(config.GetConfigFilePath()); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@@ -152,7 +152,7 @@ func (h *Handler) RegenerateToken(w http.ResponseWriter, r *http.Request) {
link.Token = auth.GenerateToken() link.Token = auth.GenerateToken()
h.cfg.SetLink(link) h.cfg.SetLink(link)
if err := h.cfg.Save("config.json"); err != nil { if err := h.cfg.Save(config.GetConfigFilePath()); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
@@ -221,7 +221,7 @@ func (h *Handler) UpdateConfig(w http.ResponseWriter, r *http.Request) {
h.cfg.AdminPass = req.AdminPass h.cfg.AdminPass = req.AdminPass
} }
if err := h.cfg.Save("config.json"); err != nil { if err := h.cfg.Save(config.GetConfigFilePath()); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
+20
View File
@@ -3,9 +3,20 @@ package config
import ( import (
"encoding/json" "encoding/json"
"os" "os"
"path/filepath"
"sync" "sync"
) )
var configFilePath string = "config.json"
func SetConfigFilePath(path string) {
configFilePath = path
}
func GetConfigFilePath() string {
return configFilePath
}
type Config struct { type Config struct {
ListenAddr string `json:"listen_addr"` ListenAddr string `json:"listen_addr"`
AdminPath string `json:"admin_path"` AdminPath string `json:"admin_path"`
@@ -38,6 +49,7 @@ var (
) )
func Load(path string) (*Config, error) { func Load(path string) (*Config, error) {
configFilePath = path
data, err := os.ReadFile(path) data, err := os.ReadFile(path)
if err != nil { if err != nil {
if os.IsNotExist(err) { if os.IsNotExist(err) {
@@ -73,6 +85,14 @@ func defaultConfig() *Config {
func (c *Config) Save(path string) error { func (c *Config) Save(path string) error {
c.mu.RLock() c.mu.RLock()
defer c.mu.RUnlock() defer c.mu.RUnlock()
dir := filepath.Dir(path)
if dir != "" && dir != "." {
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
}
data, err := json.MarshalIndent(c, "", " ") data, err := json.MarshalIndent(c, "", " ")
if err != nil { if err != nil {
return err return err