Outline is a beautiful, fast and flexible team knowledge base and wiki software used to organize your internal documentation, operations manuals, handbooks and more.
**Update:** This tutorial has been updated for 2024 with support for local file storage. Also, check all the comments as they have some great solutions to common problems as well!
While Outline has a hosted solution, it is open-source software. This means you can install and manage it on your own server. The Outline team has some documentation for installing it on your own, but it’s somewhat complicated (even for an experienced developer like myself).
After trying and failing many times, I decided to help you avoid the hassle by writing an easy, step-by-step tutorial to get the Outline team knowledge base and wiki running on your own server. And do it successfully – the first time!
Key Takeaways
- Outline is an exceptional knowledge base and wiki software that works for individuals, companies and teams.
- It’s easy to self host Outline for yourself when you have the right instruction manual, and this detailed guide will show you how step-by-step.
- Once complete, you’ll be up and running Outline on your own server — without the hassle!
Vision of Results
By carefully following each step of this tutorial on how to install the Outline team knowledge base and wiki on Ubuntu, you will experience the following results:
- A publicly accessible, SSL-secured URL where you can access your new Outline self hosted install. You can see the example install I built using the exact same process documented in this tutorial: https://outline.thomasgriffin.com
- A daily cron that checks for and automatically renews your SSL certificate
- A monthly cron that automatically checks for and applies any new official Outline releases.
- Peace of mind knowing you eliminated the headache of having to figure this out yourself. 💯
Prerequisites
You’ll need the following things to complete this tutorial successfully:
- A Digital Ocean account. While there are other hosting platforms you could use, I’ve chosen Digital Ocean because of the ease of setting up the server scaffolding necessary to support Outline. I cannot guarantee this tutorial will work on any other server platform as I have not tried it there.
- The ability to modify DNS records to add a subdomain for public access to your Outline instance. I recommend Cloudflare, as I will be using it for demonstration in this tutorial.
- A Google Workspace account. Outline offers many different types of authentication (such as Slack or Microsoft), but I’ve chosen Google because I have a Google Workspace account readily available to use for testing.
- OPTIONAL: an Amazon Web Services (AWS) account. If you don’t want to store your assets locally, you need this to setup and configure both IAM and S3 to host all of your Outline assets. Both options will be presented in this tutorial.
Based on my own experience of running through this tutorial multiple times to validate its results, this will take you approximately 45-60 minutes to complete. If you need to register for any of the above services, it may take you a little longer.
Additionally, this setup will typically cost you ~$6/month (excluding Google Workspace or other authentication provider fees), but if you sign up for Digital Ocean using my link, you’ll get your first 2 months free. I believe that to be reasonable given the value that Outline can provide to your team and its productivity.
Table of Contents
Since this tutorial is lengthy and technical, I’ve created a helpful table of contents to reference in case you need to jump around.
- Setting up the Server on Digital Ocean
- Installing and Configuring Server Prerequisites
- Configuring Subdomain DNS Records, Nginx and Let’s Encrypt
- Setting Up AWS IAM and S3
- Creating a Google Workspace Oauth App
- Creating and Running the Outline Docker Image
- Configuring the Nginx Server Block
- Viewing and Authenticating Into Your Outline Self Hosted Install
- Configuring SMTP
- Configuring Automatic Updates for Your Outline Self Hosted Install
- Helpful Commands, Tips and Tricks
- Wrapping Up
Let’s get started installing the Outline team knowledge base and wiki on Ubuntu!
Setting Up the Server on Digital Ocean
Outline requires a Unix based operating system to work, and since Ubuntu is popular, I’ll use that as our operating system.
Head over to your Digital Ocean account and create a new droplet. Select the datacenter of your choice, then select Ubuntu 22.04 LTS x64 as your image, and then select the option you prefer most for your server. I like the $8/month 1GB Intel SSD option, as performing SSH commands with it is notably faster than the base $6/month option.
Next, select your desired authentication method (SSH keys are the preferred option, but if that doesn’t work for you, they support root passwords).
Choose the rest of your configuration options (I recommend enabling backups), customize your droplet hostname, add any tags and then create your new droplet.
Once your droplet has been provisioned, SSH into the server using your favorite terminal client (replacing yourip
with the IP given to you by Digital Ocean):
ssh -A root@yourip
Once logged in, let’s go ahead and get everything updated on the droplet. Select “Y” or hit Return to update/upgrade anything that it recommends during the process.
sudo apt update && sudo apt upgrade
Since upgrading is likely to require some services to restart, go ahead and reboot the server now.
sudo reboot
Rebooting will log you out of your terminal session. Wait a couple of minutes, then log back in again (replacing yourip
with the IP given to you by Digital Ocean):
ssh -A root@yourip
Finally, run this command again to update and upgrade any packages that required a reboot first.
sudo apt update && sudo apt upgrade
Provisioning a Non-Root User
Next, you need to follow the guide for Initial Server Setup with Ubuntu 22.04 on Digital Ocean. In this guide, you’ll establish a more secure environment for your server, including creating a non-root user and setting up some helpful firewalls to lock down access to your server.
Please follow all the steps listed in the article! The rest of the tutorial assumes you have.
Once you’ve finished following the steps there, make sure to SSH back into your server using the new user you just created.
You are now ready to continue with installing the server prerequisites for Outline.
Installing and Configuring Server Prerequisites
Installing Core Components
Let’s install some general utilities that your server needs to get Outline up and running successfully.
First, make sure you are logged in as the non-root user you just created.
Then, run the following command in your terminal:
sudo apt update && sudo apt install apt-transport-https ca-certificates curl software-properties-common nano curl wget zip unzip gnupg
Type “Y” and hit Return to accept any prompts during installation.
Installing Docker
Outline runs inside of a Docker container, so you’ll need to install and configure Docker on your new server to get Outline up and running. You’ll add a new source for Docker to pull the latest stable release and verify its installation on your server.
Run the following commands, one after the other:
sudo apt update
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update && apt-cache policy docker-ce && sudo apt install docker-ce
Type “Y” and hit Return to accept any prompts during installation. At this point, Docker should be installed successfully on your server. To verify, run this command:
sudo systemctl status docker
You should see something output like this:
If you entered the command above, to exit the Docker menu, type :q
Now, remember the non-root user you created earlier? If not, please follow the guide for Initial Server Setup with Ubuntu 22.04 on Digital Ocean.
You’ll want to add this user to the docker
group so that you don’t have to prefix docker commands with sudo
each time. Run the following command, replacing ${USER}
with the username you chose earlier.
sudo usermod -aG docker ${USER} && su - ${USER}
Now when you run the groups
command, you should now see your user added to the docker
group.
Installing Docker Compose
In order to builder the Docker image necessary to run the open source Outline knowledge base and team wiki on your server, you need to install and configure Docker Compose.
Run the following command:
sudo apt update && sudo apt install docker-ce-cli containerd.io docker-compose-plugin docker-compose
Type “Y” and hit Return to accept any prompts during installation.
You should be able to run the following command and see the version output below:
docker compose version
Excellent! Docker is ready to be used with Docker Compose, and you now have the necessary tools installed to compose and deploy your custom Outline docker-compose.yml
file.
Securing Docker
Docker and UFW do not play along well together. Docker overwrites much of the iptables
functionality used by UFW. This means that by default, Docker exposes all of your server ports to the world. Yikes!
This is not good, so you need to secure Docker and limit port exposure on your machine. There is an excellent Github repository that explains this in more detail if you are interested in learning more.
To secure Docker and allow UFW to work as expected, run the following command:
sudo nano /etc/ufw/after.rules
When prompted, add the following code to the very end of the file (after the final COMMIT
text):
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP
COMMIT
# END UFW AND DOCKER
Hit Crtl + X, Y then Return to save the file. Next, reload the UFW application by running this command (you may need to run it twice):
sudo systemctl restart ufw
Finally, you need to reboot your machine for all the upgrades and changes to take full effect. Run the following command to reboot your machine:
sudo reboot
At this point, the SSH connection to your machine will close. Wait about 60 seconds or so, then log back in, replacing ${USER}
with the non-root user you created earlier along with the IP address for your server:
ssh -A ${USER}@yourip
Before moving on with Docker, you need to configure a few other services and systems first. You’ll do that now and return to Docker later in the tutorial.
Configuring Subdomain DNS Records, Nginx and Let’s Encrypt
DNS Records
As I mentioned earlier, I’m using Cloudflare to manage my DNS records. You’ll need to grab the IP address of your new Digital Ocean droplet and create a new A record that points to a subdomain of your choosing.
Add your new A record and update your DNS records. I’ve chosen my subdomain to be outline
, so you can see my Outline self hosted install at https://outline.thomasgriffin.com. If you’re using Cloudflare, turn off their proxy setting for now. You can turn it back on once you finish the tutorial.
Now that you’ve configured subdomain access, you need to add a web server and SSL certificate to handle public requests.
For this tutorial, you’ll use Nginx as a reverse proxy to access Outline in your Docker container, and you’ll use Let’s Encrypt to handle SSL certificate generation and management.
Nginx
Ubuntu ships with an older version of Nginx by default, so you’ll want to grab the latest release to use.
Run the following commands in order in your terminal:
curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
If it looks like the process is hung on this step, it’s likely that you need to type in your sudo
user password in order to proceed.
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg arch=amd64] \
http://nginx.org/packages/ubuntu `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update && sudo apt install nginx
Nginx is now installed on your server. Let’s go ahead and allow web traffic on the server. Run the following command in your terminal:
sudo ufw allow 80 && sudo ufw allow 443
That’s all you need to do for now. You’ll return to Nginx to receive and properly handle incoming traffic later in the tutorial.
Let’s Encrypt
Let’s Encrypt is a server utility to manage SSL certificates. You’ll use this to generate and maintain the SSL certificate for your Outline install.
Run the following commands in order to get Let’s Encrypt installed on your server:
sudo apt install snapd && sudo snap install core && sudo snap refresh core
sudo snap install --classic certbot
Let’s link the certbot
command to the /usr/bin
directory so you can run the certbot
command without the snap prefix:
sudo ln -s /snap/bin/certbot /usr/bin/certbot
Now you are ready to generate your SSL certificate for the subdomain chosen. Mine subdomain is outline
, e.g. outline.thomasgriffin.com
. Run the command below, replacing ${DOMAIN}
with whatever subdomain/domain combination you have chosen for your Outline self hosted install.
sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m noreply@${DOMAIN} -d ${DOMAIN} --pre-hook="systemctl stop nginx" --post-hook="systemctl start nginx"
You should now have your new SSL certificate stored at /etc/letsencrypt/live
.
Because you created the SSL certificate using the Certbot Snap tool, Certbot automatically creates a timer to renew the certificate for you. Nice!
Setting Up AWS IAM and S3
This section is optional. As of Outline v0.72.0, Outline supports storing assets locally on the server. If you’d like to do local storage only, you can skip this entire section.
Outline can accepts various types of file attachments for its documents. Because of this, you need a file storage solution to host and deliver those attachments.
Let’s setup a special IAM user and S3 bucket dedicated to your Outline install. As you create these items, jot down the associated zones, keys, secrets and names. You’ll use them later when configuring your docker-compose.yml
file.
If you don’t have an AWS account yet, go ahead and create one now.
For this tutorial, I’m using the following names for the Username and Bucket Name:
- Username:
Outline
- Bucket Name:
tg-outline-assets
Because S3 bucket names are unique, you’ll need to create your own custom bucket name. I’ll note the areas where you need to add that in the following steps.
Creating the S3 Bucket
Let’s create your S3 bucket to hold Outline attachments and assets.
As I mentioned earlier, I will be using the bucket name tg-outline-assets
. You must change this to your own unique bucket name.
Navigate to S3 in the AWS Console and click on “Create bucket” to get started.
Enter the bucket name (for this tutorial, it is tg-outline-assets
) and select the desired region. You will need to jot down your bucket region, as you’ll use this later when setting up your docker-compose.yml
file.
In the Object Ownership section, select the ACLs enabled option, leaving the Bucket owner preferred option toggled on.
In the Block Public Access section, toggle off the Block all public access setting and check the box to acknowledge the warnings. This is necessary to allow certain images to be uploaded and viewed in your Outline install.
For the remainder of the bucket settings, leave them as they have been defaulted. Scroll down to the bottom and click “Create bucket” to create your new S3 bucket.
On the main S3 bucket screen, find your new bucket and click on it. Then, click on the Permissions tab.
Scroll to the bottom of the Permissions tab and click to edit Cross-origin resource sharing (CORS).
Add the following policy configuration in the editor and save, replacing ${DOMAIN}
with the domain you have chosen for your Outline install. In this example, I am using https://outline.thomasgriffin.com
(include the https://
protocol).
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"PUT",
"POST",
"DELETE"
],
"AllowedOrigins": [
"${DOMAIN}"
],
"ExposeHeaders": []
},
{
"AllowedHeaders": [],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
Creating the IAM User and Policy
Search for “IAM” and get started by clicking “Add Users”.
Set the username as Outline
and select “Access key – Programmatic access” as the credential type. If there is no option to select programmatic access, it’s turned on by default.
On the next screen, select “Attach existing policies directly”, then click on the “Create policy” button to create a custom access policy for this user.
On the next screen, select the “JSON” tab and paste the following policy code in the editor, replacing ${BUCKET}
with the name of your S3 bucket you just created:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor",
"Effect": "Allow",
"Action": [
"s3:GetObjectAcl",
"s3:DeleteObject",
"s3:PutObject",
"s3:GetObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::${BUCKET}/*"
}
]
}
Proceed to adding any tags you would like, then continue to the next screen to give the policy a name and optional description. I’ve chosen to name the policy OutlineS3
. After review, click “Create policy” to create the new access policy.
Now that the new custom policy has been created, you need to attach it to your new IAM user. Click back over to your other IAM tab and hit the Refresh icon just above the policy results table. Type “Outline” in the search bar and then select your new custom policy.
Proceed to the next screen, adding any desired tags. Then review the modifications and click “Create user” to create the new Outline IAM user.
Once you have created the new user, I suggest you download the access credentials for safe keeping or note them somewhere, as you’ll use them when configuring your docker-compose.yml
file later in the tutorial. You can find them by going back to IAM, clicking on the new user you created, then heading to the Security Credentials tab and either downloading or creating new access keys.
(If AWS recommends a different method, ignore it, select an option such as use for CLI and then create the access keys).
Creating a Google Workspace Oauth App
Next, you need to enable authentication into Outline. While many authentication methods exist, I’ve chosen Google because I have a Google Workspace account readily available with my domain.
If using Google doesn’t work for you, you are free to try other authentication methods listed in their documentation. I cannot guarantee they will work, as I have only tested and verified the process with Google.
Creating the Cloud Project
Head over to the Google Developers Console and, if necessary, switch to the appropriate Google Workspace user account.
Select the project caret dropdown in the header menu and click on “New Project” to get started.
Give the project a name (I’ve called it Outline Auth), select the locations and click “Create” to create the new project.
Adding Authentication APIs
Make sure that your new project is selected in the header menu (the same place where you clicked the dropdown caret to get started), and then click on the “Enable APIs and Services” button to add the necessary authentication APIs to your project.
In the search bar, type “google+” and then select the Google+ API option. Once selected, click “Enable” to enable the API for your project.
Configuring the Oauth Consent Flow
Next, you need to configure the Oauth consent flow for authentication requests.
Click on the “Oauth consent screen” link in the lefthand sidebar. Select the “Internal” option and then click “Create”.
Give the app a name (I’ve named mine Outline Auth) and fill out the User support email. Under Authorized domains, add your top level domain.
For this tutorial, since my Outline instance is found at https://outline.thomasgriffin.com
, I’ll add thomasgriffin.com
as an authorized domain.
Finish by adding in a developer contact email address and click “Save and Continue”.
On the Scopes screen, click on “Add or Remove Scopes” and select the first, second and third options in the list. Then scroll to the bottom of the flyout window and click “Update”.
Scroll to the bottom of the screen and click “Save and Continue”.
Generating Oauth Credentials
Finally, you need to generate Oauth credentials for the Google Cloud project you’ve created.
Click on the “Credentials” link in the lefthand sidebar. Click on the “Create Credentials” button and then select “Oauth client ID” for the credential type.
Once the next screen, select “Web application” as the application type and give it a name. For this tutorial, I have named mine Outline Oauth Client
.
Under “Authorized JavaScript origins”, enter your subdomain URL. For this tutorial, mine is https://outline.thomasgriffin.com
.
Under Authorized redirect URIs, enter the following URL, replacing ${DOMAIN}
with your subdomain/domain name:
https://${DOMAIN}/auth/google.callback
Click “Create” to create your new project credentials. Copy the client ID and secret and jot them down in a safe place, as you’ll use them when you configure your docker-compose.yml
file in the next step.
Creating and Running the Outline Docker Image
You are now ready to generate your custom docker-compose.yml
file that defines the services necessary to run Outline on your droplet.
First, you’ll need to create a new directory on the server as your Outline project “home”. Remember the non-root user you created from the Digital Ocean tutorial at the beginning of this article? You’ll use that user’s home directory to store your files. Run the command below, replacing ${USER}
with the name of the user you created earlier.
mkdir -p /home/${USER}/docker && mkdir -p /home/${USER}/docker/logs && cd /home/${USER}/docker && touch docker.env && touch docker-compose.yml
Before you boot Docker, you’ll need to add some necessary environment variables to your new docker.env
file. I’m not using all of the available variables for this tutorial, so if you want to know more, click here to see all of the available environment variables.
Here are the variables you will be using in your docker.env
file:
## Required Variables
SECRET_KEY=
UTILS_SECRET=
FORCE_HTTPS=
ENABLE_UPDATES=
WEB_CONCURRENCY=
## Postgres Variables
POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=
DATABASE_URL=
PGSSLMODE=
## Redis Variables
REDIS_URL=
## Domain Variables
URL=
PORT=
## Rate Limiting Variables
RATE_LIMITER_ENABLED=
RATE_LIMITER_DURATION_WINDOW=
RATE_LIMITER_REQUESTS=
## Local File Storage Variables - ONLY USE IF STORING ASSETS LOCALLY
FILE_STORAGE=
FILE_STORAGE_LOCAL_ROOT_DIR=
FILE_STORAGE_UPLOAD_MAX_SIZE=
## AWS Variables - OPTIONAL, REMOVE IF NOT USING AWS FOR ASSET STORAGE
AWS_REGION=
AWS_S3_FORCE_PATH_STYLE=
AWS_S3_UPLOAD_BUCKET_NAME=
AWS_S3_UPLOAD_BUCKET_URL=
AWS_S3_UPLOAD_MAX_SIZE=
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=
## Google Login Authentication Variables
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
A few points of information on the variables listed above:
- We’ll generate 3 unique keys for the
${SECRET_KEY}
,${UTILS_SECRET}
and${POSTGRES_PASSWORD}
variables. - Since we will be terminating SSL, we can set the
${FORCE_HTTPS}
variable tofalse
. - For the
${URL}
variable, replace it with the HTTPS URL for your Outline install, e.g.https://outline.thomasgriffin.com
- Grab the access keys, client IDs and other keys that you generated when walking through the AWS and Google Workspace parts of the tutorial. You’ll need to enter them in your
docker.env
file. - Wherever else you see
${VARIABLE}
in thedocker.env
file, make sure to replace it with the appropriate value. - If you want to use local file storage, set the
${FILE_STORAGE}
variable tolocal
. If you want to use AWS S3, set the value tos3
.
To generate the unique keys, run the following command three times. After each time, copy the output and replace ${SECRET_KEY}
, ${UTILS_SECRET}
and ${POSTGRES_PASSWORD}
variables respectively in the docker.env
file contents below.
openssl rand -hex 32
To edit the file in the terminal, run the following command:
nano docker.env
Here’s the code that goes in docker.env
. Don’t forget to run the commands and replace the appropriate variables!
## Required Variables
SECRET_KEY=${SECRET_KEY}
UTILS_SECRET=${UTILS_SECRET}
FORCE_HTTPS=false
ENABLE_UPDATES=true
WEB_CONCURRENCY=2
## Postgres Variables
POSTGRES_USER=outline_user
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
POSTGRES_DB=outline
DATABASE_URL=postgres://outline_user:${POSTGRES_PASSWORD}@postgres:5432/outline
PGSSLMODE=disable
## Redis Variables
REDIS_URL=redis://redis:6379
## Domain Variables
URL=${URL}
PORT=3000
## Rate Limiting Variables
RATE_LIMITER_ENABLED=true
RATE_LIMITER_DURATION_WINDOW=60
RATE_LIMITER_REQUESTS=600
## Local File Storage Variables - IF USING AWS, CHANGE VALUE TO s3
FILE_STORAGE=local
FILE_STORAGE_LOCAL_ROOT_DIR=/var/lib/outline/data
FILE_STORAGE_UPLOAD_MAX_SIZE=26214400
## AWS Variables
AWS_REGION=${AWS_BUCKET_REGION}
AWS_S3_FORCE_PATH_STYLE=false
AWS_S3_UPLOAD_BUCKET_NAME=${AWS_BUCKET_NAME}
AWS_S3_UPLOAD_BUCKET_URL=https://${AWS_BUCKET_NAME}.s3.${AWS_BUCKET_REGION}.amazonaws.com
AWS_S3_UPLOAD_MAX_SIZE=26214400
AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY}
AWS_SECRET_ACCESS_KEY=${AWS_SECRET_KEY}
## Google Login Authentication Variables
GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
GOOGLE_CLIENT_SECRET=${GOOGLE_CLIENT_SECRET}
Next, you’ll modify the docker-compose.yml
file to define the images you need to run Outline:
nano docker-compose.yml
Add the following code in the command prompt:
version: "3"
services:
outline:
image: outlinewiki/outline:latest
restart: always
env_file: docker.env
command: sh -c "yarn --env=production-ssl-disabled && yarn start --env=production-ssl-disabled"
ports:
- "3000:3000"
volumes:
- storage-data:/var/lib/outline/data
depends_on:
- postgres
- redis
redis:
image: redis:7
restart: always
env_file: docker.env
expose:
- "6379"
volumes:
- ./redis.conf:/redis.conf
command: ["redis-server", "/redis.conf"]
postgres:
image: postgres:14
restart: always
env_file: docker.env
expose:
- "5432"
volumes:
- database-data:/var/lib/postgresql/data
volumes:
storage-data:
database-data:
Finally, save the file (Ctrl + X, Y and then Return). Now you are ready to get Outline up and running with Docker!
Run the following command to boot your new Outline Docker container:
docker-compose up -d
You should see some information output to your terminal. It will look something like this:
If you happen to see an error, a common one is because docker-compose
does not like tabs. You’ll want to convert tabs to spaces in the docker-compose.yml
file.
You can validate that things are working in the container by running this command:
docker ps
Additionally, it’s helpful to check the Docker logs to ensure no errors have been encountered. You can check those logs by running the following command:
docker-compose logs
If you see any errors in the logs, take a break from the tutorial to get them resolved.
If you have any issues resolving them, you can leave a comment on this article, reach out to me via my contact form or ping me on Twitter. I’m happy to help!
Now you are ready to configure the Nginx server block so that your new Outline knowledge base and team wiki install is accessible to the public.
Configuring the Nginx Server Block
This is the final step to accessing your new Outline knowledge base and team wiki install. You need to be able to receive and handle incoming web traffic from your new subdomain, e.g. https://outline.thomasgriffin.com.
Because Outline is running in Docker, Nginx needs to act as a reverse proxy for web traffic. You’ll configure those details now.
First, you need to improve your SSL security exchanges by creating a Diffie-Helman exchange key. Run the following command in your terminal:
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
Next, run the following command to create a new configuration file for your Outline application:
sudo nano /etc/nginx/conf.d/outline.conf
Inside of the editing screen, copy and paste the code below, replacing the following variables:
- Replace
${DOMAIN}
with the domain you have selected, e.g.outline.thomasgriffin.com
- Replace
${USER}
with the non-root user you created when you followed the initial setup tutorial for Ubuntu on Digital Ocean, e.g.thomas
server {
listen 80;
listen [::]:80;
server_name ${DOMAIN};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ${DOMAIN};
access_log off;
error_log /home/${USER}/docker/logs/error.log;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS;
ssl_prefer_server_ciphers on;
ssl_session_timeout 24h;
ssl_stapling on;
ssl_stapling_verify on;
ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/${DOMAIN}/chain.pem;
ssl_dhparam /etc/ssl/certs/dhparam.pem;
ssl_session_cache shared:OutlineSSL:10m;
ssl_session_tickets off;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $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;
}
}
Once done editing, hit Ctrl + X, then Y and Return to save the file.
You can further optimize your Nginx server blocks later. These are some basic configuration settings designed to get you up and running in a secure way.
To verify everything looks good, run the following command:
sudo nginx -t
If you received any errors, review them and edit your outline.conf
file to fix the errors, and then re-run the command above to validate the fixes.
Once everything looks good, run the following command to reload Nginx and apply the configuration changes:
sudo systemctl restart nginx
Viewing and Authenticating Into Your Outline Self Hosted Install
You should be able to visit your url, e.g. https://outline.thomasgriffin.com, and see a screen that looks like this:
Click on the button to log in with Google, and then log in using the email address domain associated with the custom Oauth client you created earlier.
Congratulations! Enjoy your new Outline self hosted install! 🎉
From here, I’ll be sharing some additional configurations, such as setting up SMTP so email works from your server as well as configuring Outline to automatically check for and apply updates once per month.
I’ve spent countless hours both figuring out how to get Outline installed for myself as well as writing, testing and validating this tutorial. If it has been helpful to you, please share it with others using the social buttons associated with this tutorial.
Thanks in advance for your vote of support when you do!
Let’s continue with the tutorial.
Configuring SMTP
If you want to invite teammates to your Outline self hosted install, you need to configure SMTP support. Otherwise, your emails will never leave the server.
You’ll need a transactional email service for this. I recommend SendLayer. It’s one of my company’s products, and it’s got a free plan for your first 500 emails.
Sign up for a free plan. Once done, add a domain for sending email. I recommend using a separate subdomain for transactional emails. For example, mine is outlinemail.thomasgriffin.com
.
After you add your domain, you’ll be asked to add some new DNS records to finish the setup process. Just like you did in the steps above to add your subdomain for your Outline install, you’ll do the same type of work here.
Here’s an example of the records you’ll be asked to configure:
Once you have configured and verified your DNS records, head over to the SMTP Credentials tab. You’ll need to grab the credentials to add to your docker.env
file.
Once you have those SMTP credentials in hand, return to your docker.env
file (located at /home/${USER}/docker
) and add the following at the bottom, replacing the SMTP variables with the credentials from SendLayer. The ${FROM_EMAIL}
variable should be from the subdomain you’ve setup for SMTP, and the ${REPLY_EMAIL}
variable can be whatever you would like it to be.
## SMTP Variables
SMTP_HOST=smtp.sendlayer.net
SMTP_PORT=587
SMTP_USERNAME=${SMTP_USERNAME}
SMTP_PASSWORD=${SMTP_PASSWORD}
SMTP_FROM_EMAIL=${FROM_EMAIL}
SMTP_REPLY_EMAIL=${REPLY_EMAIL}
SMTP_SECURE=false
Once you’ve saved the file, you’ll need to apply the changes to your Docker containers. Run the following command in your terminal:
docker-compose down --remove-orphans && docker-compose up -d
You may notice a brief 502 Bad Gateway
error from Nginx after you reload Docker. It usually resolves in under 30 seconds.
You can now invite your teammates to collaborate on your new Outline install.. and they’ll actually receive your email invitations!
Configuring Automatic Updates for Your Outline Self Hosted Install
If you’re anything like me, once you set something up, you find it a hassle to revisit and maintain it with rudimentary updates.
Fortunately, you can easily automate this task using the system cron. Let’s create two jobs: one that triggers daily Outline scheduled jobs, and one that automatically checks for updates once per month (and if an update for Outline found, it’s automatically installed, applied and restarted).
Daily Scheduled Jobs
Run this command in your terminal to create the new daily cron job to trigger Outline scheduled jobs:
sudo nano /etc/cron.daily/outline-daily
Add the following code when prompted, replacing the ${DOMAIN}
variable with the domain you’ve chosen for your Outline install (e.g. outline.thomasgriffin.com) and ${UTILS_SECRET}
with the UTILS_SECRET
variable from your docker.env
file:
#!/bin/sh
curl https://${DOMAIN}/api/cron.daily?token=${UTILS_SECRET}
Save the file (Ctrl + X, Y and then Return). Then, make it executable by running the following command:
sudo chmod +x /etc/cron.daily/outline-daily
The cron will now run once per daily and trigger any jobs that Outline has scheduled.
Monthly Updates
Run this command in your terminal to create the new monthly cron job to update Outline:
sudo nano /etc/cron.monthly/outline-update
Add the following code when prompted, replacing the ${USER}
variable with the non-root user you created at the beginning of this tutorial:
#!/bin/sh
cd /home/${USER}/docker
docker-compose down --remove-orphans
docker pull outlinewiki/outline
docker pull redis:7
docker pull postgres:14
docker-compose run --rm outline yarn --env=production-ssl-disabled
docker-compose up -d
Save the file (Ctrl + X, Y and then Return).
Next, you need to make sure the monthly cron is executable. Run this command in your terminal:
sudo chmod +x /etc/cron.monthly/outline-update
The cron will now run once per month and automatically update Outline to the latest released version. It will also run any new database migrations that might be part of the Outline update.
Once again, congratulations! You’ve installed the Outline team knowledge base and wiki on Ubuntu successfully!
If you have found this helpful, please let the world know. I spent lots of time getting this to work and writing this tutorial for you. You can quickly share it using the social buttons on this article.
Also, I’d love to know if you’ve gotten it setup successfully or if you need some help. Drop a comment below, reach out on my contact form or ping me on Twitter.
Helpful Commands, Tips and Tricks
When working with complex setups like this, it’s helpful to have a list of commands/tips/tricks to make the management and debugging aspect easier.
Below, you will find some helpful things I’ve used during the process of getting Outline running on my own site.
Removing Old Database Volumes
If for some reason Postgres does not behave when you initially run Docker, you may end up with a bad volume of data.
Because of how Docker works, subsequent shut downs and start ups will skip steps for provisioning databases and users. If you find that you are missing a database or user role in the logs (docker-compose logs
), you can run the following two commands to remove old database volumes so they can be fully rebuilt:
docker volume ls
docker volume rm <volume_name>
Note that when you do this, you’ll lose all of your data. This is mostly helpful when initially setting up your Outline install.
Typically the postgres volume will be obvious, having postgres somewhere in its name. Remove it, then you can bring the docker containers down (docker-compose down
) and back up again (docker-compose up -d
).
Completely Wiping Docker
It’s not hard, but it was hard to find the right commands to do it easily.
To remove all containers and volumes, run this command:
docker rm -vf $(docker ps -aq)
To remove all the images, run this command:
docker rmi -f $(docker images -aq)
Then you are free to run docker-compose up -d
again, and it will do so in a completely fresh way.
Wrapping Up
Thank you for your time. I hope you are experiencing the Vision of Results as I described them earlier.
If you have found this helpful, please share it with others. I spent numerous hours getting this to work and documenting it for you. You can quickly share it using the social buttons on this article.
Additionally, I’d love to know if you’ve gotten it setup successfully or if you need some help. Drop a comment below, reach out on my contact form or ping me on Twitter.
And if you are interested in more of my writing, here’s a few great places to start:
- Reflections on Greatness (And How to Become Great) Everybody wants to be great at something. But what does it actually take to be great? The answer might surprise, and I share an interesting graph to explain why.
- How to Communicate Effectively (In Any Situation) Effective communication is a critical skill that everyone needs to develop. In this article, I define the requirements, provide commentary and share helpful examples on how you can be more effective in your communication.
- Welcome to Leadership Flourish as a leader with battle-tested leadership principles, insights and tactics.
Have a great day!
Thomas
R. Kennedy
Amazing tutorial here! I had an existing server running Docker, Redis and Postgres with other stuff installed on the same server but used your tutorial to understand how to hook them together and it was especially useful re: the AWS S3 settings which don’t seem very detailed in the default install instructions. Well done here, Thomas. Thank you.
Thomas Griffin
Thanks Reess! Appreciate the kind words, and I’m glad you found this tutorial for installing the Outline Knowledge Base / Wiki on Ubuntu helpful! 🥂
Praveena Sarathchandra
Very well-written tutorial Thomas! Thank you so much for putting it together. Saved us many hours of pulling our hair out for making it work! Cheers!
Thomas Griffin
Thanks for the kind words! Happy you were able to get the Outline wiki installed successfully. 🚀
Jeongwoo Hong
Your tutorial was especially useful for building an outline wiki on a specific domain address. thank you But I ran into one problem. After starting with docker-compose, I use the wiki for a while, and then I get a 502 error when I try again after a few hours or a day. The redis docker’s log shows an error related to Redis.
ReplyError: READONLY You can’t write against a read only replica.
at parseError(/opt/outline/node_modules/redis-parser/lib/parser.js:179:12)
at parseType(/opt/outline/node_modules/redis-parser/lib/parser.js:302:14) {
command: { name: ‘del’, args: [ ‘UPDATES_KEY’ ] }
There was someone else who had the same problem as me.
https://github.com/outline/outline/discussions/3682
I’m not very good with Redis. I haven’t found a good solution yet.
Do you have any advice for you?
Thomas Griffin
Unfortunately I do not have any experience fixing this particular issue with Redis. It sounds like something is causing Redis to flip over into read only mode. Have you tried to restart the Redis service in Docker? That might clear out any cache or other issues causing this, and it might be that it solves the problem more long term.
Roland
excellent tutorial, how could it be achieved using GCP Cloud storage instead of aws S3?
Thomas Griffin
Hey Roland – thanks for the kind words, and glad you’ve found it helpful to get the Outline knowledge base and wiki set up for yourself!
Regarding GCP Cloud Storage, it would seem that it is not supported at this time. You can always create an issue on the Github repo to make a request for that feature!
Sven
Hi Thomas,
Thanks so much for the tutorial.
How do I ensure that Redis is not accessible to the public? With the given config, which I believe loads the default one, it seems anyone is able to access it.
Thomas Griffin
Hey Sven – thanks for the kind words!
Regarding your comment, I actually ran into this issue as well when going through the tutorial, and with the config I provided, it should not be publicly accessible. You can test by running this command:
telnet {ip} 6379
Simple replace
{ip}
with the IP address of your server. I have tested with the one used for this tutorial, and it does not allow any connections. Let me know what you discover when you try it out yourself!Sam
Hi Sven & Thomas,
The
port
key in the docker compose does indeed allow public access to the redis (and postgres) ports. I think insecurity is also related to JEONGWOO HONG’s post above, where it can result in server crashes / 502s.I documented a solution here: https://github.com/outline/outline/discussions/3682#discussioncomment-3658318
Basically, changing the
port
key toexpose
and enforcing some firewall rules on your server (which I assume Thomas did via Digital Ocean, hence not encountering this in the first place).Good luck!
Thomas Griffin
Update: Sam’s solution did work, so I have updated the tutorial accordingly.
Sam – thank you so much for sharing your solution! I will test and update this tutorial accordingly once I verify that it works as well.
I will also check my UFW rules to see if I configured any for this. It is possible that I did and just forgot to add them into the tutorial. If I did, I’ll make sure to update the tutorial to include those new firewall rules.
Sam
This article is amazing and a life-saver. I completed setup of my own outline instance without any issues at all by following all of the steps.
Thank you so much!
Thomas Griffin
Fantastic news, Sam! Glad to hear it. 🚀
Sam
Also noting that in Outline’s setup docs, there’s a page talking about scheduled jobs and setting up a daily cronjob to run it: https://app.getoutline.com/share/770a97da-13e5-401e-9f8a-37949c19f97e/doc/scheduled-jobs-RhZzCt770H
I’m not sure what it does TBH and didn’t see it in your article, but have just set it up on my end. Cheers.
Thomas Griffin
Update: I have updated the tutorial to include a section for creating the daily cron that runs scheduled jobs in Outline.
Sam – thank you again for sharing this information! I will review and update the tutorial accordingly (and also my own install so that this runs daily as well).
Again, thank you for sharing your information here. Lots of people will be able to set up the Outline knowledge base and wiki properly because of the tutorial and valuable things you have shared here!
Revel
This is really helpful. Thank you!
Thomas Griffin
Glad you found it helpful, Revel!
Jere
What does this sentence mean?
command:
sh -c "yarn sequelize:migrate --env=production-ssl-disabled && yarn start --env=production-ssl-disabled"
Thank you so much!
Thomas Griffin
Hey Jere,
It means that when a Docker container is created, that command is run once the Outline service is installed and booted up. It ensures that your database migrations have run and that the Outline application is running and available to access.
Hope that explanation helps!
Jeff
Thanks for sharing!
I’m looking for an internal wiki/KB and I’ve been trial’n BookStack, wiki.js and Joplin. Each one has a feature(s) that’s not available in the others.
Outline looks appealing but I can’t find an admin demo, anywhere. Have you used BookStack or wiki.js/ Do you know how they compare to Outline?
I wish it was easy to spin up an Outline container in Portainer to test with but the setup process seems to be quite a bit more involved than with the others I’ve mentioned. I’d also want to self-host everything and not use an external S3.
Thomas Griffin
Hey Jeff – I’ve not tried the other wiki platforms you have mentioned, so I’m not able to comment on their merits or how they might compare with Outline. I also wish Outline was easier to set up. The introduction of a simple email/password authentication system and local asset storage would greatly simplify the installation process. Until then, following the steps in this tutorial is the best way to set it up with confidence!
Matthew
Great Article and will be trying it out to install Outline in my environment
Would it be possible for you to add into this great Guide on using minio onprem hosted S3 Bucket instead of using Amazon S3 Bucket so everything is for Outline is onprem?
Thomas Griffin
Hey Matthew – thanks for the kind words! Yes, I do plan on updating the article soon (first half of 2023) to incorporate using Minio as well.
Harry
Hey Thomas,
Thank you so much for this article! However, i’ve 5th time in and still unable to get this to work.
My container “docker_outline_1” is looping at restart and I can’t figure out why. The logs give the following error.:
yarn run v1.22.18
error Command “sequelize:migrate” not found.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
If you have any suggestion, it would be fantastic. I’m pulling my hair out!
Thomas Griffin
Hey Harry,
It looks like in a recent changelog, they removed the
sequelize:migrate
command. In your docker.env file, you need to replaceyarn sequelize:migrate
withyarn db:migrate
. This should allow things to work.I’ve updated the tutorial to reflect this change. Hope that helps!
Harry
You are an absolute legend!
Last question 🙂 – do you know if there is a way to change the X-Frame-Options to ALLOW? I have tried overwriting using the nginx config file and using cloudflare workers, but doesn’t seem to do anything.
Thanks again!
Harry
I managed to do it. For anyone else looking to implement the wiki inside another app/website. You can use the “modify response headers” in Transform Rules section of Firestore.
Thanks again Thomas.
Thomas Griffin
Glad it is working now Harry, and thanks for sharing those additional details regarding firewall rules. That should be very helpful for others who run into the same issue!
jvm
thanks so much for the fantastic tutorial. I’ve had it up and running incident free for a month, but upon the monthly cron job updating I get a 502 bad gateway. I’m able to restore a backup through dropbox and carry on – but how do I disable the cron job once enabled? Or how do I manually update outline?
Thomas Griffin
You can run
crontab -e
in your terminal to find a list of your cron jobs, and then you can simply edit the cron with nano to remove the command.If you want to update Outline manually, simply copy the command you found in the cron job before you remove it, and then when you want to update Outline, run each line step by step in your terminal to complete the update process.
jvm
amazing – thanks so much
Glenn
Thanks for this great guide on Outline. I had two questions:
1) Can you please advise how to save the data that’s been put in the Outline wiki? How would I save the data that’s contained in the wiki prior to updating to a new version which could potentially break the current configuration? If its saving the database then what exact database file needs to be saved? Is each Outline “Collection” a separate folder in the database? I’m unsure of the data backup process. I know there’s an export feature to markdown but if I have like 5 collections and 50 different pages, I would rather backup my entire Outline data rather than export 50 different markdown files and then need to manually reupload them after.
2) How does updating the Outline container work? Do all of the containers connected to Outline (Redis, Postgres, Minio) need to be updated as well or can Outline just on its own be updated? Any special procedures to update Outline?
Thank you so much!
Thomas Griffin
Hey Glenn – glad you enjoyed the tutorial!
To answer your questions:
1. I would recommend turning on Digital Ocean backups. That will automatically backup your data each day, and then you can always log in to your DO panel and perform a manual backup just before you proceed with the upgrade. By doing this, even if something goes wrong with the upgrade process, you’ll have peace of mind knowing your data is not lost.
2. In the current process I have listed, I update all of the services in the container, but you don’t have to do that if you don’t want to. You can comment out or remove the extra services and only allow Outline itself to be updated. And if you don’t like the cron, you can just copy the commands and run them manually yourself. 🙂
Hope these answers are helpful!
Vasile Ciuban
Hi, I followed your procedure step by step, but I don’t understand why I keep getting this error:
502 Bad Gateway
nginx/1.24.0
really frustrating, it’s all app is runing but not working
Thomas Griffin
Hey Vasile – can you run
docker-compose logs
and share the errors are experiencing?Renzo
I also have the same problem, apparently my error is when running yarn, apparently I don’t have permissions on /opt/outline
Vasile Ciuban
Also
Periodically running Docker ps I see the docker_outline_1 container often restarts,
Because UP time is different than creation time unlike redis and postgres
Thomas Griffin
Ok, thank you. Nothing obvious stands out here. Can you also share your Nginx config file here? This is an Nginx issue, but I am not seeing any Nginx errors listed here. Also, if you can find your Nginx logs in the docker container and can share, that would also be very helpful.
Thomas Griffin
I saw the comment you shared with your Nginx logs. Nothing looks out of the ordinary to me. It appears like Nginx is having an issue proxying to the docker container.
Confirming that your
docker.env
has the ports open on"3000:3000"
?Have you tried rebooting docker, e.g.
docker-compose down --remove-orphans && docker-compose up -d
Renzo Barros
Hi, I am getting 502 Bad Gateway error following all the steps as the article.
Thomas Griffin
Sorry you are having that issue Renzo! Can you share your Nginx config file and Nginx error log file?
Vasile Ciuban
HI,
After 3 days of testing, I finally got it to work.
What you need to do is in docker.env edit this:
## Redis Variables
REDIS_URL=redis://docker_redis_1:6379
DATABASE_URL=postgres://outline_user:pass@docker_postgres_1:5432/outline
As url of redis and postgress you have to put the name of the docker container that you get it with docker ps
in my case they are : docker_postgres_1 and docker_redis_1
then into nginx
you have to put your public domain without https only docs.example.com at the server_name
and in proxy_pass you have to put the ip of your machine.
run this command and it gives you your lan ip
hostname -I | awk ‘{print $1}’
Thomas Griffin
Thanks for sharing Vasile! I wonder – does your server also use Nginx for anything else? It seems like those changes mean that you also have Nginx running for something else.
Francesco R. Di Caprio
Hi Thomas. Thanks for this beautiful guide. I wanted to tell you that Outline must not be migrated manually since version 0.69.0. Therefore the command “sequelize:migrate” will fail. You should update docker-compose.yml to only use
command: sh -c “yarn start –env=production-ssl-disabled”
Regards
Thomas Griffin
Yes Francesco, I made sure to update this once that version came out so that it is no longer part of the tutorial. Thanks for the comment!
Alain
Hello Thomas. My sincerest gratitude for this exquisite tutorial. This step by step guide is nothing short of exceptional. You clearly have a natural talent for breaking down complex concepts into understandable pieces, believe me.
I’ve meticulously followed every single detail, but at the end I have a “502 Bad Gateway” Nginx error. Right now with “docker ps” I can see Postgres and Redis images with an “Up” status of a given time, however Outline’s says only 2 minutes. So, at some point, and for reasons unknown, it’s restarting. I honestly have no idea what’s happening. I’ll share with you my logs. Apologies in advance if this is not the proper channel for that. Please help and thanks.
Logs just after complete the first up -d:
docker ps (https://pastebin.com/93svmMLd)
docker-compose logs (https://pastebin.com/pWU2fjMm)
Logs after a while:
docker ps (https://pastebin.com/M0rExWhw)
docker-compose logs (https://pastebin.com/t4vk6zjK)
Thomas Griffin
Hey Alain – sorry you’ve had issues with the dreaded 502 gateway error. I too remember a similar issue like this, but honestly I cannot remember how I went about resolving it. I think it was a permissions related issue OR that there is a problem with your database credentials (maybe you copied them down incorrectly or the names are accidentally mismatched), but I should have jotted that note down.
I wish I had more information to share. I would re-check the credentials in your docker environment file and make sure everything is correct for postgres.
Raghu
Thank you TG for such an in-depth tutorial! I followed the steps till the NGINX server block set up, but I see a 502 on my app.
On running `docker-compose logs | grep -i error` i saw the following –
“`
error Could not write file “/opt/outline/yarn-error.log”: “EACCES: permission denied, open ‘/opt/outline/yarn-error.log'”
outline_1 | error An unexpected error occurred: “EACCES: permission denied, unlink ‘/opt/outline/node_modules/.yarn-integrity'”.
“`
This is preventing the outline container from going “up”.
can you please help me resolve this?
Thomas Griffin
Hey Raghu – someone else reached out to me in my contact form to ask about a similar issue. The issue they shared was that the `/opt/outline` directory was owned by the root user but that it needed to be owned by the `nodejs` user. Once they fixed those permissions, it worked. I have not be able to verify this, but that might at least get you in the right direction. You might want to manually connect to the container and check the user that it is running as. If it is `nodejs`, then changing the ownership of the affected directories will likely fix the issue for you. Hope that helps!
Victor
I got the same issue (on AWS EC2)
To resolve this, I launched these commands:
docker-compose run –rm outline yarn db:create –env=production-ssl-disabled
docker-compose run –rm outline yarn db:migrate –env=production-ssl-disabled
As requested on the official documentation, and deleted this on the docker-compose file ( command: sh -c “yarn –env=production-ssl-disabled && yarn start –env=production-ssl-disabled”)
darionco
Thank you for the guide, I was having the same 502 Bad Gateway Error that most people seem to have lately and based on this thread:
https://github.com/yarnpkg/yarn/issues/1806
I decided to run the Outline image as root by adding
user: root
to theoutline
section ofdocker-compose.yaml
Might not be the most optimal solution, but it is by far the easiest. Hopefully this will help someone!
Thomas Griffin
Awesome, thanks for sharing that! Can you share what your
docker-compose.yaml
looks like with that change? I’ll likely update the tutorial based on these suggestions.darionco
Sure thing, here is the relevant part:
“`
outline:
image: outlinewiki/outline:latest
restart: always
env_file: docker.env
user: root
command: sh -c “yarn –env=production-ssl-disabled && yarn start –env=production-ssl-disabled”
ports:
– “3000:3000”
depends_on:
– postgres
– redis
“`
Something else that I did was to use DigitalOcean’s spaces instead of AWS’ S3, for that the `docker.env` config looks like this:
“`
## AWS Variables
AWS_REGION=${REGION}
AWS_S3_UPLOAD_BUCKET_NAME=${BUCKET_NAME}
AWS_S3_UPLOAD_BUCKET_URL=https://${AWS_S3_UPLOAD_BUCKET_NAME}.${AWS_REGION}.digitaloceanspaces.com
AWS_S3_ACCELERATE_URL=https://${AWS_S3_UPLOAD_BUCKET_NAME}.${AWS_REGION}.digitaloceanspaces.com
AWS_S3_UPLOAD_MAX_SIZE=26214400
AWS_ACCESS_KEY_ID=${ACCESS_KEY_ID}
AWS_SECRET_ACCESS_KEY=${SECRET_ACCESS_KEY}
AWS_S3_FORCE_PATH_STYLE=false
AWS_S3_ACL=private
“`
Then on the CORS options for the bucket I made sure to add
`origin: ${DOMAIN}`, `allowed_methods: GET, PUT, DELETE, POST, HEAD` and `allowed_headers: Accept, Content-Type, Origin`
Hope that helps!
Thomas Griffin
Super helpful – thanks so much for sharing it here and for the community to benefit from!
John
I am also in the 502 error boat. But, instead of DigitalOcean, I am running my service on an EC2 instance.
Now, does this require me to open some ports (3000 etc.) in the security policy?
The exact error I am getting is (docker/logs/error.log):
[error] 4622#4622: *21 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 171.76.87.217, server: wiki.bindins.me, request: “GET /favicon.ico HTTP/2.0”, upstream: “http://127.0.0.1:3000/favicon.ico”, host: “wiki.bindins.me”, referrer: “https://wiki.bindins.me/”
Thomas Griffin
Hey John – if you’re docker-compose file looks like what I have shared, all the necessary ports should be exposed. I’ve noticed a couple of folks have mentioned in the comments that changing the user to
user: root
in the outline section of the docker-compose file has resolved those issues. Have you tried this?Craig Hodges
Just want to chime in. I was getting the Yarn permission denied error as well, and @darionco ‘ s user:root fix in the compose yml solves the permission issue.
Feigo
local storage are available from v0.72.0
Thomas Griffin
Hey Feigo – I’ve just updated the tutorial today with support for the new local file storage update in Outline. Thanks!
Mike
I can’t login on your Test instance at outline.yourpage.com
If I want to login via email (gmail) I don’t get any magic link. If I want to login via google I get „I’m not in the organisation to login“
Thomas Griffin
Hey Mike – that’s how it is supposed to work. It is locked down to just my own Google Workspace organization, so you cannot log in. It will work the same for you if you connect it to your own Google Workspace organization during the tutorial.
const
Thanks. nginx config needs fixing though. duplicate `proxy_set_header Host` headers make the reverse proxy confused.
Thomas Griffin
Thanks for catching that mistake! I’ve updated the tutorial to remove the duplicate directives.
Will
First off; absolutely EPIC walkthrough – I spent so much time trying to set up Outline on my own and this was a complete life saver! Thank you!
Secondly, I am in the camp of folks who got the 502 Error repeatedly. Completely wiping Docker helped one time, but the second time I was able to get a bit more in the weeds and found a solution for that instance (no guarantee this works in all situations) but running `sudo certbot` and `Attempt to reinstall this existing certificate` solved the issue for me.
I noticed that I had an error in the nginx logs about requesting certificate status, so re-installing the cert was the solve there. Hope this helps someone out there!
Thomas Griffin
Hey Will – glad you liked the tutorial, and thanks for sharing that tidbit! I wonder if there is a way to do this (reinstall the existing certificate) from the start, rather than needing to do it at the very end? I’ll be going through the walkthrough again soon and will test it out!
Alberto
Hi Thomas,
thanks for your great guide!
Unfortunately I’ve tried to install from scratch 3 times but I’ve got 502 Bad Gateway (nginx/1.26.0). I tried all the workarounds suggested in the comments here but they didn’t work.
Installed in ubuntu 22.04 on Azure.
Any ideas?
Thomas Griffin
Hey Alberto – I’m sorry you’ve run into those same 502 errors. Unfortunately, I’m not sure how this will work on Azure. I’ve only tested using Linux/Ubuntu distributions, so I can’t guarantee this will work on Azure environments.