YOURLS 1.10.6 Docker Compose 部署指南

YOURLS 1.10.6 Docker Compose 部署指南:yourls 官方镜像 + MySQL 8.0 双服务编排、安装向导、登录 nonce 实录、301 短链验证与排障沉淀,全部命令带实测回显。

YOURLSYOURLS自托管Docker2026/10/30

YOURLS 1.10.6 Docker Compose 部署指南

‍‍​​‌​> 目标:在一台 Linux 服务器上用 Docker Compose 完成 YOURLS 1.10.6 + MySQL 8.0 双服务编排部署,从零到拿到第一条 301 短链。本文全部命令与回显均于 2026-10-30 在 Ubuntu 22.04 服务器(IP 192.168.1.200)实测通过。

一、环境信息

  • 操作系统:Ubuntu 22.04(IP 192.168.1.200,已安装 Docker Engine 与 Compose 插件);
  • 架构:x86_64;
  • YOURLS:1.10.6(官方镜像 yourls:1.10.6,759MB;镜像内为 Apache 2.4.69 + PHP 8.5.12);
  • 数据库:MySQL 8.0(官方镜像 mysql:8.0,1.1GB);
  • 端口规划:YOURLS 容器内监听 8080,宿主机映射 8134;
  • 数据目录:/opt/yourls/user(YOURLS 用户层:配置、插件、页面、语言包)与 /opt/yourls/mysql(数据库文件);
  • 短链站点地址:http://192.168.1.200:8134(生产环境换成自有域名,如 https://s.example.com);
  • 演示账号:用户名 admin、密码 q1w2e3r4、MySQL 业务密码同为 q1w2e3r4。

二、镜像选型说明

YOURLS 的 Docker 镜像有三类可选:yourls(Docker 官方镜像,由 docker-library 审核,docker pull yourls 即可)、yourls/yourls(项目方同名镜像)以及第三方构建。本文采用 Docker 官方镜像 yourls:1.10.6,理由:官方渠道维护、与 PHP/Apache 版本组合经过 docker-library 测试、支持 _FILE 后缀环境变量读取 Docker Secrets。官方镜像内置 Apache 2.4.69 与 PHP 8.5.12,应用代码位于容器内 /var/www/html,启动时由 entrypoint 脚本完成「检查环境变量 → 生成 user/config.php → 等待数据库就绪 → 启动 Apache」的全过程,无需手工初始化。

数据库镜像选 mysql:8.0 而非 8.4/9.x:YOURLS 官方兼容面以 MySQL/MariaDB 稳定线为主,8.0 是最保守可靠的选择(MariaDB 11 亦可替换,compose 写法相同)。

三、前置条件

  • 服务器已安装 Docker Engine 与 docker compose 插件(安装方法见 《Docker Compose 安装与多容器编排》);
  • 服务器可访问外网或已配置镜像加速(拉取 yourls:1.10.6 与 mysql:8.0);
  • 端口 8134 未被占用,验证方法:
ss -ltn | grep 8134 || echo "8134 空闲"

实测回显:

8134 空闲
  • 规划好 YOURLS 站点地址:它决定了所有生成的短链 URL 前缀,务必与实际访问地址完全一致(含端口、不含末尾斜杠),否则会出现登录后 301 回跳与短链域名错乱(排障实录见第九节)。

四、部署步骤

4.1 创建目录与编排文件

mkdir -p /opt/yourls/user /opt/yourls/mysql /opt/yourls/compose
cd /opt/yourls/compose

创建 docker-compose.yml(以下为实测原文件,可直接复制替换站点地址与密码):

name: yourls-1.10.6-stack

services:
  yourls:
    image: yourls:1.10.6
    container_name: yourls-1.10.6-web
    restart: unless-stopped
    ports:
      - "8134:8080"
    environment:
      YOURLS_SITE: "http://192.168.1.200:8134"
      YOURLS_USER: "admin"
      YOURLS_PASS: "q1w2e3r4"
      YOURLS_DB_HOST: "mysql"
      YOURLS_DB_USER: "yourls"
      YOURLS_DB_PASS: "q1w2e3r4"
      YOURLS_DB_NAME: "yourls"
      YOURLS_DB_PREFIX: "yourls_"
      YOURLS_UNIQUE_URLS: "false"
      YOURLS_URL_CONVERT: "62"
    volumes:
      - /opt/yourls/user:/var/www/html/user
    depends_on:
      - mysql
    networks:
      - yourls-net

  mysql:
    image: mysql:8.0
    container_name: yourls-1.10.6-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: "q1w2e3r4"
      MYSQL_DATABASE: "yourls"
      MYSQL_USER: "yourls"
      MYSQL_PASSWORD: "q1w2e3r4"
    volumes:
      - /opt/yourls/mysql:/var/lib/mysql
    networks:
      - yourls-net

networks:
  yourls-net:
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.59.0/24

关键项说明:YOURLS_SITE 必须与实际访问地址一致;YOURLS_DB_HOST 指向 compose 内的 mysql 服务名;YOURLS_UNIQUE_URLS: false 允许同一长链创建多条短链(默认 true 全局唯一);YOURLS_URL_CONVERT: 62 使用 62 进制短码(区分大小写,短码空间更大,36 为默认);ipam.subnet 显式指定网段避免与既有 compose 网络冲突(无此需求可删除 networks 里的 ipam 段)。

4.2 启动编排栈

docker compose up -d

实测回显:

 Container yourls-1.10.6-mysql Starting
 Container yourls-1.10.6-mysql Started
 Container yourls-1.10.6-web Starting
 Container yourls-1.10.6-web Started

4.3 确认服务状态

docker compose ps

实测回显:

NAME                  IMAGE           COMMAND                  SERVICE   CREATED          STATUS          PORTS
yourls-1.10.6-mysql   mysql:8.0       "docker-entrypoint.s…"   mysql     26 seconds ago   Up 25 seconds   3306/tcp, 33060/tcp
yourls-1.10.6-web     yourls:1.10.6   "container-entrypoin…"   yourls    26 seconds ago   Up 25 seconds   80/tcp, 8443/tcp, 0.0.0.0:8134->8080/tcp, [::]:8134->8080/tcp

查看 YOURLS 启动日志确认初始化完成:

docker compose logs yourls

实测回显(节选):

yourls-1.10.6-web  | YOURLS not found in /var/www/html - copying now...
yourls-1.10.6-web  | Complete! YOURLS has been successfully copied to /var/www/html
yourls-1.10.6-web  | Running custom script /docker-entrypoint-init.d/*
yourls-1.10.6-web  | ... ignoring /docker-entrypoint-init.d/*
yourls-1.10.6-web  | AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.89.59.3. Set the 'ServerName' directive globally to suppress this message
yourls-1.10.6-web  | [Fri Oct 30 07:19:16.115745 2026] [mpm_prefork:notice] [pid 1:tid 1] AH00163: Apache/2.4.69 (Debian) PHP/8.5.12 configured -- resuming normal operations

YOURLS has been successfully copied 表示应用代码已就位,Apache/2.4.69 (Debian) PHP/8.5.12 configured -- resuming normal operations 表示 Web 服务已监听。AH00558 提示是无害警告(未配置全局 ServerName),不影响使用。

4.4 完成安装向导

首次访问根路径会得到 403——这是官方镜像文档明确注明的行为(「On first instantiation, reaching the root folder will generate an error. Access the YOURLS administration interface via the path /admin/」),因为安装完成前短链表不存在:

curl -s -o /dev/null -w '%{http_code}\n' http://192.168.1.200:8134/

实测回显:

403

浏览器访问安装向导(或命令行查看页面确认版本):

curl -s http://192.168.1.200:8134/admin/install.php | grep -oE '<title>[^<]+</title>'

实测回显:

<title>Install YOURLS &laquo; YOURLS &mdash; Your Own URL Shortener | http://192.168.1.200:8134/</title>

安装页是一个 POST 表单(按钮 Install YOURLS),浏览器中直接点击即可;命令行等价操作:

curl -s "http://192.168.1.200:8134/admin/install.php" -d 'install=Install YOURLS'

实测回显(节选):

 File .htaccess successfully created/updated.
 Table 'yourls_url' created.
 Table 'yourls_options' created.
 Table 'yourls_log' created.
 YOURLS tables successfully created.
 » YOURLS Administration Page

三张核心表(yourls_url/yourls_options/yourls_log)建表成功即安装完成。到库侧复核一遍:

docker exec yourls-1.10.6-mysql sh -c 'mysql -uyourls -pq1w2e3r4 yourls -e "SHOW TABLES;"'

实测回显:

Tables_in_yourls
yourls_log
yourls_options
yourls_url

4.5 登录管理后台

浏览器打开 http://192.168.1.200:8134/admin/,输入 admin / q1w2e3r4 登录。登录表单带 nonce 防 CSRF 令牌,命令行模拟需先取 nonce 再提交:

# 从登录页取 nonce(每次会话不同)
NONCE=$(curl -s -c /tmp/yourls-cookie.txt "http://192.168.1.200:8134/admin/index.php" \
  | grep -oE 'name="nonce" value="[a-z0-9]+"' | grep -oE '[a-z0-9]{10}')
# 带 nonce 提交登录
curl -s -b /tmp/yourls-cookie.txt -c /tmp/yourls-cookie.txt -o /dev/null \
  -w 'login http:%{http_code} redirect:%{redirect_url}\n' \
  "http://192.168.1.200:8134/admin/index.php" \
  -d "username=admin&password=q1w2e3r4&nonce=$NONCE&submit=Login"
# 确认已进入后台
curl -s -b /tmp/yourls-cookie.txt "http://192.168.1.200:8134/admin/index.php" | grep -oE '<title>[^<]+</title>'

实测回显:

login http:301 redirect:http://192.168.1.200:8134/admin/index.php
<title>YOURLS &mdash; Your Own URL Shortener | http://192.168.1.200:8134/</title>

登录成功后页面标题从「Login — YOURLS」变为「YOURLS — Your Own URL Shortener」,同时服务端种下名为 yourls_<随机串> 的会话 cookie。

4.6 创建第一条短链并验证 301 跳转

用内置 API 创建短链(API 认证细节见本专栏 《YOURLS 1.10.6 API 使用详解》,此处用最直观的用户名密码参数):

curl -s "http://192.168.1.200:8134/yourls-api.php" \
  --data-urlencode 'url=https://www.quzuo.net/' \
  --data-urlencode 'title=Quzuo 主站' \
  --data-urlencode 'keyword=quzuo' \
  --data-urlencode 'action=shorturl' --data-urlencode 'format=json' \
  --data-urlencode 'username=admin' --data-urlencode 'password=q1w2e3r4'

实测回显:

{
    "status": "success",
    "code": "",
    "message": "https://www.quzuo.net/ added to database",
    "errorCode": "",
    "statusCode": "200",
    "url": {
        "keyword": "quzuo",
        "url": "https://www.quzuo.net/",
        "title": "Quzuo \u4e3b\u7ad9",
        "date": "2026-10-30 07:21:34",
        "ip": "192.168.1.200"
    },
    "title": "Quzuo \u4e3b\u7ad9",
    "shorturl": "http://192.168.1.200:8134/quzuo"
}

访问短链验证 301 重定向:

curl -sI "http://192.168.1.200:8134/quzuo" | head -8

实测回显:

HTTP/1.1 301 Moved Permanently
Date: Fri, 30 Oct 2026 07:21:42 GMT
Server: Apache/2.4.69 (Debian)
X-Powered-By: PHP/8.5.12
X-Robots-Tag: noindex
Location: https://www.quzuo.net/
Content-Type: text/html; charset=UTF-8

Location 指向长链、X-Robots-Tag: noindex 防搜索引擎收录,部署闭环完成。

五、数据持久化说明

本编排把两类数据都落在宿主机目录(bind mount):

宿主机目录容器内路径内容
/opt/yourls/mysql/var/lib/mysqlMySQL 全部数据文件(实验实测约 202MB:系统库 + yourls 三张表)
/opt/yourls/user/var/www/html/userYOURLS 用户层:config.php、plugins/、pages/、languages/

首次启动后 /opt/yourls/user 会被 entrypoint 写入以下文件(实测 ls /opt/yourls/user):

config-container.php
config-sample.php
config.php
index.html
languages
pages
plugins

其中 config.php 是由环境变量生成的实际生效配置(内容为读取 YOURLS_* 环境变量的 PHP 代码),config-container.php 是镜像内置的容器适配引导文件。不要再手工编辑 config.php 覆盖环境变量——容器化形态下配置的唯一事实来源是 compose 的 environment 段;要自定义环境变量覆盖不到的高级参数,做法是在 user/ 下放置自定义 PHP 或构建派生镜像,见下一节。

持久化验证:重启栈后数据不丢:

docker compose restart && sleep 10 && curl -s -o /dev/null -w '%{http_code}\n' http://192.168.1.200:8134/quzuo

实测回显(重启后短链依然 301):

301

六、环境变量表

YOURLS 官方镜像的全部环境变量(来源:docker-library 官方镜像文档与镜像内 entrypoint 实测,2026-10-30):

环境变量必填默认值说明
YOURLS_SITE是无站点 URL,小写、无末尾斜杠;决定短链域名前缀
YOURLS_USER是无管理账号用户名
YOURLS_PASS是无管理账号密码
YOURLS_DB_HOST否(有 mysql 服务时必填)mysql数据库主机,非标端口写 host:port
YOURLS_DB_USER否root数据库用户名
YOURLS_DB_PASS否空数据库密码
YOURLS_DB_NAME否yourls数据库名,需预先创建
YOURLS_DB_PREFIX否yourls_表前缀
YOURLS_UNIQUE_URLS否true同一长链是否只允许一条短链
YOURLS_URL_CONVERT否36短码进制:36 纯小写 / 62 区分大小写
YOURLS_PRIVATE否true私密模式(后台登录 + API 鉴权)
YOURLS_COOKIEKEY否自动随机cookie 加密盐
YOURLS_HOURS_OFFSET否0时区偏移小时数
YOURLS_LANG否空界面语言(翻译文件放 user/languages/)
YOURLS_DEBUG否false调试模式
YOURLS_NO_VERSION_CHECK否true是否禁用版本更新检查
YOURLS_NOSTATS否false是否禁用统计功能

此外,以上变量全部支持 <名>_FILE 后缀形式(如 YOURLS_DB_PASS_FILE=/run/secrets/db_pass),从文件读取敏感值以对接 Docker Secrets——这是官方镜像文档明确列出的支持清单(YOURLS_DB_HOST/USER/PASS/NAME/PREFIX/SITE/USER/PASS 八项)。

七、配置参数说明与配置文件挂载

容器化 YOURLS 的配置分三层:

  1. 环境变量层(compose environment):覆盖 user/config.php 的绝大多数开关,是首选配置入口,变量全集见上表;
  2. user/ 目录挂载层:/opt/yourls/user 挂到容器 /var/www/html/user,可放入插件(plugins/)、静态页(pages/)、翻译(languages/);YOURLS 官方镜像文档注明插件/页面/语言分别放入上述子目录后在后台启用,并保证读写执行权限;
  3. 高级常量层:极少数环境变量不覆盖的常量(如 YOURLS_COOKIEKEY 显式固定值)可在 compose 里直接给值;若需在 config.php 之外追加 PHP 级定制(钩子、过滤器),可挂载自定义 PHP 文件进 user/ 并由 YOURLS 加载机制引入。裸机形态下手工编辑 user/config.php 的完整参数说明,见本专栏 《YOURLS 1.10.6 配置参数详解》。

八、等价 docker run

不使用 compose 时,以下两条 docker run 等价于第四节的编排(先建网络,后起库与应用):

docker network create --subnet 10.89.59.0/24 yourls-net

实测回显(已存在时):

Error response from daemon: network with name yourls-net already exists
# 1. 启动 MySQL
docker run -d --name yourls-1.10.6-mysql \
  --network yourls-net \
  -e MYSQL_ROOT_PASSWORD="q1w2e3r4" \
  -e MYSQL_DATABASE="yourls" \
  -e MYSQL_USER="yourls" \
  -e MYSQL_PASSWORD="q1w2e3r4" \
  -v /opt/yourls/mysql:/var/lib/mysql \
  mysql:8.0

# 2. 启动 YOURLS
docker run -d --name yourls-1.10.6-web \
  --network yourls-net \
  -p 8134:8080 \
  -e YOURLS_SITE="http://192.168.1.200:8134" \
  -e YOURLS_USER="admin" \
  -e YOURLS_PASS="q1w2e3r4" \
  -e YOURLS_DB_HOST="mysql" \
  -e YOURLS_DB_USER="yourls" \
  -e YOURLS_DB_PASS="q1w2e3r4" \
  -e YOURLS_DB_NAME="yourls" \
  -v /opt/yourls/user:/var/www/html/user \
  yourls:1.10.6

启动后的安装向导、登录、建链步骤与 4.4–4.6 完全一致。

九、常用运维命令与常见问题

常用运维命令:

docker compose ps                      # 查看双服务状态
docker compose logs -f yourls          # 跟踪 YOURLS 日志
docker compose restart yourls          # 只重启 YOURLS
docker compose down                    # 停止并移除(数据在宿主机目录,不受影响)
docker compose pull && docker compose up -d   # 升级:改 yml 中 image tag 后拉新启动

常见问题(含实测排障实录):

Q1:根路径访问 403 Forbidden? 安装完成前根路径必然 403(短链表不存在),从 /admin/ 进安装向导即可;安装完成后根路径就是短链跳转入口,不存在首页。

Q2:登录后又被 301 踢回登录页,cookie 不生效? 排障实录:实测中用 http://localhost:8134/admin/index.php 提交登录,返回 301 redirect:http://192.168.1.200:8134/admin/index.php——YOURLS 把请求重定向到 YOURLS_SITE 定义的站点地址,而 localhost 访问与站点地址不一致导致会话 cookie 域不匹配。解决:始终用与 YOURLS_SITE 完全一致的地址访问(本例为 http://192.168.1.200:8134),换用正式域名时同步修改 YOURLS_SITE 并重启。

Q3:YOURLS 容器反复重启或日志报数据库连接失败? MySQL 首次初始化(生成数据目录)需要 20–40 秒,YOURLS entrypoint 会等待数据库就绪;若仍失败,检查 YOURLS_DB_HOST/USER/PASS 与 mysql 服务的 MYSQL_USER/MYSQL_PASSWORD 是否一一对应、MYSQL_DATABASE 是否与 YOURLS_DB_NAME 一致(本编排均为 yourls)。

Q4:启动日志出现 AH00558: apache2: Could not reliably determine the server's fully qualified domain name? 无害警告,Apache 未配置全局 ServerName 时的标准提示,YOURLS 功能不受影响;介意可在 compose 加自定义 Apache 配置挂载消除。

Q5:API 返回 {"message":"Please log in","errorCode":"403"}? 私密模式(YOURLS_PRIVATE=true 默认开启)下 API 必须带凭据(username/password 参数或 signature 签名),认证方式详见本专栏 《YOURLS 1.10.6 API 使用详解》。

Q6:创建重复长链报 409? 1.10.5 起重复长 URL 返回 HTTP 409 Conflict(旧版为 400),属预期行为;需要同一长链多条短链时把 YOURLS_UNIQUE_URLS 设为 false(本编排已如此配置)。

十、参考链接