How to Host Your Website on a Raspberry Pi with Cloudflare Tunnels


How to Host Your Website on a Raspberry Pi with Cloudflare Tunnels

In this guide, we’ll walk through setting up a secure and accessible web server using a Raspberry Pi and Cloudflare Tunnels. This setup allows you to host your website from home without exposing your home IP address or opening ports on your router, thanks to Cloudflare’s secure tunneling technology.

Prerequisites:

  • A Raspberry Pi (We used a Raspberry Pi 4 with 8GB RAM, but other models should work with adjustments)
  • Raspberry Pi OS installed on the Pi
  • SSH access to your Raspberry Pi
  • A domain name you own
  • A Cloudflare account
  • A static website ready to be deployed (We used an Astro site for this example, but the steps apply to other types of sites as well)

Step 1: Prepare Your Raspberry Pi

First, ensure your Raspberry Pi is up to date and install Nginx, which will serve as our web server.

  1. Update your system:

    sudo apt update
    sudo apt full-upgrade
    sudo reboot
    
  2. Install Nginx:

    sudo apt install nginx
    
  3. Verify Nginx Installation:

    Visit your Raspberry Pi’s local IP address in a browser. You should see the default Nginx welcome page.

Step 2: Build and Deploy Your Website

With your Raspberry Pi ready, it’s time to build your website and place it where Nginx can serve it.

  1. Navigate to your project directory and build your website:

    cd /path/to/your/website/project
    npm run build
    

    This creates a dist folder (or your configured output folder) containing your website’s static files.

  2. Create a directory for your website:

    sudo mkdir -p /var/www/mywebsite
    
  3. Copy your website files:

    sudo cp -r /path/to/your/website/project/dist/* /var/www/mywebsite/
    

    Note: It is recommended to delete old files before copying the new ones to prevent any old files from staying in your website’s directory. You can delete them with:

    sudo rm -rf /var/www/mywebsite/*
    

Step 3: Configure Nginx

Configure Nginx to serve your website.

  1. Create a new Nginx configuration file:

    sudo nano /etc/nginx/sites-available/mywebsite
    
  2. Add the following configuration, adjusting your domain and paths as necessary:

    server {
        listen 80;
        server_name yourdomain.com [www.yourdomain.com](https://www.yourdomain.com);
    
        root /var/www/mywebsite;
        index index.html;
    
        location / {
            try_files $uri $uri/ =404;
        }
    }
    
  3. Enable the site and disable the default site:

    sudo ln -s /etc/nginx/sites-available/mywebsite /etc/nginx/sites-enabled/
    sudo unlink /etc/nginx/sites-enabled/default
    
  4. Test and reload Nginx configuration:

    sudo nginx -t
    sudo systemctl reload nginx
    

Step 4: Install and Configure Cloudflared

Install the Cloudflare Tunnel daemon (cloudflared) and set up a tunnel.

  1. Download and install cloudflared:

    wget [https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb](https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb)
    sudo dpkg -i cloudflared-linux-arm64.deb
    
  2. Authenticate cloudflared:

    cloudflared tunnel login
    

    Follow the prompts in your browser to log in to your Cloudflare account and select your domain.

  3. Create a tunnel:

    cloudflared tunnel create mytunnel
    
  4. Configure the tunnel:

    sudo mkdir /etc/cloudflared
    sudo nano /etc/cloudflared/config.yml
    

    Add the following configuration, replacing mytunnel with your tunnel name, <UUID> with your tunnel’s UUID, and yourdomain.com with your domain:

    tunnel: mytunnel
    credentials-file: /home/yourusername/.cloudflared/<UUID>.json
    ingress:
      - hostname: yourdomain.com
        service: http://localhost:80
      - hostname: [www.yourdomain.com](https://www.yourdomain.com)
        service: http://localhost:80
      - service: http_status:404
    
  5. Run the tunnel:

    cloudflared tunnel --config /etc/cloudflared/config.yml run
    

Step 5: Configure DNS Records in Cloudflare

  1. Log in to your Cloudflare dashboard and go to the DNS settings for your domain.

  2. Add CNAME records for your root domain and www subdomain pointing to your tunnel’s .cfargotunnel.com address.

    • Type: CNAME
    • Name: @ (for the root domain)
    • Target: <your-tunnel-id>.cfargotunnel.com
    • Proxy status: Proxied
    • TTL: Auto

    Repeat for the www subdomain:

    • Type: CNAME
    • Name: www
    • Target: <your-tunnel-id>.cfargotunnel.com
    • Proxy status: Proxied
    • TTL: Auto

Step 6: Set up cloudflared as a systemd Service

To ensure cloudflared runs automatically on startup:

  1. Create a systemd service file:

    sudo nano /etc/systemd/system/cloudflared.service
    
  2. Add the following content, adjusting paths and usernames as needed:

    [Unit]
    Description=Cloudflared Tunnel
    After=network.target
    
    [Service]
    TimeoutStartSec=0
    Type=notify
    ExecStart=/usr/local/bin/cloudflared tunnel --config /etc/cloudflared/config.yml run mytunnel
    User=yourusername
    Group=yourusername
    Restart=on-failure
    RestartSec=10
    
    [Install]
    WantedBy=multi-user.target
    
  3. Enable and start the service:

    sudo systemctl enable cloudflared
    sudo systemctl start cloudflared
    

Step 7: Secure Your Server

Enhance your server’s security by setting up a firewall and a brute-force protection tool.

  1. Install and configure ufw (Uncomplicated Firewall):

    sudo apt install ufw
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow ssh
    sudo ufw allow http
    sudo ufw allow https
    sudo ufw enable
    
  2. Install and configure fail2ban:

    sudo apt install fail2ban
    sudo systemctl start fail2ban
    sudo systemctl enable fail2ban
    sudo nano /etc/fail2ban/jail.local
    

    Add the following configuration to jail.local:

    [DEFAULT]
    bantime = 3600
    banaction = iptables-multiport
    findtime = 600
    maxretry = 3
    
    [sshd]
    enabled = true
    
    [nginx-http-auth]
    enabled = true
    port = http,https
    filter = nginx-http-auth
    logpath = /var/log/nginx/error.log
    
    [nginx-badbots]
    enabled = true
    port = http,https
    filter = nginx-badbots
    logpath = /var/log/nginx/access.log
    
    [nginx-noscript]
    enabled = true
    port = http,https
    filter = nginx-noscript
    logpath = /var/log/nginx/access.log
    

    Restart fail2ban:

    sudo systemctl restart fail2ban
    

Conclusion

You’ve now successfully set up a web server on your Raspberry Pi using Cloudflare Tunnels, Nginx, and enhanced its security with ufw and fail2ban. This setup provides a secure and efficient way to host your website from home. Remember to keep your system updated and monitor logs regularly to maintain security and performance.

Further Enhancements:

  • HTTPS: Cloudflare Tunnel automatically provisions SSL certificates, so your site should be accessible via HTTPS.
  • Caching: Configure Cloudflare’s caching options to improve performance.
  • Dynamic DNS: If your home IP address changes, consider setting up dynamic DNS to update your Cloudflare DNS records automatically.
  • Monitoring: Set up monitoring tools to keep an eye on your server’s performance and uptime.