Website Self-Hosting with Orange Pi 3 LTS ✅

Overview

  • Ghost docker container as the website engine, running the GUI and decoration.
  • Cloudflare Tunnel to make the site publicly reachable on HTTPS 443 without port forwarding.
  • Cloudflare handles custom domain andrewcieslak.work
  • Docker runs "cloudflared" and the "ghost" container on Orange Pi 3 LTS

Step by Step instructions:

  • NOTE!!! Wherever there is a "{VALUE}", this is a PLACEHOLDER that must be replaced by the value described within. Ex: {DEVICE_IP} means replace "{DEVICE_IP}" with your device IP address.
  1. Flash Orange Pi OS. Ensure WiFi connects on every boot of the Orange Pi through initial WiFi configuration when flashing OS, or manually through wpa_supplicant.
  2. Connect to the OrangePi through ssh: (OrangePi username first, device IP address 2nd)
ssh {USERNAME}@{ORANGEPI_IP}
  1. Install docker headless on Debian on the Orange Pi.
sudo apt update
sudo apt upgrade -y
curl -fsSL https://get.docker.com | sudo sh
sudo systemctl enable docker
sudo systemctl start docker
sudo usermod -aG docker $USER
exit
  • Re-enter ssh and then check:
docker run hello-world
  1. Install ghost on Orange Pi where 2368 is the Ghost port. First, create a folder for Ghost:
mkdir -p /opt/ghost
cd /opt/ghost

Create/edit compose file:

sudo nano docker-compose.yml

Paste this config. file:

version: "3.9"

services:
  ghost:
    image: ghost:5-alpine
    container_name: ghost
    restart: unless-stopped
    ports:
      - "2368:2368"
    environment:
      security__staffDeviceVerification: false
      NODE_ENV: "production"
      url: "https://www.{DOMAIN_NAME}"
	  database__client: "sqlite3"
	  database__connection__filename: "/var/lib/ghost/content/data/ghost.db"
	  server__trustProxy: "true"
    volumes:
      - ghost-content:/var/lib/ghost/content

volumes:
  ghost-content:

Save and exit with Ctrl+O->Enter->Ctrl+X. Then launch and test Ghost with:

docker compose up -d
docker compose ps
  1. Install cloudflared on Orange Pi:
curl -L \
  https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64 \
  -o cloudflared
chmod +x cloudflared
sudo mv cloudflared /usr/local/bin/cloudflared
cloudflared --version
  1. Login to Cloudflare and select tunnel domain
cloudflared tunnel login

Select desired domain in browser from the given URL

  1. Create the tunnel
cloudflared tunnel create ghost-tunnel

This gives a tunnel UUID that must be saved.

  1. Create tunnel config file
sudo mkdir -p /etc/cloudflared
sudo nano /etc/cloudflared/config.yml
  • Paste the following config. file
tunnel: {TUNNEL_UUID}
credentials-file: /home/{USERNAME}/.cloudflared/{TUNNEL_UUID}.json

ingress:
  - hostname: {DOMAIN_NAME}
    service: http://127.0.0.1:2368

  - hostname: www.{DOMAIN_NAME}
    service: http://127.0.0.1:2368

  - service: http_status:404
  1. Wire DNS to the tunnel
cloudflared tunnel route dns ghost-tunnel {DOMAIN_NAME}
cloudflared tunnel route dns ghost-tunnel www.{DOMAIN_NAME}
  1. Launch the tunnel
cloudflared tunnel run ghost-tunnel

And test it with https://{DOMAIN_NAME} in any browser. Ghost should now be available, and adding "/ghost" to the end of the url opens the admin interface and starts to allow website editing.

  1. Redirect root to WWW at Cloudflare
    "Rules"->"Overview"->"Redirect Rules"->"Custom filter expression"->
    "When incoming requests match…"
  • Field=Hostname
  • Operator=equals
  • Value={DOMAIN_NAME}
    "Then..."
  • Type=Static
  • URL=https://www.{DOMAIN_NAME}
  • Status code=301
  • Preserve query string=Checked
    ->Save rule.
  1. Once confirmed, lock in the settings via:
sudo cloudflared service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared
systemctl status cloudflared

Now that I finished explaining this process and outlining it:

I realize that I likely can turn this into an executable script. The downside of this would be that it would likely only be configured for my exact install situation with the OrangePi 3 LTS OS image that I used, while this process above can likely be understood and extrapolated for more diverse use...