本文写于 2023年03月25日,距今已超过 1 年,距 2023年03月25日 的最后一次修改也已超过 3 个月,部分内容可能已经过时,您可以按需阅读。如果图片无法显示或者下载链接失效,请给我反馈,谢谢!


Visits: 260

0 0 投票数
评分

这是一款适用于个人或团队场景使用的开源文档/Wiki软件,Outline。

我在这两篇文章(https://soulteary.com/2021/09/05/opensource-documentation-wiki-software-outline-part-1.html、https://soulteary.com/2021/09/11/opensource-documentation-wiki-software-outline-part-2.html)看到了这个工具,打算试一试,结合那篇文章中罗列的信息,加上我自己的理解,基本上可以把这款软件的特点罗列如下:

  • 能够将数据完全自托管管理,不涉及私有格式,而且可以随时导出成开源格式(例如 PDF、Markdown)
  • Markdown 语法、所见即所得,可以直接上传附件和图片,也支持代码片段、数学公式
  • 类 Notion,允许插入富文本内容、卡片式渲染
  • 个人使用和管理文档,并在需要时可以邀请用户协同编辑、分享文档
  • 层级嵌套,方便分类和整理
  • 历史版本记录,并在文档被改动/编辑后有邮件提醒

缺点也不少:

  • 不支持本地登录,只支持 OAuth 登录
  • 不支持本地存储,只能使用 AWS S3 或者兼容 S3 协议的存储,例如 Minio
  • 从文档中删除图片,未必能清理后端存储中的文件
  • 没有评论功能,权限管理的层级不够丰富
  • 很多设置项不能在网页端修改,只能重启 docker-compose
  • 极度简陋的自托管支持,只能靠社区成员的零碎的讨论来解决问题

官方提供的 docker-compose 安装教程(https://docs.getoutline.com/s/hosting/doc/docker-7pfeLP5a8t)非常简陋,有很多细节都没有解释,所以并不是开箱即用的。根据官方提供的模板,做了很多尝试,我终于搭建起来了。我把缺少的细节都记录一下。

我的 docker-compose 采用 env_file 读取环境参数,然后把环境参数都写在 .env 文件里面,这样我就也可以在 docker-compose.yml 里面用环境变量,方便些。

我把 https-portal 删掉了,我打算直接开放 outline 的 3000 端口,之后用 NGINX 转发;Redis、Postgres 都只用容器内网络通讯,不开放端口;Minio 我开放了 9000 端口,也绑定了一个控制台,因为这样也可以方便后面管理(虽然理论上它也只需要容器内通讯)。

outline:
    image: ${DOCKER_OUTLINE_IMAGE_NAME}
    container_name: outline
    env_file: ./.env
    ports:
      - "9303:3000"
    restart: always
    networks:
      - outline
    extra_hosts:
      - "${DOCKER_OUTLINE_HOSTNAME}:0.0.0.0"
    depends_on:
      - postgres
      - redis
      - storage
  image: ${DOCKER_REDIS_IMAGE_NAME}
    env_file: ./.env
    volumes:
      - ./redis.conf:/redis.conf
    container_name: ${DOCKER_REDIS_HOSTNAME}
    restart: always
    networks:
      - outline
    command: ["redis-server", "/redis.conf"]
postgres:
    image: ${DOCKER_POSTGRES_IMAGE_NAME}
    env_file: ./.env
    volumes:
      - ./database-data:/var/lib/postgresql/data
    container_name: ${DOCKER_POSTGRES_HOST}
    restart: always
    networks:
      - outline
  image: ${DOCKER_MINIO_IMAGE_NAME}
    container_name: ${OUTLINE_MINIO}
    env_file: ./.env
    ports:
      - "${DOCKER_OUTLINE_MINIO_PORT}:9000"
      - "${DOCKER_OUTLINE_MINIO_ADMIN_PORT}:9001"
    command: "minio server /data --console-address 0.0.0.0:${DOCKER_OUTLINE_MINIO_ADMIN_PORT}"
    restart: always
    extra_hosts:
      - "${DOCKER_MINIO_HOSTNAME}:0.0.0.0"
      - "${DOCKER_MINIO_ADMIN_DOMAIN}:0.0.0.0"
    volumes:
      - ./storage-data:/data
    networks:
       - outline
networks:
  outline:
    external: true

.env 文件保留了环境变量,根据自己的情况修改。

所有的 IMAGE_NAME 我都用了此刻(2023-03-23)最新的。

DOCKER_OUTLINE_IMAGE_NAME=outlinewiki/outline:0.68.1
DOCKER_POSTGRES_IMAGE_NAME=postgres:15.2
DOCKER_REDIS_IMAGE_NAME=redis:7.2-rc1
DOCKER_MINIO_IMAGE_NAME=minio/minio:RELEASE.2023-03-22T06-36-24Z

Outline 相关的参数如下:

DOCKER_OUTLINE_HOSTNAME=outline.example.com
OUTLINE_URL=https://${DOCKER_OUTLINE_HOSTNAME}
URL=${OUTLINE_URL}
PORT=3000

Postgres 和 Redis 的参数没有特殊的地方,只要注意容器内地址通讯即可,例如:

DATABASE_URL=postgres://${DOCKER_POSTGRES_USER}:${DOCKER_POSTGRES_PASS}@${DOCKER_POSTGRES_HOST}:5432/${DOCKER_POSTGRES_DBNAME}

当然也要注意把改过名字的参数类型映射回 docker 的环境变量会用的名字,以及我 disable 了 PostgreSQL 的 SSL。

POSTGRES_USER=${DOCKER_POSTGRES_USER}
PGSSLMODE=disable

Outline 不支持本地存储,他只开放了 AWS S3 存储,但是也可以使用兼容 S3 协议的其他存储(比如 Minio)。

Minio 是一个兼容 S3 协议的存储,简单说就是启动了一个服务之后,它把 S3 处理请求解析后,把文件存放到本地。docker-compose 中我们启动了这个 Minio 的 docker 镜像,并把 /data 目录挂载到了本地持久存储。

初始化 Minio 的时候,我提供了 MINIO_ROOT_USERMINIO_ROOT_PASSWORD,这两个后面会当作 S3 的 Access ID 和 Secret Key 来使用。它们都只由小写 a-z 和数字组成,前者 16 位,后者 64 位,我使用 https://onlinerandomtools.com/generate-random-string 生成。

因为是自己的 Minio,所以 MINIO_REGION_NAME 就可以随便写了,这个后面会当作 S3 的 Region 来使用。

DOCKER_MINIO_HOSTNAME=minio.example.com
DOCKER_MINIO_ADMIN_DOMAIN=minio-admin.example.com

为了管理方便,docker-compose 还启动了 9001 管理界面,这里我们做一下重定向。

MINIO_BROWSER=on
MINIO_BROWSER_REDIRECT_URL=https://${DOCKER_MINIO_ADMIN_DOMAIN}
DOCKER_OUTLINE_MINIO_PORT=9000
DOCKER_OUTLINE_MINIO_ADMIN_PORT=9001

后面大部分参数都可以按照官方示例(https://github.com/outline/outline/blob/main/.env.sample)中的说明来操作,比如使用 openssl rand -hex 32 来生成 SECRET KEY 等等。

AWS 存储就使用 Minio。

AWS_ACCESS_KEY_ID=${MINIO_ROOT_USER}
AWS_SECRET_ACCESS_KEY=${MINIO_ROOT_PASSWORD}
AWS_REGION=${MINIO_REGION_NAME}
AWS_S3_UPLOAD_BUCKET_URL=https://${DOCKER_MINIO_HOSTNAME}
AWS_S3_UPLOAD_BUCKET_NAME=outline
AWS_S3_UPLOAD_MAX_SIZE=26214400
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private

登录是个大麻烦,Outline 不支持本地用户登录,它目前只支持 Slack、Azure、Google 以及 OIDC,所以需要去各平台生成 OAuth Token,还挺麻烦的。好在 GitLab 支持标准 OIDC 协议,而我有一个私有部署的 GitLab 实例,就直接接入了。

首先填写通用的信息,如下:

OIDC_AUTH_URI=https://gitlab.example.com/oauth/authorize
OIDC_TOKEN_URI=https://gitlab.example.com/oauth/token
OIDC_USERINFO_URI=https://gitlab.example.com/oauth/userinfo
OIDC_USERNAME_CLAIM=username
OIDC_DISPLAY_NAME=GitLab
OIDC_SCOPES=openid email

接着去管理中心 – 应用 – 实例 OAuth 应用程序 (https://gitlab.example.com/admin/applications),新建一个应用。

回调 URI 写 https://outline.example.com/auth/oidc.callback,范围勾选 openidemail,视情况选择是否可信和是否私密。

image

点击保存应用之后,把 CLIENT_IDCLIENT_SECRET 填写到 .env 文件中。

还有剩下一些杂项,根据情况修改。

我把 FORCE_HTTPS 改成了 falseDEFAULT_LANGUAGE 改成了 zh_CN。因为我不打算使用 Slack,所以我还把 Slack 的默认数据都删掉了。我启用了 SMTP,我用的是 mailgun 的服务,所以修改了 TLS_CIPHERS 以支持 587 TLS。

SMTP_TLS_CIPHERS=TLSv1.2
SMTP_SECURE=false

接下去还要修改 NGINX 配置。

首先是 Outline。

Outline 的核心是 proxy_pass 的时候要加上一些 Header。

location / {
    proxy_pass        http://localhost:9303;

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_set_header Access-Control-Allow-Origin "*";
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header Host $host;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Scheme $scheme;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_redirect off;
}

如果遇到跨域的问题还要加 Allow-Origin。

add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS,PUT;
add_header Access-Control-Allow-Headers Origin,X-Requested-With,Content-Type,Accept,Authorization;

if ($request_method = 'OPTIONS') {
  return 204;
}

接着是 Minio。

Minio 直接转发就可以,不要带 Allow-Origin,也不要带 proxy_set_header,不然可能会出现奇怪的 CORS 错误(因为 Minio 有默认的 Allow * 的配置),或者可能出现管理界面 400 错误。

# minio-admin.example.com
location / {
    proxy_pass        http://localhost:9001;
}
# minio.example.com
location / {
    proxy_pass        http://localhost:9000;
}

接下来要新建一个 Minio 存储桶。

这一步也可以使用命令行完成,例如运行一个 minio/mc 的客户端,使用 /usr/bin/mc mb 来创建一个桶,并设置访问权限。

我访问了 minio.example.com,这会被自动重定向到 minio-admin.example.com,我使用刚才上面的 Access ID 和 Secret Key 作为用户名和密码登录,然后选择左侧 Buckets,新建一个存储桶,名称就用 docker-compose 或者 .env 文件中设置的。上例是 outline。

image
image

回到 docker-compose 和 .env 的目录,启动 docker-compose up -d

首次运行还需要创建数据库以及执行迁移。

docker-compose run --rm outline yarn db:create --env=production-ssl-disabled
docker-compose run --rm outline yarn db:migrate --env=production-ssl-disabled

运行之后可能还要根据自己的情况执行下面这个命令。这个命令是解决在内存不足的情况下后台保存可能会失败的问题。这个值是在主机级别,而不是容器级别。Redis 推荐 1 的原因是他们的后台保存机制(https://redis.io/topics/faq#background-saving-fails-with-a-fork-error-under-linux-even-if-i-have-a-lot-of-free-ram)。

sysctl vm.overcommit_memory=1

此时回到 outline.example.com 应该一切正常了。

image
0 0 投票数
评分
1条留言
订阅评论
提醒
guest

在点击发表评论按钮时,网络请求的数据包含浏览器版本、操作系统版本和 IP 地址;您的网络服务提供商、雇主或学校、政府机构可能会看到您的访问活动;根据浏览器默认行为、操作系统设置和安全防护软件的设置不同,您的浏览器可能会也可能不会在本地 Cookies 缓存您输入的用户名、邮箱以便下次评论使用。

请对自己的言行负责。

您想以什么身份发表评论
邮箱将在您的评论被回复时给您通知
(可选)如果您也有个人网站,不妨分享一下
我对这篇文章的评分
这篇文章给您带来多大帮助
1 评论
内联反馈
查看所有评论
خبرة المصنع
خبرة المصنع Chrome 114.0.0.0 Windows 10
游客
2023年12月28日 21:50

I do not even know how I ended up here, but I thought this post was great. I don’t know who you are but definitely you’re going to a famous blogger if you aren’t already 😉 Cheers!