diff --git a/README.orig.md b/README.orig.md new file mode 100644 index 0000000..0429a08 --- /dev/null +++ b/README.orig.md @@ -0,0 +1,3 @@ +# Docs + +The core documentation on how to setup an SBC as a lolipop cloud \ No newline at end of file diff --git a/armbian/README.md b/armbian/README.md new file mode 100644 index 0000000..8befeb7 --- /dev/null +++ b/armbian/README.md @@ -0,0 +1,3 @@ +# Armbian + +Setup an SBC as a lolipop router and private LAN \ No newline at end of file diff --git a/armbian/base_setup.md b/armbian/base_setup.md new file mode 100644 index 0000000..8f90de7 --- /dev/null +++ b/armbian/base_setup.md @@ -0,0 +1,47 @@ +# Base Setup + +Fundamental setup after first boot/reboot. + +## Pro Tip + +```sudo -sHu root``` is a handy trick when doing a lot of administrative stuff at the command line + +## Upgrade Packages + +``` bash + +apt update +apt upgrade +systemctl reboot + +``` + +## DISABLE Automatic Update Downloads + +*Note: this is to save bandwidth, time, etc when travelling* + +### /etc/apt/apt.conf.d/02periodic + +Change ```APT::Periodic::Enable "1";``` to ```APT::Periodic::Enable "0";``` + +### /etc/apt/apt.conf.d/20auto-upgrades + +Change ```APT::Periodic::Update-Package-Lists "1";``` to ```APT::Periodic::Update-Package-Lists "0";``` + +Change ```APT::Periodic::Unattended-Upgrade "1";``` to ```APT::Periodic::Unattended-Upgrade "0";``` + +## Tweak OpenSSH Config + +Edit ```/etc/ssh/sshd_config``` + +Make sure the following are set and/or adjusted. + +- ```PermitRootLogin no``` + +Restart the service + +```systemctl restart sshd``` + +## Networking + +See ```network_manager.md``` for details on getting online after running the above commands for how to get online and configure routing. diff --git a/armbian/borg.md b/armbian/borg.md new file mode 100644 index 0000000..9bb1224 --- /dev/null +++ b/armbian/borg.md @@ -0,0 +1,88 @@ +# Borg Backups + +The BETTER backup solution. + +**BE MINDFUL OF RUNNING BORG. IT CAN CAUSE PROBLEMS WITH DISK IOPS AND RAM USAGE. BEST USED WHEN THE MACHINE IS KNOWN TO BE IDLE!!!** + +## Inspiration / Further Reading + +- [https://borgbackup.readthedocs.io/en/stable/installation.html#from-source](https://borgbackup.readthedocs.io/en/stable/installation.html#from-source) + +## Install + +Note this is built using sources (kinda). May take awhile on most arm boards. + +``` bash + +# install build dependencies +apt update +apt install python-setuptools python3-setuptools \ + python3 python3-dev python3-pip python-virtualenv \ + libssl-dev openssl \ + libacl1-dev libacl1 \ + build-essential \ + libfuse-dev fuse pkg-config +pip3 install borgbackup[fuse] + +``` + +## Upgrades + +Per the docs + +> To upgrade Borg to a new version later, run the following after activating your virtual environment: + +```pip install -U borgbackup[fuse]``` + +## Initialize Backup Repo + +*Note: assumes you have a ```/tank``` on external disk* + +``` bash + +cd /tank/backup +borg init --encryption none . # No crypto/auth for speed (see docs for more infos) + +``` + +## Backup Script + +Setup a backup script that backs up everything (**note the excludes**) to the initialized repository. + +Run ```/root/borg_backup.sh``` any time you want to take a backup. + +``` bash + +cat > /root/borg_backup.sh < /root/update_caddy.sh < /etc/caddy/Caddyfile < /etc/unbound/local_zone/caddy.conf <> /etc/chrony/chrony.conf <> /etc/docker/daemon.json < /etc/sysctl.d/20-routing.conf < /etc/incron.d/unbound.conf < /etc/incron.d/caddy.conf < /etc/incron.d/acme-sh.conf < /root/docker/acme.sh/acme.sh <&1 | less +munin-node-configure --shell 2>&1 | less +systemcl restart munin-node +systemctl enable munin-node + +``` + +### Serving Output Via Caddy + +``` bash + +cat > /etc/caddy/services/munin.conf < WiFi > 3G/LTE for connection priority. (*Note: NetworkManager assumes this too*) + +## Install / Enable + +``` bash + +apt update +# Install additional deps +apt install ebtables ipset +# Install + add-ons +apt install network-manager \ + network-manager-openvpn network-manager-pptp +systemctl enable NetworkManager # Enable the service +systemctl start NetworkManager # Start the service + +``` + +## Disable Stock Networking + +Edit ```/etc/network/interfaces``` and make sure eth0 directives aren't present. + +Reboot after above cleanup of interfaces file. + +## ProTip + +```nmtui``` can be used for an ncurses graphical interface for NetworkManager + +## Set Hostname + +``` bash + +nmcli general hostname [hostname] # Additional parm sets hostname +systemctl reboot # Reboot to pickup the change + +``` + +## Get Status + +Some commands that help getting the status of NetworkManager + +- ```nmcli networking connectivity``` +- ```nmcli monitor``` +- ```nmcli device monitor``` +- ```nmcli connection monitor``` + +## Enable / Disable ALL + +Handy if you want to shut down *all* networking for some reason + +```nmcli networking on|off``` + +## Radio Control + +Control WiFi / GSM radios + +### Wifi + +```nmcli radio wifi [on|off]``` + +### 3G/LTE + +```nmcli radio wwan [on|off]``` + +## Connection / Device Related + +Some useful commands for adjusting connection/device status + +- ```nmcli connection reload # Reload any changes / updates (this isn't automagic by default)``` +- ```nmcli connection show --active``` +- ```nmcli connection up [id]``` +- ```nmcli connection down [id]``` +- ```nmcli device status``` +- ```nmcli device show [ifname]``` +- ```nmcli device connect [ifname]``` +- ```nmcli device disconnect [ifname]``` + +## Disable Orange Pi Zero Internal WiFi + +If you're using an Orange Pi Zero, the internal WiFi adapter is unstable at best. The following will disable the adapter. + +``` bash + +nmcli device status # Verify the internal WiFi is shwoing as wlan0 +nmcli device disconnect wlan0 # Run this if it shows as connected +nmcli device set wlan0 autoconnect no + +``` + +## Setup Networks + +Some configuration via ```nmcli``` for various networks/interfaces/devices that may or may not be in use at any given moment. These commands just make NetworkManager aware of the overall topology and connections. Routing, firewall and more is setup later. + +*Note: Add autoconnect false if you don't want the connection auto started if a device is present* + +### Clear Existing + +Run ```nmcli connection show``` to get a list of active network connections. We will want to remove all of these. + +Run ```nmcli connection del [UUID]``` for each UUID listed in the previous commands output. + +### Management Ethernet + +*Note: It's assumed the on-board ethernet adapter will be used for management and an EXTERNAL USB Ethernet adapter used for WAN (if needed)* + +``` bash + +# Management via usb ethernet adapter +# includes network sharing +nmcli connection add save yes \ + type ethernet \ + con-name mgmt \ + ifname eth0 \ + -- \ + ipv4.method shared \ + ipv4.addr 172.16.16.16/24 \ + ipv6.method ignore +nmcli device set eth0 autoconnect yes + +``` + +### WiFi 2.4ghz Access Point + +*Note: You can use ```802-11-wireless.channel #``` in the below command to force a channel to be used* + +``` bash + +# Get the ifname of the wifi adapter with `nmcli dev show` + +# HostAP mode (2.4ghz / wireless access point) +# includes network sharing +nmcli connection add save yes \ + type wifi \ + con-name wifi-ap-24 \ + ifname [wifi iface] \ + ssid 24.lolipop.domain.tld \ + -- \ + ipv4.method shared \ + ipv4.addresses 172.17.17.17/24 \ + ipv6.method ignore \ + 802-11-wireless.mode ap \ + 802-11-wireless.band bg \ + 802-11-wireless.channel 11 \ + 802-11-wireless-security.key-mgmt wpa-psk \ + 802-11-wireless-security.proto rsn \ + 802-11-wireless-security.psk MyPassword + +``` + +### WiFi 5ghz Access Point + +*Note: You can use ```802-11-wireless.channel #``` in the below command to force a channel to be used* + +``` bash + +# Get the ifname of the wifi adapter with `nmcli dev show` + +# HostAP mode (5ghz / wireless access point) +# includes network sharing +nmcli connection add save yes \ + type wifi \ + con-name wifi-ap-50 \ + ifname [wifi iface] \ + ssid 50.lolipop.domain.tld \ + -- \ + ipv4.method shared \ + ipv4.addresses 172.18.18.18/24 \ + ipv6.method ignore \ + 802-11-wireless.mode ap \ + 802-11-wireless.band a \ + 802-11-wireless.channel 40 \ + 802-11-wireless-security.key-mgmt wpa-psk \ + 802-11-wireless-security.proto rsn \ + 802-11-wireless-security.psk MyPassword + +``` + +### WAN - Ethernet (External USB Adapter) + +*Note: It's assumed you'll be using a USB Ethernet adapter for WAN if needed. This matches the overall use of USB devices that are plugged/unplugged as necessary for WAN needs* + +``` bash + +# WAN via ethernet cable +nmcli connection add save yes \ + type ethernet \ + con-name wan-eth \ + ifname eth1 \ + -- \ + ipv4.method auto \ + ipv6.method auto +nmcli device set eth1 autoconnect yes + +``` + +### WAN - WiFi Bridge + +``` bash + +# Get list of access points in the area +nmcli dev wifi list + +# Get the ifname of the client wifi adapter with `nmcli dev show` + +# WAN via Client mode (wireless bridge) +# Note the ASK flag so you're prompted to enter user/pass type infos +nmcli connection add save yes \ + type wifi \ + con-name wan-wifi \ + ifname [wifi iface] \ + ssid [ssidFromAbove] \ + -- \ + wifi-sec.key-mgmt wpa-psk \ + wifi-sec.psk [wpaPassword] +nmcli device set [wifi iface] autoconnect yes + +``` + +### WAN - GSM (3G/LTE) + +See [Modem Manager](modem_manager.md) for details on integrating a 3G/LTE modem into the networking setup. + +## Auto Config + +Once the above is setup Network Manager should handle the auto configuration of your WAN/LAN/Modems/etc for you. diff --git a/armbian/nextcloud.md b/armbian/nextcloud.md new file mode 100644 index 0000000..5881bed --- /dev/null +++ b/armbian/nextcloud.md @@ -0,0 +1,262 @@ +# NextCloud + +NextCloud in a container. A simple PHP-FPM deployment. You'll need the Web Server container setup to get access. This just gives a very basic, non-web-server version of NextCloud. + +*NOTE: You may want to use a filesystem on a USB disk instead of /var for the volumes setup in the below Docker command(s) to help reduce writes to the micro sd card* + +## Inspiration / Sources + +- [https://github.com/nextcloud/docker](https://github.com/nextcloud/docker) +- [https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion](https://github.com/JrCs/docker-letsencrypt-nginx-proxy-companion) +- [https://hub.docker.com/_/nextcloud/](https://hub.docker.com/_/nextcloud/) +- [https://hub.docker.com/r/arm64v8/nextcloud/](https://hub.docker.com/r/arm64v8/nextcloud/) +- [https://hub.docker.com/r/arm32v5/nextcloud/](https://hub.docker.com/r/arm32v5/nextcloud/) +- [https://hub.docker.com/r/arm32v7/nextcloud/](https://hub.docker.com/r/arm32v7/nextcloud/) + +## Install / Update / Run Script + +Setup a generic script that'll auto update NextCloud, build a container and launch it. You should only run this script at first launch and/or when you're looking for updates. + +``` bash + +mkdir /var/nextcloud +chown www-data /var/nextcloud + +cat > /root/docker/nextcloud.sh < /etc/unbound/local_zone/nextcloud.conf < /etc/caddy/services/nextcloud.conf < 'activity',``` to the file. + +#### Add Cronjob + +In the settings change from ```Ajax``` for scheduled jobs to ```Cron``` and run the following commands on your device. + +This will lessen the page loads and keep the cron job constrained to a reasonable duration. + +``` bash + +cat > /etc/systemd/system/nextcloudcron.service < /etc/systemd/system/nextcloudcron.timer < /etc/systemd/system/unbound.service.d/10-after-docker.conf < /root/docker/pi-hole.sh < /etc/NetworkManager/dnsmasq-shared.d/pi-hole.conf < /etc/unbound/local_zone/pi-hole.conf < /etc/caddy/services/pi-hole.conf < /etc/pia/server_list.txt << EOF +us-west.privateinternetaccess.com=PIA - USA (West) +us-east.privateinternetaccess.com=PIA - USA (East) +us-midwest.privateinternetaccess.com=PIA - USA (Midwest) +aus.privateinternetaccess.com=PIA - Australia (Sydney) +austria.privateinternetaccess.com=PIA - Austria +belgium.privateinternetaccess.com=PIA - Belgium +ca-toronto.privateinternetaccess.com=PIA - Canada (Toronto) (East) +ca-vancouver.privateinternetaccess.com=PIA - Canada (Vancouver) (West) +fi.privateinternetaccess.com=PIA - Finland +france.privateinternetaccess.com=PIA - France +germany.privateinternetaccess.com=PIA - Germany +hk.privateinternetaccess.com=PIA - Hong Kong +in.privateinternetaccess.com=PIA - India +japan.privateinternetaccess.com=PIA - Japan +mexico.privateinternetaccess.com=PIA - Mexico +nl.privateinternetaccess.com=PIA - Netherlands +no.privateinternetaccess.com=PIA - Norway +sg.privateinternetaccess.com=PIA - Singapore +spain.privateinternetaccess.com=PIA - Spain +sweden.privateinternetaccess.com=PIA - Sweden +swiss.privateinternetaccess.com=PIA - Switzerland +turkey.privateinternetaccess.com=PIA - Turkey +uk-london.privateinternetaccess.com=PIA - UK (London) +brazil.privateinternetaccess.com=PIA - Brazil +EOF + +``` + +#### Setup NeworkManager Profiles + +Some fancy bash tricks to get the full list of NetworkManager PIA connections imported in one copy/paste. + +*Note: You'll need to fill in ```[your_username]``` and ```[your_password]``` before running this block of commands. + +``` bash + +export PIA_USER="[your_username]" +export PIA_PASSWORD="[your_password]" +while read line; +do +desc=$(echo $line | cut -f2 -d'=') +dns=$(echo $line | cut -f1 -d'=') +file="/etc/NetworkManager/system-connections/$desc" + +cat > "$file" < /root/docker/postgres.sh << EOF +#!/bin/bash + +VERSION="" + +ARCH=\`arch\` + +# Cleanup arch/container image here +if [ \$ARCH == "aarch64" ] +then + echo "64bit arm" + VERSION="arm64v8/postgres:latest" +else + echo "32bit arm" + VERSION="arm32v7/postgres:latest" +fi + +docker pull \$VERSION + +# Cleanup existing container +docker stop postgres +docker rm postgres + +# Re-run/create container with latest image +docker run \\ + --name postgres \\ + --restart unless-stopped \\ + --net docker-private \\ + --ip 172.30.12.12 \\ + -e TZ=UTC \\ + -e DEBUG=1 \\ + -e POSTGRES_PASSWORD=test1234 \\ + -v /var/postgres/data:/var/lib/postgresql/data \\ + \$VERSION +EOF + +chmod a+x /root/docker/postgres.sh + +``` + +## Run Postgres + +Simply execute ```/root/docker/postgres.sh``` to update/run Postgres. diff --git a/armbian/searx.md b/armbian/searx.md new file mode 100644 index 0000000..c76540f --- /dev/null +++ b/armbian/searx.md @@ -0,0 +1,112 @@ +# Searx + +Self hosted metasearch. Prevent profiling by major search engines + +## Inspiration / Further Reading + +- [https://asciimoo.github.io/searx/](https://asciimoo.github.io/searx/) +- [https://github.com/asciimoo/morty](https://github.com/asciimoo/morty) +- [https://asciimoo.github.io/searx/user/own-instance.html](https://asciimoo.github.io/searx/user/own-instance.html) + +## Install / Update / Run Script + +Setup a generic script that'll auto update Searx, build a container and launch it. You should only run this script at first launch and/or when you're looking for updates. + +``` bash + +mkdir -p /var/searx +chown root:root /var/searx +mkdir -p /root/docker/searx +git clone https://github.com/asciimoo/searx.git /root/docker/searx/src + +cat > /root/docker/searx/searx.sh << EOF +#!/bin/bash + +cd /root/docker/searx/src +git checkout Dockerfile +git fetch +LATESTTAG=\`git describe --abbrev=0 --tags\` +git checkout \$LATESTTAG + +ARCH=\`arch\` + +# Cleanup arch/container image here +if [ \$ARCH == "aarch64" ] +then + echo "64bit arm" + sed -i 's_alpine:3.5_arm64v8/alpine:3.5_g' Dockerfile +else + echo "32bit arm" + sed -i 's_alpine:3.5_arm32v6/alpine:3.5_g' Dockerfile +fi + +docker build \\ + --file ./Dockerfile \\ + --tag searx/searx:\$LATESTTAG \\ + . + +# Cleanup existing container +docker stop searx +docker rm searx + +# Re-run/create container with latest image +docker run \\ + --name searx \\ + --restart unless-stopped \\ + --net docker-private \\ + --ip 172.30.8.8 \\ + -e TZ=UTC \\ + -e DEBUG=1 \\ + -e BASE_URL=searx.domain.tld \\ + searx/searx:\$LATESTTAG +EOF + +chmod a+x /root/docker/searx/searx.sh + +``` + +## Run Searx + +Simply execute ```/root/docker/searx/searx.sh``` to update/run Gogs. + +## Serving Via Caddy + +``` bash + +cat > /etc/caddy/services/searx.conf < /etc/unbound/local_zone/searx.conf < /var/syncthing/.config/syncthing/config.xml < + + false + true + false + false + 10 + /tank/syncthing + + +EOF +chown syncthing -R /var/syncthing +chgrp syncthing -R /var/syncthing + +``` + +## Install Syncthing + +Grab the latest release of syncthing, drop it in place, setup system service. + +``` bash + +RELEASE=`curl -s https://api.github.com/repos/syncthing/syncthing/releases/latest | jq -r .tag_name` +ARCH=`arch` +if [ $ARCH == "aarch64" ] +then + ARCH="arm64" +else + ARCH="arm" +fi + +gpg --keyserver keyserver.ubuntu.com --recv-key D26E6ED000654A3E +mkdir -p /tmp/syncthing +cd /tmp/syncthing +curl -sLO https://github.com/syncthing/syncthing/releases/download/${RELEASE}/syncthing-linux-${ARCH}-${RELEASE}.tar.gz +curl -sLO https://github.com/syncthing/syncthing/releases/download/${RELEASE}/sha256sum.txt.asc +gpg --verify sha256sum.txt.asc +grep syncthing-linux-${ARCH} sha256sum.txt.asc | sha256sum +tar -zxf syncthing-linux-${ARCH}-${RELEASE}.tar.gz +mv syncthing-linux-${ARCH}-${RELEASE}/syncthing /usr/bin/syncthing +chmod a+x /usr/bin/syncthing +mv syncthing-linux-${ARCH}-${RELEASE}/etc/linux-systemd/system/syncthing@.service /etc/systemd/system +systemctl daemon-reload +cd ~ +rm -rf /tmp/syncthing + +``` + +## Adjust firewall to allow syncthing on internal network(s) + +``` bash + +firewall-cmd --permanent --zone=internal --add-port 22000/tcp --add-port 21027/udp +# Allow GUI from docker containers (it'll be proxied by the main web proxy container for ssl purposes) +firewall-cmd --permanent --zone=trusted --add-port 22000/tcp --add-port 21027/udp --add-port 8384/tcp +firewall-cmd --reload + +``` + +## Run Syncthing Via systemd Service + +``` bash + +systemctl enable syncthing@syncthing.service +systemctl start syncthing@syncthing.service + +``` + +## Setup Update Script + +Syncthing has an auto update mechanism. Script it so it can be run at any point to get updates. + +``` bash + +cat > /root/update_syncthing.sh < /etc/unbound/local_zone/syncthing.conf < /etc/caddy/services/syncthing.conf < /root/docker/ttrss.sh << EOF +#!/bin/bash + +ARCH=\`arch\` +HUBIMAGE="" + +# Cleanup arch/container image here +if [ \$ARCH == "aarch64" ] +then + echo "64bit arm" + HUBIMAGE="lsioarmhf/tt-rss-aarch64:latest" +else + echo "32bit arm" + HUBIMAGE="lsioarmhf/tt-rss:latest" +fi + +# Cleanup existing container +docker stop ttrss +docker rm ttrss + +# Re-run/create container with latest image +docker run \\ + --name ttrss \\ + --restart unless-stopped \\ + --net docker-private \\ + --ip 172.30.13.13 \\ + -e TZ=UTC \\ + -e DEBUG=1 \\ + -v /var/ttrss:/config \\ + \$HUBIMAGE +EOF + +chmod a+x /root/docker/ttrss.sh + +``` + +## Run TT-RSS + +Simply execute ```/root/docker/ttrss.sh``` to update/run TT-RSS. + +## Serving Via Caddy + +``` bash + +cat > /etc/caddy/services/ttrss.conf < /etc/unbound/local_zone/ttrss.conf < /root/docker/turtl/src/config/config.yaml <' + invites: 'invites@turtlapp.com' + # TODO: replace this with a long, unique value. seriously. write down a dream + # you had, or the short story you came up with during your creative writing + # class in your freshmen year of college. have fun with it. + secure_hash_salt: "Plaque is a figment of the liberal media and the dental industry to scare you into buying useless appliances and pastes. Now, I've read the arguments on both sides and I haven't found any evidence yet to support the need to brush your teeth. Ever." + +sync: + # how many sync records can a client send at a time? it's a good idea to have + # a limit here, lest a rogue client flood the server with sync items + max_bulk_sync_records: 32 + +plugins: + plugin_location: '/var/www/turtl/server/plugins' + analytics: + enabled: false + email: + enabled: false + premium: + enabled: false + +uploads: + # if set to a path, files will be uploaded to the local filesystem instead of + # S3. otherwise, set to false + local: '/var/www/turtl/server/public/uploads' + # if true, downloading local files will be proxied through the turtl server. + # this avoids needing to set up any CORS config in your favorite webserver, + # but may slightly affect performance on high-demand servers. + local_proxy: true + # if local_proxy is false, this is should be the url path the uploaded files + # are publicly available on + url: 'http://api.turtl.dev/uploads' + +s3: + token: 'IHADAPETSNAKEBUTHEDIEDNOOOOO' + secret: '' + bucket: '' +endpoint: 'https://s3.amazonaws.com' +EOF + +``` + +## Install / Setup + +``` bash + +cat > /root/docker/turtl/turtl.sh < /etc/caddy/services/turtl.conf < /etc/unbound/local_zone/turtl.conf < /etc/unbound/root.key < /etc/unbound/unbound.conf < /etc/systemd/system/roothints.service < /etc/systemd/system/roothints.timer < /etc/autovpn/default + +``` + +## Setup Docker networks to exclude + +``` bash + +# Get network names of ALL docker connections +nmcli con show +echo "[name1],[name2]" > /etc/autovpn/exclude + +``` + +## Setup script that will auto activate VPN + +This will auto-activate whenever NetworkManager says that the network is in a state of ```Connected-Global```. It may take a few minutes to get the whole network online/activated. + +Put the below script at ```/etc/autovpn/autovpn.py``` + +``` python + +#!/usr/bin/env python3 +""" +Copyright 2011 Domen Kozar. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY DOMEN KOZAR ''AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DOMEN KOZAR OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the +authors and should not be interpreted as representing official policies, either expressed +or implied, of DOMEN KOZAR. + +USAGE +===== + +1) clone gist somewhere (eg. /home/user/autovpn/) +2) add to /etc/rc.local: python /home/user/autovpn/autovpn.py "myvpn" 'Auto homenetwork,Auto worknetwork' >> /var/log/autovpn.log& +3) reboot :-) + +CHANGELOG +========= + +0.2 (28.01.2012) +---------------- + +* feature: use logging module +* bug: script would fail if there was no active connection + +0.1 (01.01.2012) +---------------- + +* bug: compatible with NM 0.9, dropped support for 0.8 +* feature: specify networks that vpn is not autoconnected + +KNOWN ISSUES +============ + +* it will always use first active network connection + +""" +import sys +import logging + +from dbus.mainloop.glib import DBusGMainLoop +import dbus +from gi.repository import GObject as gobject + + +logger = logging.getLogger(__name__) +logging.basicConfig( + level=logging.INFO, + filename='/var/log/autovpn.log', + filemode='a', +) + + +class AutoVPN(object): + """Solves two jobs, tested with NetworkManager 0.9.x: + + * if VPN connection is not disconnected by user himself, reconnect (configurable max_attempts) + * on new active network connection, activate VPN + + :param vpn_name: Name of VPN connection that will be used for autovpn + :param ignore_networks: Comma separated network names in NM that will not force VPN usage + :param max_attempts: Maximum number of attempts of reconnection VPN session on failures + :param delay: Miliseconds to wait before reconnecting VPN + + """ + + def __init__(self, vpn_name, ignore_networks='', max_attempts=5, delay=5000): + self.vpn_name = vpn_name + self.max_attempts = max_attempts + self.delay = delay + self.failed_attempts = 0 + self.bus = dbus.SystemBus() + self.ignore_networks = filter(None, ignore_networks.split(',')) + self.activate_vpn() # Auto connect at startup (Listen for StateChanged going forward) + self.get_network_manager().connect_to_signal("StateChanged", self.onNetworkStateChanged) + logger.info("Maintaining connection for %s, reattempting up to %d times with %d ms between retries", vpn_name, max_attempts, delay) + + def onNetworkStateChanged(self, state): + """Handles network status changes and activates the VPN on established connection.""" + logger.debug("Network state changed: %d", state) + if state == 70: + self.activate_vpn() + + def onVpnStateChanged(self, state, reason): + """Handles different VPN status changes and eventually reconnects the VPN.""" + # vpn connected or user disconnected manually? + if state == 5 or (state == 7 and reason == 2): + self.failed_attempts = 0 + if state == 5: + logger.info("VPN %s connected", self.vpn_name) + else: + logger.info("User disconnected manually") + return + # connection failed or unknown? + elif state in [6, 7]: + # reconnect if we haven't reached max_attempts + if not self.max_attempts or self.failed_attempts < self.max_attempts: + logger.info("Connection failed, attempting to reconnect") + self.failed_attempts += 1 + gobject.timeout_add(self.delay, self.activate_vpn) + else: + logger.info("Connection failed, exceeded %d max attempts.", self.max_attempts) + self.failed_attempts = 0 + + def get_network_manager(self): + """Gets the network manager dbus interface.""" + logger.debug("Getting NetworkManager DBUS interface") + proxy = self.bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager') + return dbus.Interface(proxy, 'org.freedesktop.NetworkManager') + + def get_vpn_interface(self, name): + 'Gets the VPN connection interface with the specified name.' + logger.debug("Getting %s VPN connection DBUS interface", name) + proxy = self.bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager/Settings') + iface = dbus.Interface(proxy, 'org.freedesktop.NetworkManager.Settings') + connections = iface.ListConnections() + for connection in connections: + proxy = self.bus.get_object('org.freedesktop.NetworkManager', connection) + iface = dbus.Interface(proxy, 'org.freedesktop.NetworkManager.Settings.Connection') + con_settings = iface.GetSettings()['connection'] + if con_settings['type'] == 'vpn' and con_settings['uuid'] == name: + logger.debug("Got %s interface", name) + return iface + logger.error("Unable to acquire %s VPN interface. Does it exist?", name) + return None + + def get_active_connection(self): + """Gets the dbus interface of the first active + network connection or returns None. + """ + logger.debug("Getting active network connection") + proxy = self.bus.get_object('org.freedesktop.NetworkManager', '/org/freedesktop/NetworkManager') + iface = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties') + active_connections = iface.Get('org.freedesktop.NetworkManager', 'ActiveConnections') + if len(active_connections) == 0: + logger.info("No active connections found") + return None + logger.info("Found %d active connection(s)", len(active_connections)) + return active_connections[0] + + def activate_vpn(self): + """Activates the vpn connection.""" + logger.info("Activating %s VPN connection", self.vpn_name) + vpn_con = self.get_vpn_interface(self.vpn_name) + active_con = self.get_active_connection() + if active_con is None: + return + + # check if we have to ignore vpn + proxy = self.bus.get_object('org.freedesktop.NetworkManager', active_con) + con = dbus.Interface(proxy, 'org.freedesktop.DBus.Properties').Get('org.freedesktop.NetworkManager.Connection.Active', 'Connection') + proxy = self.bus.get_object('org.freedesktop.NetworkManager', con) + settings = dbus.Interface(proxy, 'org.freedesktop.NetworkManager.Settings.Connection').GetSettings() + if settings['connection']['id'] in self.ignore_networks: + logger.info("Ignored network connection %s based on settings", settings['connection']['id']) + return + + # activate vpn and watch for reconnects + if vpn_con and active_con: + try: + new_con = self.get_network_manager().ActivateConnection( + vpn_con, + dbus.ObjectPath("/"), + active_con, + ) + proxy = self.bus.get_object('org.freedesktop.NetworkManager', new_con) + iface = dbus.Interface(proxy, 'org.freedesktop.NetworkManager.VPN.Connection') + iface.connect_to_signal('VpnStateChanged', self.onVpnStateChanged) + logger.info("VPN %s should be active (soon)", self.vpn_name) + except dbus.exceptions.DBusException: + # Ignore dbus connections (in case VPN already active when this script runs) + # TODO: Do this handling better; maybe check active/inactive status above and bail if already active? + pass + +if __name__ == '__main__': + if len(sys.argv) < 2: + print('usage: autovpn VPN_CONNECTION_NAME ') + print('-> activates vpn if any network connection is active') + print('-> and reconnects VPN on failure') + sys.exit(0) + + # set up the main loop + DBusGMainLoop(set_as_default=True) + loop = gobject.MainLoop() + # TODO: argparse + if len(sys.argv) > 2: + AutoVPN(sys.argv[1], sys.argv[2]) + else: + AutoVPN(sys.argv[1]) + loop.run() + +``` + +## Setup Script + +``` bash + +# Set permissions as required by NetworkManager +chown root:root /etc/autovpn/autovpn.py +chmod 0700 /etc/autovpn/autovpn.py + +``` + +## Setup the script as a systemd service + +``` bash + +cat > /etc/systemd/system/autovpn.service < /root/docker/wallabag/wallabag.sh < /etc/caddy/services/wallabag.conf < /etc/unbound/local_zone/wallabag.conf < # sets the mode (6 pairing) +SN, # Set device name +SP,1234 # Set pin code (up to 20 alphanumeric) +SY,0000 # Set a lower antenna power mode (0 in this case, FFF4 for -12, FFF8 for -8, FFFC for -4) +S|,0A03 # Cycle on for 3 seconds and off for 10 seconds (adjust per how fiddly your bt is to connect) +R,1 # Reboot device +--- # Exit command mode +``` + +## Enable New Serial tty + +Start / enable a new serial tty with the following + +``` bash + +# Adjust the default serial-getty config for the BT device/oPi +cat > /etc/systemd/system/serial-getty@ttyS1.service <> /etc/chrony/chrony.conf < /etc/systemd/system/gps-logger.service < /etc/systemd/system/gpsconvert.service < /etc/systemd/system/gpsconvert.timer < /sys/class/i2c-adapter/i2c-0/new_device # setup device so it's seen +dmesg | grep rtc # verify the kernel sees the rtc +ls /dev/rtc* # should have rtc1 +hwclock -f /dev/rtc1 --systohc -D --noadjfile --utc # set / init the rtc +hwclock -r -f /dev/rtc1 # read the value from the rtc +hwclock -w -f /dev/rtc1 # write the current time to the rtc +apt remove --purge fake-hwclock # purge the fake hwclock as we have a real one now + +``` + +## Udev Rules + +``` bash +# setup udev rule to setup the new rtc as the primary for the board +# `udevadm info -a -p /sys/class/rtc/rtc1` gets the details for the below entries +cat > /etc/udev/rules.d/99-rtc1.rules < /etc/systemd/system/rtc0-shutdown-fix.service < /etc/systemd/system/rtc0-online.service < /etc/systemd/system/rtc1-online.service < /sys/class/i2c-adapter/i2c-0/new_device \ +&& /sbin/hwclock -s -f /dev/rtc1' + +[Install] +WantedBy=time-sync.target +After=rtc0-online +EOF + +systemctl daemon-reload +systemctl + +``` + +## Misc Notes + +``` bash + +date # Wait for this to get sync'd via whatever ntp you're doing +hwclock -r -f /dev/rtc1 # Verify this isn't right +hwclock -w -f /dev/rtc1 # Write ntp system time -> rtc +hwclock -r -f /dev/rtc1 # Verify the write worked +ls -l /dev/rtc* # Check rtc dev node is present +hwclock -r -f /dev/rtc1 # read time from external rtc +hwclock -r -f /dev/rtc0 # read time from internal rtc + +``` diff --git a/hardware_notes.md b/hardware_notes.md new file mode 100644 index 0000000..7a238a2 --- /dev/null +++ b/hardware_notes.md @@ -0,0 +1,106 @@ +# Hardware Notes + +Various notes and tidbits that may deserve consideration. + +## USB Storage + +If you're going to run services like NextCloud, Syncthing and/or Samba you will want to consider what kind of USB disk to use. I'd recommend a [Sandisk Cruzer Fit (link)](https://www.sandisk.com/home/usb-flash/cruzer-fit) or [Sandisk Ultra Fit (link)](https://www.sandisk.com/home/usb-flash/ultra-fit-usb) or similar, low power flash drive. Full hard disks that aren't SSD's tend to be power hungry and can cause problems with SBCs. + +## WiFi + +- The author has had decent luck with the [ASUS USB-N13 (link)](https://www.asus.com/us/Networking/USB-N13/) adapter in client mode. Be minful of your 2.4ghz channel setup. If this adapter and your AP share a channel in 2.4ghz this adapter *will* drop packets and/or suffer disconnections + - Sometimes a reboot is necessary to get authentication to work properly after initial setup + - The author has **NOT** tested AP mode +- The author has had very good luck with the [ASUS USB-N53 (link)](https://www.asus.com/us/Networking/USBN53/) in AP mode. *Both* 2.4ghz and 5ghz can used for AP mode at the same time. + - The author has **NOT** tested client mode +- The author has had decent luck with the TP-Link N150 USB WiFi adapter in client mode +- The author could not get the TP-Link N300 USB WiFi adapter to work in client mode + +## Single Board Computers (SBC) + +### Orange Pi Zero + +The Orange Pi Zero has buggy WiFi and will **NOT** work for production purposes. However, the rest of the device is functional. Please note the WiFi chip in the Orange Pi Zero is "junk" (per the driver devs) and is unlikely to ever be supported fully. + +You'll need/want a USB hub and USB WiFi adapter for this device. + +### Pine64 + +- The 'Euler Bus' has dedicated ```DC IN``` and ```GND``` pins. If you run into power problems, consider these headers for powering the board. +- [Pinout reference (link)](http://files.pine64.org/doc/Pine%20A64%20Schematic/Pine%20A64%20Pin%20Assignment%20160119.pdf) + +### Raspberry Pi + +The Raspberry Pi devices are notorious for power problems. Especially lack of power for USB devices. You'll want to do a little additional research to ensure you have a good power supply. + +## Expansion / Hardware Ideas + +### WiFi Antennas + +- [https://www.mouser.com/ProductDetail/?qs=%2fv8iy7V9uiwj65CKT%2f%252b6tQ%3d%3d](https://www.mouser.com/ProductDetail/?qs=%2fv8iy7V9uiwj65CKT%2f%252b6tQ%3d%3d) +- [https://www.mouser.com/ProductDetail/?qs=G9o9YCnxvoZVoyw0A06Ktg%3d%3d](https://www.mouser.com/ProductDetail/?qs=G9o9YCnxvoZVoyw0A06Ktg%3d%3d) +- [https://www.mouser.com/ProductDetail/?qs=WUa1z%2fNV9%252b2lzv2ZS%2f50GQ%3d%3d](https://www.mouser.com/ProductDetail/?qs=WUa1z%2fNV9%252b2lzv2ZS%2f50GQ%3d%3d) +- [https://www.mouser.com/ProductDetail/?qs=RuW%2fu%252bNMQmv6yDroBT8RNQ%3d%3d](https://www.mouser.com/ProductDetail/?qs=RuW%2fu%252bNMQmv6yDroBT8RNQ%3d%3d) +- [https://www.mouser.com/ProductDetail/Antenova/SR4W030-100?qs=sGAEpiMZZMuBTKBKvsBmlN73K%2f2BcYXln6YUd9YVZ3FLX3OerI69PA%3d%3d](https://www.mouser.com/ProductDetail/Antenova/SR4W030-100?qs=sGAEpiMZZMuBTKBKvsBmlN73K%2f2BcYXln6YUd9YVZ3FLX3OerI69PA%3d%3d) +- [https://www.mouser.com/ProductDetail/Antenova/SRF2W021-100?qs=sGAEpiMZZMuBTKBKvsBmlMeP1Lut7uca61hspfdOxQexT8ZJsKeXqw%3d%3d](https://www.mouser.com/ProductDetail/Antenova/SRF2W021-100?qs=sGAEpiMZZMuBTKBKvsBmlMeP1Lut7uca61hspfdOxQexT8ZJsKeXqw%3d%3d) + +### Power / LiPo Batteries + +- [SparkFun mosfet power control (link)](https://www.sparkfun.com/products/12959) +- [Pimoroni On/Off shim (link)](https://www.adafruit.com/product/3581) +- [SparkFun Charger/Booster (link)](https://learn.sparkfun.com/tutorials/sparkfun-5v1a-lipo-chargerbooster-hookup-guide) +- [Power Meter](https://www.sparkfun.com/products/14331) +- [Pimoroni LiPo shim (link)](https://www.adafruit.com/product/3196) + +### Storage + +- [Ableconn mSATA Hat (link)](https://www.amazon.com/dp/B00WQJ8BH2) +- [Ableconn nvme Hat (link)](https://www.amazon.com/dp/B01LZ0LCTU) + +### Displays + +- [Waveshare 4.2 inch e-ink display (link)](https://www.waveshare.com/product/modules/oleds-lcds/e-paper/4.2inch-e-paper-module.htm?___SID=U) +- [Waveshare 2.9 inch e-ink display (link)](https://www.waveshare.com/product/modules/oleds-lcds/e-paper/2.9inch-e-paper-module.htm?___SID=U) +- [Pimoroni e-ink hat (link)](https://www.adafruit.com/product/3743) + +### Input + +- [Waveshare touch keypad (link)](https://www.waveshare.com/product/RPi-Touch-Keypad.htm) +- [Pimoroni touch button hat (link)](https://www.adafruit.com/product/3472) +- [Pimoroni push button shim (link)](https://www.adafruit.com/product/3582) +- [Adafruit display+button hat (link)](https://www.adafruit.com/product/3531) +- [Adafruit joystick+button hat (link)](https://www.adafruit.com/product/3464) +- [Pimoroni display+button hat (link)](https://www.adafruit.com/product/2694) + +### Cell Data + +- [LTE rPi Shield (link)](http://sixfab.com/product/raspberry-pi-3g-4glte-base-shield-v2/) +- [LTE/4G pciE (link)](http://sixfab.com/product/quectel-ec25-mini-pcle-4glte-module/) +- [3G pciE (link)](http://sixfab.com/product/quectel-uc20-mini-pcle-3g-module/) + +### Misc + +- [SparkFun TTL serial usb adapter (link)](https://www.sparkfun.com/products/14050) +- [Adafruit TTL serial usb adapter (link)](https://www.adafruit.com/product/3309) +- [SparkFun Bluetooth Mate Silver (link)](https://www.sparkfun.com/products/12576) +- [Adafruit GPS (link)](https://www.adafruit.com/product/746) +- [Pimoroni mini hat extender (link)](https://www.adafruit.com/product/3182) +- [Pimoroni hat extender (link)](https://www.adafruit.com/product/3742) + +## 3d Printed Cases + +- Pine64 [(source)](https://www.thingiverse.com/thing:1831345) : ```3d_printer_sources/Pine_A64_Two-Parts_case.zip``` +- Orange Pi Zero [Plus] Base [(source)](https://www.thingiverse.com/thing:2776831) : ```3d_printer_sources/Orange_Pi_Zero_-_Minimal_Mount.zip``` +- Orange Pi Zero [Plus] Case [(source)](https://www.thingiverse.com/thing:1939780) : ```3d_printer_sources/Orange_Pi_Zero_Case.zip``` +- Orange Pi Zero [Plus] + Expansion Board Case [(source)](https://www.thingiverse.com/thing:2353879) : ```3d_printer_sources/Orange_Pi_Zero_+_Expansion_Board_Case.zip``` +- Orange Pi Zero [Plus] + NAS Board Case [(source)](https://www.thingiverse.com/thing:2122451) : ```3d_printer_sources/Orange_Pi_Zero_NAS_Board_Case.zip``` +- Orange Pi PC Case (External Mounts) [(source)](https://www.thingiverse.com/thing:2239240) : ```3d_printer_sources/Orange_PI_PC_Case_with_External_mounts_+_M5_mount.zip``` +- Orange Pi PC NAS Case [(source)](https://www.thingiverse.com/thing:2468854) : ```3d_printer_sources/Orange_PI_PC_NAS_Case.zip``` +- Orange Pi One Case [(source)](https://www.thingiverse.com/thing:1447933) : ```3d_printer_sources/OrangePi_One_Case.zip``` +- Orange Pi One NAS Case [(source)](https://www.thingiverse.com/thing:2790266) : ```3d_printer_sources/Orange_Pi_One_NAS_Case.zip``` +- Orange Pi Zero NAS Case (minimal) [(source)](https://www.thingiverse.com/thing:2740032) : ```3d_printer_sources/Orange_Pi_Zero_NAS_minimal.zip``` +- Orange Pi Zero 2+ H5 Case [(source)](https://www.thingiverse.com/thing:2797865) : ```3d_printer_sources/Orange_Pi_Zero_2+_H5_Case.zip``` +- Orange Pi Zero 2 Case [(source)](https://www.thingiverse.com/thing:2626323) : ```3d_printer_sources/Orange_Pi_Zero_2_Case.zip``` +- Orange Pi Plus 2E Case [(source)](https://www.thingiverse.com/thing:2251219) : ```3d_printer_sources/Orange_Pi_plus_2e_case.zip``` +- Orange Pi Plus 2E Case (alt) [(source)](https://www.thingiverse.com/thing:1916113) : ```3d_printer_sources/Orange_Pi_Plus_2E_case_2.zip``` +- Orange Pi Zero Plus2 H3 Case [(source)](https://www.thingiverse.com/thing:2802598) : ```3d_printer_sources/ \ No newline at end of file diff --git a/preflight.md b/preflight.md new file mode 100644 index 0000000..4cbf1a2 --- /dev/null +++ b/preflight.md @@ -0,0 +1,46 @@ +# Preflight + +Some things you may or may not want to consider ahead of time + +## Hardware + +- Orange Pi R1 +- Orange Pi Zero Plus +- Pine64 Plus + - (see [hardware notes](hardware_notes.md) for additional considerations) +- Orange Pi Zero + - (see [hardware notes](hardware_notes.md) for additional considerations) +- Raspberry Pi + - (see [hardware notes](hardware_notes.md) for additional considerations) + +### Offical Support + +Be sure to check OpenWRT/Armbian for your chosen router/boards support status. A number are going to be officially supported while others will have development snapshots avilable. + +## Domain + +If you want to have an 'official' domain for your device, it's possible and this documentation will cover some of the setup. + +### Registrars + +A couple of good registrars for registering a domain + +- [http://namecheap.com/](http://namecheap.com/) +- [https://uniregistry.com/](https://uniregistry.com/) + +### TLDs (Top Level Domains) + +Some good TLDs for a lolipop device + +- .zone +- .host +- .travel +- .link +- .online +- .net +- .tech +- .club + +### Domain Preflight + +In your chosen registrar you'll need to setup API access if you want to use Let's Encrypt for SSL certificates (recommended). Check with your registrar for necessary information on setup. diff --git a/virtualization.md b/virtualization.md new file mode 100644 index 0000000..162605b --- /dev/null +++ b/virtualization.md @@ -0,0 +1,208 @@ +# Virtualization + +Some notes on setting up Docker build hosts using emulation. Specifically using qemu to setup arm32v7 and arm64v8 environments for Docker builds. + +Handy if you need are using an SBC that's too 'small' for building searx/gogs but *can* run the final Docker image. + +## Inspiration / Further Reading + +- [https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/](https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/) +- [https://github.com/petrosagg/armv7hf-python-dockerhub/blob/master/Dockerfile](https://github.com/petrosagg/armv7hf-python-dockerhub/blob/master/Dockerfile) +- [https://github.com/ViViDboarder/docker-rpi-homebridge/blob/master/Dockerfile](https://github.com/ViViDboarder/docker-rpi-homebridge/blob/master/Dockerfile) + - This BREAKS when not cross building so you can't easily run docker build / up on a docker file w/ these in it +- [https://wiki.qemu.org/Documentation/Platforms/ARM](https://wiki.qemu.org/Documentation/Platforms/ARM) +- [https://translatedcode.wordpress.com/2016/11/03/installing-debian-on-qemus-32-bit-arm-virt-board/](https://translatedcode.wordpress.com/2016/11/03/installing-debian-on-qemus-32-bit-arm-virt-board/) +- [https://translatedcode.wordpress.com/2017/07/24/installing-debian-on-qemus-64-bit-arm-virt-board/](https://translatedcode.wordpress.com/2017/07/24/installing-debian-on-qemus-64-bit-arm-virt-board/) +- [https://www.raymii.org/s/articles/virt-install_introduction_and_copy_paste_distro_install_commands.html](https://www.raymii.org/s/articles/virt-install_introduction_and_copy_paste_distro_install_commands.html) +- [http://ftp.nl.debian.org/debian/dists/stretch/main/](http://ftp.nl.debian.org/debian/dists/stretch/main/) +- [https://www.collabora.com/news-and-blog/blog/2017/06/20/debian-armhf-vm-on-arm64-server/](https://www.collabora.com/news-and-blog/blog/2017/06/20/debian-armhf-vm-on-arm64-server/) +- [http://blog.system76.com/post/139138591598/howto-qemu-w-ubuntu-xenial-host-uefi-guest](http://blog.system76.com/post/139138591598/howto-qemu-w-ubuntu-xenial-host-uefi-guest) + +## Minor notes + +- Use arm64 for arm64v8 +- Use armhf for arm32v + +## Prep + +``` bash + +apt install qemu-system-arm libguestfs-tools qemu-efi qemu-efi-aarch64 qemu-efi-arm + +``` + +## Plain QEMU + +These processes will let you bootstrap a virtual machine for later import into libvirt management engines. + +### 64bit arm v8 + +``` bash + +# Probably should have this in a dedicated dir, no? +mkdir arm64v8 +cd arm64v8 +# Pull installer +wget http://ports.ubuntu.com/ubuntu-ports/dists/xenial/main/installer-arm64/current/images/netboot/mini.iso +mv mini.iso net-install.iso +# Create storage for VM +qemu-img create -f qcow2 arm64v8-xenial.qcow2 16G +# Prep EFI boot +cp /usr/share/AAVMF/AAVMF_VARS.fd AAVMF_VARS.fd +# Install +# WARNING: YOU MUST TWEAK THE GRUB KERNEL CONSOLE LINE TO HAVE 'console=ttyAMA0' IMMEDIATELY FOLLOWING THE KERNEL IMAGE OR YOU WON'T GET OUTPUT +# NOTE: Use CTRL-H for backspace and CTRL-X to boot +# NOTE: virtio-blk-device and virtio-net-device are necessary as the mini.iso (renamed to net-install.iso) doesn't support PCI (fixed post-install) +qemu-system-aarch64 -M virt -m 2048 -smp 4 -cpu cortex-a53 \ + -drive if=pflash,format=raw,readonly,file=/usr/share/AAVMF/AAVMF_CODE.fd \ + -drive if=pflash,format=raw,file=AAVMF_VARS.fd \ + -cdrom net-install.iso \ + -drive if=none,file=arm64v8-xenial.qcow2,format=qcow2,id=hd \ + -device virtio-blk-device,drive=hd \ + -netdev user,id=arm0 -device virtio-net-device,netdev=arm0 \ + -nographic -no-reboot +# Backup base install (just in case) +cp arm64v8-xenial.qcow2 arm64v8-xenial-base-install.qcow2 +# Run the VM with the necessary parms/infos +qemu-system-aarch64 -M virt -m 2048 -smp 4 -cpu cortex-a53 \ + -drive if=pflash,format=raw,readonly,file=/usr/share/AAVMF/AAVMF_CODE.fd \ + -drive if=pflash,format=raw,file=AAVMF_VARS.fd \ + -drive if=none,file=arm64v8-xenial.qcow2,format=qcow2,id=hd \ + -device virtio-blk-device,drive=hd \ + -netdev user,id=arm0 -device virtio-net-device,netdev=arm0 \ + -nographic -no-reboot + +``` + +### 32bit arm v7 + +``` bash + +# Probably should have this in a dedicated dir, no? +mkdir arm32v7 +cd arm32v7 +# Get netbook kernel/initrd +wget -O installer-vmlinuz http://ports.ubuntu.com/ubuntu-ports/dists/xenial/main/installer-armhf/current/images/generic-lpae/netboot/vmlinuz +wget -O installer-initrd.gz http://ports.ubuntu.com/ubuntu-ports/dists/xenial/main/installer-armhf/current/images/generic-lpae/netboot/initrd.gz +# Create storage for VM +qemu-img create -f qcow2 arm32v7-xenial.qcow2 16G +# Prep EFI boot +cp /usr/share/AAVMF/AAVMF32_VARS.fd AAVMF32_VARS.fd +# Install +qemu-system-arm -M virt -m 2048 -smp 4 -cpu cortex-a15 \ + -kernel installer-vmlinuz \ + -initrd installer-initrd.gz \ + -drive if=none,file=arm32v7-xenial.qcow2,format=qcow2,id=hd \ + -device virtio-blk-pci,drive=hd \ + -netdev user,id=arm0 -device virtio-net-pci,netdev=arm0 \ + -nographic -no-reboot +# Backup base install (just in case) +cp arm32v7-xenial.qcow2 arm32v7-xenial-base-install.qcow2 +# Copy vmlinuz/initrd from root filesystem for final boot +virt-filesystems -a arm32v7-xenial.qcow2 +virt-ls -a arm32v7-xenial.qcow2 /boot/ +virt-copy-out -a arm32v7-xenial.qcow2 /boot/vmlinuz-4.4.0-127-generic-lpae /boot/initrd.img-4.4.0-127-generic-lpae . +# Boot! +qemu-system-arm -M virt -m 2048 -smp 4 -cpu cortex-a15 \ + -kernel vmlinuz-4.4.0-127-generic-lpae \ + -initrd initrd.img-4.4.0-127-generic-lpae \ + -drive if=none,file=arm32v7-xenial.qcow2,format=qcow2,id=hd \ + -device virtio-blk-pci,drive=hd \ + -netdev user,id=arm0 -device virtio-net-pci,netdev=arm0 \ + -nographic -no-reboot + +``` + +## virsh/virt-install + +This section is very much a work in progress. Based on further research / reading you'll need to bootstrap the VM with raw qemu and then import to virsh. + +``` bash + +virt-install --name ubuntu-16.04-arm64v8 \ + --import \ + --virt-type qemu \ + --arch aarch64 \ + --machine virt \ + --memory 2048 \ + --vcpus 4 \ + --noacpi \ + --os-type linux \ + --os-variant ubuntu16.04 \ + --disk path=template-ubuntu-16.04-arm64v8.qcow2,size=25,bus=virtio \ + --network default \ + --graphics none \ + +``` + +## Useful virsh commands + +For post install usage + +``` bash + +virsh list --all # List all VMs +virsh dumpxml --domain VM_NAME # Dump the XML for the VM +virsh destroy --domain VM_NAME # Force shutdown VM +virsh undefine --domain VM_NAME # Remove/Delete VM +virsh console VM_NAME +virsh edit VM_NAME +rm DISK_IMAGE_PATH + +``` + +## First Boot + +``` bash + +vim /etc/default/grub +update-grub +apt update && apt install sudo vim tmux screen wget curl htop git nano rsync iotop nload unzip +ufw allow ssh +ufw enable + +``` + +## rclone + +``` bash + +curl https://rclone.org/install.sh | sudo bash + +``` + +## Docker + +``` bash + +apt remove docker docker-engine docker.io +apt install apt-transport-https ca-certificates curl gnupg2 software-properties-common + +echo "deb [arch=arm64] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list + +echo "deb [arch=armhf] https://download.docker.com/linux/ubuntu \ + $(lsb_release -cs) stable" | \ + sudo tee /etc/apt/sources.list.d/docker.list + +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - +apt update +apt install docker-ce python3 python3-pip +pip3 install docker-compose +poweroff + +``` + +## Export Docker Container Images + +``` bash + +for repo in `docker image ls --format "{{.Repository}}"`; do + outfile=`echo $repo | sed 's+/+_+g'` + echo "$repo -> $outfile" + docker save -o ${outfile}.tar $repo +done + +``` +