Test gluetun config

This commit is contained in:
Nicolas Meienberger 2022-03-30 21:26:01 +02:00
parent deca40974d
commit 4939cd323d
26 changed files with 203 additions and 290 deletions

26
.gitignore vendored
View file

@ -1,24 +1,14 @@
.env
nginx/*
letsencrypt/*
app-data/wg-easy/*
app-data/*
!app-data/.gitkeep
state/*
!state/.gitkeep
tipi.config.json
# Commit empty directories
!nignx/.gitkeep
!letsencrypt/.gitkeep
# Nextcloud app
app-data/nextcloud/data/nextcloud/*
app-data/nextcloud/data/db/*
app-data/nextcloud/data/redis/*
!app-data/nextcloud/data/db/.gitkeep
!app-data/nextcloud/data/redis/.gitkeep
# wg-easy app
!app-data/wg-easy/.gitkeep
# Pi-hole app
app-data/pi-hole/data/pihole/*
app-data/pi-hole/data/dnsmasq/*
!app-data/pi-hole/data/unbound
!letsencrypt/.gitkeep

View file

@ -1,5 +0,0 @@
[defaults]
INVENTORY = hosts
[ssh_connections]
pipelining = true

View file

@ -1,15 +0,0 @@
packages:
- nano
- exfat-fuse
- exfat-utils
- ca-certificates
- curl
- gnupg
- lsb-release
- nfs-common
- unbound
- dnsutils
### ZSH Settings
zsh_theme: "powerlevel10k/powerlevel10k"
ohmyzsh_git_url: https://github.com/robbyrussell/oh-my-zsh

View file

@ -1,87 +0,0 @@
- name: Update packages
apt:
update_cache: yes
upgrade: yes
- name: Install essential packages
package:
name: "{{ packages }}"
state: latest
- name: Check if docker is installed
stat:
path: /usr/bin/docker
register: docker_status
- name: Check if docker pgp key is installed
stat:
path: /usr/share/keyrings/docker-archive-keyring.gpg
register: docker_pgp_key_status
- name: Download docker
shell: "curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg"
when: not docker_pgp_key_status.stat.exists
- name: Setup stable docker repository
shell: 'echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null'
when: not docker_status.stat.exists
- name: Update packages
apt:
update_cache: yes
upgrade: yes
- name: Install essential packages
package:
name:
- docker-ce
- docker-ce-cli
- containerd.io
state: latest
- name: Add group docker
group:
name: docker
- name: Add user to group docker
user:
name: "{{ username }}"
group: docker
- name: Disable SSH password auth
lineinfile:
dest: /etc/ssh/sshd_config
regexp: "^#PasswordAuthentication yes"
line: "PasswordAuthentication no"
register: sshd_config
- name: Enable passwordless sudo for "{{ username }}"
lineinfile:
dest: /etc/sudoers
regexp: "^%wheel"
line: "{{ username }} ALL=(ALL) NOPASSWD: ALL"
validate: "/usr/sbin/visudo -cf %s"
- name: Restart SSH daemon
service:
name: sshd
state: restarted
when: sshd_config.changed
- name: Allow SSH in UFW
community.general.ufw:
rule: allow
port: 22
from: 192.168.2.0/24
proto: tcp
- name: Allow port 111 for NFS
community.general.ufw:
rule: allow
port: 111
from: 192.168.2.0/24
when: nfs_share is defined
- name: Enable UFW
community.general.ufw:
state: enabled

View file

@ -1,7 +0,0 @@
version: "3.7"
networks:
default:
external:
name: tipi_main_network

View file

View file

@ -1,7 +1,8 @@
version: "3.7"
services:
db:
db-nextcloud:
network_mode: "container:gluetun"
user: '1000:1000'
image: mariadb:10.5.12
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
@ -9,48 +10,22 @@ services:
volumes:
- ${APP_DATA_DIR}/data/db:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=moneyprintergobrrr
- MYSQL_PASSWORD=moneyprintergobrrr
- MYSQL_ROOT_PASSWORD=password
- MYSQL_PASSWORD=password
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
networks:
default:
ipv4_address: $APP_NEXTCLOUD_DB_IP
redis:
redis-nextcloud:
network_mode: "container:gluetun"
user: '1000:1000'
image: redis:6.2.2-buster
restart: on-failure
volumes:
- "${APP_DATA_DIR}/data/redis:/data"
networks:
default:
ipv4_address: $APP_NEXTCLOUD_REDIS_IP
web:
image: nextcloud:22.1.1-apache
restart: unless-stopped
ports:
- ${APP_NEXTCLOUD_PORT}:80
volumes:
- ${APP_DATA_DIR}/data/nextcloud:/var/www/html
environment:
- MYSQL_HOST=${APP_NEXTCLOUD_DB_IP}
- REDIS_HOST=${APP_NEXTCLOUD_REDIS_IP}
- MYSQL_PASSWORD=moneyprintergobrrr
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- NEXTCLOUD_ADMIN_USER=tipi
- NEXTCLOUD_ADMIN_PASSWORD=moneyprintergobrrr
- NEXTCLOUD_TRUSTED_DOMAINS=${APP_NEXTCLOUD_PORT}
depends_on:
- db
- redis
networks:
default:
ipv4_address: $APP_NEXTCLOUD_IP
cron:
network_mode: "container:gluetun"
image: nextcloud:22.0.0-apache
restart: on-failure
volumes:
@ -59,6 +34,31 @@ services:
depends_on:
- db
- redis
networks:
default:
ipv4_address: $APP_NEXTCLOUD_CRON_IP
web-nextcloud:
network_mode: "container:gluetun"
image: nextcloud:22.1.1-apache
restart: unless-stopped
ports:
- ${APP_NEXTCLOUD_PORT}:80
volumes:
- ${APP_DATA_DIR}/data/nextcloud:/var/www/html
environment:
- MYSQL_HOST=db-nextcloud
- REDIS_HOST=redis-nextcloud
- MYSQL_PASSWORD=password
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- NEXTCLOUD_ADMIN_USER=tipi
- NEXTCLOUD_ADMIN_PASSWORD=password
- NEXTCLOUD_TRUSTED_DOMAINS=${APP_NEXTCLOUD_PORT}
depends_on:
- db
- redis
labels:
traefik.enable: true
traefik.http.routers.traefik.rule: Host(`nextcloud.${DOMAIN}`)
traefik.http.services.traefik.loadbalancer.server.port: $APP_NEXTCLOUD_PORT

View file

View file

View file

@ -2,29 +2,31 @@ version: "3.7"
services:
unbound:
user: '1000:1000'
network_mode: "container:gluetun"
image: "klutchell/unbound:latest"
volumes:
- ${APP_DATA_DIR}/data/unbound:/etc/unbound
networks:
default:
ipv4_address: $APP_UNBOUND_IP
server:
pihole:
network_mode: "container:gluetun"
image: pihole/pihole
restart: on-failure
ports:
- 53:53
- 53:53/udp
# - 53:53
# - 53:53/udp
- ${APP_PI_HOLE_PORT}:80
volumes:
- ${APP_DATA_DIR}/data/pihole:/etc/pihole/
- ${APP_DATA_DIR}/data/dnsmasq:/etc/dnsmasq.d/
environment:
- VIRTUAL_HOST=${APP_DOMAIN}
- VIRTUAL_HOST="pihole.${DOMAIN}"
- WEBPASSWORD=${APP_PASSWORD}
- PIHOLE_DNS=${APP_UNBOUND_IP}
- PIHOLE_DNS=unbound
depends_on:
- unbound
networks:
default:
ipv4_address: $APP_PI_HOLE_IP
labels:
traefik.enable: true
traefik.http.routers.traefik.rule: Host(`pihole.${DOMAIN}`)
traefik.http.services.traefik.loadbalancer.server.port: $APP_PI_HOLE_PORT

View file

@ -1,22 +1,26 @@
version: '3.7'
services:
wg-easy:
image: 'weejewel/wg-easy'
network_mode: "container:gluetun"
image: 'weejewel/wg-easy:latest'
restart: unless-stopped
volumes:
- ${APP_DATA_DIR}:/etc/wireguard
environment:
WG_HOST: 'wireguard.meienberger.dev'
PASSWORD: 'moneyprintergobrrr'
PASSWORD: 'password'
WG_DEFAULT_DNS: 'pihole'
# WG_POST_UP: ...
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
ports:
- '51820:51820/udp'
- '51821:51821/tcp'
networks:
default:
ipv4_address: $APP_WG_EASY_IP
# ports:
# - '51820:51820/udp'
# - '51821:51821/tcp'
labels:
traefik.enable: true
traefik.http.routers.traefik.rule: Host(`wg.${DOMAIN}`)
traefik.http.services.traefik.loadbalancer.server.port: $APP_WGEASY_PORT

View file

@ -1,24 +1,64 @@
version: '3.7'
services:
nginx-proxy:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
gluetun:
container_name: gluetun
image: qmcgaw/gluetun
cap_add:
- NET_ADMIN
environment:
- VPN_SERVICE_PROVIDER=mullvad
- VPN_TYPE=wireguard
- WIREGUARD_PRIVATE_KEY=${WIREGUARD_PRIVATE_KEY}
- WIREGUARD_ADDRESSES=${WIREGUARD_ADDRESSES}
- SERVER_COUNTRIES=Switzerland
- OWNED_ONLY=yes
ports:
- "${APP_WGEASY_PORT}:51821"
- '51820:51820'
- '80:80'
- '81:81'
- '443:443'
nginx-proxy:
network_mode: "service:gluetun"
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
volumes:
- ${PWD}/nginx:/data
- ${PWD}/letsencrypt:/etc/letsencrypt
networks:
default:
ipv4_address: $NGINX_PROXY_IP
# traefik-app:
# image: traefik:latest
# restart: always
# # ports:
# # - 80:80
# # - 443:443
# volumes:
# - /var/run/docker.sock:/var/run/docker.sock:ro
# - ${PWD}/letsencrypt:/letsencrypt
# command:
# - --api.insecure=true
# - --providers.docker
# - --providers.docker.exposedbydefault=false
# - --entrypoints.web.address=:80
# - --entrypoints.web.http.redirections.entrypoint.to=websecure
# # - --entrypoints.web.forwardedHeaders.trustedIPs=172.26.0.0/16,172.80.0.0/24
# - --entrypoints.websecure.address=:443
# # - --entrypoints.websecure.forwardedHeaders.trustedIPs=172.26.0.0/16,172.80.0.0/24
# # - --entrypoints.websecure.http.tls.domains[0].main=${DOMAIN}
# # - --entrypoints.websecure.http.tls.domains[0].sans=*.${DOMAIN}
# - --entrypoints.websecure.http.tls.certresolver=myresolver
# # - --certificatesresolvers.myresolver.acme.dnschallenge=true
# # - --certificatesresolvers.myresolver.acme.dnschallenge.provider=infomaniak
# # - --certificatesresolvers.myresolver.acme.email=${MAIL_ADR}
# - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
# environment:
# # INFOMANIAK_ACCESS_TOKEN: ${INFOMANIAK_ACCESS_TOKEN}
# INFOMANIAK_POLLING_NTERVAL: 10
# INFOMANIAK_PROPAGATION_TIMEOUT: 180
# labels:
# traefik.enable: true
# traefik.http.routers.traefik.rule: Host(`proxy.${DOMAIN}`)
# traefik.http.services.traefik.loadbalancer.server.port: 8080
networks:
default:
name: tipi_main_network
ipam:
driver: default
config:
- subnet: "$NETWORK_IP/24"

View file

@ -1,8 +1,16 @@
#!/usr/bin/env bash
set -euo pipefail
ROOT_FOLDER="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
# use greadlink instead of readlink on osx
if [[ "$(uname)" == "Darwin" ]]; then
rdlk=greadlink
else
rdlk=readlink
fi
ROOT_FOLDER="$($rdlk -f $(dirname "${BASH_SOURCE[0]}")/..)"
STATE_FOLDER="${ROOT_FOLDER}/state"
DOMAIN="thisprops.com"
show_help() {
cat << EOF
@ -74,17 +82,17 @@ compose() {
# App data folder
local env_file="${ROOT_FOLDER}/.env"
local app_base_compose_file="${ROOT_FOLDER}/apps/docker-compose.common.yml"
local app_compose_file="${app_dir}/docker-compose.yml"
local app_url="${app}.${DOMAIN}"
# Vars to use in compose file
export APP_DATA_DIR="${app_data_dir}"
export APP_URL="${app_url}"
export APP_PASSWORD="password"
docker-compose \
--env-file "${env_file}" \
--project-name "${app}" \
--file "${app_base_compose_file}" \
--file "${app_compose_file}" \
"${@}"
}

View file

@ -1,26 +1,29 @@
# Constants
NETWORK_IP="10.21.21.0"
GATEWAY_IP="10.21.21.1"
NGINX_IP="10.21.21.2"
NGINX_PORT="80"
TIPI_IP="$1"
USERNAME="$(whoami)"
ROOT_FOLDER="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
# Constants
NGINX_PORT="80"
# Apps
APP_PI_HOLE_PORT="8081"
APP_PI_HOLE_IP="10.21.21.20"
echo
echo "======================================"
if [[ -f "${ROOT_FOLDER}/state/configured" ]]; then
echo "=========== RECONFIGURING ============"
else
echo "============ CONFIGURING ============="
fi
echo "=============== TIPI ================="
echo "======================================"
echo
# Store paths to intermediary config files
ANSIBLE_HOSTS_FILE="./templates/ansible-hosts-sample.cfg"
ENV_FILE="./templates/.env"
# Remove intermediary config files
[[ -f "$ENV_FILE" ]] && rm -f "$ENV_FILE"
[[ -f "$ANSIBLE_HOSTS_FILE" ]] && rm -f "$ANSIBLE_HOSTS_FILE"
# Copy template configs to intermediary configs
[[ -f "./templates/.env-sample" ]] && cp "./templates/.env-sample" "$ENV_FILE"
[[ -f "./templates/ansible-hosts-sample.cfg" ]] && cp "./templates/ansible-hosts-sample.cfg" "$ANSIBLE_HOSTS_FILE"
# Install jq if not installed
if ! command -v jq > /dev/null; then
@ -29,55 +32,33 @@ if ! command -v jq > /dev/null; then
apt-get install -y jq
fi
# Install ansible if not installed
if ! command -v ansible > /dev/null; then
echo "Installing Ansible..."
apt-get update
apt-get install -y software-properties-common
apt-add-repository -y ppa:ansible/ansible
apt-get update
apt-get install -y ansible
# Install docker if not installed
if ! command -v docker > /dev/null; then
echo "Installing docker..."
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
fi
# Install ssh-keygen if not installed
if ! command -v ssh-keygen > /dev/null; then
echo "Installing ssh-keygen..."
apt-get update
apt-get install -y ssh-keygen
fi
# Generate ssh keys
if [[ ! -f "~/ssh/id_rsa_tipi" ]]; then
echo "Generating ssh keys..."
mkdir -p "~/ssh"
ssh-keygen -t rsa -b 4096 -f "~/ssh/id_rsa_tipi" -N ""
# Install docker-compose if not installed
if ! command -v docker-compose > /dev/null; then
echo "Installing docker-compose..."
curl -L "https://github.com/docker/compose/releases/download/v2.3.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
fi
echo "Generating config files..."
for template in "${ENV_FILE}" "${ANSIBLE_HOSTS_FILE}"; do
# Umbrel
sed -i "s/<network-ip>/${NETWORK_IP}/g" "${template}"
sed -i "s/<gateway-ip>/${GATEWAY_IP}/g" "${template}"
sed -i "s/<nginx-ip>/${NGINX_IP}/g" "${template}"
for template in "${ENV_FILE}"; do
sed -i "s/<nginx-port>/${NGINX_PORT}/g" "${template}"
# Apps
sed -i "s/<app-pi-hole-port>/${APP_PI_HOLE_PORT}/g" "${template}"
sed -i "s/<app-pi-hole-ip>/${APP_PI_HOLE_IP}/g" "${template}"
# Ansible
sed -i "s/<host_ip>/${TIPI_IP}/g" "${template}"
sed -i "s/<username>/${USERNAME}/g" "${template}"
sed -i "s/<domain>/${DOMAIN}/g" "${template}"
done
# Copy SSH keys to ansible host
echo "Copying SSH keys to tipi server..."
ssh-copy-id -i "~/ssh/id_rsa_tipi" "${USERNAME}@${TIPI_IP}"
mv -f "$ENV_FILE" "./.env"
mv -f "$ANSIBLE_HOSTS_FILE" "./ansible/hosts"
echo "Configuring permissions..."
find "$UMBREL_ROOT" -path "$UMBREL_ROOT/app-data" -prune -o -exec chown 1000:1000 {} + || true
echo
find "$ROOT_FOLDER" -path "$ROOT_FOLDER/app-data" -prune -o -exec chown 1000:1000 {} + || true
# Run ansible playbook
echo "Running Ansible playbook..."
ansible-playbook -i "./ansible/hosts" "./ansible/playbook.yml"
# Create configured status
touch "${ROOT_FOLDER}/state/configured"

View file

@ -1,7 +1,15 @@
#!/usr/bin/env bash
ROOT_FOLDER="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
# use greadlink instead of readlink on osx
if [[ "$(uname)" == "Darwin" ]]; then
readlink=greadlink
else
readlink=readlink
fi
ROOT_FOLDER="$($readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
STATE_FOLDER="${ROOT_FOLDER}/state"
DOMAIN=local
if [[ $UID != 0 ]]; then
echo "Tipi must be started as root"
@ -10,8 +18,19 @@ if [[ $UID != 0 ]]; then
exit 1
fi
# Configure Umbrel if it isn't already configured
if [[ ! -f "${STATE_FOLDER}/configured" ]]; then
"${ROOT_FOLDER}/scripts/configure.sh"
fi
export DOCKER_CLIENT_TIMEOUT=240
export COMPOSE_HTTP_TIMEOUT=240
# Run docker-compose
docker-compose up -d
docker-compose up --detach --remove-orphans --build || {
echo "Failed to start containers"
exit 1
}
# Get field from json file
function get_json_field() {

View file

@ -1,6 +1,14 @@
#!/usr/bin/env bash
set -euo pipefail
# use greadlink instead of readlink on osx
if [[ "$(uname)" == "Darwin" ]]; then
readlink=greadlink
else
readlink=readlink
fi
if [[ $UID != 0 ]]; then
echo "Tipi must be stopped as root"
echo "Please re-run this script as"
@ -8,7 +16,7 @@ if [[ $UID != 0 ]]; then
exit 1
fi
ROOT_FOLDER="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
ROOT_FOLDER="$($readlink -f $(dirname "${BASH_SOURCE[0]}")/..)"
STATE_FOLDER="${ROOT_FOLDER}/state"
cd "$ROOT_FOLDER"
@ -32,4 +40,4 @@ done
echo "Stopping Docker services..."
echo
docker-compose down
docker-compose down --remove-orphans --rmi local

0
state/.gitkeep Normal file
View file

View file

@ -1,3 +1,3 @@
{
"installed": "wg-easy nextcloud pi-hole"
"installed": ""
}

View file

@ -1,3 +1,6 @@
# Only edit this file if you know what you are doing!
# It will be overwritten on update.
#Umbrel
NETWORK_IP=<network-ip>
GATEWAY_IP=<gateway-ip>

View file

@ -1,2 +0,0 @@
[home]
homeserver ansible_host=<host_ip> ansible_user=<username> ansible_connection=ssh ansible_ssh_private_key_file=<ssh_key_path>

View file

@ -1,31 +0,0 @@
# Warning: it's not recommended to modify these files directly. Any
# modifications you make can break the functionality of your umbrel. These files
# are automatically reset with every Umbrel update.
user nginx;
worker_processes 1;
error_log /dev/stdout info;
events {
worker_connections 1024;
}
http {
access_log /dev/stdout;
proxy_read_timeout 600;
default_type application/octet-stream;
server {
listen 80;
location / {
proxy_pass http://<dashboard-ip>:3004/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
}

5
tipi.config.json.example Normal file
View file

@ -0,0 +1,5 @@
{
"main": {
"domain": "mydomain.com"
}
}