Peertube is a federated alternative to Youtube. It uses the same technology (activity pub) as Mastodon under the hood to share videos between instances. This project has been highlighted by the recent events with the Blender foundation and MIT OpenCourseWare.

In order to set up Peertube we need a Postgres instance, Redis instance, and some SMTP service. If you plan on setting everything up on a single server I recommend using the docker-compose file provided by Peertube using the environment variables we define below. Instead we will be setting up each component on a separate Ubuntu 16.04 VPS instance.

  1. Setting Up Docker/Postgres/Redis/Domain/Mailgun:

If you need to setup these resources I have provided tutorials as well as scripts to help you get started.

  • Setting up a domain: I recommend buying a domain using Google domains and pointing their DNS servers to Digital Ocean. This will allow you to manage your DNS records in Digital Ocean. Once your domain is created you will need to create an A record for ipv4 connections and a AAAA for ipv6 connections.

  • Docker: script*, tutorial

  • Postgres: script*, tutorial

  • Redis: script*, tutorial

  • Mailgun: tutorial

  • Nginx: script*, tutorial

  • Let's Encrypt: script*, tutorial

  • To run the scripts above activate the pipenv environment and run a command which is similar to the one below. Also, there may be additional configuration needed after the scripts run.

python file_name -s user@server-ip
  1. Setting up Peertube

We will download version 1.0.0-beta.11-stretch of Peertube's Docker image.

docker pull chocobozzz/peertube:v1.0.0-beta.11-stretch

Now we need to create a file with our configuration. These configs will help us set up our server. Some of these variables will be configurable in the configuration tab of your admin user. Please replace the value if it has “example” or is capitalized.

touch .peertube.env

In order to use the Peertube instance we will need to route to the container using Nginx.

4. Setting Up Nginx

Add the following server block to your /etc/nginx/sites-available. I took most of this configuration from the project. I needed to make slight modifications in order for it to work with my setup.

server {

  listen [::]:443 ssl http2;
  listen 443 ssl http2;

  add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
  add_header X-Content-Type-Options nosniff;
  add_header X-XSS-Protection "1; mode=block";
  add_header X-Robots-Tag none;

  location / {
           proxy_pass http://SOME-IP/;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header Host $host;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

           # Hard limit, PeerTube does not support videos > 8GB
           client_max_body_size 8G;
           proxy_connect_timeout       600;
           proxy_send_timeout          600;
           proxy_read_timeout          600;
           send_timeout                600;
  location /static/webseed {
    # Clients usually have 4 simultaneous webseed connections, 
    # so the real limit is 3MB/s per client
    limit_rate 800k;

    if ($request_method = 'OPTIONS') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
      add_header 'Access-Control-Max-Age' 1728000;
      add_header 'Content-Type' 'text/plain charset=UTF-8';
      add_header 'Content-Length' 0;
      return 204;

   if ($request_method = 'GET') {
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'Range,DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';

      # Don't spam access log file with byte range requests
      access_log off;
    proxy_set_header Host $host;
    proxy_pass http://SOME-IP;
    #alias /root/data/videos;


  # Websocket tracker
  location /tracker/socket {
    # Peers send a message to the tracker every 15 minutes
    # Don't close the websocket before this time
    proxy_read_timeout 1200s;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_pass http://SOME-IP;

server {
    if ($host = {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    if ($host = {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    return 404;

Once this looks good copy the file to /etc/nginx/sites-enabled and restart Nginx. Also, remove the default files if they are in the sites-enabled directory.

mv /etc/nginx/sites-available/ /etc/nginx/sites-enabled/

systemctl restart nginx

After adding this configuration make sure the certificate you set up using Let's Encrypt is still working. If it isn't please re-run the script.

5. Running Peertube

To launch Peertube run the command below.

docker run --env-file .peertube.env -v /root/data:/data -v /root/config:/config -d chocobozzz/peertube:v1.0.0-beta.11-stretch

And to check the logs run the command below.

docker logs CONTAINER_ID -f

If you see a warning that that says “It seems PeerTube was started (and created some data) with another domain name.". You should run the following commands.

docker exec -it CONTAINER_NAME /bin/sh

Inside of the container run:

npm run update-host

If you don't follow these steps you will be unable to federate with other instances

  1. Uploading your first video

If you have videos on Youtube and want to import them into Peertube I recommend shelling into to container, and using the commands below.

docker exec -it CONTAINER_ID /bin/sh

Run the script now like below. You will be prompted for your user password

node dist/server/tools/import-videos.js \
    -u "" \
    -U "USERNAME" \
    -t ""

Hope this was helpful! You can checkout my instance at