This article is to document how I managed to set up a personal cloud with raspberry pi 4B and mapped it to my own domain through Fast Reverse Proxy. Note this article is mainly for my own reference, so certain very detailed steps I will skip when it is obvious to me.

An update on 2024-12-23, I accidentally breaked the SD card on my pi, and now have to use usb drive to boot up.

What I have?

  • Raspberry Pi 4B with
  • A VPS with public IP address
    • I choose cheapest one as not any real intensive jobs were run there
  • My own domain (zhengzhicheng.com)

Setup Overview

The following diagram shows it maps the incoming traffic to the my local Raspberry pi through the VPS.

FRP and caddy are the main tools used in VPS, serving different purposes. Caddy is used to

  • Automatically obtain and renew TLS/SSL certificates for my site via Let’s Encrypt
  • Work as a reverse proxy to forward client requests from port 443 to port 8080

FRP is used to

  • Work as a reverse proxy to expose my local service (nextcloud) at pi to the Internet via public ip address offered by VPS

Argon Case and Smart Switch are used to

  • remotely power on and off the pi to save electrical bills

Steps

Step 1 => Pi setup

  1. Setup my Raspberry Pi 4B with argon case and plugged them into a smart plug so that I can remotely power on my Pi only when needed to avoid unnecessary electric charges

  2. OS installation I used Raspberry Pi Imager to install raspberry lite OS into my pi, I choose not to install any desktop environment because I am using it as a server and don’t want to waste extras resources for the GUI. Just make sure ssh is enabled when using the software to create the install medium so that I can ssh into it immediately after the set up.

  3. Install necessary tools

    • Docker and docker-compose
    • Tmux (Optional but I can’t work on command line without it!)
  4. Mount hard disk during start up

    • Check disk uuid by running sudo blkid
    • Add a line to /etc/fstab with UUID=your-disk-uuid /mnt/ssd1 brtfs defaults 0 2 (my ssd is formatted with btrfs)
    • Test if it works by running sudo mount -a
  5. Test!

Step 2 => Nextcloud setup

  1. Create a Docker Compose file
version: '3'

services:
  db:
    image: mariadb:latest
    restart: always
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: tbc
      MYSQL_DATABASE: tbc
      MYSQL_USER: tbc
      MYSQL_PASSWORD: tbc

  app:
    image: nextcloud:latest
    restart: always
    ports:
      - 8080:80
    volumes:
      - /mnt/ssd1/nextcloud_data:/var/www/html
    environment:
      MYSQL_PASSWORD: tbc
      MYSQL_DATABASE: tbc
      MYSQL_USER: tbc
      MYSQL_HOST: tbc
    depends_on:
      - db

volumes:
  db_data:
  nextcloud_data:
  1. Run docker compose up -d on the directory where the docker-compose.yml is located, and check if nextcloud instance is up at http://pi_ip_address:8080

  2. Create a frpc configuration file frpc.toml

    serverAddr = "207.148.119.198"
    serverPort = 7000
    
    [[proxies]]
    name = "nextcloud"
    type = "tcp"
    localIP = "127.0.0.1"
    localPort = 8080
    remotePort = 8080
    
    [[proxies]]
    name = "ssh"
    type = "tcp"
    localIP = "127.0.0.1"
    localPort = 22
    remotePort = 6000
    

    Then run frps -c frps.toml and test if nextcloud instance is accessible at my domain

  3. Lastly, create systemd service to start frps and docker compose automatically after pi boots up

Step 3 => Domain and vps setup

  1. Add DNS record for my site in Alibaba cloud’s console to resolve it to the public ip address

  2. Setup Caddy Since my site is bought from Alibaba cloud, I need to compile a caddy binary with alidns support, luckily there is already such a module in Github https://github.com/caddy-dns/alidns So I can just do xcaddy build --with github.com/caddy-dns/alidns

    • Create a Caddyfile with following configuration

      nc.zhengzhicheng.com {
        reverse_proxy localhost:8080
        tls {
          dns alidns {
            access_key_id {env.ALIYUN_ACCESS_KEY_ID}
            access_key_secret {env.ALIYUN_ACCESS_KEY_SECRET}
          }
        }
      }
      
    • Run caddy caddy run --config Caddyfile

  3. Set up FRP Server Service side configuration This is minimal, just one line bindPort = 7000 is enough, also can change to other ports, just make sure it is aligned with client side port. Then run frps -c frps.toml

  4. After tested and if it working, create systemd service to start frps and caddy automatically after system boots up

Mistakes I made

  • If using firewall tools such as ufw, remember to unblock port 22 for ssh connection, otherwise you can’t ssh to pi afterwards
    • After I stupidly installed ufw on vps and rebooted without unblocking port 22, I can’t ssh to my pi anymore. And since I installed server version without gui, I have to manually mount my sd hard (where the raspberry pi lite os is installed) to another Linux machine and modify ufw config file on the rootfs to enable port 22 again
  • Get a VPS with address that can be accessed even within corporate network
    • This is generally not a good idea but currently I take notes during work a lot, and not able to sync it to personal cloud immediately really frustrates me(maybe just my problem)
    • I forgot to test this before doing the configuration on my first vps and ended up doing the same thing again after I found out it does not work!
    • Maybe I should automate these steps in a script in the future

Conclusion

After all is done, when I need to access my files in the code, I can just open my phone app to switch on the raspberry pi and wait a few minutes, and then switch it off when I am done. Even though it seems a bit troublesome, but I think it’s better than keeping it on 24/7 and pay the extra eletrical bills. This functionality provided by this setup is very little but it satisfy my current need, a personalized webdav server. I plan to upgrade to a NAS in the future when I got the budget.