Docker 搭建自用随机图片 API(含手机/电脑端自动分流)

前言

我们在美化博客(如 Halo)时,经常需要用到随机图片 API 作为文章封面或背景。市面上的免费 API 虽然多,但经常遇到不稳、挂掉或者 HTTPS 混合内容报错的问题。

与其依赖别人,不如利用手里的服务器(VPS)自己搭建一个。本文将分享一个 零依赖、纯 Docker、支持手机 / 电脑自动分流 的部署方案。

主要优势:

  • 速度快:直接部署在自己的服务器上。

  • 不报错:直接输出图片流(非重定向),完美解决 HTTPS 混合内容和防盗链问题。

  • 智能分流:自动识别手机和电脑,返回不同尺寸的壁纸。


1. 准备工作

  • 一台安装好 Docker 的服务器(如 Debian/Ubuntu)。

  • 一个域名(用于配置 HTTPS)。

  • 若干张喜欢的横屏和竖屏壁纸。

2. 部署步骤

2.1 创建项目目录

登录服务器,创建存放代码和图片的目录结构:

Bash

# 创建主目录
mkdir -p /opt/random-img

# 创建图片子目录(分别存放电脑和手机图)
mkdir -p /opt/random-img/images/pc
mkdir -p /opt/random-img/images/mobile

# 进入目录
cd /opt/random-img

2.2 编写核心代码 (index.php)

创建并编辑 index.php 文件:

Bash

vim index.php

粘贴以下代码。这段代码的核心逻辑是获取 User-Agent,判断设备类型后从对应文件夹读取图片,并直接输出二进制流。

PHP

<?php
/**
 * 自建随机图片 API
 * 特性:支持移动端/PC端分流,支持直接输出图片流(解决防盗链)
 */

// 1. 获取用户设备标识
$ua = $_SERVER['HTTP_USER_AGENT'];

// 2. 判断设备类型
// 如果包含 iPhone, Android, Mobile 等关键词,判定为手机
if (preg_match('/(iPhone|Android|Mobile)/i', $ua)) {
    $path = './images/mobile/';
} else {
    // 否则默认为电脑
    $path = './images/pc/';
}

// 3. 读取目录下的图片
$files = array();
if (is_dir($path) && $handle = opendir($path)) {
    while (false !== ($file = readdir($handle))) {
        if ($file != "." && $file != "..") {
            // 仅读取常见图片格式
            if (preg_match("/\.(jpg|jpeg|png|gif|webp)$/i", $file)) {
                $files[] = $file;
            }
        }
    }
    closedir($handle);
}

// 4. 错误处理
if (empty($files)) {
    http_response_code(404);
    die("Error: No images found in " . $path);
}

// 5. 随机抽取一张
$random_img = $files[array_rand($files)];
$file_path = $path . $random_img;

// 6. 输出图片头信息
$mime_type = mime_content_type($file_path);
header('Content-Type: ' . $mime_type);
header('Content-Length: ' . filesize($file_path));

// 禁止浏览器缓存 (确保每次刷新都是新图,且切换设备时不串图)
header("Cache-Control: no-cache, no-store, must-revalidate");
header("Pragma: no-cache");
header("Expires: 0");

// 7. 直接输出图片数据
readfile($file_path);
?>

2.3 编写 Docker 配置文件

创建 docker-compose.yml

Bash

vim docker-compose.yml

粘贴以下内容:

YAML

version: '3'
services:
  random-api:
    image: php:8.2-apache
    container_name: random-api
    restart: always
    ports:
      - "8089:80"  # 宿主机端口 8089,可自行修改
    volumes:
      - ./index.php:/var/www/html/index.php
      - ./images:/var/www/html/images
    logging:
      driver: "json-file"
      options:
        max-size: "10m"

2.4 上传图片(重要)

将你的壁纸分别上传到对应目录:

  • 横屏 / 电脑图 -> /opt/random-img/images/pc/

  • 竖屏 / 手机图 -> /opt/random-img/images/mobile/

2.5 修复权限问题(避坑关键点)

Docker 容器内的 Apache 默认使用 www-data 用户,如果你用 root 上传图片,容器可能会因为权限不足报错 Permission denied

执行以下命令修复权限:

Bash

chmod -R 755 /opt/random-img/images

2.6 启动服务

Bash

docker compose up -d

3. 域名与 HTTPS 配置

为了让博客正常加载,建议配置反向代理并开启 HTTPS。

以 Nginx Proxy Manager 或 1Panel 为例:

  1. 添加反向代理。

  2. 域名:填写你的二级域名(如 img.example.com)。

  3. 目标地址http://127.0.0.1:8089

  4. 申请并开启 SSL 证书(强制 HTTPS)。


4. 在 Halo 博客中调用

这是最后一步,也是最容易出错的一步。

在 Halo 后台 -> 设置 / 文章封面 中填写链接时,必须在链接末尾加上伪装后缀,欺骗 Halo 系统这是一张静态图片,否则无法保存或显示。

  • 错误写法https://img.example.com/

  • 正确写法https://img.example.com/?.jpg

效果展示

  • PC 访问:自动加载横版大图。

  • 手机访问:自动加载竖版壁纸。

  • 速度:秒开,且无混合内容报错。


消息盒子

# 暂无消息 #

只显示最新10条未读和已读信息