Owning Your Data: Self-hosting Standard Notes at Home

Owning Your Data: Self-hosting Standard Notes at Home

This article is about self-hosting Standard Notes in your home network. Standard Notes is a free, open-source, and completely encrypted notes app which can be self-hosted anywhere. Alternatively, they also offer both free and paid PaaS solutions for hosting content on their servers. This post deals with hosting Standard Notes at home on a Synology NAS running on DSM 7.2. Alternatively, it can also be hosted on Raspberry Pi, Portainer, or any Linux server similarly. As my router sits behind a primary router which does not allow port forwarding, Cloudflare tunnel will be used to connect to the NAS as a reverse proxy. Alternatively, if your server is connected to a primary router, port forwarding can be used to connect via the Internet. However, opening up ports on a router should only be done if there are proper firewall rules in place. Also, Cloudflare traffic is end-to-end encrypted by default throughout the Cloudflare tunnel, so you need not manually setup HTTPS encryption.

Prerequisites

Standard Notes will be running as a Docker container on the NAS. In order to run Docker containers on DS 7.2, Docker and/or Container Manager needs to be installed. Also, we will be using Docker-compose to run Standard Notes and its dependencies. It needs to be manually installed (if not already available) and run via CLI. For this, it is necessary to open up port 22 in the NAS to allow ssh connections.

Domain registration

Domain registration can be done via Cloudflare or if you already have an existing domain name, it can either be transferred to Cloudflare or it can also be connected to the Cloudflare tunnel by adding CNAME or Alias records to your existing domain. If you're not going to use a Zero-Trust Tunnel, then you are free to use any domain provider.

Cloudflare Zero-Trust Tunnel

Cloudflare tunnels need to be configured to connect to the NAS via the internet. You can create a tunnel by navigating to Cloudflare's Zero trust dashboard and create a new tunnel under Access ⇾ Tunnels. You will then receive a token with which you can connect your client. Take a note of this token and keep this tab open until our client connector has been connected to the tunnel successfully.

Configuration

In order to map volumes, create the following folder structure in your NAS file system.

volume1	/
├── homes/
│   ├── your_username/
│   │   ├── standard_notes/
│   │   │   ├── logs/
│   │   │   ├── uploads/
│   │   │   ├── data/
│   │   │   │   ├── mysql/
│   │   │   │   ├── import/
│   │   │   │   └── redis/

Then login to the server via SSH and navigate to the standard_notes directory.

ssh [email protected]
cd standard_notes

Create a .env file in this working directory and copy the default values from Standard Notes docs.

touch .env
curl https://raw.githubusercontent.com/standardnotes/server/main/.env.sample > .env

The default .env file should be as follows.

######
# DB #
######

DB_HOST=db
DB_PORT=3306
DB_USERNAME=std_notes_user
DB_PASSWORD=changeme123
DB_DATABASE=standard_notes_db
DB_TYPE=mysql

#########
# CACHE #
#########

REDIS_PORT=6379
REDIS_HOST=cache
CACHE_TYPE=redis

########
# KEYS #
########

AUTH_JWT_SECRET=
AUTH_SERVER_ENCRYPTION_SERVER_KEY=
VALET_TOKEN_SECRET=

Open your .env file and make sure the values for the variables in the KEYS section are properly set. You can run the following command in order to generate a key value for each of the required environment variable.

openssl rand -hex 32

Copy the LocalStack bootstrap script and place it in your working directory. Ensure the file has executable permissions.

curl https://raw.githubusercontent.com/standardnotes/server/main/docker/localstack_bootstrap.sh > localstack_bootstrap.sh
chmod +x localstack_bootstrap.sh

Copy the docker-compose.example.yml file to a file called docker-compose.yml in the working folder.

curl https://raw.githubusercontent.com/standardnotes/server/main/docker-compose.example.yml > docker-compose.yml

You can customize the server port in services/ports in the docker-compose.yml file, if you have other services running in the default port 3000.

Next, change the default database password. Generate a secure random string and replace this string in the DB_PASSWORD field in .env file and in MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD fields in docker-compose.yml file.

If you want to use Cloudflare zero trust tunnels, add the following service to your docker-compose.yml file.

cloudflared: 
    image: cloudflare/cloudflared:latest
    container_name: cloudflare-tunnel-for-standard-notes
    restart: always
    command: tunnel --no-autoupdate run
    environment: 
      - TUNNEL_TOKEN=cloudflare-tunnel-token-noted-above

Enter the TUNNEL_TOKEN value noted previously.

The final docker-compose.yml file should be as follows.

services:
  server:
    image: standardnotes/server
    env_file: .env
    container_name: server_self_hosted
    restart: unless-stopped
    ports:
      - 3000:3000
      - 3125:3104
    volumes:
      - ./logs:/var/lib/server/logs
      - ./uploads:/opt/bundled/files/packages/files/dist/uploads
    networks:
      - standardnotes_self_hosted

  localstack:
    image: localstack/localstack:1.3
    container_name: localstack_self_hosted
    expose:
      - 4566
    restart: unless-stopped
    environment:
      - SERVICES=sns,sqs
      - HOSTNAME_EXTERNAL=localstack
      - LS_LOG=warn
    volumes:
      - ./localstack_bootstrap.sh:/etc/localstack/init/ready.d/localstack_bootstrap.sh
    networks:
      - standardnotes_self_hosted
  cloudflared: 
    image: cloudflare/cloudflared:latest
    container_name: cloudflare-tunnel-for-standard-notes
    restart: always
    command: tunnel --no-autoupdate run
    environment: 
      - TUNNEL_TOKEN=cloudflare-tunnel-token-noted-above
      
  db:
    image: mysql:8
    container_name: db_self_hosted
    environment:
      - MYSQL_DATABASE=standard_notes_db
      - MYSQL_USER=std_notes_user
      - MYSQL_ROOT_PASSWORD=enter_changed_password
      - MYSQL_PASSWORD=enter_changed_password
    expose:
      - 3306
    restart: unless-stopped
    command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci
    volumes:
      - ./data/mysql:/var/lib/mysql
      - ./data/import:/docker-entrypoint-initdb.d
    networks:
      - standardnotes_self_hosted

  cache:
    image: redis:6.0-alpine
    container_name: cache_self_hosted
    volumes:
      - ./data/redis/:/data
    expose:
      - 6379
    restart: unless-stopped
    networks:
      - standardnotes_self_hosted

networks:
  standardnotes_self_hosted:
    name: standardnotes_self_hosted

To spin up all the services in this environment, run the following docker-compose command.

sudo docker-compose pull && sudo docker-compose up -d

It will take a moment for the infrastructure to spin up. Deploying the YAML file will also start up the Cloudflare tunnel. Navigate to Cloudflare tunnel page to see the status of the connector. Once the connection is established, you can configure where to route the traffic to. Select Public hostname as yourdomain.com and enter Service as http://192.168.xxx.xxx:3000. You can also host it in a custom subdomain, depending on your preference.

You can monitor deployment logs using the following command.

tail -f logs/*.log

If you encounter issues, check the error logs: tail -f logs/*.err.

After the infrastructure is up and running, you can check it's available by visiting https://<subdomain or www>.<your-domain-name>.<TLD> in your browser.

Using your new server

Download the Standard Notes app or visit https://app.standardnotes.com/ to create an account in your self-hosted server and start using it. Note that if you are an existing Standard Notes user using the default PaaS solution and want to migrate to the self-hosted server, you cannot use your existing account. You will need to re-register on your new server. You can export backup of your existing notes from your old account and import them in the new account easily. This will import all your existing notes and plugins too.

To create a new account in the new server, click on the account menu, choose Advanced options and enter the address of your new server in Custom sync server. Then, register for a new account and begin using your private new secure Standard Notes server! Note that it is very easy to forget that you need to specify your Custom Sync server via the Advanced options dropdown while creating a new account or logging in via your mobile or desktop application. Otherwise, it will try to log you in using Standard Note's default PaaS server, where your account is obviously not registered. Therefore, always remember to specify your Custom Sync Server while logging in.

Select the Create free account or Sign in option.
Make sure to specify Custom Sync Server while creating an account or logging in.

After successful installation and setup of Standard Notes, you may disable ssh access on Synology NAS again, to enhance protection.

All your notes are now safely stored in your home under your full control and not in an unknown server elsewhere managed by someone else.

Happy Hacking!