outline 介绍
Outline 是一个开源的Wiki 知识库和团队协作文档管理工具,美观、实时协作、功能丰富且兼容 Markdown,设计用于帮助团队和组织有效地创建、共享和管理文档。
注意:官方提供的服务提供30天试用,之后每月10美元或每年100美元。由于outline是开源工具,完全支持自建outline。
官方文档:https://docs.getoutline.com/s/hosting
outline部署规划
部署前置要求:
- 准备一台云服务器,例如 阿里云ECS服务器 或轻量服务器,本部署示例购买1台阿里云ECS服务器(包年包月购买3年具有2.6折的最低优惠),服务器配置为2核CPU/4G内存/100G磁盘,绑定公网IP,带宽按流量计费;
- 准备操作系统,本示例使用
Ubuntu 22.04 LTS
操作系统; - 准备可用域名,并配置好域名解析,本示例使用阿里云域名;
- SSL证书,由
https-portal
通过Let's Encrypt
自动申请免费证书; - 主机上已安装
docker
和docker compose
。
整体部署架构图:
部署组件清单:
我们采用 https-portal 作为反向代理和负载均衡器,本地磁盘
作为文件存储,Keycloak
作为身份和访问管理工具,并且利用 PostgreSQL
和 Redis
作为数据库和缓存,来支撑 Outline
的运行。
名称 | 说明 | 版本 |
---|---|---|
https-portal | 基于nginx实现的反向代理和负载均衡器,用于管理和路由 HTTP 请求,提供 SSL 终止和路径路由功能。 | 1.24.1 |
Keycloak | 开源的身份和访问管理工具,用于提供单点登录和身份认证功能,支持 OAuth2 和 SAML 协议。 | 25.0.4 |
Outline | 开源的知识库和文档管理工具,用于团队协作、文档编辑和知识共享。 | 0.78.0 |
Redis | 高性能的内存数据存储,用于缓存和会话管理,提高应用性能。 | 7.4.0 |
PostgreSQL | 开源的关系型数据库管理系统,用于存储 Outline 的持久化数据。 | 16.2 |
Outline文件存储选择
Outline文件存储支持以下两种形式,本示例采用Local file system
,以简化部署:
Local file system
:如果希望将文件上传存储在运行 Outline 的同一服务器上,则可以使用本地文件系统存储选项来实现。AWS S3
:由于AWS S3是对象存储的标准,因此不一定使用云上的AWS S3存储,例如可以通过自建minio来实现,完整的支持列表见下表。
Outline 可以与绝大多数 S3 兼容的 API 一起使用,因为使用的是可用 API 接口的一个非常小的子集,以下内容已经过社区成员的测试。
Service | Compatible |
---|---|
Amazon S3 | ✅ |
Minio | ✅ |
DigitalOcean Object Storage | ✅ |
Alibaba Cloud / Aliyun OSS | ✅ (discussion) |
Scaleway | ✅ (discussion) |
Cloudflare R2 | ❌ (discussion) |
Backblaze | ❌ (discussion) |
OVH Object Storage | ❌ |
身份验证提供程序选择
Outline 可以配置为接受各种 SSO、OIDC 和 SAML 身份验证选项,具体取决于所使用的版本,本部署示例使用支持OIDC的keycloak。
- Microsoft / Azure
- Slack
- OIDC
- Discord
- GitLab
- Email magic link
- SAML
- Okta
- OneLogin
注:Outline不支持邮箱+密码认证
前置配置工作
1. 配置域名解析
域名配置清单:
域名地址 | 解析A记录值 | 说明 |
---|---|---|
https://docs.example.com |
120.79.11.68 | 用于访问 Outline 应用程序的主域名,提供知识库和文档管理功能,供团队成员进行协作和编辑。 |
https://auth.example.com |
120.79.11.68 | 用于访问 Keycloak 身份认证服务的域名,提供用户身份验证、授权管理和单点登录服务。 |
说明:
- 基本域名为
example.com
,前缀可自定义,请将example.com
域名更改为您自己的域名; - 示例公网IP地址
120.79.12.68
为Outline云主机的公网IP地址。
域名解析A记录示例:
2. 配置安全组规则
安全组规则放通清单:
端口号 | 协议 | 用途说明 |
---|---|---|
80 | TCP | Traefik 代理的 HTTP 端口,用于处理未加密的 Web 流量。 |
443 | TCP | Traefik 代理的 HTTPS 端口,用于处理加密的 Web 流量(SSL/TLS)。 |
安全组配置示例
3. 创建目录结构
创建组件安装目录
mkdir -p /data/{
keycloak,outline}
确认目录结构
root@ecs01:~# apt install -y tree
root@ubuntu:~# tree /data/
/data/
├── keycloak
└── outline
2 directories, 0 files
4. 创建docker网络
手动创建docker网络
docker network create stack-network
确认docker网络创建成功
root@ecs01:~# docker network ls
NETWORK ID NAME DRIVER SCOPE
55509fbd4813 bridge bridge local
00b8d117c799 host host local
a1e5cf67efab none null local
f0f830bcea64 stack-network bridge local
keycloak部署
创建环境变量文件
cd /data/keycloak
cat >/data/keycloak/.env<<EOF
# Keycloak Variables
KEYCLOAK_POSTGRES_IMAGE_TAG=docker.io/library/postgres:16.2
KEYCLOAK_IMAGE_TAG=docker.io/keycloak/keycloak:25.0.4
KEYCLOAK_DB_NAME=keycloakdb
KEYCLOAK_DB_USER=keycloakdbuser
KEYCLOAK_DB_PASSWORD=keycloakdbpass
KEYCLOAK_ADMIN_USERNAME=keycloakadmin
KEYCLOAK_ADMIN_PASSWORD=keycloakadminpass
KEYCLOAK_HOSTNAME=auth.example.com
EOF
参数说明
KEYCLOAK_POSTGRES_IMAGE_TAG=docker.io/library/postgres:16.2
: 指定用于 Keycloak 数据库的 PostgreSQL 镜像版本标签。KEYCLOAK_IMAGE_TAG=docker.io/keycloak/keycloak:25.0.4
: 指定 Keycloak 服务的镜像版本标签。KEYCLOAK_DB_NAME=keycloakdb
: Keycloak 使用的数据库名称。KEYCLOAK_DB_USER=keycloakdbuser
: 连接 Keycloak 数据库的用户名。KEYCLOAK_DB_PASSWORD=keycloakdbpass
: 连接 Keycloak 数据库的用户密码。KEYCLOAK_ADMIN_USERNAME=keycloakadmin
: Keycloak 管理员账户的用户名,用于登录 Keycloak 管理控制台。KEYCLOAK_ADMIN_PASSWORD=keycloakadminpass
: Keycloak 管理员账户的密码,用于登录 Keycloak 管理控制台。KEYCLOAK_HOSTNAME=auth.example.com
: 指定 Keycloak 服务的主机名,用于通过域名访问 Keycloak,替换为您自己的域名。
创建docker-compose文件
cat >/data/keycloak/docker-compose.yaml<<'EOF'
name: 'keyclock'
networks:
stack-network:
external: true
volumes:
keycloak-postgres:
services:
postgres-keycloak:
image: ${
KEYCLOAK_POSTGRES_IMAGE_TAG}
volumes:
- keycloak-postgres:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${
KEYCLOAK_DB_NAME}
POSTGRES_USER: ${
KEYCLOAK_DB_USER}
POSTGRES_PASSWORD: ${
KEYCLOAK_DB_PASSWORD}
networks:
- stack-network
healthcheck:
test: [ "CMD", "pg_isready", "-q", "-d", "${KEYCLOAK_DB_NAME}", "-U", "${KEYCLOAK_DB_USER}" ]
interval: 10s
timeout: 5s
retries: 3
start_period: 60s
restart: unless-stopped
keycloak:
image: ${
KEYCLOAK_IMAGE_TAG}
command: start-dev
environment:
KC_DB: postgres
KC_DB_URL_HOST: postgres-keycloak
KC_DB_URL_DATABASE: ${
KEYCLOAK_DB_NAME}
KC_DB_USERNAME: ${
KEYCLOAK_DB_USER}
KC_DB_PASSWORD: ${
KEYCLOAK_DB_PASSWORD}
KC_DB_SCHEMA: public
KEYCLOAK_ADMIN: ${
KEYCLOAK_ADMIN_USERNAME}
KEYCLOAK_ADMIN_PASSWORD: ${
KEYCLOAK_ADMIN_PASSWORD}
KC_HEALTH_ENABLED: 'true'
KC_HOSTNAME: ${
KEYCLOAK_HOSTNAME}
KC_HTTP_ENABLED: 'true'
KC_PROXY_HEADERS: 'xforwarded'
PROXY_ADDRESS_FORWARDING: 'true'
networks:
- stack-network
healthcheck:
test:
- "CMD-SHELL"
- |
exec 3<>/dev/tcp/localhost/9000 &&
echo -e 'GET /health/ready HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' >&3 &&
cat <&3 | tee /tmp/healthcheck.log | grep -q '200 OK'
interval: 10s
timeout: 5s
retries: 3
start_period: 90s
restart: unless-stopped
depends_on:
postgres-keycloak:
condition: service_healthy
启动keycloak容器
docker compose up -d
确认容器运行状态
root@ecs01:/data/keycloak# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
keyclock-keycloak-1 docker.io/keycloak/keycloak:25.0.4 "/opt/keycloak/bin/k…" keycloak 4 hours ago Up 4 hours (healthy) 8080/tcp, 8443/tcp, 9000/tcp
keyclock-postgres-keycloak-1 docker.io/library/postgres:16.2 "docker-entrypoint.s…" postgres-keycloak 4 hours ago Up 4 hours (healthy) 5432/tcp
root@ecs01:/data/keycloak#
outline部署
参考:官方示例环境变量文件:https://github.com/outline/outline/blob/main/.env.sample
创建环境变量文件
cd /data/outline
cat >/data/outline/docker.env<<EOF
# –––––––––––––––– REQUIRED ––––––––––––––––
NODE_ENV=production
# Generate a hex-encoded 32-byte random key. You should use `openssl rand -hex 32`
# in your terminal to generate a random value.
SECRET_KEY=98ea98adade7b6af8c4252651b195d4083c484b833b8e0e638623ae60cc7d24e
# Generate a unique random key. The format is not important but you could still use
# `openssl rand -hex 32` in your terminal to produce this.
UTILS_SECRET=98ea98adade7b6af8c4252651b195d4083c484b833b8e0e638623ae60cc7d24e
# For production point these at your databases, in development the default
# should work out of the box.
DATABASE_URL=postgres://user:pass@postgres:5432/outline
DATABASE_CONNECTION_POOL_MIN=
DATABASE_CONNECTION_POOL_MAX=
# Uncomment this to disable SSL for connecting to Postgres
PGSSLMODE=disable
# For redis you can either specify an ioredis compatible url like this
REDIS_URL=redis://redis:6379
# or alternatively, if you would like to provide additional connection options,
# use a base64 encoded JSON connection option object. Refer to the ioredis documentation
# for a list of available options.
# Example: Use Redis Sentinel for high availability
# {"sentinels":[{"host":"sentinel-0","port":26379},{"host":"sentinel-1","port":26379}],"name":"mymaster"}
# REDIS_URL=ioredis://eyJzZW50aW5lbHMiOlt7Imhvc3QiOiJzZW50aW5lbC0wIiwicG9ydCI6MjYzNzl9LHsiaG9zdCI6InNlbnRpbmVsLTEiLCJwb3J0IjoyNjM3OX1dLCJuYW1lIjoibXltYXN0ZXIifQ==
# URL should point to the fully qualified, publicly accessible URL. If using a
# proxy the port in URL and PORT may be different.
URL=https://docs.example.com
PORT=3000
# See [documentation](docs/SERVICES.md) on running a separate collaboration
# server, for normal operation this does not need to be set.
COLLABORATION_URL=
# Specify what storage system to use. Possible value is one of "s3" or "local".
# For "local", the avatar images and document attachments will be saved on local disk.
FILE_STORAGE=local
# If "local" is configured for FILE_STORAGE above, then this sets the parent directory under
# which all attachments/images go. Make sure that the process has permissions to create
# this path and also to write files to it.
FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data
# Maximum allowed size for the uploaded attachment.
FILE_STORAGE_UPLOAD_MAX_SIZE=262144000
# Override the maximum size of document imports, generally this should be lower
# than the document attachment maximum size.
FILE_STORAGE_IMPORT_MAX_SIZE=
# Override the maximum size of workspace imports, these can be especially large
# and the files are temporary being automatically deleted after a period of time.
FILE_STORAGE_WORKSPACE_IMPORT_MAX_SIZE=
# To support uploading of images for avatars and document attachments in a distributed
# architecture an s3-compatible storage can be configured if FILE_STORAGE=s3 above.
AWS_ACCESS_KEY_ID=get_a_key_from_aws
AWS_SECRET_ACCESS_KEY=get_the_secret_of_above_key
AWS_REGION=xx-xxxx-x
AWS_S3_ACCELERATE_URL=
AWS_S3_UPLOAD_BUCKET_URL=http://s3:4569
AWS_S3_UPLOAD_BUCKET_NAME=bucket_name_here
AWS_S3_FORCE_PATH_STYLE=true
AWS_S3_ACL=private
# –––––––––––––– AUTHENTICATION ––––––––––––––
# Third party signin credentials, at least ONE OF EITHER Google, Slack,
# or Microsoft is required for a working installation or you'll have no sign-in
# options.
# To configure Slack auth, you'll need to create an Application at
# => https://api.slack.com/apps
#
# When configuring the Client ID, add a redirect URL under "OAuth & Permissions":
# https://<URL>/auth/slack.callback
SLACK_CLIENT_ID=get_a_key_from_slack
SLACK_CLIENT_SECRET=get_the_secret_of_above_key
# To configure Google auth, you'll need to create an OAuth Client ID at
# => https://console.cloud.google.com/apis/credentials
#
# When configuring the Client ID, add an Authorized redirect URI:
# https://<URL>/auth/google.callback
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# To configure Microsoft/Azure auth, you'll need to create an OAuth Client. See
# the guide for details on setting up your Azure App:
# => https://wiki.generaloutline.com/share/dfa77e56-d4d2-4b51-8ff8-84ea6608faa4
AZURE_CLIENT_ID=
AZURE_CLIENT_SECRET=
AZURE_RESOURCE_APP_ID=
# To configure generic OIDC auth, you'll need some kind of identity provider.
# See documentation for whichever IdP you use to acquire the following info:
# Redirect URI is https://<URL>/auth/oidc.callback
OIDC_CLIENT_ID=outline
OIDC_CLIENT_SECRET=Bz8GjPI9E7QqAZcGoQRaktEsW155V5u2
OIDC_AUTH_URI=https://auth.example.com/realms/outline/protocol/openid-connect/auth
OIDC_TOKEN_URI=https://auth.example.com/realms/outline/protocol/openid-connect/token
OIDC_USERINFO_URI=https://auth.example.com/realms/outline/protocol/openid-connect/userinfo
OIDC_LOGOUT_URI=
# Specify which claims to derive user information from
# Supports any valid JSON path with the JWT payload
OIDC_USERNAME_CLAIM=preferred_username
# Display name for OIDC authentication
OIDC_DISPLAY_NAME=OpenID Connect
# Space separated auth scopes.
OIDC_SCOPES=openid profile email
# To configure the GitHub integration, you'll need to create a GitHub App at
# => https://github.com/settings/apps
#
# When configuring the Client ID, add a redirect URL under "Permissions & events":
# https://<URL>/api/github.callback
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
GITHUB_APP_NAME=
GITHUB_APP_ID=
GITHUB_APP_PRIVATE_KEY=
# To configure Discord auth, you'll need to create a Discord Application at
# => https://discord.com/developers/applications/
#
# When configuring the Client ID, add a redirect URL under "OAuth2":
# https://<URL>/auth/discord.callback
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
# DISCORD_SERVER_ID should be the ID of the Discord server that Outline is
# integrated with.
# Used to verify that the user is a member of the server as well as server
# metadata such as nicknames, server icon and name.
DISCORD_SERVER_ID=
# DISCORD_SERVER_ROLES should be a comma separated list of role IDs that are
# allowed to access Outline. If this is not set, all members of the server
# will be allowed to access Outline.
# DISCORD_SERVER_ID and DISCORD_SERVER_ROLES must be set together.
DISCORD_SERVER_ROLES=
# –––––––––––––––– OPTIONAL ––––––––––––––––
# Base64 encoded private key and certificate for HTTPS termination. This is only
# required if you do not use an external reverse proxy. See documentation:
# https://wiki.generaloutline.com/share/1c922644-40d8-41fe-98f9-df2b67239d45
SSL_KEY=
SSL_CERT=
# If using a Cloudfront/Cloudflare distribution or similar it can be set below.
# This will cause paths to javascript, stylesheets, and images to be updated to
# the hostname defined in CDN_URL. In your CDN configuration the origin server
# should be set to the same as URL.
CDN_URL=
# Auto-redirect to https in production. The default is true but you may set to
# false if you can be sure that SSL is terminated at an external loadbalancer.
FORCE_HTTPS=true
# Have the installation check for updates by sending anonymized statistics to
# the maintainers
ENABLE_UPDATES=true
# How many processes should be spawned. As a reasonable rule divide your servers
# available memory by 512 for a rough estimate
WEB_CONCURRENCY=1
# You can remove this line if your reverse proxy already logs incoming http
# requests and this ends up being duplicative
DEBUG=http
# Configure lowest severity level for server logs. Should be one of
# error, warn, info, http, verbose, debug and silly
LOG_LEVEL=info
# For a complete Slack integration with search and posting to channels the
# following configs are also needed, some more details
# => https://wiki.generaloutline.com/share/be25efd1-b3ef-4450-b8e5-c4a4fc11e02a
#
SLACK_VERIFICATION_TOKEN=your_token
SLACK_APP_ID=A0XXXXXXX
SLACK_MESSAGE_ACTIONS=true
# For Dropbox integration, follow these instructions to get the key https://www.dropbox.com/developers/embedder#setup
# and do not forget to whitelist your domain name in the app settings
DROPBOX_APP_KEY=
# Optionally enable Sentry (sentry.io) to track errors and performance,
# and optionally add a Sentry proxy tunnel for bypassing ad blockers in the UI:
# https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option)
SENTRY_DSN=
SENTRY_TUNNEL=
# To support sending outgoing transactional emails such as "document updated" or
# "you've been invited" you'll need to provide authentication for an SMTP server
SMTP_HOST=
SMTP_PORT=
SMTP_USERNAME=
SMTP_PASSWORD=
SMTP_FROM_EMAIL=
SMTP_REPLY_EMAIL=
SMTP_TLS_CIPHERS=
SMTP_SECURE=true
# The default interface language. See translate.getoutline.com for a list of
# available language codes and their rough percentage translated.
DEFAULT_LANGUAGE=en_US
# Optionally enable rate limiter at application web server
RATE_LIMITER_ENABLED=true
# Configure default throttling parameters for rate limiter
RATE_LIMITER_REQUESTS=1000
RATE_LIMITER_DURATION_WINDOW=60
# Iframely API config
#IFRAMELY_URL=
#IFRAMELY_API_KEY=
EOF
参数说明
FILE_STORAGE=local
:使用本地存储FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data
指定本地存储路径1IFRAMELY_URL=
:注释该行,避免启动报错OIDC_CLIENT_SECRET
:在部署keycloak后再进行配置
参考:官方示例docker-compose文件:https://docs.getoutline.com/s/hosting/doc/docker-7pfeLP5a8t
创建docker-compose文件
cat >/data/outline/docker-compose.yaml<<'EOF'
name: "outline"
networks:
stack-network:
external: true
services:
outline:
image: docker.getoutline.com/outlinewiki/outline:0.78.0
env_file: ./docker.env
networks:
- stack-network
ports:
- "3000:3000"
volumes:
- storage-data:/var/lib/outline/data
depends_on:
- postgres
- redis
redis:
image: redis:7.4.0
env_file: ./docker.env
networks:
- stack-network
ports:
- "6379:6379"
volumes:
- ./redis.conf:/redis.conf
command: ["redis-server", "/redis.conf"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 30s
retries: 3
postgres:
image: postgres:16.2
env_file: ./docker.env
networks:
- stack-network
ports:
- "5432:5432"
volumes:
- database-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD", "pg_isready", "-d", "outline", "-U", "user"]
interval: 30s
timeout: 20s
retries: 3
environment:
POSTGRES_USER: 'user'
POSTGRES_PASSWORD: 'pass'
POSTGRES_DB: 'outline'
https-portal:
image: steveltn/https-portal:1.24.1
env_file: ./docker.env
networks:
- stack-network
ports:
- '80:80'
- '443:443'
#links:
# - outline
restart: always
volumes:
- https-portal-data:/var/lib/https-portal
healthcheck:
test: ["CMD", "service", "nginx", "status"]
interval: 30s
timeout: 20s
retries: 3
environment:
DOMAINS: 'docs.example.com -> http://outline:3000, auth.example.com -> http://keycloak:8080'
STAGE: 'production'
WEBSOCKET: 'true'
CLIENT_MAX_BODY_SIZE: '0'
volumes:
https-portal-data:
storage-data:
database-data:
启动outline容器
docker compose up -d
确认容器运行状态
root@ecs01:/data/outline# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
outline-https-portal-1 steveltn/https-portal:1.24.1 "/init" https-portal 50 seconds ago Up 3 seconds (healthy) 0.0.0.0:80->80/tcp, :::80->80/tcp, 0.0.0.0:443->443/tcp, :::443->443/tcp
outline-outline-1 outlinewiki/outline:0.78.0 "docker-entrypoint.s…" outline 4 hours ago Up 4 hours (healthy) 3000/tcp
outline-postgres-outline-1 postgres:16.2 "docker-entrypoint.s…" postgres-outline 4 hours ago Up 4 hours (healthy) 5432/tcp
outline-redis-1 redis:7.4.0 "docker-entrypoint.s…" redis 4 hours ago Up 4 hours (healthy) 6379/tcp
root@ecs01:/data/outline#
keycloak配置
浏览器访问keycloak控制台: https://auth.example.com
,输入keycloak登录账号keycloakadmin
及设置的密码。
登录后下拉选择Create realm,新建realm
指定Realm name名称为outline
接下来,在“Manage”部分中选择“Clients”,然后单击“Create client”按钮。
在“Client type”字段中,选择“OpenID Connect”。
在“Client ID”字段中,输入“outline”(小写),然后单击“下一步”按钮。
接下来,您需要启用“Client authentication”并在“Authentication flow”部分中选择“Standard flow”。应禁用所有其他值。
单击“下一步”按钮。
设置登录选项
# Root URL
https://docs.example.com/
# Home URL
https://docs.example.com/
# Valid redirect URIs
https://docs.example.com/*
请注意,docs.example.com
是我服务的域名。因此,您需要指定您的域名,该域名指向安装了 https-portals 服务的服务器的 IP 地址,这会将请求重定向到 Outline。
单击“保存”按钮。
导航到“Credentials”选项卡并复制“Client Secret”字段的内容。
后续将“客户端密钥”字段的复制内容粘贴到outline docker.env
文件中的OIDC_CLIENT_SECRET
变量中。
Bz8GjPI9E7QqAZcGoQRaktEsW155V5u2
现在让我们创建一个能够使用 Keycloak 登录 Outline 的用户。
在“Manage”部分中选择“Users”,然后单击“Create new user”按钮。
在下一步中,您需要指定:用户名、电子邮件地址、名字、姓氏和密码。
请注意,如果您提供电子邮件地址,用户不仅可以使用用户名还可以使用电子邮件登录 Outline。
单击“创建”按钮。
接下来,您需要为新用户设置密码。
转到“Credentials”选项卡,然后单击“Set password”按钮。
输入强密码并单击“保存”按钮。
单击“保存密码”按钮确认为用户分配新密码。新密码已成功设置。
现在,可以修改 Outline docker.env配置文件中的OIDC_CLIENT_SECRET
参数。
$ cd /data/outline
$ vim /data/outline/docker.env
......
OIDC_CLIENT_SECRET=Bz8GjPI9E7QqAZcGoQRaktEsW155V5u2
......
重新启动outline容器
cd /data/outline
docker compose up -d
outline访问
浏览器访问outline控制台: https://docs.example.com
,输入outline登录账号admin
及设置的密码。
首先会跳转到keycloak进行认证:
Outline 登录后如下
新建文档集及文档
至此,我们在一台云服务器上,通过docker-compose方式完成了outline的部署。