Browse Source

Merge branch 'docker' into 'master'

Docker

See merge request cyber5k/mistborn!1
merge-requests/1/merge
Steven Foerster 6 years ago
parent
commit
b3a10eaac0
  1. 10
      LICENSE
  2. 172
      base.yml
  3. 6
      compose/production/postgres/Dockerfile
  4. 5
      compose/production/postgres/maintenance/_sourced/constants.sh
  5. 12
      compose/production/postgres/maintenance/_sourced/countdown.sh
  6. 41
      compose/production/postgres/maintenance/_sourced/messages.sh
  7. 16
      compose/production/postgres/maintenance/_sourced/yes_no.sh
  8. 38
      compose/production/postgres/maintenance/backup
  9. 22
      compose/production/postgres/maintenance/backups
  10. 55
      compose/production/postgres/maintenance/restore
  11. 13
      compose/production/tor/Dockerfile
  12. 25
      compose/production/tor/torrc
  13. 5
      compose/production/traefik/Dockerfile
  14. 176
      compose/production/traefik/traefik.toml
  15. 24
      extra/bitwarden.yml
  16. 20
      extra/homeassistant.yml
  17. 24
      extra/jellyfin.yml
  18. 29
      extra/nextcloud.yml
  19. 21
      extra/onlyoffice.yml
  20. 25
      extra/raspap.yml
  21. 65
      extra/rocketchat.yml
  22. 28
      extra/syncthing.yml
  23. 16
      extra/tor.yml
  24. 8
      scripts/conf/15-iptables.conf
  25. 2
      scripts/conf/20auto-upgrades
  26. 36
      scripts/conf/50unattended-upgrades
  27. 3
      scripts/conf/cockpit.conf
  28. 238
      scripts/install.sh
  29. 37
      scripts/services/Mistborn-base.service
  30. 23
      scripts/services/Mistborn-bitwarden.service
  31. 21
      scripts/services/Mistborn-homeassistant.service
  32. 21
      scripts/services/Mistborn-jellyfin.service
  33. 21
      scripts/services/Mistborn-nextcloud.service
  34. 21
      scripts/services/Mistborn-onlyoffice.service
  35. 21
      scripts/services/Mistborn-raspap.service
  36. 23
      scripts/services/Mistborn-rocketchat.service
  37. 25
      scripts/services/Mistborn-syncthing.service
  38. 23
      scripts/services/Mistborn-tor.service
  39. 4
      scripts/services/raspap/install.sh
  40. 29
      scripts/subinstallers/cockpit.sh
  41. 70
      scripts/subinstallers/docker.sh
  42. 64
      scripts/subinstallers/gen_prod_env.sh
  43. 119
      scripts/subinstallers/iptables.sh
  44. 22
      scripts/subinstallers/wireguard.sh

10
LICENSE

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
The MIT License (MIT)
Copyright (c) 2019, Steven Foerster
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.

172
base.yml

@ -0,0 +1,172 @@ @@ -0,0 +1,172 @@
version: '3'
volumes:
production_postgres_data: {}
production_postgres_data_backups: {}
production_traefik: {}
services:
django: &django
image: cyber5k/mistborn:latest
container_name: mistborn_production_django
depends_on:
- postgres
- redis
labels:
- "traefik.enable=true"
- "traefik.port=5000"
env_file:
- ./.envs/.production/.django
- ./.envs/.production/.postgres
volumes:
- /home/mistborn/.ssh:/ssh
- ../mistborn_volumes/base/media:/mistborn-media
- ../mistborn_volumes/base/private_media:/mistborn-private-media
command: /start
postgres:
build:
context: .
dockerfile: ./compose/production/postgres/Dockerfile
image: mistborn_production_postgres
container_name: mistborn_production_postgres
volumes:
- production_postgres_data:/var/lib/postgresql/data
- production_postgres_data_backups:/backups
env_file:
- ./.envs/.production/.postgres
traefik:
build:
context: .
dockerfile: ./compose/production/traefik/Dockerfile
image: mistborn_production_traefik
container_name: mistborn_production_traefik
depends_on:
- django
volumes:
- production_traefik:/etc/traefik/acme
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- "0.0.0.0:80:80/tcp"
redis:
image: redis:5.0
container_name: mistborn_production_redis
celeryworker:
image: cyber5k/mistborn:latest
container_name: mistborn_production_celeryworker
volumes:
- /home/mistborn/.ssh:/ssh
- ../mistborn_volumes/base/media:/mistborn-media
- ../mistborn_volumes/base/private_media:/mistborn-private-media
env_file:
- ./.envs/.production/.django
- ./.envs/.production/.postgres
- ./.envs/.production/.pihole
networks:
default:
dns_net:
ipv4_address: 10.2.1.3
dns:
- 10.2.1.2
depends_on:
- traefik
- pihole
command: /start-celeryworker
celeryworker-low-priority:
image: cyber5k/mistborn:latest
container_name: mistborn_production_celeryworker_low_priority
volumes:
- /home/mistborn/.ssh:/ssh
- ../mistborn_volumes/base/media:/mistborn-media
- ../mistborn_volumes/base/private_media:/mistborn-private-media
env_file:
- ./.envs/.production/.django
- ./.envs/.production/.postgres
- ./.envs/.production/.pihole
networks:
default:
dns_net:
ipv4_address: 10.2.1.4
dns:
- 10.2.1.2
depends_on:
- traefik
- pihole
command: /start-celeryworker-low-priority
celerybeat:
image: cyber5k/mistborn:latest
container_name: mistborn_production_celerybeat
env_file:
- ./.envs/.production/.django
- ./.envs/.production/.postgres
command: /start-celerybeat
flower:
image: cyber5k/mistborn:latest
container_name: mistborn_production_flower
ports:
- "5555:5555/tcp"
command: /start-flower
pihole:
container_name: mistborn_production_pihole
image: pihole/pihole:latest
ports:
- "53:53/tcp"
- "53:53/udp"
labels:
- "traefik.enable=true"
environment:
- ServerIP=10.2.0.3
- DNS1='10.2.0.2#5054' # docs say port 5054, was 54; use network_mode: host to see which port is used
- DNS2=''
- IPv6='false'
- DNSMASQ_LISTENING=all
# TZ: 'America/New York'
# Volumes store your data between container upgrades
env_file:
- ./.envs/.production/.pihole
volumes:
- ../mistborn_volumes/base/pihole/etc-pihole:/etc/pihole/
- ../mistborn_volumes/base/pihole/etc-dnsmasqd:/etc/dnsmasq.d/
dns:
- 127.0.0.1
networks:
default:
pihole_net:
ipv4_address: 10.2.0.3
dns_net:
ipv4_address: 10.2.1.2
restart: unless-stopped
dnscrypt-proxy:
container_name: mistborn_production_dnscrypt_proxy
image: djaydev/dnscrypt-proxy
environment:
- DNSCRYPT_LISTEN_PORT=5054
# resolvers: https://download.dnscrypt.info/dnscrypt-resolvers/v2/public-resolvers.md
#- DNSCRYPT_SERVER_NAMES=['scaleway-fr','google','yandex','cloudflare']
- DNSCRYPT_SERVER_NAMES=['cloudflare','dnswarden-doh1','dnswarden-doh2','dnswarden-doh3','securedns-doh','adguard-dns-doh']
networks:
pihole_net:
ipv4_address: 10.2.0.2
restart: unless-stopped
networks:
pihole_net:
driver: bridge
ipam:
config:
- subnet: 10.2.0.0/29
dns_net:
driver: bridge
ipam:
config:
- subnet: 10.2.1.0/24

6
compose/production/postgres/Dockerfile

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
FROM postgres:11.3
COPY ./compose/production/postgres/maintenance /usr/local/bin/maintenance
RUN chmod +x /usr/local/bin/maintenance/*
RUN mv /usr/local/bin/maintenance/* /usr/local/bin \
&& rmdir /usr/local/bin/maintenance

5
compose/production/postgres/maintenance/_sourced/constants.sh

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
#!/usr/bin/env bash
BACKUP_DIR_PATH='/backups'
BACKUP_FILE_PREFIX='backup'

12
compose/production/postgres/maintenance/_sourced/countdown.sh

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
#!/usr/bin/env bash
countdown() {
declare desc="A simple countdown. Source: https://superuser.com/a/611582"
local seconds="${1}"
local d=$(($(date +%s) + "${seconds}"))
while [ "$d" -ge `date +%s` ]; do
echo -ne "$(date -u --date @$(($d - `date +%s`)) +%H:%M:%S)\r";
sleep 0.1
done
}

41
compose/production/postgres/maintenance/_sourced/messages.sh

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
#!/usr/bin/env bash
message_newline() {
echo
}
message_debug()
{
echo -e "DEBUG: ${@}"
}
message_welcome()
{
echo -e "\e[1m${@}\e[0m"
}
message_warning()
{
echo -e "\e[33mWARNING\e[0m: ${@}"
}
message_error()
{
echo -e "\e[31mERROR\e[0m: ${@}"
}
message_info()
{
echo -e "\e[37mINFO\e[0m: ${@}"
}
message_suggestion()
{
echo -e "\e[33mSUGGESTION\e[0m: ${@}"
}
message_success()
{
echo -e "\e[32mSUCCESS\e[0m: ${@}"
}

16
compose/production/postgres/maintenance/_sourced/yes_no.sh

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
#!/usr/bin/env bash
yes_no() {
declare desc="Prompt for confirmation. \$\"\{1\}\": confirmation message."
local arg1="${1}"
local response=
read -r -p "${arg1} (y/[n])? " response
if [[ "${response}" =~ ^[Yy]$ ]]
then
exit 0
else
exit 1
fi
}

38
compose/production/postgres/maintenance/backup

@ -0,0 +1,38 @@ @@ -0,0 +1,38 @@
#!/usr/bin/env bash
### Create a database backup.
###
### Usage:
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres backup
set -o errexit
set -o pipefail
set -o nounset
working_dir="$(dirname ${0})"
source "${working_dir}/_sourced/constants.sh"
source "${working_dir}/_sourced/messages.sh"
message_welcome "Backing up the '${POSTGRES_DB}' database..."
if [[ "${POSTGRES_USER}" == "postgres" ]]; then
message_error "Backing up as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again."
exit 1
fi
export PGHOST="${POSTGRES_HOST}"
export PGPORT="${POSTGRES_PORT}"
export PGUSER="${POSTGRES_USER}"
export PGPASSWORD="${POSTGRES_PASSWORD}"
export PGDATABASE="${POSTGRES_DB}"
backup_filename="${BACKUP_FILE_PREFIX}_$(date +'%Y_%m_%dT%H_%M_%S').sql.gz"
pg_dump | gzip > "${BACKUP_DIR_PATH}/${backup_filename}"
message_success "'${POSTGRES_DB}' database backup '${backup_filename}' has been created and placed in '${BACKUP_DIR_PATH}'."

22
compose/production/postgres/maintenance/backups

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
#!/usr/bin/env bash
### View backups.
###
### Usage:
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres backups
set -o errexit
set -o pipefail
set -o nounset
working_dir="$(dirname ${0})"
source "${working_dir}/_sourced/constants.sh"
source "${working_dir}/_sourced/messages.sh"
message_welcome "These are the backups you have got:"
ls -lht "${BACKUP_DIR_PATH}"

55
compose/production/postgres/maintenance/restore

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
#!/usr/bin/env bash
### Restore database from a backup.
###
### Parameters:
### <1> filename of an existing backup.
###
### Usage:
### $ docker-compose -f <environment>.yml (exec |run --rm) postgres restore <1>
set -o errexit
set -o pipefail
set -o nounset
working_dir="$(dirname ${0})"
source "${working_dir}/_sourced/constants.sh"
source "${working_dir}/_sourced/messages.sh"
if [[ -z ${1+x} ]]; then
message_error "Backup filename is not specified yet it is a required parameter. Make sure you provide one and try again."
exit 1
fi
backup_filename="${BACKUP_DIR_PATH}/${1}"
if [[ ! -f "${backup_filename}" ]]; then
message_error "No backup with the specified filename found. Check out the 'backups' maintenance script output to see if there is one and try again."
exit 1
fi
message_welcome "Restoring the '${POSTGRES_DB}' database from the '${backup_filename}' backup..."
if [[ "${POSTGRES_USER}" == "postgres" ]]; then
message_error "Restoring as 'postgres' user is not supported. Assign 'POSTGRES_USER' env with another one and try again."
exit 1
fi
export PGHOST="${POSTGRES_HOST}"
export PGPORT="${POSTGRES_PORT}"
export PGUSER="${POSTGRES_USER}"
export PGPASSWORD="${POSTGRES_PASSWORD}"
export PGDATABASE="${POSTGRES_DB}"
message_info "Dropping the database..."
dropdb "${PGDATABASE}"
message_info "Creating a new database..."
createdb --owner="${POSTGRES_USER}"
message_info "Applying the backup to the new database..."
gunzip -c "${backup_filename}" | psql "${POSTGRES_DB}"
message_success "The '${POSTGRES_DB}' database has been restored from the '${backup_filename}' backup."

13
compose/production/tor/Dockerfile

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
FROM alpine:latest
RUN apk update \
&& apk upgrade \
&& apk add tor \
&& rm /var/cache/apk/*
EXPOSE 9150
ADD ./compose/production/tor/torrc /etc/tor/torrc
USER tor
CMD /usr/bin/tor -f /etc/tor/torrc

25
compose/production/tor/torrc

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
## The directory for keeping all the keys/etc
DataDirectory /var/lib/tor
## Tor opens a socks proxy on port 9150
SocksPort 0.0.0.0:9150
## Entry policies to allow/deny SOCKS requests based on IP address.
## SocksPolicy accept 192.168.1.0/24
SocksPolicy accept 172.17.0.0/16
SocksPolicy accept 10.0.0.0/8
SocksPolicy reject *
## Logs go to stdout at level "notice"
Log notice stdout
ControlPort 9051
# Try for at most NUM seconds when building circuits. If the circuit isn't open in that time, give up on it. (Default: 1 minute.)
CircuitBuildTimeout 5
# Send a padding cell every N seconds to keep firewalls from closing our connections while Tor is not in use.
KeepalivePeriod 60
# Force Tor to consider whether to build a new circuit every NUM seconds.
NewCircuitPeriod 15
# How many entry guards should we keep at a time?
NumEntryGuards 8

5
compose/production/traefik/Dockerfile

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
FROM traefik:alpine
RUN mkdir -p /etc/traefik/acme
RUN touch /etc/traefik/acme/acme.json
RUN chmod 600 /etc/traefik/acme/acme.json
COPY ./compose/production/traefik/traefik.toml /etc/traefik

176
compose/production/traefik/traefik.toml

@ -0,0 +1,176 @@ @@ -0,0 +1,176 @@
#debug = true
logLevel = "ERROR" #DEBUG, INFO, WARN, ERROR, FATAL, PANIC
InsecureSkipVerify = true
#defaultEntryPoints = ["http", "https"]
defaultEntryPoints = ["http"]
# Entrypoints, http and https
[entryPoints]
# http should be redirected to https
[entryPoints.http]
address = ":80"
#[entryPoints.http.redirect]
#entryPoint = "https"
# https is the default
#[entryPoints.https]
#address = ":443"
# [entryPoints.https.tls]
## Enable ACME (Let's Encrypt): automatic SSL
#[acme]
## Email address used for registration
#email = "steven@cyber5k.com"
#storage = "/etc/traefik/acme/acme.json"
#entryPoint = "https"
#onDemand = false
#OnHostRule = true
# # Use a HTTP-01 acme challenge rather than TLS-SNI-01 challenge
# [acme.httpChallenge]
# entryPoint = "http"
[file]
[backends]
[backends.django]
[backends.django.servers.server1]
url = "http://django:5000"
[backends.pihole]
[backends.pihole.servers.server1]
url = "http://pihole:80"
[backends.homeassistant]
[backends.homeassistant.servers.server1]
url = "http://homeassistant:8123"
[backends.syncthing]
[backends.syncthing.servers.server1]
url = "http://syncthing:8384"
[backends.rocketchat]
[backends.rocketchat.servers.server1]
url = "http://rocketchat:3000"
[backends.nextcloud]
[backends.nextcloud.servers.server1]
url = "http://nextcloud:80"
[backends.onlyoffice]
[backends.onlyoffice.servers.server1]
url = "http://onlyoffice:80"
[backends.bitwarden]
[backends.bitwarden.servers.server1]
url = "http://bitwarden:80"
[backends.jellyfin]
[backends.jellyfin.servers.server1]
url = "http://jellyfin:8096"
[backends.raspap]
[backends.raspap.servers.server1]
url = "http://raspap:80"
[backends.cockpit]
[backends.cockpit.servers.server1]
url = "http://IPV4_PUBLIC:9090"
[frontends]
[frontends.django]
backend = "django"
passHostHeader = true
[frontends.django.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.django.routes.dr1]
#rule = "Host:mistborn.cyber5k.com"
rule = "Host:home.mistborn"
[frontends.pihole]
backend = "pihole"
passHostHeader = true
[frontends.pihole.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.pihole.routes.dr1]
rule = "Host:pihole.mistborn"
[frontends.homeassistant]
backend = "homeassistant"
passHostHeader = true
[frontends.homeassistant.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.homeassistant.routes.dr1]
rule = "Host:hass.mistborn"
[frontends.syncthing]
backend = "syncthing"
passHostHeader = true
[frontends.syncthing.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.syncthing.routes.dr1]
rule = "Host:syncthing.mistborn"
[frontends.rocketchat]
backend = "rocketchat"
passHostHeader = true
[frontends.rocketchat.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.rocketchat.routes.dr1]
rule = "Host:chat.mistborn"
[frontends.nextcloud]
backend = "nextcloud"
passHostHeader = true
[frontends.nextcloud.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.nextcloud.routes.dr1]
rule = "Host:nextcloud.mistborn"
[frontends.onlyoffice]
backend = "onlyoffice"
passHostHeader = true
[frontends.onlyoffice.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.onlyoffice.routes.dr1]
rule = "Host:onlyoffice.mistborn"
[frontends.bitwarden]
backend = "bitwarden"
passHostHeader = true
[frontends.bitwarden.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.bitwarden.routes.dr1]
rule = "Host:bitwarden.mistborn"
[frontends.jellyfin]
backend = "jellyfin"
passHostHeader = true
[frontends.jellyfin.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.jellyfin.routes.dr1]
rule = "Host:jellyfin.mistborn"
[frontends.raspap]
backend = "raspap"
passHostHeader = true
[frontends.raspap.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.raspap.routes.dr1]
rule = "Host:raspap.mistborn"
[frontends.cockpit]
backend = "cockpit"
passHostHeader = true
[frontends.cockpit.headers]
HostsProxyHeaders = ['X-CSRFToken']
[frontends.cockpit.routes.dr1]
rule = "Host:cockpit.mistborn"
## Connection to docker host system (docker.sock)
#[docker]
#endpoint = "unix:///var/run/docker.sock"
#domain = "localhost"
#watch = true
## This will hide all docker containers that don't have explicitly
## set label to "enable"
#exposedbydefault = false

24
extra/bitwarden.yml

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
version: '3'
#volumes:
# production_bitwarden_data: {}
services:
bitwarden:
image: bitwardenrs/server:latest
container_name: mistborn_production_bitwarden
env_file:
- ../.envs/.production/.bitwarden
volumes:
- ../../mistborn_volumes/extra/bitwarden:/data
labels:
- "traefik.enable=true"
- "traefik.port=80"
ports:
- 3012:3012/tcp
restart: unless-stopped
networks:
default:
external:
name: mistborn_default

20
extra/homeassistant.yml

@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
version: '3'
services:
homeassistant:
container_name: mistborn_production_home_assistant
image: homeassistant/home-assistant:stable
volumes:
- ../../mistborn_volumes/extra/homeassistant/config:/config
environment:
- TZ=America/New_York
labels:
- "traefik.enable=true"
- "traefik.port=8123"
restart: unless-stopped
#network_mode: host
networks:
default:
external:
name: mistborn_default

24
extra/jellyfin.yml

@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
version: '3'
volumes:
production_jellyfin_config: {}
production_jellyfin_cache: {}
#production_nextcloud: {}
services:
jellyfin:
image: jellyfin/jellyfin:latest
container_name: mistborn_production_jellyfin
volumes:
- production_jellyfin_config:/config
- production_jellyfin_cache:/cache
- ../../mistborn_volumes/extra/nextcloud:/media:ro
labels:
- "traefik.enable=true"
- "traefik.port=8096"
restart: unless-stopped
networks:
default:
external:
name: mistborn_default

29
extra/nextcloud.yml

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
version: '3'
#volumes:
# production_nextcloud: {}
services:
nextcloud:
image: nextcloud
container_name: mistborn_production_nextcloud
env_file:
- ../.envs/.production/.postgres
- ../.envs/.production/.nextcloud
labels:
- "traefik.enable=true"
- "traefik.port=80"
volumes:
- ../../mistborn_volumes/extra/nextcloud:/var/www/html
#- ./volumes/extra/nextcloud/config:/var/www/html/config
#- ./volumes/extra/nextcloud/custom_apps:/var/www/html/custom_apps
#- ./volumes/extra/nextcloud/data:/var/www/html/data
#- ./volumes/extra/nextcloud/themes:/var/www/html/themes
environment:
- VIRTUAL_HOST=nextcloud.mistborn
restart: unless-stopped
networks:
default:
external:
name: mistborn_default

21
extra/onlyoffice.yml

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
version: '3'
services:
onlyoffice:
container_name: mistborn_production_onlyoffice
image: onlyoffice/documentserver:latest
volumes:
- ../../mistborn_volumes/extra/onlyoffice/logs:/var/log/onlyoffice
- ../../mistborn_volumes/extra/onlyoffice/cache:/var/lib/onlyoffice
env_file:
- ../.envs/.production/.onlyoffice
labels:
- "traefik.enable=true"
- "traefik.port=80"
restart: unless-stopped
#network_mode: host
networks:
default:
external:
name: mistborn_default

25
extra/raspap.yml

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
version: '3'
services:
raspap:
build:
context: ..
dockerfile: ./compose/production/raspap/Dockerfile
#user: root
image: mistborn_production_raspap
container_name: mistborn_production_raspap
labels:
- "traefik.enable=true"
- "traefik.port=80"
env_file:
- ../.envs/.production/.pihole
command: /start
volumes:
#- ~/.ssh:/ssh:ro
- ../../mistborn_volumes/extra/raspap/etc-raspap:/etc/raspap
#- ../volumes/extra/raspap/etc-lighttpd:/etc/lighttpd
networks:
default:
external:
name: mistborn_default

65
extra/rocketchat.yml

@ -0,0 +1,65 @@ @@ -0,0 +1,65 @@
version: '3'
services:
# rocketchat
rocketchat:
image: rocket.chat:latest
container_name: mistborn_production_rocketchat
command: bash -c 'for i in `seq 1 30`; do node main.js && s=$$? && break || s=$$?; echo "Tried $$i times. Waiting 5 secs..."; sleep 5; done; (exit $$s)'
restart: unless-stopped
volumes:
- ../../mistborn_volumes/extra/rocketchat/uploads:/app/uploads
environment:
- PORT=3000
- ROOT_URL=http://chat.mistborn
- MONGO_URL=mongodb://mongo:27017/rocketchat
- MONGO_OPLOG_URL=mongodb://mongo:27017/local
- Accounts_UseDNSDomainCheck=False
labels:
- "traefik.enable=true"
- "traefik.port=3000"
depends_on:
- mongo
#ports:
# - 3000:3000
mongo:
image: mongo:4.0
container_name: mistborn_production_rocketchat_mongo
restart: unless-stopped
volumes:
- ../volumes/extra/rocketchat/data/db:/data/db
- ../volumes/extra/rocketchat/data/dump:/dump
command: mongod --smallfiles --oplogSize 128 --replSet rs0 --storageEngine=mmapv1
# this container's job is just run the command to initialize the replica set.
# it will run the command and remove himself (it will not stay running)
mongo-init-replica:
image: mongo
command: 'bash -c "for i in `seq 1 30`; do mongo mongo/rocketchat --eval \"rs.initiate({ _id: ''rs0'', members: [ { _id: 0, host: ''localhost:27017'' } ]})\" && s=$$? && break || s=$$?; echo \"Tried $$i times. Waiting 5 secs...\"; sleep 5; done; (exit $$s)"'
depends_on:
- mongo
# hubot, the popular chatbot (add the bot user first and change the password before starting this image)
hubot:
image: rocketchat/hubot-rocketchat:latest
container_name: mistborn_production_rocketchat_hubot
restart: unless-stopped
environment:
- ROCKETCHAT_URL=chat.mistborn #:3000
# you can add more scripts as you'd like here, they need to be installable by npm
- EXTERNAL_SCRIPTS=hubot-help,hubot-seen,hubot-links,hubot-diagnostics
env_file:
- ../.envs/.production/.rocketchat
depends_on:
- rocketchat
volumes:
- ../volumes/extra/rocketchat/hubot/scripts:/home/hubot/scripts
# this is used to expose the hubot port for notifications on the host on port 3001, e.g. for hubot-jenkins-notifier
ports:
- 3001:8080/tcp
networks:
default:
external:
name: mistborn_default

28
extra/syncthing.yml

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
version: '3'
services:
syncthing:
image: linuxserver/syncthing
container_name: mistborn_production_syncthing
environment:
- PUID=1000
- PGID=1000
- TZ=Amereica/New_York
- UMASK_SET=022
volumes:
- ../../mistborn_volumes/extra/syncthing/config:/config
- ../../mistborn_volumes/extra/syncthing/data1:/data1
- ../../mistborn_volumes/extra/syncthing/data2:/data2
ports:
#- 8384:8384
- 22000:22000/tcp # listening port
- 21027:21027/udp # protocol discovery
labels:
- "traefik.enable=true"
- "traefik.port=8384"
restart: unless-stopped
networks:
default:
external:
name: mistborn_default

16
extra/tor.yml

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
version: '3'
services:
tor-client:
build:
context: ..
dockerfile: ./compose/production/tor/Dockerfile
image: mistborn_production_tor
container_name: mistborn_production_tor
ports:
- 9150:9150/tcp
networks:
default:
external:
name: mistborn_default

8
scripts/conf/15-iptables.conf

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
# Log kernel iptables dropped messages to iptables.log
$template MyTemplate,"%$day%-%timegenerated:1:3:date-rfc3164%-%$year% %timegenerated:12:19:date-rfc3339% %HOSTNAME% %syslogtag% %msg%\n"
:msg,contains,"[IPTables-Dropped]:" /var/log/iptables.log;MyTemplate #RSYSLOG_FileFormat
# Uncomment the following to stop logging anything that matches the last rule.
# Doing this will stop logging kernel generated UFW log messages to the file
# normally containing kern.* messages (eg, /var/log/kern.log)
#& stop

2
scripts/conf/20auto-upgrades

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";

36
scripts/conf/50unattended-upgrades

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
// Automatically upgrade packages from these (origin, archive) pairs
Unattended-Upgrade::Allowed-Origins {
// ${distro_id} and ${distro_codename} will be automatically expanded
"${distro_id} stable";
"${distro_id} ${distro_codename}-security";
// Autoupdate Nginx
"nginx:${distro_codename}";
// Autoupdate WireGuard
"LP-PPA-wireguard-wireguard:${distro_codename}";
};
// List of packages to not update
Unattended-Upgrade::Package-Blacklist {
};
// Do automatic removal of new unused dependencies after the upgrade
// (equivalent to apt-get autoremove)
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// Automatically reboot *WITHOUT CONFIRMATION* if a
// the file /var/run/reboot-required is found after the upgrade
Unattended-Upgrade::Automatic-Reboot "true";
// If automatic reboot is enabled and needed, reboot at the specific
// time instead of immediately
// Default: "now"
Unattended-Upgrade::Automatic-Reboot-Time "00:00";
// Avoid conffile dpkg prompt by *always* leaving the modified configuration in
// place and putting the new package configuration in a .dpkg-dist file
Dpkg::Options {
"--force-confdef";
"--force-confold";
};

3
scripts/conf/cockpit.conf

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
[WebService]
ProtocolHeader = X-Forwarded-Proto
AllowUnencrypted=true

238
scripts/install.sh

@ -0,0 +1,238 @@ @@ -0,0 +1,238 @@
#!/bin/bash
set -e
## ensure run as nonroot user
#if [ "$EUID" -eq 0 ]; then
MISTBORN_USER="mistborn"
if [ $(whoami) != "$MISTBORN_USER" ]; then
echo "Creating user: $MISTBORN_USER"
sudo useradd -s /bin/bash -d /home/$MISTBORN_USER -m -G sudo $MISTBORN_USER 2>/dev/null || true
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
#echo "SCRIPTPATH: $SCRIPTPATH"
FILENAME=$(basename -- "$0")
#echo "FILENAME: $FILENAME"
FULLPATH="$SCRIPTPATH/$FILENAME"
#echo "FULLPATH: $FULLPATH"
# SUDO
case `sudo grep -e "^$MISTBORN_USER.*" /etc/sudoers >/dev/null; echo $?` in
0)
echo "$MISTBORN_USER already in sudoers"
;;
1)
echo "Adding $MISTBORN_USER to sudoers"
sudo bash -c "echo '$MISTBORN_USER ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers"
;;
*)
echo "There was a problem checking sudoers"
;;
esac
# get git branch if one exists (default to master)
pushd .
cd $SCRIPTPATH
GIT_BRANCH=$(git symbolic-ref --short HEAD || echo "master")
popd
sudo cp $FULLPATH /home/$MISTBORN_USER
sudo chown $MISTBORN_USER:$MISTBORN_USER /home/$MISTBORN_USER/$FILENAME
sudo SSH_CLIENT="$SSH_CLIENT" MISTBORN_DEFAULT_PASSWORD="$MISTBORN_DEFAULT_PASSWORD" GIT_BRANCH="$GIT_BRANCH" -i -u $MISTBORN_USER bash -c "/home/$MISTBORN_USER/$FILENAME" # self-referential call
exit 0
fi
echo "Running as $USER"
# banner
echo -e " ____ _ ____ _ __"
echo -e " / ___| _| |__ ___ _ __ | ___|| |/ /"
echo -e "| | | | | | '_ \ / _ \ '__| |___ \| ' /"
echo -e "| |__| |_| | |_) | __/ | ___) | . \ "
echo -e " \____\__, |_.__/ \___|_| |____/|_|\_\ "
echo -e " |___/"
echo -e " __ __ _ _ _"
echo -e "| \/ (_)___| |_| |__ ___ _ __ _ __"
echo -e "| |\/| | / __| __| '_ \ / _ \| '__| '_ \ "
echo -e "| | | | \__ \ |_| |_) | (_) | | | | | |"
echo -e "|_| |_|_|___/\__|_.__/ \___/|_| |_| |_|"
echo -e ""
# Get OS info
# Determine OS platform
UNAME=$(uname | tr "[:upper:]" "[:lower:]")
DISTRO=""
# If Linux, try to determine specific distribution
if [ "$UNAME" == "linux" ]; then
# use /etc/os-release to get distro
DISTRO=$(cat /etc/os-release | awk -F= '/^ID=/{print $2}')
fi
echo "UNAME: $UNAME"
echo "DISTRO: $DISTRO"
# INPUT default admin password
if [ -z "${MISTBORN_DEFAULT_PASSWORD}" ]; then
read -p "(Mistborn) Set default admin password: " -s MISTBORN_DEFAULT_PASSWORD
echo
else
echo "MISTBORN_DEFAULT_PASSWORD is already set"
fi
# SSH keys
if [ ! -f ~/.ssh/id_rsa ]; then
echo "Generating SSH keypair for $USER"
ssh-keygen -t rsa -b 4096 -N "" -m pem -f ~/.ssh/id_rsa -q
# Authorized keys
echo "from=\"172.16.0.0/12,192.168.0.0/16,10.0.0.0/8\" $(cat ~/.ssh/id_rsa.pub)" > ~/.ssh/authorized_keys
else
echo "SSH key exists for $USER"
fi
sudo rm -rf /opt/mistborn 2>/dev/null || true
# clone to /opt and change directory
echo "Cloning $GIT_BRANCH branch from mistborn repo"
sudo git clone https://gitlab.com/cyber5k/mistborn.git -b $GIT_BRANCH /opt/mistborn
sudo chown -R $USER:$USER /opt/mistborn
pushd .
cd /opt/mistborn
git submodule update --init --recursive
# iptables
echo "Setting up firewall (iptables)"
if [ ! -f "/etc/iptables/rules.v4" ]; then
echo "Setting iptables rules..."
./scripts/subinstallers/iptables.sh
else
echo "iptables rules exist. Leaving alone."
fi
# SSH Server
sudo apt-get install -y openssh-server
sudo sed -i 's/#PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/#PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
sudo sed -i 's/PermitRootLogin.*/PermitRootLogin prohibit-password/' /etc/ssh/sshd_config
sudo systemctl restart ssh
# Additional tools fail2ban
sudo apt-get install -y dnsutils fail2ban
# Install kernel headers
if [ "$DISTRO" == "ubuntu" ] || [ "$DISTRO" == "debian" ]; then
sudo apt install -y linux-headers-$(uname -r)
elif [ "$DISTRO" == "raspbian" ]; then
sudo apt-get install -y raspberrypi-kernel-headers
fi
# Wireugard
source ./scripts/subinstallers/wireguard.sh
# Docker
source ./scripts/subinstallers/docker.sh
# Unattended upgrades
sudo apt-get install -y unattended-upgrades
# Cockpit
source ./scripts/subinstallers/cockpit.sh
# Mistborn
# final setup vars
iface=$(ip -o -4 route show to default | egrep -o 'dev [^ ]*' | awk '{print $2}')
IPV4_PUBLIC=$(ip -o -4 route show default | egrep -o 'dev [^ ]*' | awk '{print $2}' | xargs ip -4 addr show | grep 'inet ' | awk '{print $2}' | grep -o "^[0-9.]*" | tr -cd '\11\12\15\40-\176' | head -1) # tail -1 to get last
# clean
if [ -f "/etc/systemd/system/Mistborn-base.service" ]; then
sudo systemctl stop Mistborn*.service 2>/dev/null || true
sudo systemctl disable Mistborn*.service 2>/dev/null || true
fi
sudo docker volume rm -f mistborn_production_postgres_data 2>/dev/null || true
sudo docker volume rm -f mistborn_production_postgres_data_backups 2>/dev/null || true
sudo docker volume rm -f mistborn_production_traefik 2>/dev/null || true
# generate production .env file
if [ ! -d ./.envs/.production ]; then
./scripts/subinstallers/gen_prod_env.sh "$MISTBORN_DEFAULT_PASSWORD"
fi
# unattended upgrades
sudo cp ./scripts/conf/20auto-upgrades /etc/apt/apt.conf.d/
sudo cp ./scripts/conf/50unattended-upgrades /etc/apt/apt.conf.d/
sudo systemctl stop unattended-upgrades
sudo systemctl daemon-reload
sudo systemctl restart unattended-upgrades
# setup Mistborn services
# install and start base services
# default interface
sudo cp ./scripts/services/Mistborn* /etc/systemd/system/
sudo find /etc/systemd/system/ -type f -name 'Mistborn*' | xargs sudo sed -i "s/User=.*/User=$USER/"
sudo find /etc/systemd/system/ -type f -name 'Mistborn*' | xargs sudo sed -i "s/ root:root / $USER:$USER /"
sudo find /etc/systemd/system/ -type f -name 'Mistborn*' | xargs sudo sed -i "s/DIFACE/$iface/"
if [ "$DISTRO" == "debian" ] || [ "$DISTRO" == "raspbian" ]; then
# remove systemd-resolved lines
sudo sed -i '/.*systemd-resolved/d' /etc/systemd/system/Mistborn-base.service
fi
# setup local volumes for pihole
sudo mkdir -p ../mistborn_volumes/
sudo chown -R root:root ../mistborn_volumes/
sudo mkdir -p ../mistborn_volumes/base/pihole/etc-pihole
sudo mkdir -p ../mistborn_volumes/base/pihole/etc-dnsmasqd
echo "addn-hosts=/etc/pihole/lan.list" | sudo tee ../mistborn_volumes/base/pihole/etc-dnsmasqd/02-lan.conf
sudo touch ../mistborn_volumes/base/pihole/etc-pihole/lan.list
sudo mkdir -p ../mistborn_volumes/extra
# Traefik final setup (cockpit)
sudo sed -i "s/IPV4_PUBLIC/$IPV4_PUBLIC/" ./compose/production/traefik/traefik.toml
# Download docker images while DNS is operable
sudo docker-compose -f base.yml pull || true
sudo docker-compose -f base.yml build
# DNS
sudo systemctl stop systemd-resolved 2>/dev/null || true
sudo systemctl disable systemd-resolved 2>/dev/null || true
# array of dns entries to add (not not already present)
declare -a dnslist=("pihole.mistborn" \
"home.mistborn" \
"hass.mistborn" \
"syncthing.mistborn" \
"chat.mistborn" \
"tor.mistborn" \
"nextcloud.mistborn" \
"onlyoffice.mistborn" \
"bitwarden.mistborn" \
"jellyfin.mistborn" \
"raspap.mistborn" \
"cockpit.mistborn")
for dnsname in "${dnslist[@]}"
do
sudo grep -qF "$dnsname" ../mistborn_volumes/base/pihole/etc-pihole/lan.list \
&& echo "$dnsname already in DNS" \
|| echo "$IPV4_PUBLIC $dnsname" | sudo tee -a ../mistborn_volumes/base/pihole/etc-pihole/lan.list
done
# ResolvConf (OpenResolv installed with Wireguard)
sudo sed -i "s/#name_servers.*/name_servers=$IPV4_PUBLIC/" /etc/resolvconf.conf
sudo sed -i "s/name_servers.*/name_servers=$IPV4_PUBLIC/" /etc/resolvconf.conf
#sudo sed -i "s/#name_servers.*/name_servers=127.0.0.1/" /etc/resolvconf.conf
sudo resolvconf -u 1>/dev/null 2>&1
echo "backup up original volumes folder"
sudo mkdir -p ../mistborn_backup
sudo tar -czf ../mistborn_backup/mistborn_volumes_backup.tar.gz ../mistborn_volumes 1>/dev/null 2>&1
# start base service
sudo systemctl enable Mistborn-base.service
sudo systemctl start Mistborn-base.service
popd

37
scripts/services/Mistborn-base.service

@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
[Unit]
Description=Mistborn Base
Requires=docker.service
After=docker.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/base.yml down
ExecStartPre=/bin/chown -R root:root /opt/mistborn_volumes/
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/base.yml build
ExecStartPre=/bin/systemctl stop systemd-resolved
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p udp --dport 53 -j MISTBORN_LOG_DROP
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 53 -j MISTBORN_LOG_DROP
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 80 -j MISTBORN_LOG_DROP
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 5555 -j MISTBORN_LOG_DROP
ExecStartPre=/sbin/iptables -A OUTPUT -o DIFACE -p udp --dport 53 -j MISTBORN_LOG_DROP
ExecStartPre=/sbin/ip6tables -A OUTPUT -p udp --dport 53 -j MISTBORN_LOG_DROP
ExecStartPre=/sbin/resolvconf -u
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/base.yml up
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/base.yml down
# Post stop
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p udp --dport 53 -j MISTBORN_LOG_DROP
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 53 -j MISTBORN_LOG_DROP
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 80 -j MISTBORN_LOG_DROP
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 5555 -j MISTBORN_LOG_DROP
ExecStopPost=/sbin/iptables -D OUTPUT -o DIFACE -p udp --dport 53 -j MISTBORN_LOG_DROP
ExecStopPost=/sbin/ip6tables -D OUTPUT -p udp --dport 53 -j MISTBORN_LOG_DROP
ExecStopPost=/bin/systemctl start systemd-resolved
[Install]
WantedBy=multi-user.target

23
scripts/services/Mistborn-bitwarden.service

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
[Unit]
Description=Mistborn Bitwarden Service
Requires=Mistborn-base.service
After=Mistborn-base.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/bitwarden.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 3012 -j MISTBORN_LOG_DROP
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/bitwarden.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/bitwarden.yml down
# Post stop
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 3012 -j MISTBORN_LOG_DROP
[Install]
WantedBy=multi-user.target

21
scripts/services/Mistborn-homeassistant.service

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
[Unit]
Description=Mistborn Home Assistant
Requires=Mistborn-base.service
After=Mistborn-base.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/homeassistant.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/homeassistant.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/homeassistant.yml down
# Post stop
[Install]
WantedBy=multi-user.target

21
scripts/services/Mistborn-jellyfin.service

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
[Unit]
Description=Mistborn Jellyfin Service
Requires=Mistborn-nextcloud.service
After=Mistborn-nextcloud.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/jellyfin.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/jellyfin.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/jellyfin.yml down
# Post stop
[Install]
WantedBy=multi-user.target

21
scripts/services/Mistborn-nextcloud.service

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
[Unit]
Description=Mistborn Nextcloud Service
Requires=Mistborn-base.service
After=Mistborn-base.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/nextcloud.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/nextcloud.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/nextcloud.yml down
# Post stop
[Install]
WantedBy=multi-user.target

21
scripts/services/Mistborn-onlyoffice.service

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
[Unit]
Description=Mistborn OnlyOffice Service
Requires=Mistborn-base.service
After=Mistborn-base.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/onlyoffice.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/onlyoffice.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/onlyoffice.yml down
# Post stop
[Install]
WantedBy=multi-user.target

21
scripts/services/Mistborn-raspap.service

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
[Unit]
Description=Mistborn RaspAP Service
Requires=Mistborn-base.service
After=Mistborn-base.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/raspap.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/raspap.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/raspap.yml down
# Post stop
[Install]
WantedBy=multi-user.target

23
scripts/services/Mistborn-rocketchat.service

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
[Unit]
Description=Mistborn Rocket Chat Service
Requires=Mistborn-base.service
After=Mistborn-base.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/rocketchat.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 3001 -j MISTBORN_LOG_DROP
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/rocketchat.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/rocketchat.yml down
# Post stop
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 3001 -j MISTBORN_LOG_DROP
[Install]
WantedBy=multi-user.target

25
scripts/services/Mistborn-syncthing.service

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
[Unit]
Description=Mistborn Syncthing Service
Requires=Mistborn-base.service
After=Mistborn-base.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/syncthing.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p udp --dport 21027 -j MISTBORN_LOG_DROP
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 22000 -j MISTBORN_LOG_DROP
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/syncthing.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/syncthing.yml down
# Post stop
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p udp --dport 21027 -j MISTBORN_LOG_DROP
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 22000 -j MISTBORN_LOG_DROP
[Install]
WantedBy=multi-user.target

23
scripts/services/Mistborn-tor.service

@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
[Unit]
Description=Mistborn Tor Service
Requires=Mistborn-base.service
After=Mistborn-base.service
[Service]
Restart=always
User=root
Group=docker
PermissionsStartOnly=true
# Shutdown container (if running) when unit is stopped
ExecStartPre=/usr/local/bin/docker-compose -f /opt/mistborn/extra/tor.yml down
ExecStartPre=/bin/chown -R --from=root:root root:root /opt/mistborn_volumes/
ExecStartPre=/sbin/iptables -I DOCKER-USER -i DIFACE -p tcp --dport 9150 -j MISTBORN_LOG_DROP
# Start container when unit is started
ExecStart=/usr/local/bin/docker-compose -f /opt/mistborn/extra/tor.yml up --build
# Stop container when unit is stopped
ExecStop=/usr/local/bin/docker-compose -f /opt/mistborn/extra/tor.yml down
# Post stop
ExecStopPost=/sbin/iptables -D DOCKER-USER -i DIFACE -p tcp --dport 9150 -j MISTBORN_LOG_DROP
[Install]
WantedBy=multi-user.target

4
scripts/services/raspap/install.sh

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
#!/bin/bash
# install on gateway
sudo apt-get install -y hostapd vnstat

29
scripts/subinstallers/cockpit.sh

@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
#!/bin/bash
# Cockpit
echo "Installing Cockpit"
if [ "$DISTRO" == "ubuntu" ]; then
echo "Ubuntu backports enabled by default"
sudo apt-get install -y cockpit cockpit-docker
elif [ "$DISTRO" == "debian" ]; then
sudo grep -qF "buster-backports" /etc/apt/sources.list.d/backports.list \
&& echo "buster-backports already in sources" \
|| echo 'deb http://deb.debian.org/debian buster-backports main' | sudo tee -a /etc/apt/sources.list.d/backports.list
sudo apt-get install -y cockpit cockpit-docker
elif [ "$DISTRO" == "raspbian" ]; then
echo "Raspbian repos contain cockpit"
sudo apt-get install -y cockpit cockpit-docker
fi
sudo cp ./scripts/conf/cockpit.conf /etc/cockpit/cockpit.conf
sudo systemctl restart cockpit.socket
# create system cockpit user
echo "Creating cockpit user"
sudo useradd -s /bin/bash -d /home/cockpit -m -G sudo -p $(openssl passwd -1 "$MISTBORN_DEFAULT_PASSWORD") cockpit || true

70
scripts/subinstallers/docker.sh

@ -0,0 +1,70 @@ @@ -0,0 +1,70 @@
#!/bin/bash
# Docker
# dependencies
echo "Installing Docker dependencies"
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
# Docker repo key
echo "Adding docker repository key"
if [ "$DISTRO" == "ubuntu" ]; then
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
elif [ "$DISTRO" == "debian" ]; then
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add -
elif [ "$DISTRO" == "raspbian" ]; then
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | sudo apt-key add -
fi
# Docker repo to source list
echo "Adding docker to sources list"
if [ "$DISTRO" == "ubuntu" ]; then
sudo add-apt-repository -y \
"deb https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
elif [ "$DISTRO" == "debian" ]; then
sudo add-apt-repository -y \
"deb https://download.docker.com/linux/debian \
$(lsb_release -cs) \
stable"
elif [ "$DISTRO" == "raspbian" ]; then
echo "deb [arch=armhf] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list
fi
# install Docker
echo "Installing docker"
sudo apt-get update
if [ "$DISTRO" == "ubuntu" ] || [ "$DISTRO" == "debian" ]; then
sudo apt-get install -y docker-ce docker-ce-cli containerd.io
elif [ "$DISTRO" == "raspbian" ]; then
sudo apt install -y --no-install-recommends \
docker-ce \
cgroupfs-mount
fi
# Docker group
sudo usermod -aG docker $USER
# Docker Compose
echo "Installing Docker Compose"
#if [ "$DISTRO" == "ubuntu" ] || [ "$DISTRO" == "debian" ]; then
# sudo curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
# sudo chmod +x /usr/local/bin/docker-compose
#elif [ "$DISTRO" == "raspbian" ]; then
# Install required packages
sudo apt update
sudo apt install -y python python3-pip libffi-dev python-backports.ssl-match-hostname
# Install Docker Compose from pip
# This might take a while
sudo pip3 install docker-compose
#fi

64
scripts/subinstallers/gen_prod_env.sh

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
#!/bin/sh
# generate production .env file for Django
mkdir -p ./.envs/.production
DJANGO_PROD_FILE="./.envs/.production/.django"
DJANGO_SECRET_KEY=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(50)]))")
#CELERY_FLOWER_PASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
MISTBORN_DEFAULT_PASSWORD="$1"
echo "DJANGO_SETTINGS_MODULE=config.settings.production" > $DJANGO_PROD_FILE
echo "DJANGO_SECRET_KEY=$DJANGO_SECRET_KEY" >> $DJANGO_PROD_FILE
echo "DJANGO_ADMIN_URL=admin/" >> $DJANGO_PROD_FILE
echo "USE_DOCKER=yes" >> $DJANGO_PROD_FILE
echo "REDIS_URL=redis://redis:6379/0" >> $DJANGO_PROD_FILE
echo "CELERY_FLOWER_USER=prod" >> $DJANGO_PROD_FILE
echo "CELERY_FLOWER_PASSWORD=$MISTBORN_DEFAULT_PASSWORD" >> $DJANGO_PROD_FILE
echo "MISTBORN_DEFAULT_PASSWORD=$MISTBORN_DEFAULT_PASSWORD" >> $DJANGO_PROD_FILE
echo "#MAILGUN_API_KEY=" >> $DJANGO_PROD_FILE
echo "#MAILGUN_API_URL=" >> $DJANGO_PROD_FILE
echo "#SENTRY_DNS=" >> $DJANGO_PROD_FILE
# generate production .env file for postgresql
POSTGRES_PROD_FILE="./.envs/.production/.postgres"
POSTGRES_PASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
echo "POSTGRES_HOST=postgres" > $POSTGRES_PROD_FILE
echo "POSTGRES_PORT=5432" >> $POSTGRES_PROD_FILE
echo "POSTGRES_DB=mistborn" >> $POSTGRES_PROD_FILE
echo "POSTGRES_USER=prod" >> $POSTGRES_PROD_FILE
echo "POSTGRES_PASSWORD=$POSTGRES_PASSWORD" >> $POSTGRES_PROD_FILE
# generate production .env file for pihole
PIHOLE_PROD_FILE="./.envs/.production/.pihole"
#WEBPASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
WEBPASSWORD="$1"
echo "TZ=\"America/New York\"" > $PIHOLE_PROD_FILE
echo "WEBPASSWORD=$WEBPASSWORD" >> $PIHOLE_PROD_FILE
# generate rocketchat .env files
ROCKETCHAT_PROD_FILE="./.envs/.production/.rocketchat"
#ROCKETCHAT_PASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
ROCKETCHAT_PASSWORD="$1"
echo "ROCKETCHAT_USER=bot" > $ROCKETCHAT_PROD_FILE
echo "ROCKETCHAT_ROOM=GENERAL" >> $ROCKETCHAT_PROD_FILE
echo "BOT_NAME=bot" >> $ROCKETCHAT_PROD_FILE
echo "ROCKETCHAT_PASSWORD=$ROCKETCHAT_PASSWORD" >> $ROCKETCHAT_PROD_FILE
# generate nextcloud .env files
NEXTCLOUD_PROD_FILE="./.envs/.production/.nextcloud"
#NEXTCLOUD_PASSWORD=$(python3 -c "import secrets; import string; print(f''.join([secrets.choice(string.ascii_letters+string.digits) for x in range(32)]))")
NEXTCLOUD_PASSWORD="$1"
echo "NEXTCLOUD_ADMIN_USER=mistborn" > $NEXTCLOUD_PROD_FILE
echo "NEXTCLOUD_ADMIN_PASSWORD=$NEXTCLOUD_PASSWORD" >> $NEXTCLOUD_PROD_FILE
echo "NEXTCLOUD_TRUSTED_DOMAINS=nextcloud.mistborn" >> $NEXTCLOUD_PROD_FILE
# generate onlyoffice .env files
ONLYOFFICE_PROD_FILE="./.envs/.production/.onlyoffice"
JWT_SECRET="$1"
echo "JWT_ENABLED=true" > $ONLYOFFICE_PROD_FILE
echo "JWT_SECRET=$JWT_SECRET" >> $ONLYOFFICE_PROD_FILE
# generate bitwarden .env files
BITWARDEN_PROD_FILE="./.envs/.production/.bitwarden"
echo "WEBSOCKET_ENABLED=true" > $BITWARDEN_PROD_FILE
echo "SIGNUPS_ALLOWED=true" >> $BITWARDEN_PROD_FILE

119
scripts/subinstallers/iptables.sh

@ -0,0 +1,119 @@ @@ -0,0 +1,119 @@
#!/bin/bash
set -e
echo "stop iptables wrappers"
if [ "$DISTRO" == "ubuntu" ]; then
# Disable UFW
sudo systemctl stop ufw || true
sudo systemctl disable ufw || true
fi
# default interface
iface=$(ip -o -4 route show to default | egrep -o 'dev [^ ]*' | awk '{print $2}')
# real public interface
riface=$(ip -o -4 route get 1.1.1.1 | egrep -o 'dev [^ ]*' | awk '{print $2}')
# resetting iptables
sudo iptables -F
sudo iptables -t nat -F
sudo iptables -X MISTBORN_LOG_DROP 2>/dev/null || true
sudo iptables -X MISTBORN_WIREGUARD_INPUT 2>/dev/null || true
sudo iptables -X MISTBORN_WIREGUARD_FORWARD 2>/dev/null || true
sudo iptables -X MISTBORN_DOCKER_INPUT 2>/dev/null || true
# iptables: log and drop chain
sudo iptables -N MISTBORN_LOG_DROP
sudo iptables -A MISTBORN_LOG_DROP -m limit --limit 2/min -j LOG --log-prefix "[IPTables-Dropped]: " --log-level 4
sudo iptables -A MISTBORN_LOG_DROP -j DROP
# wireguard rules chains
sudo iptables -N MISTBORN_WIREGUARD_INPUT
sudo iptables -N MISTBORN_WIREGUARD_FORWARD
# iptables
echo "Setting iptables rules"
sudo iptables -P INPUT ACCEPT
sudo iptables -I INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
# if installing over SSH, add SSH rule
if [ ! -z "${SSH_CLIENT}" ]; then
SSH_SRC=$(echo $SSH_CLIENT | awk '{print $1}')
sudo iptables -A INPUT -p tcp -s $SSH_SRC --dport 22 -j ACCEPT
fi
# docker rules
sudo iptables -N MISTBORN_DOCKER_INPUT
sudo iptables -A MISTBORN_DOCKER_INPUT -i br-+ -j ACCEPT
#sudo iptables -A INPUT ! -i $iface -s 172.16.0.0/12 -j ACCEPT
# last rules
sudo iptables -A INPUT -j MISTBORN_DOCKER_INPUT
sudo iptables -A INPUT -j MISTBORN_WIREGUARD_INPUT
sudo iptables -A INPUT -j MISTBORN_LOG_DROP
sudo iptables -A FORWARD -j MISTBORN_WIREGUARD_FORWARD
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
#if [ "$iface" == "$riface" ]; then
sudo iptables -t nat -I POSTROUTING -o $iface -j MASQUERADE
#else
# sudo iptables -t nat -I POSTROUTING -o $iface -j MASQUERADE
# sudo iptables -t nat -I POSTROUTING -o $riface -j MASQUERADE
#fi
# resetting ip6tables rules
sudo ip6tables -F
sudo ip6tables -t nat -F
sudo ip6tables -X MISTBORN_LOG_DROP 2>/dev/null || true
# ip6tables: log and drop chain
sudo ip6tables -N MISTBORN_LOG_DROP
sudo ip6tables -A MISTBORN_LOG_DROP -m limit --limit 6/min -j LOG --log-prefix "[IPTables-Dropped]: " --log-level 4
sudo ip6tables -A MISTBORN_LOG_DROP -j DROP
# ip6tables
echo "Setting ip6tables rules"
sudo ip6tables -P INPUT ACCEPT
sudo ip6tables -I INPUT -i lo -j ACCEPT
sudo ip6tables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo ip6tables -A INPUT -j MISTBORN_LOG_DROP
sudo ip6tables -P INPUT DROP
sudo ip6tables -P FORWARD DROP
sudo ip6tables -P OUTPUT ACCEPT
# initial load update package list
sudo apt-get update
# iptables-persistent
if [ ! "$(dpkg-query -l iptables-persistent)" ]; then
echo "Installing iptables-persistent"
# answer variables
echo iptables-persistent iptables-persistent/autosave_v4 boolean true | sudo debconf-set-selections
echo iptables-persistent iptables-persistent/autosave_v6 boolean true | sudo debconf-set-selections
# install
sudo apt-get install -y iptables-persistent ipset
else
echo "Saving iptables rules"
sudo bash -c "iptables-save > /etc/iptables/rules.v4"
echo "Saving ip6tables rules"
sudo bash -c "ip6tables-save > /etc/iptables/rules.v6"
fi
# IP forwarding
sudo sed -i 's/.*net.ipv4.ip_forward.*/net.ipv4.ip_forward=1/' /etc/sysctl.conf
sudo sysctl -p /etc/sysctl.conf
# rsyslog to create /var/log/iptables.log
sudo cp ./scripts/conf/15-iptables.conf /etc/rsyslog.d/
sudo chown root:root /etc/rsyslog.d/15-iptables.conf
sudo systemctl restart rsyslog

22
scripts/subinstallers/wireguard.sh

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
#!/bin/bash
# Wireguard
if [ "$DISTRO" == "raspbian" ]; then
echo "Adding Wireguard repo keys"
sudo apt-get install -y dirmngr
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 8B48AD6246925553
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 7638D0442B90D010
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 04EE7237B7D453EC
fi
echo "Installing Wireguard"
if [ "$DISTRO" == "ubuntu" ]; then
# Ubuntu
sudo add-apt-repository -y ppa:wireguard/wireguard
elif [ "$DISTRO" == "debian" ] || [ "$DISTRO" == "raspbian" ]; then
# Debian
sudo bash -c 'echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable.list'
sudo bash -c "printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable"
fi
sudo apt-get update
sudo apt-get install -y openresolv wireguard
Loading…
Cancel
Save