Compare commits

..

No commits in common. "6a4822fcfbdd2e3310a369fa43df25944bf30134" and "c4ffbb00e22211a2e34e7800a6cc660b05b1e0fc" have entirely different histories.

34 changed files with 278 additions and 928 deletions

56
LICENCE
View file

@ -1,56 +0,0 @@
Copyright © 2017, Michael Stapelberg and contributors
Copyright © 2021, guardianproject
Copyright © 2025-2026, SR2 Communications Limited
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* 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.
* Neither the name of Michael Stapelberg nor the
names of contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Michael Stapelberg ''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 Michael Stapelberg 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.
Additionally, we include here the original licence terms as required by the terms
of the Butter Box for Raspberry Pi project, which apply only to the code derived
from that project:
MIT License
Copyright (c) 2021 guardianproject
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,28 +1,5 @@
# Butter Churn
# Churn
[![License](https://img.shields.io/badge/License-BSD_3--Clause-orange.svg)](https://opensource.org/licenses/BSD-3-Clause)
This is work in progress.
Tool for building Butter Box disk images.
## Usage
To build a butter image, run:
```sh
vmdb2 --rootfs-tarball=my_image.tar.gz --output my_image.img --log my_image.log
```
## Copyright and Licence
© 2017, Michael Stapelberg and contributors
© 2021 guardianproject
© SR2 Communications Limited
See [LICENCE](./LICENCE) for details of the BSD-3 clause licence.
This project is a derivative work of:
* [Butter Box for Raspberry Pi](https://gitlab.com/likebutter/butterbox-rpi)
licensed under the MIT licence.
* [Raspberry Pi Image Specs](https://salsa.debian.org/raspi-team/image-specs)
licensed under the 3-clause BSD licence.
To build a butter image, run vmdb2 --rootfs-tarball=my_image.tar.gz --output my_image.img --log my_image.log

View file

@ -13,28 +13,28 @@
name: "{{ butter_user }}"
state: present
- name: Add butter user to sudo group
ansible.builtin.user:
name: "{{ butter_user }}"
groups: sudo
append: true
- name: Get supported interface modes
command: iw list
register: iw_list
ignore_errors: yes
when: not (is_vmdb2 | bool)
- name: Allow passwordless sudo for butter user
ansible.builtin.lineinfile:
path: /etc/sudoers
state: present
regexp: "^{{ butter_user }}"
line: "{{ butter_user }} ALL=(ALL) NOPASSWD:ALL"
validate: '/usr/sbin/visudo -cf %s'
- name: Search for AP mode support
set_fact:
ap_mode_supported: "{{ 'AP' in iw_list.stdout }}"
when: not (is_vmdb2 | bool)
- name: Show AP mode support result
debug:
msg: >
Wi-Fi AP mode supported: {{ ap_mode_supported }}
when: not (is_vmdb2 | bool)
- name: Make sure /etc/resolv.conf is populated
ansible.builtin.lineinfile:
lineinfile:
path: /etc/resolv.conf
regexp: '^nameserver 1.1.1.1'
line: 'nameserver 1.1.1.1'
state: present
insertafter: EOF
create: true
owner: root
group: root
mode: '0644'
create: yes

View file

@ -4,9 +4,11 @@
become: true
tasks:
- name: Print Dendrite process info for debugging
become: yes
ansible.builtin.shell: |
echo "=== Dendrite PIDs ==="
pgrep -u {{ butter_user }} -f dendrite || echo "No dendrite PIDs found"
echo
echo "=== Full process tree of Dendrite ==="
for pid in $(pgrep -u {{ butter_user }} -f dendrite); do
@ -14,28 +16,34 @@
pstree -p $pid || echo "pstree not available for PID $pid"
echo
done
echo "=== Open files under VMDB mount ==="
lsof +D /tmp/tmpyu_8dsew || echo "No open files found"
echo "=== Current working directories of processes in mount ==="
lsof +D /tmp/tmpyu_8dsew | awk '{print $2, $NF}' | sort | uniq
register: dendrite_debug
when: is_vmdb2 | bool
changed_when: false
- name: Show debug output
ansible.builtin.debug:
debug:
msg: "{{ dendrite_debug.stdout_lines }}"
when: is_vmdb2 | bool
- name: Kill any running Dendrite process
become: yes
ansible.builtin.shell: |
set -o pipefail && pgrep -u {{ butter_user }} -f dendrite | xargs -r kill -9
pgrep -u {{ butter_user }} -f dendrite | xargs -r kill -9
register: dendrite_cleanup
changed_when: dendrite_cleanup.stdout != ""
when: is_vmdb2 | bool
- name: Show cleanup output
ansible.builtin.debug:
msg: "{{ dendrite_cleanup.stdout_lines }}"
when: is_vmdb2 | bool
- name: Give processes time to exit
ansible.builtin.pause:
seconds: 5
become: yes
shell: sleep 5
when: is_vmdb2 | bool

View file

View file

@ -4,7 +4,7 @@
become: true
tasks:
- name: Create madmail directory
ansible.builtin.file:
file:
path: "/home/{{ butter_user }}/madmail"
state: directory
owner: "{{ butter_user }}"
@ -12,22 +12,20 @@
mode: "0755"
- name: Download pre-built madmail archive
ansible.builtin.get_url:
get_url:
url: "https://github.com/themadorg/madmail/releases/download/v0.12.7/madmail-linux-{{ go_arch_map[ansible_architecture] }}.tar.gz"
dest: "/tmp/madmail-linux-{{ go_arch_map[ansible_architecture] }}.tar.gz"
mode: '0644'
- name: Untar madmail
ansible.builtin.unarchive:
unarchive:
src: "/tmp/madmail-linux-{{ go_arch_map[ansible_architecture] }}.tar.gz"
dest: "/home/{{ butter_user }}/madmail"
remote_src: true
# extra_opts: [--strip-components=1]
remote_src: yes
#extra_opts: [--strip-components=1]
- name: Ensure butter_user owns madmail directory
ansible.builtin.file:
file:
path: "/home/{{ butter_user }}/madmail"
state: directory
recurse: true
owner: "{{ butter_user }}"
group: "{{ butter_user }}"
recurse: yes

View file

@ -1,102 +0,0 @@
---
- name: Deploy butter portal
hosts: all
become: true
tasks:
- name: "Ensure /tmp/butter-portal is absent"
ansible.builtin.file:
path: "/home/{{ butter_user }}/butter-portal"
state: absent
- name: "Clone the portal repo"
ansible.builtin.git:
repo: "https://guardianproject.dev/butter/butter-portal"
dest: "/home/{{ butter_user }}/butter-portal"
version: main
- name: Install requirements
ansible.builtin.pip:
requirements: "/home/{{ butter_user }}/butter-portal/requirements.txt"
virtualenv: "/home/{{ butter_user }}/portal_env"
virtualenv_python: python3
- name: Seed database
ansible.builtin.shell: |
echo "Starting db initialisation!"
source /home/{{ butter_user }}/portal_env/bin/activate
flask db init
flask db migrate
flask db upgrade
flask seed-settings
args:
chdir: "/home/{{ butter_user }}/butter-portal"
executable: /bin/bash
creates: "/home/{{ butter_user }}/butter-portal/app.db"
register: database_init
- name: Template portal systemd service file
ansible.builtin.template:
src: templates/butterbox-portal.service.j2
dest: /lib/systemd/system/butterbox-portal.service
owner: root
group: root
mode: '0644'
- name: Template portal change manager service file
ansible.builtin.template:
src: templates/change-manager.service.j2
dest: /lib/systemd/system/change-manager.service
owner: root
group: root
mode: '0644'
- name: Template nginx config
ansible.builtin.template:
src: templates/nginx-config.j2
dest: /etc/nginx/sites-available/default
owner: root
group: root
mode: '0644'
- name: Enable portal by symlink
ansible.builtin.file:
src: /lib/systemd/system/butterbox-portal.service
dest: /etc/systemd/system/multi-user.target.wants/butterbox-portal.service
state: link
- name: Enable change manager by symlink
ansible.builtin.file:
src: /lib/systemd/system/change-manager.service
dest: /etc/systemd/system/multi-user.target.wants/change-manager.service
state: link
- name: Ensure butter_user owns portal directory
ansible.builtin.file:
path: "/home/{{ butter_user }}/butter-portal"
state: directory
recurse: true
owner: "{{ butter_user }}"
group: "{{ butter_user }}"
# - name: Template portal reverse proxy config for Lighttpd
# ansible.builtin.get_url:
# src: templates/50-butter-portal-reverse-proxy.conf
# dest: /etc/lighttpd/conf-available/50-butter-portal-reverse-proxy.conf
# owner: root
# group: root
# mode: '0644'
#
# - name: Ensure old symlink is removed if it exists
# ansible.builtin.file:
# path: /etc/lighttpd/conf-enabled/50-butter-portal-reverse-proxy.conf
# state: absent
# force: true
#
# - name: Enable reverse proxy config for portal in Lighttpd
# ansible.builtin.file:
# src: /etc/lighttpd/conf-available/50-butter-portal-reverse-proxy.conf
# dest: /etc/lighttpd/conf-enabled/50-butter-portal-reverse-proxy.conf
# state: link
# force: true
#
# - debug: var=database_init.stdout_lines

View file

@ -0,0 +1,59 @@
---
- name: Deploy butter site
hosts: all
become: true
tasks:
- name: Install unzip
apt:
name:
- unzip
state: present
update_cache: yes
when: not ( is_vmdb2 | bool )
- name: Ensure /etc/resolv.conf contains nameserver 1.1.1.1
copy:
dest: /etc/resolv.conf
content: "nameserver 1.1.1.1\n"
owner: root
group: root
mode: '0644'
when: is_vmdb2 | bool
- name: Ensure /tmp/butter-site is absent
file:
path: /tmp/butter-site
state: absent
- name: Ensure /tmp/site.zip is absent
file:
path: /tmp/site.zip
state: absent
- name: Download the butter-box UI zip file
get_url:
url: "https://likebutter.gitlab.io/butter-box-ui/site-{{ butter_language }}.zip"
dest: /tmp/site.zip
mode: '0644'
- name: Ensure /tmp/butter-site directory exists
file:
path: /tmp/butter-site
state: directory
mode: '0755'
- name: Unarchive site.zip to /tmp/butter-site
unarchive:
src: /tmp/site.zip
dest: /tmp/butter-site
remote_src: yes
- name: Copy contents to /var/www/html/
copy:
src: /tmp/butter-site/
dest: /var/www/html/
owner: www-data
group: www-data
mode: '0755'
remote_src: yes

View file

@ -4,6 +4,8 @@ go_version: "1.24.6"
go_arch_map:
x86_64: "amd64"
aarch64: "arm64"
script_base_url: "https://gitlab.com/likebutter/butterbox-rpi/-/raw/main/scripts"
config_base_url: "https://gitlab.com/likebutter/butterbox-rpi/-/raw/main/configs"
vmdb2_script_base_dir: "butterbox-rpi/scripts"
vmdb2_config_base_dir: "butterbox-rpi/configs"

View file

@ -10,4 +10,4 @@
register: firmware_update
changed_when: firmware_update.rc == 0
failed_when: firmware_update.rc != 0
ignore_errors: true
ignore_errors: yes

View file

@ -4,18 +4,18 @@
become: true
tasks:
- name: Install deps
ansible.builtin.apt:
apt:
name:
- git
- vim
- lighttpd
- sudo
state: present
update_cache: true
when: not (is_vmdb2 | bool)
update_cache: yes
when: not ( is_vmdb2 | bool )
- name: Create dendrite directories
ansible.builtin.file:
file:
path: "/home/{{ butter_user }}/dendrite/bin"
state: directory
owner: "{{ butter_user }}"
@ -23,72 +23,94 @@
mode: "0755"
- name: Download pre-built dendrite archive
ansible.builtin.get_url:
get_url:
url: "https://guardianproject.dev/api/packages/butter/generic/dendrite/latest/dendrite-{{ go_arch_map[ansible_architecture] }}.tar.gz"
dest: /tmp
mode: '0644'
- name: Untar dendrite
ansible.builtin.unarchive:
unarchive:
src: "/tmp/dendrite-{{ go_arch_map[ansible_architecture] }}.tar.gz"
dest: "/home/{{ butter_user }}/dendrite/bin"
remote_src: true
remote_src: yes
extra_opts: [--strip-components=2]
- name: Ensure butter_user owns Dendrite directory
ansible.builtin.file:
file:
path: "/home/{{ butter_user }}/dendrite"
state: directory
recurse: true
recurse: yes
- name: Generate Matrix signing key
ansible.builtin.command: ./bin/generate-keys --private-key matrix_key.pem
command: ./bin/generate-keys --private-key matrix_key.pem
args:
creates: "/home/{{ butter_user }}/dendrite/matrix_key.pem"
chdir: "/home/{{ butter_user }}/dendrite"
- name: Generate self-signed TLS certificate (optional)
ansible.builtin.command: ./bin/generate-keys --tls-cert server.crt --tls-key server.key
command: ./bin/generate-keys --tls-cert server.crt --tls-key server.key
args:
chdir: "/home/{{ butter_user }}/dendrite"
creates: "/home/{{ butter_user }}/dendrite/server.key"
- name: Download Dendrite config to target
ansible.builtin.template:
src: "templates/butterbox-dendrite.conf.j2"
get_url:
url: "{{ config_base_url }}/butterbox-dendrite.conf"
dest: "/home/{{ butter_user }}/dendrite/butterbox-dendrite.conf"
owner: "{{ butter_user }}"
group: "{{ butter_user }}"
mode: '0644'
- name: Replace REPLACEME with butter_name in config
replace:
path: "/home/{{ butter_user }}/dendrite/butterbox-dendrite.conf"
regexp: 'REPLACEME'
replace: "{{ butter_name }}"
- name: Replace /home/pi with /home/butter_user in config
replace:
path: "/home/{{ butter_user }}/dendrite/butterbox-dendrite.conf"
regexp: '/pi/'
replace: "/{{ butter_user }}/"
- name: Create log directory for Dendrite
ansible.builtin.file:
file:
path: "/var/log/dendrite"
state: directory
owner: "{{ butter_user }}"
group: "{{ butter_user }}"
mode: '0755'
recurse: true
recurse: yes
- name: template dendrite systemd service file
ansible.builtin.template:
src: templates/butterbox-dendrite.service.j2
- name: Download dendrite systemd service file
get_url:
url: "{{ config_base_url }}/butterbox-dendrite.service"
dest: /lib/systemd/system/dendrite.service
owner: root
group: root
mode: '0644'
- name: Replace /home/pi with /home/butter_user in service file
replace:
path: /lib/systemd/system/dendrite.service
regexp: '/pi/'
replace: "/{{ butter_user }}/"
- name: Replace pi with butter_user in service file
replace:
path: /lib/systemd/system/dendrite.service
regexp: 'User=pi'
replace: "User={{ butter_user }}"
- name: Enable dendrite by symlink
ansible.builtin.file:
file:
src: /lib/systemd/system/dendrite.service
dest: /etc/systemd/system/multi-user.target.wants/dendrite.service
state: link
- name: Ensure butter_user owns Dendrite directory
ansible.builtin.file:
file:
path: "/home/{{ butter_user }}/dendrite"
state: directory
recurse: true
recurse: yes
owner: "{{ butter_user }}"
group: "{{ butter_user }}"
mode: "0755"
@ -100,10 +122,31 @@
name: dendrite
when: not (is_vmdb2 | bool)
- name: Download Matrix reverse proxy config for Lighttpd
get_url:
url: "{{ config_base_url }}/50-matrix-reverse-proxy.conf"
dest: /etc/lighttpd/conf-available/50-matrix-reverse-proxy.conf
owner: root
group: root
mode: '0644'
- name: Ensure old symlink is removed if it exists
file:
path: /etc/lighttpd/conf-enabled/50-matrix-reverse-proxy.conf
state: absent
force: true
- name: Enable reverse proxy config for Matrix in Lighttpd
file:
src: /etc/lighttpd/conf-available/50-matrix-reverse-proxy.conf
dest: /etc/lighttpd/conf-enabled/50-matrix-reverse-proxy.conf
state: link
force: true
- name: Start dendrite as user butter_user
become: true
become: yes
become_user: "{{ butter_user }}"
ansible.builtin.shell: |
shell: |
nohup /home/{{ butter_user }}/dendrite/bin/dendrite \
--config /home/{{ butter_user }}/dendrite/butterbox-dendrite.conf \
-really-enable-open-registration \
@ -111,29 +154,28 @@
args:
chdir: "/home/{{ butter_user }}"
when: is_vmdb2 | bool
changed_when: false
- name: Wait for Dendrite client API to be available
ansible.builtin.wait_for:
wait_for:
host: "127.0.0.1"
port: 8008
delay: 3 # wait a few seconds before first check
timeout: 60 # give it up to a minute to start
state: started
when: is_vmdb2 | bool
- name: Copy public room script
ansible.builtin.template:
template:
src: templates/create_public_room.sh.j2
dest: "/home/{{ butter_user }}/create_public_room.sh"
mode: '0755'
- name: Run the create_public_room.sh script
ansible.builtin.command: "/home/{{ butter_user }}/create_public_room.sh"
command: "/home/{{ butter_user }}/create_public_room.sh"
register: room_creation
ignore_errors: false
changed_when: false
ignore_errors: false
- name: Show room creation output
ansible.builtin.debug:
debug:
var: room_creation.stdout

View file

@ -4,21 +4,20 @@
become: true
tasks:
- name: Install Node.js 22 (needed for matrix-js-sdk)
ansible.builtin.shell: |
set -o pipefail curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
shell: |
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -y nodejs
args:
executable: /bin/bash
creates: /bin/npm
- name: Ensure previous keanu-weblite temp directory is removed
ansible.builtin.file:
file:
path: /tmp/keanu-weblite
state: absent
delegate_to: localhost
- name: Clone keanu-weblite repository (dev branch)
ansible.builtin.git:
git:
repo: https://gitlab.com/keanuapp/keanuapp-weblite.git
dest: /tmp/keanu-weblite
version: dev
@ -26,38 +25,51 @@
delegate_to: localhost
- name: Run npm install
ansible.builtin.command: npm install
shell: npm install
args:
chdir: /tmp/keanu-weblite
delegate_to: localhost
changed_when: false
- name: Download keanu-weblite config file
ansible.builtin.template:
src: "templates/keanu-weblite-config.json.j2"
get_url:
url: "{{ config_base_url }}/keanu-weblite-config.json"
dest: /tmp/keanu-weblite/src/assets/config.json
mode: '0644'
delegate_to: localhost
- name: Replace REPLACEME with butter_name in config.json
replace:
path: /tmp/keanu-weblite/src/assets/config.json
regexp: 'REPLACEME'
replace: "{{ butter_name }}"
delegate_to: localhost
- name: Run npm build with legacy OpenSSL option
ansible.builtin.shell: |
shell: |
export NODE_OPTIONS=--openssl-legacy-provider
npm run build
args:
chdir: /tmp/keanu-weblite
delegate_to: localhost
changed_when: false
- name: Copy build output to /var/www/html/chat
ansible.builtin.copy:
src: /tmp/keanu-weblite/dist/
dest: /var/www/html/chat/
mode: '0755'
become: true
copy:
src: /tmp/keanu-weblite/dist/
dest: /var/www/html/chat/
- name: Set permissions for /var/www/html/chat
ansible.builtin.file:
become: true
file:
path: /var/www/html/chat
owner: www-data
group: www-data
mode: '0755'
recurse: true
recurse: yes
- name: Restart lighttpd service
ansible.builtin.systemd:
name: lighttpd
state: restarted
when: not (is_vmdb2 | bool)

View file

@ -9,27 +9,21 @@
raspap_adblock: 0
tasks:
- name: ensure lighttpd listens on port 8080
ansible.builtin.lineinfile:
path: /etc/lighttpd/lighttpd.conf
regexp: '^server.port'
line: server.port=8080
- name: Check if RaspAP is already installed
ansible.builtin.stat:
path: /var/www/html/raspap
path: /var/www/html/admin
register: raspap_stat
- name: Download RaspAP install script
ansible.builtin.get_url:
get_url:
url: https://install.raspap.com
dest: /tmp/raspap_install.sh
mode: "0755"
when: not raspap_stat.stat.exists
when: not raspap_stat.stat.exists
- name: Run RaspAP install script
ansible.builtin.shell: |
pwd && ls -alh / && /usr/bin/bash /tmp/raspap_install.sh --yes --path /var/www/html/raspap \
pwd && ls -alh / && /usr/bin/bash /tmp/raspap_install.sh --yes --path /var/www/html/admin \
--check 0 \
--wireguard {{ raspap_wireguard }} \
--openvpn {{ raspap_openvpn }} \
@ -41,44 +35,45 @@
failed_when: raspap_install.rc != 0
- name: Remove /var/www/html.* directories if they exist
become: true
ansible.builtin.shell: |
find /var/www/html.* -maxdepth 0 -type d -exec rm -r {} \; || :
changed_when: false
- name: Ensure /etc/hostapd directory exists
ansible.builtin.file:
file:
path: /etc/hostapd
state: directory
mode: '0755'
- name: Template RaspAP network config to target
ansible.builtin.template:
template:
src: "hostapd.conf.j2"
dest: "/etc/hostapd/hostapd.conf"
mode: '0644'
- name: Copy hostapd set_hostapd_iface config script
ansible.builtin.template:
template:
src: "set_hostapd_iface.py"
dest: "/usr/local/bin/set_hostapd_iface.py"
mode: '0744'
mode: '0755'
- name: Template hostapd set_hostapd_iface service file
ansible.builtin.template:
- name: Copy hostapd set_hostapd_iface service file
template:
src: "set-hostapd-iface.service.j2"
dest: "/lib/systemd/system/set-hostapd-iface.service"
mode: '0644'
mode: '0755'
- name: Template hostapd raspapd systemd service file
ansible.builtin.template:
src: "templates/raspapd.service.j2"
- name: Download hostapd raspapd systemd service file
get_url:
url: "{{ config_base_url }}/raspapd.service"
dest: "/lib/systemd/system/raspapd.service"
owner: root
group: root
mode: '0644'
- name: Enable service raspapd, avahi-daemon, and set_hostapd_iface by symlink
ansible.builtin.file:
file:
src: "/lib/systemd/system/{{ item }}"
dest: "/etc/systemd/system/multi-user.target.wants/{{ item }}"
state: link
@ -87,17 +82,20 @@
- "set-hostapd-iface.service"
- "avahi-daemon.service"
- name: Disable service raspapd restapi service
ansible.builtin.file:
path: "/etc/systemd/system/multi-user.target.wants/{{ item }}"
state: absent
with_items:
- "restapi.service"
- name: Copy dnsmasq config
ansible.builtin.template:
template:
src: "butterbox-dnsmasq.conf.j2"
dest: /etc/dnsmasq.d/butterbox-dnsmasq.conf
owner: root
group: root
mode: '0644'
- name: Restart service raspapd, issue daemon-reload to pick up config changes
ansible.builtin.systemd_service:
state: restarted
daemon_reload: true
name: "{{ item }}"
when: not (is_vmdb2 | bool)
with_items:
- raspapd
- set-hostapd-iface

View file

@ -4,31 +4,51 @@
become: true
tasks:
- name: Copy systemd services
ansible.builtin.template:
src: "{{ item }}"
copy:
src: "{{ vmdb2_config_base_dir }}/{{ item }}"
dest: "/etc/systemd/system/{{ item }}"
mode: '0644'
loop:
- udisks2-mount@.service
- serve-usb@.service
- name: Enable services by symlink
ansible.builtin.file:
src: "/etc/systemd/system/{{ item }}"
file:
src: "/etc/systemd/system/{{ item }}"
dest: "/etc/systemd/system/multi-user.target.wants/{{ item }}"
state: link
loop:
- udisks2-mount@.service
- serve-usb@.service
- name: Copy web UI assets (remote to remote)
copy:
src: "/var/www/html/assets/{{ item.src }}"
dest: "/var/www/html/{{ item.dest }}"
remote_src: true
loop:
- { src: "css/butter-dir-listing.css", dest: "butter-dir-listing.css" }
- { src: "js/butter-dir-listing.js", dest: "butter-dir-listing.js" }
- name: Install Lighttpd USB config
copy:
src: "{{ vmdb2_config_base_dir }}/50-usb-butter.conf"
dest: "/etc/lighttpd/conf-available/50-usb-butter.conf"
- name: Install udev rule
ansible.builtin.copy:
copy:
src: "templates/99-usb-butter.rules"
dest: "/etc/udev/rules.d/99-usb-butter.rules"
mode: '0644'
- name: Install udev trigger script
ansible.builtin.template:
src: templates/on-usb-drive-mounted.sh.j2
copy:
src: "{{ vmdb2_script_base_dir }}/on-usb-drive-mounted.sh"
dest: /usr/bin/on-usb-drive-mounted.sh
mode: '0744'
mode: '0755'
- name: Reload udev rules
command: udevadm control --reload-rules
when: not (is_vmdb2 | bool)
- name: Reload systemd daemon
command: systemctl daemon-reload
when: not (is_vmdb2 | bool)

View file

@ -4,15 +4,15 @@
- "base"
- "ap"
- "matrix"
- import_playbook: delta-chat.yml
tags: "delta-chat"
- import_playbook: install-rasp-ap.yml
tags: "ap"
when: ap_mode_supported | bool
- import_playbook: deploy-butter-portal.yml
- import_playbook: deploy-butter-site.yml
tags:
- "website"
- "usb"
- import_playbook: delta-chat.yml
tags: "delta-chat"
- import_playbook: install-chat.yml
tags: "matrix"
- import_playbook: cleanup.yml

View file

@ -4,8 +4,8 @@
become: true
tasks:
- name: Copy wpa_supplicant config
ansible.builtin.template:
src: "wpa_supplicant.conf"
copy:
src: "{{ vmdb2_config_base_dir }}/wpa_supplicant.conf"
dest: /etc/wpa_supplicant/wpa_supplicant.conf
force: true
mode: '0644'

View file

@ -1,7 +1,7 @@
# Using udev to mount newly attached usb drives doesn't work.
# https://unix.stackexchange.com/a/507150/223286
# So, we depend on udisks to mount the disk. *Then* we want to
# to setup the symlink.
# to setup the symlink and lighttpd config with our script.
# We can run the script immediately because it waits for the disk
# to be mounted.

View file

@ -1,380 +0,0 @@
# This is the Dendrite configuration file.
#
# The configuration is split up into sections - each Dendrite component has a
# configuration section, in addition to the "global" section which applies to
# all components.
#
# At a minimum, to get started, you will need to update the settings in the
# "global" section for your deployment, and you will need to check that the
# database "connection_string" line in each component section is correct.
#
# Each component with a "database" section can accept the following formats
# for "connection_string":
# SQLite: file:filename.db
# file:///path/to/filename.db
# PostgreSQL: postgresql://user:pass@hostname/database?params=...
#
# SQLite is embedded into Dendrite and therefore no further prerequisites are
# needed for the database when using SQLite mode. However, performance with
# PostgreSQL is significantly better and recommended for multi-user deployments.
# SQLite is typically around 20-30% slower than PostgreSQL when tested with a
# small number of users and likely will perform worse still with a higher volume
# of users.
#
# The "max_open_conns" and "max_idle_conns" settings configure the maximum
# number of open/idle database connections. The value 0 will use the database
# engine default, and a negative value will use unlimited connections. The
# "conn_max_lifetime" option controls the maximum length of time a database
# connection can be idle in seconds - a negative value is unlimited.
# The version of the configuration file.
version: 2
# Global Matrix configuration. This configuration applies to all components.
global:
# The domain name of this homeserver.
server_name: {{ butter_name }}.local
# The path to the signing private key file, used to sign requests and events.
# Note that this is NOT the same private key as used for TLS! To generate a
# signing key, use "./bin/generate-keys --private-key matrix_key.pem".
private_key: /home/{{ butter_user }}/dendrite/matrix_key.pem
# The paths and expiry timestamps (as a UNIX timestamp in millisecond precision)
# to old signing private keys that were formerly in use on this domain. These
# keys will not be used for federation request or event signing, but will be
# provided to any other homeserver that asks when trying to verify old events.
# old_private_keys:
# - private_key: old_matrix_key.pem
# expired_at: 1601024554498
# How long a remote server can cache our server signing key before requesting it
# again. Increasing this number will reduce the number of requests made by other
# servers for our key but increases the period that a compromised key will be
# considered valid by other homeservers.
key_validity_period: 168h0m0s
# The server name to delegate server-server communications to, with optional port
# e.g. localhost:443
well_known_server_name: ""
# Lists of domains that the server will trust as identity servers to verify third
# party identifiers such as phone numbers and email addresses.
trusted_third_party_id_servers:
- matrix.org
- vector.im
# Disables federation. Dendrite will not be able to make any outbound HTTP requests
# to other servers and the federation API will not be exposed.
disable_federation: false
# Configures the handling of presence events.
presence:
# Whether inbound presence events are allowed, e.g. receiving presence events from other servers
enable_inbound: false
# Whether outbound presence events are allowed, e.g. sending presence events to other servers
enable_outbound: false
# Server notices allows server admins to send messages to all users.
server_notices:
enabled: false
# The server localpart to be used when sending notices, ensure this is not yet taken
local_part: "_server"
# The displayname to be used when sending notices
display_name: "Server alerts"
# The mxid of the avatar to use
avatar_url: ""
# The roomname to be used when creating messages
room_name: "Server Alerts"
# Configuration for NATS JetStream
jetstream:
# A list of NATS Server addresses to connect to. If none are specified, an
# internal NATS server will be started automatically when running Dendrite
# in monolith mode. It is required to specify the address of at least one
# NATS Server node if running in polylith mode.
addresses:
# - localhost:4222
# Keep all NATS streams in memory, rather than persisting it to the storage
# path below. This option is present primarily for integration testing and
# should not be used on a real world Dendrite deployment.
in_memory: false
# Persistent directory to store JetStream streams in. This directory
# should be preserved across Dendrite restarts.
storage_path: /home/{{ butter_user }}/dendrite/jetstream
# The prefix to use for stream names for this homeserver - really only
# useful if running more than one Dendrite on the same NATS deployment.
topic_prefix: Dendrite
# Configuration for Prometheus metric collection.
metrics:
# Whether or not Prometheus metrics are enabled.
enabled: false
# HTTP basic authentication to protect access to monitoring.
basic_auth:
username: metrics
password: metrics
# DNS cache options. The DNS cache may reduce the load on DNS servers
# if there is no local caching resolver available for use.
dns_cache:
# Whether or not the DNS cache is enabled.
enabled: false
# Maximum number of entries to hold in the DNS cache, and
# for how long those items should be considered valid in seconds.
cache_size: 256
cache_lifetime: "5m" # 5minutes; see https://pkg.go.dev/time@master#ParseDuration for more
# Configuration for the Appservice API.
app_service_api:
internal_api:
listen: http://localhost:7777 # Only used in polylith deployments
connect: http://localhost:7777 # Only used in polylith deployments
database:
connection_string: file:///home/{{ butter_user }}/dendrite/appservice.db
max_open_conns: 10
max_idle_conns: 2
conn_max_lifetime: -1
# Disable the validation of TLS certificates of appservices. This is
# not recommended in production since it may allow appservice traffic
# to be sent to an unverified endpoint.
disable_tls_validation: false
# Appservice configuration files to load into this homeserver.
config_files: []
# Configuration for the Client API.
client_api:
internal_api:
listen: http://localhost:7771 # Only used in polylith deployments
connect: http://localhost:7771 # Only used in polylith deployments
external_api:
listen: http://[::]:8071
# Prevents new users from being able to register on this homeserver, except when
# using the registration shared secret below.
registration_disabled: false
# Prevents new guest accounts from being created. Guest registration is also
# disabled implicitly by setting 'registration_disabled' above.
guests_disabled: true
# If set, allows registration by anyone who knows the shared secret, regardless of
# whether registration is otherwise disabled.
registration_shared_secret: ""
# Whether to require reCAPTCHA for registration.
enable_registration_captcha: false
# Settings for ReCAPTCHA.
recaptcha_public_key: ""
recaptcha_private_key: ""
recaptcha_bypass_secret: ""
recaptcha_siteverify_api: ""
# TURN server information that this homeserver should send to clients.
turn:
turn_user_lifetime: ""
turn_uris: []
turn_shared_secret: ""
turn_username: ""
turn_password: ""
# Settings for rate-limited endpoints. Rate limiting will kick in after the
# threshold number of "slots" have been taken by requests from a specific
# host. Each "slot" will be released after the cooloff time in milliseconds.
rate_limiting:
enabled: true
threshold: 5
cooloff_ms: 500
# Configuration for the Federation API.
federation_api:
internal_api:
listen: http://localhost:7772 # Only used in polylith deployments
connect: http://localhost:7772 # Only used in polylith deployments
external_api:
listen: http://[::]:8072
database:
connection_string: file:///home/{{ butter_user }}/dendrite/federationapi.db
max_open_conns: 10
max_idle_conns: 2
conn_max_lifetime: -1
# How many times we will try to resend a failed transaction to a specific server. The
# backoff is 2**x seconds, so 1 = 2 seconds, 2 = 4 seconds, 3 = 8 seconds etc.
send_max_retries: 16
# Disable the validation of TLS certificates of remote federated homeservers. Do not
# enable this option in production as it presents a security risk!
disable_tls_validation: false
# Perspective keyservers to use as a backup when direct key fetches fail. This may
# be required to satisfy key requests for servers that are no longer online when
# joining some rooms.
key_perspectives:
- server_name: matrix.org
keys:
- key_id: ed25519:auto
public_key: Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw
- key_id: ed25519:a_RXGa
public_key: l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ
# This option will control whether Dendrite will prefer to look up keys directly
# or whether it should try perspective servers first, using direct fetches as a
# last resort.
prefer_direct_fetch: false
# Configuration for the Key Server (for end-to-end encryption).
key_server:
internal_api:
listen: http://localhost:7779 # Only used in polylith deployments
connect: http://localhost:7779 # Only used in polylith deployments
database:
connection_string: file:///home/{{ butter_user }}/dendrite/keyserver.db
max_open_conns: 10
max_idle_conns: 2
conn_max_lifetime: -1
# Configuration for the Media API.
media_api:
internal_api:
listen: http://localhost:7774 # Only used in polylith deployments
connect: http://localhost:7774 # Only used in polylith deployments
external_api:
listen: http://[::]:8074
database:
connection_string: file:///home/{{ butter_user }}/dendrite/mediaapi.db
max_open_conns: 5
max_idle_conns: 2
conn_max_lifetime: -1
# Storage path for uploaded media. May be relative or absolute.
base_path: /home/{{ butter_user }}/dendrite/media_store
# The maximum allowed file size (in bytes) for media uploads to this homeserver
# (0 = unlimited). If using a reverse proxy, ensure it allows requests at
# least this large (e.g. client_max_body_size in nginx.)
# 1GB = 1 048 576 000 (1024*1024*1000)
max_file_size_bytes: 1048576000
# Whether to dynamically generate thumbnails if needed.
dynamic_thumbnails: true
# The maximum number of simultaneous thumbnail generators to run.
max_thumbnail_generators: 10
# A list of thumbnail sizes to be generated for media content.
thumbnail_sizes:
- width: 32
height: 32
method: crop
- width: 96
height: 96
method: crop
- width: 640
height: 480
method: scale
# Configuration for experimental MSC's
mscs:
# A list of enabled MSC's
# Currently valid values are:
# - msc2836 (Threading, see https://github.com/matrix-org/matrix-doc/pull/2836)
# - msc2946 (Spaces Summary, see https://github.com/matrix-org/matrix-doc/pull/2946)
mscs: []
database:
connection_string: file:///home/{{ butter_user }}/dendrite/mscs.db
max_open_conns: 5
max_idle_conns: 2
conn_max_lifetime: -1
# Configuration for the Room Server.
room_server:
internal_api:
listen: http://localhost:7770 # Only used in polylith deployments
connect: http://localhost:7770 # Only used in polylith deployments
database:
connection_string: file:///home/{{ butter_user }}/dendrite/roomserver.db
max_open_conns: 10
max_idle_conns: 2
conn_max_lifetime: -1
# Configuration for the Sync API.
sync_api:
internal_api:
listen: http://localhost:7773 # Only used in polylith deployments
connect: http://localhost:7773 # Only used in polylith deployments
external_api:
listen: http://[::]:8073
database:
connection_string: file:///home/{{ butter_user }}/dendrite/syncapi.db
max_open_conns: 10
max_idle_conns: 2
conn_max_lifetime: -1
# This option controls which HTTP header to inspect to find the real remote IP
# address of the client. This is likely required if Dendrite is running behind
# a reverse proxy server.
# real_ip_header: X-Real-IP
# Configuration for the User API.
user_api:
# The cost when hashing passwords on registration/login. Default: 10. Min: 4, Max: 31
# See https://pkg.go.dev/golang.org/x/crypto/bcrypt for more information.
# Setting this lower makes registration/login consume less CPU resources at the cost of security
# should the database be compromised. Setting this higher makes registration/login consume more
# CPU resources but makes it harder to brute force password hashes.
# This value can be low if performing tests or on embedded Dendrite instances (e.g WASM builds)
# bcrypt_cost: 10
internal_api:
listen: http://localhost:7781 # Only used in polylith deployments
connect: http://localhost:7781 # Only used in polylith deployments
account_database:
connection_string: file:///home/{{ butter_user }}/dendrite/userapi_accounts.db
max_open_conns: 10
max_idle_conns: 2
conn_max_lifetime: -1
# The length of time that a token issued for a relying party from
# /_matrix/client/r0/user/{userId}/openid/request_token endpoint
# is considered to be valid in milliseconds.
# The default lifetime is 3600000ms (60 minutes).
# openid_token_lifetime_ms: 3600000
# Configuration for Opentracing.
# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on
# how this works and how to set it up.
tracing:
enabled: false
jaeger:
serviceName: ""
disabled: false
rpc_metrics: false
tags: []
sampler: null
reporter: null
headers: null
baggage_restrictions: null
throttler: null
# Logging configuration
logging:
- type: std
level: info
- type: file
# The logging level, must be one of debug, info, warn, error, fatal, panic.
level: info
params:
path: /var/log/dendrite/
# Not part of the dendrite-sample file, but required by 0.13.7
relay_api:
database:
connection_string: file:///home/{{ butter_user }}/dendrite/relay_api.db

View file

@ -1,14 +0,0 @@
[Unit]
Description=Dendrite Service
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User={{ butter_user }}
ExecStart=/home/{{ butter_user }}/dendrite/bin/dendrite --config /home/{{ butter_user }}/dendrite/butterbox-dendrite.conf -really-enable-open-registration
[Install]
WantedBy=multi-user.target

View file

@ -1,4 +1,4 @@
interface=wlan0
dhcp-range=10.3.141.50,10.3.141.255,255.255.255.0,12h
dhcp-option=6,10.3.141.1
address=/{{ butter_name }}.local/10.3.141.1
address=/{{ butter_name }}.lan/10.3.141.1

View file

@ -1,14 +0,0 @@
[Unit]
Description=Portal Service
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=always
RestartSec=1
User={{ butter_user }}
ExecStart=/bin/bash -c 'source /home/{{ butter_user }}/portal_env/bin/activate && cd /home/{{ butter_user }}/butter-portal && flask --app butter-portal.py run'
[Install]
WantedBy=multi-user.target

View file

@ -1,15 +0,0 @@
[Unit]
Description=Butterbox setting management service
After=network.target
StartLimitIntervalSec=0
[Service]
Type=simple
Restart=on-failure
RestartSec=1
User=root
ExecStart=/bin/bash -c "chmod 600 /etc/ssh/*key && python3 change_manager.py"
WorkingDirectory=/home/{{ butter_user }}/butter-portal
Environment=PYTHONUNBUFFERED=1
[Install]
WantedBy=multi-user.target

View file

@ -7,7 +7,7 @@ beacon_int=100
ssid={{ butter_name }}
channel=1
hw_mode=g
ieee80211ac=1
ieee80211n=0
interface=wlan0
wpa=none
wpa_pairwise=CCMP

View file

@ -1,10 +0,0 @@
{
"appName": "Keanu on Butter Box",
"appNames": {},
"productLink": "{{ butter_name }}.local",
"defaultServer": "http://{{ butter_name }}.local",
"rtl": false,
"analytics": {
"enabled": false
}
}

View file

@ -1,22 +0,0 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name {{ butter_name }}.local;
location ^~ /chat {
alias /var/www/html/chat;
}
location ^~ /raspap {
proxy_pass http://127.0.0.1:8080;
}
location ^~ /_matrix {
proxy_pass http://127.0.0.1:8008;
}
location / {
proxy_pass http://127.0.0.1:5000;
}
}

View file

@ -1,48 +0,0 @@
#!/bin/bash
# Run by udev when a USB drive is inserted
# usage: /usr/bin/on-usb-drive-mounted.sh /media/%k
# If the drive inserted contains a directory named "butter",
# symlink it to /media/usb-butter
device="$1"
# The device might not be mounted yet, so wait for it.
usb_mount_path=""
for ((i=0; i<10; i++)); do
usb_mount_path=$(findmnt -n -o TARGET --source "$device")
if [ -n "$usb_mount_path" ]; then
break
fi
sleep 1
done
# findmnt will briefly return 1, so don't set e until we're done with it.
set -e
if [ -z "$usb_mount_path" ]; then
echo "Device $device is not mounted"
exit 1
else
echo "Device $device mounted to: $usb_mount_path"
fi
butter_dir="$usb_mount_path"
served_dir="/media/usb-butter"
# make directory butter_dir world readable
sudo chmod -R a+rx "$butter_dir"
sudo chmod -R a+rx "/media/root/"
if [ -d "$butter_dir" ]; then
# Delete served_dir if it exists
if [ -L "$served_dir" ]; then
sudo rm "$served_dir"
fi
echo "Linking $butter_dir to $served_dir"
ln -sf "$butter_dir" "$served_dir"
sudo chown -R {{ butter_user }}:{{ butter_user }} $served_dir
else
echo "No butter directory $butter_dir found on $device"
exit 1
fi

View file

@ -1,15 +0,0 @@
[Unit]
Description=RaspAP Service Daemon
DefaultDependencies=no
# This line, which the default raspapd.service would use, results in a circular dependency
# And the symptom we see is that it doesn't boot. Instead, run this after network.target
# After=multi-user.target
After=network.target
[Service]
Type=oneshot
ExecStart=/bin/bash /etc/raspap/hostapd/servicestart.sh --interface uap0 --seconds 3
RemainAfterExit=no
[Install]
WantedBy=multi-user.target

View file

@ -1,8 +0,0 @@
[Unit]
Description=Serve USB content
BindTo=dev-%i.device
[Service]
ExecStart=/bin/sh -c '/usr/bin/on-usb-drive-mounted.sh /dev/%i'
ExecStop=/bin/sh -c 'rm /media/usb-butter/'
RemainAfterExit=yes

View file

@ -1,8 +0,0 @@
[Unit]
Description=Mount service
BindTo=dev-%i.device
[Service]
ExecStart=/bin/sh -c '/usr/bin/udisksctl mount -b /dev/%i'
ExecStop=/bin/sh -c '/usr/bin/udisksctl unmount -b /dev/%i'
RemainAfterExit=yes

View file

@ -1,3 +0,0 @@
country=US
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
ap_scan=1

View file

@ -1,57 +0,0 @@
# Creating an upgrade content pack for the butterbox
Butterboxes run [Debian OS](https://www.debian.org/) and can be upgraded using `apt update` and `apt upgrade` commands.
However, since they are often expected to operate in areas without Internet connectivity,
the following instructions detail how to create and use a content pack to allow local offline upgrades.
## Requirements
- A large (min 250GB ) Hard drive or USB Stick, formatted as FAT32 or ext4
- Internet connectivity
- A computer running Debian
## Creating a Debian mirror
- Plug in and mount the hard drive into a computer running Debian. The rest of the configuration assumes this is mounted at `/mnt`.
- Edit the Debian mirror configuration. For this, depending on what kind of butterbox you have (AMD64-based, like an old laptop, or
ARM-based, like a Raspberry Pi), edit the file "/etc/apt/mirror.list" (you may wish to back it up beforehand)
to contain the following, making sure to uncomment the line corresponding to your box.
```angular2html
############# config ##################
#
set base_path /mnt # This is where the mirror will be created, ensure it corresponds to where the hard drive is mounted
#
set mirror_path $base_path/mirror
set skel_path $base_path/skel
set var_path $base_path/var
set cleanscript $var_path/clean.sh
set postmirror_script $var_path/postmirror.sh
set run_postmirror 0
set nthreads 20
set _tilde 0
#
############# end config ##############
#deb [arch=arm64] http://ftp.us.debian.org/debian stable main contrib non-free # Uncomment for ARM64, e.g. Raspberry Pi 3 or 4
#deb [arch=amd64] http://ftp.us.debian.org/debian stable main contrib non-free # Uncomment for AMD64
# Note the mirror location, ftp.us.debian.org; you can choose any other online debian mirror to download from, keep a note of its name
```
- Run the command `apt-mirror`. This will create a Debian mirror on your hard drive, that can then be used to upgrade your butterbox.
The size of the archive varies, but will utilise somewhere in the region of 150-200GB, depending on architecture.
> Careful running this command on any metered connection, as it will attempt download hundreds of GB worth of data!
> Be patient. This command will take a while to run depending on the speed of your Internet connection.
## Updating your Butterbox
- Plug in the hard drive into your butterbox, and mount it. This assumes it is mounted at `/mnt`.
- Log in via the butterbox console, as the root user.
- ensure the date is set correctly by running date, for example: `date -s "30/12/2026 10:29"`
- edit file `/etc/apt/sources.list` to contain the following line:
` deb file:/mnt/mirror/ftp.us.debian.org/debian stable main contrib non-free`
Note that the name of the directory might vary depending on the mirror you used in the previous step.
- Congrats! Now you can run `apt update` and `apt upgrade` to update the box.

View file

@ -95,9 +95,6 @@ steps:
- wget
- dhcpcd
- python3
- python3-packaging
- python3-virtualenv
- nginx
- lighttpd
- unzip
- sudo
@ -113,7 +110,6 @@ steps:
- init-system-helpers
- syslinux
- linux-image-amd64
- git
tag: tag-root
unless: rootfs_unpacked
@ -121,7 +117,6 @@ steps:
unless: rootfs_unpacked
- shell: |
echo "butterbox" > "${ROOT?}/etc/hostname"
# Allow root logins locally with no password
@ -151,10 +146,6 @@ steps:
- shell: |
rm "${ROOT?}/etc/resolv.conf"
mkdir -p "${ROOT?}/etc/systemd/system/multi-user.target.requires/"
install -m 644 -o root -g root image-specs/rootfs/etc/systemd/system/rpi-generate-ssh-host-keys.service "${ROOT?}/etc/systemd/system/"
ln -s "${ROOT?}/etc/systemd/system/rpi-generate-ssh-host-keys.service" "${ROOT?}/etc/systemd/system/multi-user.target.requires/rpi-generate-ssh-host-keys.service"
rm -f "${ROOT?}"/etc/ssh/ssh_host_*_key*
root-fs: tag-root
# Clear /etc/machine-id and /var/lib/dbus/machine-id, as both should
@ -168,14 +159,13 @@ steps:
# Note this will also trigger ConditionFirstBoot=yes for systemd.
# On Buster, /etc/machine-id should be an emtpy file, not an absent file
# On Bullseye, /etc/machine-id should not exist in an image
#
- chroot: tag-root
shell: |
rm -f /etc/machine-id /var/lib/dbus/machine-id
echo "uninitialized" > /etc/machine-id
echo "LABEL=BOOT / ext4 rw 0 1" > /etc/fstab
- virtual-filesystems: tag-root
- ansible: tag-root
@ -184,6 +174,6 @@ steps:
extra_vars:
butter_language: en
butter_name: butterbox
tags: delta-chat,ap,base,usb,matrix,keanu,website
tags: base,usb,matrix,keanu,website
butter_user: "amd"
ap_mode_supported: "false"

View file

@ -81,11 +81,7 @@ steps:
- dhcpcd
- dnsmasq
- python3
- python3-packaging
- python3-virtualenv
- nginx
- lighttpd
- git
- unzip
- sudo
- systemd-timesyncd

View file

@ -4,7 +4,7 @@ GIT_BRANCH=$(git branch --show-current 2>/dev/null)
GIT_TAG=$(git tag 2>/dev/null | head -n1)
BUILD_DATE=$(date +"%d%m%y")
SUFFIX="${GIT_BRANCH}_${GIT_TAG}_${BUILD_DATE}"
time vmdb2 --rootfs-tarball=raspi4_$SUFFIX.tar.gz --output raspi4_butter_$SUFFIX.img --log raspi4_butter_$SUFFIX.log raspi_4_trixie.yaml
tar cvfz raspi4_butter_NOAP_$SUFFIX.img.tar.gz raspi4_butter_$SUFFIX.img
time vmdb2 --rootfs-tarball=raspi4_$SUFFIX.tar.gz --output raspi4_butter_NOAP_$SUFFIX.img --log raspi4_butter_$SUFFIX.log raspi_4_trixie.yaml
tar cvfz raspi4_butter_NOAP_$SUFFIX.img.tar.gz raspi4_butter_NOAP_$SUFFIX.img
#curl -H "Authorization: token" $CHURN_SECRET -X PUT --upload-file raspi4_butter_$SUFFIX.img.tar.gz https://guardianproject.dev/api/packages/butter/generic/churn/latest/raspi4_butter_$SUFFIX.img.tar.gz
#rm *img *tar.gz