Setting up a Filecoin Saturn Node

The opinions expressed are solely my own and do not express the views or opinions of my employer 😀.

Summary

While in Lisbon at the end of 2022 I heard about the Filecoin Saturn launch and thought this was a pretty cool idea to create an on-chain CDN on-top of IPFS. The idea intrigued me to go through the process to setup a node. My setup notes were pretty involved so I figured I’d share it with community.

What is Filecoin Saturn?

Filecoin Saturn is an open-source, community-run Content Delivery Network (CDN) built on Filecoin.

Saturn is a Web3 CDN in Filecoin’s retrieval market. On one side of the network, websites buy fast, low-cost content delivery. On the other side, Saturn node operators earn Filecoin by fulfilling requests.

Prerequisites

Acquire a server with the recommended specifications

At the time of writing this (January 2023) the specifications are as follows:

Minimum RequirementsRecommended Requirements
CPU with 6 coresCPU with 12+ cores
32GB RAM128GB+ RAM
1TB SSD storage4TB+ SSD Storage
10Gbps upload link10Gbps+ upload link

Provider selection

This workload has a variable cost for data transfer and is based on the usage of the CDN service. Choosing a cloud provider that has less variable cost is more desirable for positive profit margins.

Baremetal Scenario

Some baremetal providers include 20TB of egress traffic with overages being $1 per TB. In this scenario your bandwidth costs would be $10.

Math ( (30-20) * 1 = 10 )

Cloud Scenario

AWS charges $0.09 per GB for egress costs with 100GB included for free monthly. In this scenario, your bandwidth costs would be $2961.

Math ( (30,000-100) * 0.09 = 2691 )

Create a Filecoin wallet

In order to receive your payouts via FIL you must own a Filecoin wallet. Filecoin wallets allow you to manage FIL, Filecoin’s native token. Wallets store the private keys that allow you to authorize Filecoin transactions, including paying for storage deals and sending FIL to other accounts.

Non-custodial Filecoin Wallets

File coin supports the following wallet implementations:

  • Glif Wallet – A lightweight web interface to send and receive Filecoin with a Ledger device (instructions).
  • Glif Safe – A multisig wallet with a lightweight web interface to send and receive Filecoin with a Ledger device (instructions). Check out the Glif Safe GitHub repo for more information.
  • Lotus – Includes a command-line wallet that can manage bls, sec1p256k1, multisig wallets, and supports Ledger integration.

Creating a Filecoin Wallet on Coinbase

At the time of writing this post, I’m not super bullish on FIL and as a result will be immediately converting my FIL to another currency. For this reason, I chose to create a Filecoin wallet on Coinbase.

To do so, you simply buy 1 FIL on Coinbase with your currency of choice. Then you click on “Send & Receive” and select FIL – The FIL address is your wallet address.

Coinbase will display your wallet address and QR code for sharing. Here is my QR code:

Seriously though, you might want to keep your wallet address private. All information regarding payouts, transfers, etc are public on the blockchain. Also, this data is commonly indexed and made publicly available via block explorers. Filfox is the popular block explorer for FIlecoin.

Preparing for deployment

From the above section you should have:

  • A server with the requirements and the ability to login into as root
  • A Filecoin Wallet

Now it’s time to prepare your deployment environment. In this example, I’ll be using my laptop as my deployment host but you could easily use a bastion host.

Ansible Installation

Ansible is an agent-less automation platform used to configure one or many nodes. I ran the following commands to install ansible:

brew update && brew upgrade
brew install ansible
ansible --version

Ansible Setup

The Filecoin foundation has prepared an Ansible playbook to fully configure a Saturn node however we have to prepare our deployment machine to do so.

  • Install a required Ansible Module
ansible-galaxy collection install community.docker
  • Clone the repo prepared by Filecoin and CD into it
  • Create a file called inventory.yaml and add your hosts
saturn:
  hosts:
    moon1:
      ansible_host: IP_ADDRESS
      ansible_user: root
      ansible_ssh_private_key_file: ~/.ssh/KEY
  • Note
    • In my inventory file i have a parent called “saturn” – this is for targeting all hosts
    • I could also target individuals hosts – in my inventory file they are called “moons”
  • Test end to end connectivity by running the Ansible Ping command – For me, this returns a success “pong”
ansible -vvv -i inventory.yaml saturn -m ping

moon1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "invocation": {
        "module_args": {
            "data": "pong"
        }
    },
    "ping": "pong"
}
  • Next we need to install the speedtest cli by ookla – for this I created an ansible playbook called playbooks/speedtest.yml
---
- name: Speedtest playbook
  tags: speedtst
  hosts: all
  gather_facts: false
  tasks:
    
   - name: Download speedtest script
     become: yes
     get_url:
       url: https://packagecloud.io/install/repositories/ookla/speedtest-cli/script.deb.sh
       dest: /home
       mode: 0777
       
   - name: Copy and Execute the script 
     command: bash /home/script.deb.sh

   - name: Install speedtest
     apt:
      name: speedtest
  • Run the speedtest ansible playbook to install speed test
ansible-playbook -i inventory.yaml playbooks/speedtest.yml -vvvv
  • Then we need to use speedtest to get a list of servers closest to us
ansible -i inventory.yaml saturn -m shell -a "speedtest -L"

moon1 | CHANGED | rc=0 >>
Closest servers:

   ID  Name                           Location             Country
==============================================================================
 45489  Smart City Telecom             Lake Buena Vista, FL United States
 53543  frantic.link                   Kissimmee, FL        United States
 42450  NexGen Communications          Orlando, FL          United States
 10161  CenturyLink                    Orlando, FL          United States
 28307  Summit Broadband               Orlando, FL          United States
 40227  Flash Fiber                    Orlando, FL          United States
 48319  Whitesky Communications LLC    Orlando, FL          United States
 36808  832communications              Orlando, FL          United States
 25760  The Villages                   The Villages, FL     United States
 17170  Spectrum                       Tampa, FL            United States
  • Add the additional parameters to your .env file
SATURN_NETWORK="main or test"
FIL_WALLET_ADDRESS="WalletAddress"
NODE_OPERATOR_EMAIL="YourEmail"
SPEEDTEST_SERVER_CONFIG="--server-id=PickIDFromLastCommand"
SATURN_HOME="/home/"
  • I removed the section around hardening the OS in the l1.yaml playbook because I have a playbook specifically around this which. I won’t share my playbook for security reasons but you can easily research one or create your own. Please use your own automation or best practice to harden your system. Below is the edited version of l1.yaml.
---
- name: Configure playbook
  tags: config
  hosts: all
  gather_facts: true
  tasks:
    - name: Add docker GPG key
      become: true
      become_user: root
      apt_key:
        url: https://download.docker.com/linux/{{ ansible_distribution | lower }}/gpg
    - name: Add docker repository (yum)
      become: true
      become_user: root
      # ref - https://www.ansiblepilot.com/articles/install-docker-in-redhat-like-systems-ansible-module-rpm_key-yum_repository-and-yum/
      ansible.builtin.yum_repository:
        name: docker
        description: docker repository to CentOS
        baseurl: "https://download.docker.com/linux/centos/$releasever/$basearch/stable"
        enabled: true
        gpgcheck: true
        gpgkey: "https://download.docker.com/linux/centos/gpg"
        state: present
      when: ansible_distribution == "CentOS"
    - name: Add docker repository (apt)
      become: true
      become_user: root
      ansible.builtin.apt_repository:
        filename: docker
        repo: deb [arch=amd64] https://download.docker.com/{{ ansible_system | lower }}/{{ ansible_distribution | lower }} {{ ansible_distribution_release }} stable
        state: present
      when: ansible_distribution in ["Debian", "Ubuntu"]
    - name: Install aptitude
      become: true
      become_user: root
      ansible.builtin.package:
        name:
          - aptitude
        update_cache: true
      when: ansible_distribution in ["Debian", "Ubuntu"]
    - name: Install dependencies
      become: true
      become_user: root
      ansible.builtin.package:
        name:
          - wget
          - docker-ce
          - docker-ce-cli
          - containerd.io
          - docker-compose-plugin
          - python3-pip
        state: latest
        update_cache: true
    - name: Install python packages
      become: true
      become_user: root
      ansible.builtin.pip:
        executable: pip3
        name:
          - docker>5.0.0
        state: present
    - name: Start docker
      become: true
      become_user: root
      ansible.builtin.service:
        name: docker
        enabled: true
        state: started

- name: Run playbook
  tags: run
  hosts: all
  vars:
    # this wasn't consistent between runs, so we need to store it
    homedir: "{{ ansible_env.HOME }}"
    saturn_home: "{{ saturn_root if saturn_root is defined else homedir }}"
    env_file: "{{ lookup('file', '../.env' ) }}"
  tasks:
    - name: Copy the .env file
      ansible.builtin.copy:
        src: ../.env
        dest: "{{ saturn_home }}"
    - name: Patch SATURN_HOME
      ansible.builtin.blockinfile:
        path: "{{ saturn_home }}/.env"
        block: SATURN_HOME="{{ saturn_home }}"
    - name: Get docker-compose.yml
      become: true
      become_user: root
      ansible.builtin.get_url:
        url: https://raw.githubusercontent.com/filecoin-saturn/L1-node/main/docker-compose.yml
        dest: "{{ saturn_home }}/docker-compose.yml"
    - name: Ensure we have the right $SATURN_HOME/shared permissions
      become: true
      become_user: root
      ansible.builtin.file:
        path: "{{ saturn_home }}/shared"
        mode: "0755"
        state: directory
    - name: Run docker compose
      become: true
      become_user: root
      ansible.builtin.command: docker compose up -d
      # ansible.builtin.command: docker compose restart watchtower
      # ansible.builtin.shell: (docker rm -f saturn-node || true) && (docker rm -f saturn-watchtower) && docker compose up -d
      args:
        chdir: "{{ saturn_home }}"
  • Run the l1.yaml playbook
ansible-playbook -i inventory.yaml playbooks/l1.yaml -vvvv
  • Once complete, check out the logs on the host for any errors by running the following command “docker logs –follow saturn-node”. You can also see in the logs the id of your node.
  • You can check the status of your wallet ID by visiting: https://dashboard.strn.network/address/
  • You can also check the status of your node by visiting the following url and filtering by your node id: https://dashboard.strn.network/stats

Closing

I will be posting a retrospective of my performance sometime in February of 2023. If you run into issues and need help during your setup, check out the Filecoin Foundation’s Slack: https://filecoin.io/slack.