balena-os / wifi-connect

Easy WiFi setup for Linux devices from your mobile phone or laptop
Apache License 2.0
1.3k stars 364 forks source link

Guide for Installation on Ubuntu 20.10 on Raspberry Pi 4 with Extras! #392

Open MarkProminic opened 3 years ago

MarkProminic commented 3 years ago

This guide is to document how I was able to install the Wifi-connect and Wifi-connect-api using Docker on my Raspberry Pi installed with Ubuntu 20.10 (following the ZFS Guide: Ubuntu 20.10 root on ZFS for Raspberry Pi

Installations Steps

Step 1. Install Ubuntu Per the Guide above or via the Standard Noobs Installation

Step 2. Install Docker and Docker Compose for Raspberry Pi 64 (aarch64)

Step 3. Since I wanted this to be in my existing Docker Swarm/Cluster, I Added the Following Docker-Compose Configuration to docker-compose.yaml.

Note the important parts here are to Give this container Priveleged Access, Host Network, and to define the DBUS connection as it is different in Ubuntu than BalenaOS:

---
version: "3.9"
services:
  ~~~~ Other Services Here
  wifi-connect-api:
    build:
      context: "wifi-connect-api"
      dockerfile: Dockerfile-wifi-connect-api
    image: result/latest
    network_mode: host
    privileged: true
## I am not sure how Labels work as I am new to Docker, I don't think these apply without the Balena Superviosor. Someone please correct me
    labels: 
      io.balena.features.dbus: "1"
      io.balena.features.firmware: "1"
    volumes:
    - "path/to/{ui_and_web-app.py}:/usr/src/app/"
    - type: bind
      source: /dev/bus/usb
      target: /dev/bus/usb
    - type: bind
      source: /var/run/dbus
      target: /var/run/dbus

Step 4. Download the Requirements and made my Adjustments to the Scripts, UI, etc:

git clone https://github.com/balena-io-examples/wifi-connect-api

Step 5. I Modified the Dockerfile that the Docker Compose kicks off to: Dockerfile-wifi-connect-api:

FROM balenalib/raspberrypi4-64-python
RUN install_packages dnsmasq curl
ENV WIFI_CONNECT_VERSION v4.2.5
WORKDIR /tmp/download
RUN curl -Ls https://github.com/balena-os/wifi-connect/releases/download/v4.4.5/wifi-connect-v4.4.5-linux-aarch64.tar.gz \
    | tar -xvz -C /tmp/download
RUN mv wifi-connect /usr/local/sbin
RUN rm -rdf /tmp/download
WORKDIR /usr/src/app
RUN pip install --upgrade pip
COPY ./requirements.txt /requirements.txt
RUN pip install -r /requirements.txt
COPY . ./
ENV DBUS_SYSTEM_BUS_ADDRESS unix:path=/var/run/dbus/system_bus_socket
CMD ["python", "web-app.py"]

Step 6. Run Docker Build:

docker-compose build --no-cache

Step 7. Run Docker Up to start the instance to test:

docker-compose up -d

Step 8. Verify that Wifi-Connect Launches, You can connect, it sticks, no issues occur, Etc

Congratulations! The Docker container runs! Here are the Extras!

But how do I get a Secured Connections if I redirect? Well you can Preload a Certificate using Nginx or HAproxy.

What if I want to embed the Wifi Connect page in an site? Nginx and HAproxy also have the ability to handle this. Though configs can get tricky.

Step 9. Setup Haproxy/Nginx on your Raspberry Pi as a Reverse Proxy:

Nginx and Haproxy Install

apt-get install haproxy nginx -y

IPTables Rules config:

https://forums.balena.io/t/wifi-connect-and-port-80/221264/30

Haproxy Config

frontend HTTPS-IN
    bind *:443  ssl crt /ssl/haproxy.pem
    mode http

   # BEGIN CORS
    http-response set-header Access-Control-Allow-Origin "*"
    http-response del-header X-Frame-Options
    http-response set-header Content-Security-Policy "frame-ancestors https://*:*; sandbox allow-top-navigation allow-scripts allow-popups allow-forms allow-same-origin allow-presentation a>
    http-response set-header Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Accept, Authorization, JSNLog-RequestId, activityId, applicationId, applicationUserId, cha>
    http-response set-header Access-Control-Allow-Methods "GET, DELETE, OPTIONS, POST, PUT, PATCH"
    http-response set-header X-Frame-Options: sameorigin
    http-response set-header X-XSS-Protection: 0;

    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header X-Forwarded-Proto http if !{ ssl_fc }

    # END CORS

    #ACL Definitions

    ## Host ACLs
    #Catch any URL with these Hostnames
    acl host_connect hdr(host) -i rPi-wc-lan-2.home.mydomain.com
    acl host_connecths hdr(host) -i hotspot.home.mydomain.com
    acl host_connectip hdr(host) -i 192.168.42.1

    # and send them to this backend:    
   use_backend backend_connect if host_connect
    use_backend backend_connect if host_connecths
    use_backend backend_connect if host_connectip

backend backend_connect
        mode http
        balance  leastconn
        option tcpka
        option http-keep-alive
        option forwardfor
        server Wifi-Connect hotspot.home.mydomain.com:45454  check  cookie app1

Nginx Configs

## This is the URL that you can access the client on IE: https://mydomain.com:port/wifi-connect/
        location  ^~  /wifi-connect/  {
                proxy_pass https://hotspot.home.mydomain.com:443/;
                proxy_set_header Host $proxy_host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-Proto $scheme;
        }

Step 10. Adjust the code in the Sample Script to point to a DNS entry that is set to the IP of the Gateway:

This will redirect your Phone, mobile device to the HTTPS link of the local IP of the gateway, while allowing you to also access the Wifi Interface from outside the pi, should it be connected to the LAN and you don't want your users to access the CLI or RDP/VNC into the desktop.

@app.before_request
def before_request():
    if (request.host == 'rpi-wc-lan-2.home.mydomain.com'):
        return redirect('https://rpi-wc-lan-2.home.my.domain.com:443')
    elif (request.host != 'hotspot.home.domain.com'):
        return redirect('https://hotspot.home.domain.com')

Step 11. Modify the index.html in the UI folder to remove all prefixed / in links. From:

<link rel="shortcut icon" href="/img/favicon.png">

To:

<link rel="shortcut icon" href="img/favicon.png">

Even More Extra's and Goodies

What if I want the Device to Dynamic Update it's FQDN?

Well, I have made a small bash script and followed the following Guide to setup a External DDNS server using Bind9 on Ubuntu 20.10. There are quiet a few difference in the bind that they used in their version, but the gist is there and it works perfectly.

Step 11.

Server Side:

DDNS Guide

Client Side: Example Bash script, call using rc.local, systemd, cron or some other method of your choosing:

Register.sh (rename from .txt) -- register.txt

I have sanitized and stripped this down, so you will need to replace domains, paths, usernames, etc. but you can adjust the Sed commands to modify the web-app.py file that you mounted via a volume instead of having it read only on the Docker File System.

Sources:

Other Potentially Similar Issues:

yangjie777 commented 1 year ago

I'd like to know what version of python you're using, thanks

yangjie777 commented 1 year ago

balenalib/raspberrypi4-64-python python is 3.11,What should I do, thanks