Initial commit
This commit is contained in:
35
README.md
Normal file
35
README.md
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
# My Docker Compose Projects Repo
|
||||||
|
Welcome to my humble repo of all the infrastructure I have assenbled thourtght the last months.
|
||||||
|
I have gone through A LOT with these projects and I have finally estibalished a position that I'm comfortable and (most important) happy with :)
|
||||||
|
In this README file I will go through all of the infrastructure I have
|
||||||
|
## Frontend
|
||||||
|
This section responsible to the exposure of the deployed services to the (wild) internet.
|
||||||
|
It relies on Cloudflare's Zero-Trust Tunnles feature to do so.
|
||||||
|
This is the only network "hole" I have made in my infrastructure and no port forwarding in my home-router was needed.
|
||||||
|
### Cloudflared
|
||||||
|
WIP
|
||||||
|
### Traefik
|
||||||
|
WIP
|
||||||
|
## Backend
|
||||||
|
WIP
|
||||||
|
### Postgres
|
||||||
|
WIP
|
||||||
|
### Redis
|
||||||
|
WIP
|
||||||
|
## Management
|
||||||
|
WIP
|
||||||
|
### Portainer
|
||||||
|
WIP
|
||||||
|
### Adminer
|
||||||
|
WIP
|
||||||
|
## Web-Apps
|
||||||
|
WIP
|
||||||
|
### Navidrome
|
||||||
|
WIP
|
||||||
|
### n8n
|
||||||
|
WIP
|
||||||
|
###
|
||||||
|
## Honorable Mentions
|
||||||
|
WIP
|
||||||
|
### Adguard
|
||||||
|
WIP
|
||||||
11
backend/postgres/.env.example
Normal file
11
backend/postgres/.env.example
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# PostgreSQL root user
|
||||||
|
POSTGRES_USER=
|
||||||
|
POSTGRES_PASSWORD_FILE=/run/secrets/YOUR_SECRET_PASS
|
||||||
|
|
||||||
|
# Timezone settings
|
||||||
|
TZ=
|
||||||
|
PGTZ=
|
||||||
|
|
||||||
|
# PostgreSQL settings
|
||||||
|
POSTGRES_INITDB_ARGS=--data-checksums
|
||||||
|
PGDATA=/var/lib/postgresql/18/docker
|
||||||
34
backend/postgres/compose.yml
Normal file
34
backend/postgres/compose.yml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:18
|
||||||
|
container_name: postgres
|
||||||
|
restart: always
|
||||||
|
healthcheck:
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
test:
|
||||||
|
- CMD-SHELL
|
||||||
|
- pg_isready -U $${POSTGRES_USER}
|
||||||
|
timeout: 5s
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
secrets:
|
||||||
|
- PGROOT_PASS
|
||||||
|
# - PSUSER_PASS
|
||||||
|
volumes:
|
||||||
|
- pgdata:/var/lib/postgresql/18/docker
|
||||||
|
networks:
|
||||||
|
- db
|
||||||
|
volumes:
|
||||||
|
pgdata:
|
||||||
|
name: pgdata
|
||||||
|
secrets:
|
||||||
|
PGROOT_PASS:
|
||||||
|
file: .secrets/PGROOT_PASS
|
||||||
|
# PSUSER_PASS:
|
||||||
|
# file: .secrets/PSUSER_PASS
|
||||||
|
networks:
|
||||||
|
db:
|
||||||
|
external:
|
||||||
|
true
|
||||||
28
backend/postgres/scripts/create-db.sh
Executable file
28
backend/postgres/scripts/create-db.sh
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Prompt for container name
|
||||||
|
read -p "Enter PostgreSQL container name: " CONTAINER_NAME
|
||||||
|
|
||||||
|
# Check if container is running
|
||||||
|
if [ "$(docker ps -q -f name=$CONTAINER_NAME)" = "" ]; then
|
||||||
|
echo "Container $CONTAINER_NAME is not running!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Using container: $CONTAINER_NAME"
|
||||||
|
|
||||||
|
# Prompt for PostgreSQL root credentials
|
||||||
|
read -p "Enter PostgreSQL root username: " PGROOT_USER
|
||||||
|
|
||||||
|
# Prompt for database name
|
||||||
|
read -p "Enter new PostgreSQL database name: " DB_NAME
|
||||||
|
|
||||||
|
# Check if database exists
|
||||||
|
DB_EXISTS=$(docker exec $CONTAINER_NAME psql -U $PGROOT_USER -tAc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'")
|
||||||
|
if [ "$DB_EXISTS" = "1" ]; then
|
||||||
|
echo "Database $DB_NAME already exists!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the database using docker exec and psql
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -c "CREATE DATABASE $DB_NAME;"
|
||||||
|
echo "Database $DB_NAME has been created successfully."
|
||||||
46
backend/postgres/scripts/create-user.sh
Executable file
46
backend/postgres/scripts/create-user.sh
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Prompt for container name
|
||||||
|
read -p "Enter PostgreSQL container name: " CONTAINER_NAME
|
||||||
|
|
||||||
|
# Check if container is running
|
||||||
|
if [ "$(docker ps -q -f name=$CONTAINER_NAME)" = "" ]; then
|
||||||
|
echo "Container $CONTAINER_NAME is not running!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Using container: $CONTAINER_NAME"
|
||||||
|
|
||||||
|
# Prompt for PostgreSQL root credentials
|
||||||
|
read -p "Enter PostgreSQL root username: " PGROOT_USER
|
||||||
|
|
||||||
|
# Prompt for username and password
|
||||||
|
read -p "Enter new PostgreSQL username: " DB_USER
|
||||||
|
|
||||||
|
# Check if username is provided
|
||||||
|
if [[ -z "$DB_USER" ]]; then
|
||||||
|
echo "Error: Username cannot be empty!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if user already exists in PostgreSQL
|
||||||
|
if docker exec $CONTAINER_NAME psql -U $PGROOT_USER -tAc "SELECT 1 FROM pg_catalog.pg_roles WHERE rolname='$DB_USER'" | grep -q 1; then
|
||||||
|
echo "Error: User '$DB_USER' already exists in PostgreSQL!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "User '$DB_USER' does not exist. Proceeding..."
|
||||||
|
read -s -p "Enter password for $DB_USER: " DB_PASS
|
||||||
|
echo
|
||||||
|
read -s -p "Confirm password for $DB_USER: " DB_PASS_CONFIRM
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check if passwords match
|
||||||
|
if [ "$DB_PASS" != "$DB_PASS_CONFIRM" ]; then
|
||||||
|
echo "Passwords do not match!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the user using docker exec and psql
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASS';"
|
||||||
|
|
||||||
|
echo "User $DB_USER has been created successfully."
|
||||||
110
backend/postgres/scripts/drop-user.sh
Executable file
110
backend/postgres/scripts/drop-user.sh
Executable file
@@ -0,0 +1,110 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Prompt for container name
|
||||||
|
read -p "Enter PostgreSQL container name: " CONTAINER_NAME
|
||||||
|
|
||||||
|
# Check if username is provided
|
||||||
|
if [[ -z "$CONTAINER_NAME" ]]; then
|
||||||
|
echo "Error: Container cannot be empty!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if container is running
|
||||||
|
if [ "$(docker ps -q -f name=$CONTAINER_NAME)" = "" ]; then
|
||||||
|
echo "Container $CONTAINER_NAME is not running!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Using container: $CONTAINER_NAME"
|
||||||
|
|
||||||
|
# Prompt for PostgreSQL root credentials
|
||||||
|
read -p "Enter PostgreSQL root username: " PGROOT_USER
|
||||||
|
|
||||||
|
# Prompt for username to drop
|
||||||
|
read -p "Enter PostgreSQL username to drop: " DB_USER
|
||||||
|
|
||||||
|
# Check if username is provided
|
||||||
|
if [[ -z "$DB_USER" ]]; then
|
||||||
|
echo "Error: Username cannot be empty!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Check if user exists in PostgreSQL
|
||||||
|
USER_EXISTS=$(docker exec "$CONTAINER_NAME" psql -U "$PGROOT_USER" -tAc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER';")
|
||||||
|
if [[ "$USER_EXISTS" != "1" ]]; then
|
||||||
|
echo "Error: User '$DB_USER' does not exist in PostgreSQL!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# # Check if user exists in PostgreSQL
|
||||||
|
# if ! docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $CONTAINER_NAME -tAc "SELECT 1 FROM pg_catalog.pg_roles WHERE rolname='$DB_USER'" | grep -q 1; then
|
||||||
|
# echo "Error: User '$DB_USER' does not exist in PostgreSQL!" >&2
|
||||||
|
# exit 1
|
||||||
|
# fi
|
||||||
|
|
||||||
|
echo "User '$DB_USER' exists."
|
||||||
|
|
||||||
|
# Get all databases (not just those with CONNECT privilege)
|
||||||
|
echo "Checking databases..."
|
||||||
|
ALL_DATABASES=$(docker exec $CONTAINER_NAME psql -U "$PGROOT_USER" -tAc "
|
||||||
|
SELECT datname
|
||||||
|
FROM pg_database
|
||||||
|
WHERE datname NOT IN ('template0', 'template1')
|
||||||
|
AND datallowconn = true;
|
||||||
|
")
|
||||||
|
|
||||||
|
# Check for database privileges
|
||||||
|
echo "Checking privileges for user '$DB_USER'..."
|
||||||
|
DATABASES=$(docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $CONTAINER_NAME -tAc "
|
||||||
|
SELECT datname
|
||||||
|
FROM pg_database d
|
||||||
|
WHERE has_database_privilege('$DB_USER', d.oid, 'CONNECT')
|
||||||
|
AND datname NOT IN ('template0', 'template1');
|
||||||
|
")
|
||||||
|
|
||||||
|
if [[ -n "$DATABASES" && "$DATABASES" != "" ]]; then
|
||||||
|
echo "WARNING: User '$DB_USER' has privileges on the following database(s):"
|
||||||
|
echo "$DATABASES"
|
||||||
|
echo ""
|
||||||
|
read -p "Do you want to proceed with removing this user? (yes/no): " CONFIRM
|
||||||
|
|
||||||
|
if [[ "$CONFIRM" != "yes" ]]; then
|
||||||
|
echo "Operation cancelled."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Revoke privileges from each database
|
||||||
|
echo "Revoking privileges from databases..."
|
||||||
|
while IFS= read -r DB_NAME; do
|
||||||
|
if [[ -n "$DB_NAME" ]]; then
|
||||||
|
echo " - Revoking privileges on database: $DB_NAME"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $CONTAINER_NAME -c "REVOKE ALL PRIVILEGES ON DATABASE \"$DB_NAME\" FROM \"$DB_USER\";"
|
||||||
|
|
||||||
|
# Revoke privileges on all tables, sequences, and functions in public schema
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d "$DB_NAME" -c "REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM \"$DB_USER\";"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d "$DB_NAME" -c "REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM \"$DB_USER\";"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d "$DB_NAME" -c "REVOKE ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public FROM \"$DB_USER\";"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d "$DB_NAME" -c "REVOKE ALL PRIVILEGES ON SCHEMA public FROM \"$DB_USER\";"
|
||||||
|
fi
|
||||||
|
done <<< "$DATABASES"
|
||||||
|
|
||||||
|
echo "Privileges revoked successfully."
|
||||||
|
else
|
||||||
|
echo "User '$DB_USER' has no database privileges."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reassign and drop owned objects in each database
|
||||||
|
echo "Reassigning and dropping owned objects in all databases..."
|
||||||
|
while IFS= read -r DB_NAME; do
|
||||||
|
if [[ -n "$DB_NAME" ]]; then
|
||||||
|
echo " - Processing database: $DB_NAME"
|
||||||
|
docker exec $CONTAINER_NAME psql -U "$PGROOT_USER" -d "$DB_NAME" -c "REASSIGN OWNED BY \"$DB_USER\" TO \"$PGROOT_USER\";" 2>/dev/null
|
||||||
|
docker exec $CONTAINER_NAME psql -U "$PGROOT_USER" -d "$DB_NAME" -c "DROP OWNED BY \"$DB_USER\";" 2>/dev/null
|
||||||
|
fi
|
||||||
|
done <<< "$ALL_DATABASES"
|
||||||
|
|
||||||
|
# Drop the user using docker exec and psql
|
||||||
|
echo "Dropping user '$DB_USER'..."
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $CONTAINER_NAME -c "DROP USER \"$DB_USER\";"
|
||||||
|
|
||||||
|
echo "User $DB_USER has been dropped successfully."
|
||||||
50
backend/postgres/scripts/grant-prvlgs.sh
Executable file
50
backend/postgres/scripts/grant-prvlgs.sh
Executable file
@@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Prompt for container name
|
||||||
|
read -p "Enter PostgreSQL container name: " CONTAINER_NAME
|
||||||
|
|
||||||
|
# Check if container is running
|
||||||
|
if [ "$(docker ps -q -f name=$CONTAINER_NAME)" = "" ]; then
|
||||||
|
echo "Container $CONTAINER_NAME is not running!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Using container: $CONTAINER_NAME"
|
||||||
|
|
||||||
|
# Prompt for PostgreSQL root credentials
|
||||||
|
read -p "Enter PostgreSQL root username: " PGROOT_USER
|
||||||
|
|
||||||
|
# Prompt for username and database name
|
||||||
|
read -p "Enter PostgreSQL username to grant privileges: " USERNAME
|
||||||
|
read -p "Enter PostgreSQL database name will be granted on: " DB_NAME
|
||||||
|
|
||||||
|
# Check if inputs are not empty
|
||||||
|
if [ -z "$USERNAME" ] || [ -z "$DB_NAME" ]; then
|
||||||
|
echo "Error: Username and database name cannot be empty"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Grant all privileges
|
||||||
|
echo "Granting all privileges on $DB_NAME to $USERNAME..."
|
||||||
|
|
||||||
|
# Grant database privileges
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -c "GRANT CONNECT ON DATABASE $DB_NAME TO $USERNAME;"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -c "ALTER DATABASE $DB_NAME OWNER TO $USERNAME;"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -c "ALTER USER $USERNAME CREATEDB;"
|
||||||
|
|
||||||
|
# Connect to the specific database and grant schema privileges
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $DB_NAME -c "GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO $USERNAME;"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $DB_NAME -c "GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO $USERNAME;"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $DB_NAME -c "GRANT ALL PRIVILEGES ON SCHEMA public TO $USERNAME;"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $DB_NAME -c "GRANT CREATE ON SCHEMA public TO $USERNAME;"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $DB_NAME -c "GRANT CREATE ON DATABASE $DB_NAME TO $USERNAME;"
|
||||||
|
|
||||||
|
# Grant default privileges for future tables and sequences
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $DB_NAME -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON TABLES TO $USERNAME;"
|
||||||
|
docker exec $CONTAINER_NAME psql -U $PGROOT_USER -d $DB_NAME -c "ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO $USERNAME;"
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Successfully granted all privileges"
|
||||||
|
else
|
||||||
|
echo "Error granting privileges"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
26
backend/redis/compose.yml
Normal file
26
backend/redis/compose.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
services:
|
||||||
|
redis:
|
||||||
|
command: --save 60 1 --loglevel warning
|
||||||
|
healthcheck:
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
test:
|
||||||
|
- CMD-SHELL
|
||||||
|
- redis-cli ping | grep PONG
|
||||||
|
timeout: 3s
|
||||||
|
image: docker.io/library/redis:alpine
|
||||||
|
container_name: redis
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
networks:
|
||||||
|
- db
|
||||||
|
volumes:
|
||||||
|
- redis_data:/data
|
||||||
|
volumes:
|
||||||
|
redis_data:
|
||||||
|
name: redis_data
|
||||||
|
networks:
|
||||||
|
db:
|
||||||
|
external: true
|
||||||
2
frontend/cloudflared/.env.example
Normal file
2
frontend/cloudflared/.env.example
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
TUNNEL_TOKEN=
|
||||||
|
TZ=
|
||||||
16
frontend/cloudflared/compose.yml
Normal file
16
frontend/cloudflared/compose.yml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
services:
|
||||||
|
cloudflared:
|
||||||
|
image: cloudflare/cloudflared:latest
|
||||||
|
container_name: cloudflared
|
||||||
|
restart: always
|
||||||
|
command: tunnel --no-autoupdate run
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
networks:
|
||||||
|
- frontend
|
||||||
|
networks:
|
||||||
|
frontend:
|
||||||
|
external:
|
||||||
|
true
|
||||||
5
frontend/traefik/.env.example
Normal file
5
frontend/traefik/.env.example
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
TRAEFIK_USER=
|
||||||
|
SSL_EMAIL=
|
||||||
|
CF_API_EMAIL=
|
||||||
|
CF_API_KEY=
|
||||||
|
TZ=
|
||||||
65
frontend/traefik/compose.yml
Normal file
65
frontend/traefik/compose.yml
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
services:
|
||||||
|
traefik:
|
||||||
|
image: "traefik:v3.5.3"
|
||||||
|
container_name: ${SUBDOMAIN}
|
||||||
|
restart: always
|
||||||
|
command:
|
||||||
|
- "--log.level=DEBUG"
|
||||||
|
- "--api.insecure=false"
|
||||||
|
- "--api.dashboard=true"
|
||||||
|
- "--providers.docker=true"
|
||||||
|
- "--providers.docker.exposedbydefault=false"
|
||||||
|
- "--entrypoints.web.address=:80"
|
||||||
|
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||||
|
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
|
||||||
|
- "--entrypoints.web.http.redirections.entrypoint.permanent=true"
|
||||||
|
- "--entrypoints.websecure.address=:443"
|
||||||
|
- "--entrypoints.websecure.http.tls=true"
|
||||||
|
- "--entrypoints.websecure.http.tls.certresolver=cloudflare"
|
||||||
|
- "--entrypoints.websecure.http.tls.domains[0].main=${DOMAIN_NAME}"
|
||||||
|
- "--entrypoints.websecure.http.tls.domains[0].sans=*.${DOMAIN_NAME}"
|
||||||
|
- "--entryPoints.web.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22"
|
||||||
|
- "--entryPoints.websecure.forwardedHeaders.trustedIPs=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22"
|
||||||
|
- "--certificatesresolvers.cloudflare.acme.dnschallenge=true"
|
||||||
|
- "--certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare"
|
||||||
|
- "--certificatesresolvers.cloudflare.acme.email=${CF_API_EMAIL}"
|
||||||
|
- "--certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json"
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.traefik_dashboard.rule=Host(`traefik.jojops.com`)
|
||||||
|
# - traefik.http.routers.traefik_dashboard.rule=Host(`traefik.jojops.com`) && PathPrefix(`/outpost.goauthentik.io/`)
|
||||||
|
- traefik.http.routers.traefik_dashboard.entrypoints=websecure
|
||||||
|
- traefik.http.routers.traefik_dashboard.service=api@internal
|
||||||
|
- traefik.http.routers.traefik_dashboard.tls=true
|
||||||
|
- traefik.http.middlewares.myauth.basicauth.users=${TRAEFIK_USER}
|
||||||
|
# - traefik.http.middlewares.myauth.basicauth.users=test:$$apr1$$46.RmdYB$$Rx33ChqUskl4PF1ZqSXYV1
|
||||||
|
# - traefik.http.routers.traefik_dashboard.middlewares=myauth@docker
|
||||||
|
- traefik.http.routers.traefik_dashboard.middlewares=authentik-forwardauth@docker
|
||||||
|
- traefik.http.routers.traefik_dashboard.tls.certresolver=cloudflare
|
||||||
|
# - traefik.http.routers.traefik-secure.tls.domains[0].main=jojops.com
|
||||||
|
# - traefik.http.routers.traefik-secure.tls.domains[0].sans=*.jojops.com
|
||||||
|
# - traefik.http.middlewares.myauth.redirectscheme.scheme=https
|
||||||
|
- traefik.http.services.traefik_dashboard.loadbalancer.server.port=80
|
||||||
|
# - "traefik.http.middlewares.cloudflare-ips.ipallowlist.sourcerange=173.245.48.0/20,103.21.244.0/22,103.22.200.0/22,103.31.4.0/22,141.101.64.0/18,108.162.192.0/18,190.93.240.0/20,188.114.96.0/20,197.234.240.0/22,198.41.128.0/17,162.158.0.0/15,104.16.0.0/13,104.24.0.0/14,172.64.0.0/13,131.0.72.0/22,2400:cb00::/32,2606:4700::/32,2803:f800::/32,2405:b500::/32,2405:8100::/32,2a06:98c0::/29,2c0f:f248::/32"
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
- ./traefik_data:/letsencrypt
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
networks:
|
||||||
|
- frontend
|
||||||
|
- webapp
|
||||||
|
- mgmt
|
||||||
|
networks:
|
||||||
|
frontend:
|
||||||
|
external:
|
||||||
|
true
|
||||||
|
webapp:
|
||||||
|
external:
|
||||||
|
true
|
||||||
|
mgmt:
|
||||||
|
external:
|
||||||
|
true
|
||||||
1
local/adguard/.env.example
Normal file
1
local/adguard/.env.example
Normal file
@@ -0,0 +1 @@
|
|||||||
|
IP_ADDRESS=
|
||||||
10
local/adguard/README.md
Normal file
10
local/adguard/README.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
## WIP
|
||||||
|
### Command for creating docker macvlan network
|
||||||
|
### Change all CAPITAL arguments to your config
|
||||||
|
docker network create -d macvlan -o parent=HOST_NIC --gateway DG --subnet SUB --ip-range SUB NAME
|
||||||
|
|
||||||
|
### Service for
|
||||||
|
WIP
|
||||||
|
|
||||||
|
### DNS Rewrites
|
||||||
|
Disable IPv6 at your LAN or implement it :)
|
||||||
17
local/adguard/compose.yml
Normal file
17
local/adguard/compose.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
adguard:
|
||||||
|
image: adguard/adguardhome
|
||||||
|
container_name: adguard
|
||||||
|
hostname: $HOSTNAME
|
||||||
|
restart: always
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
- ./work:/opt/adguardhome/work
|
||||||
|
- ./conf:/opt/adguardhome/conf
|
||||||
|
networks:
|
||||||
|
lan:
|
||||||
|
ipv4_address: $IP_ADDRESS
|
||||||
|
networks:
|
||||||
|
lan:
|
||||||
|
external: true
|
||||||
35
mgmt/adminer/compose.yml
Normal file
35
mgmt/adminer/compose.yml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
services:
|
||||||
|
adminer:
|
||||||
|
image: adminer:5.4.0
|
||||||
|
container_name: $SUBDOMAIN
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.tls=true
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.entrypoints=web,websecure
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.tls.certresolver=cloudflare
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.SSLRedirect=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSSeconds=315360000
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.browserXSSFilter=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.forceSTSHeader=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.SSLHost=${DOMAIN_NAME}
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSPreload=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.frameDeny=true
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.middlewares=$SUBDOMAIN@docker
|
||||||
|
- traefik.http.services.$SUBDOMAIN.loadbalancer.server.port=8080
|
||||||
|
- traefik.docker.network=webapp
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
networks:
|
||||||
|
- webapp
|
||||||
|
- db
|
||||||
|
networks:
|
||||||
|
webapp:
|
||||||
|
external:
|
||||||
|
true
|
||||||
|
db:
|
||||||
|
external:
|
||||||
|
true
|
||||||
31
mgmt/authentik/.env.example
Normal file
31
mgmt/authentik/.env.example
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
DOMAIN_NAME=
|
||||||
|
SUBDOMAIN=
|
||||||
|
|
||||||
|
# Authentik Configuration
|
||||||
|
AUTHENTIK_SECRET_KEY=file:///run/secrets/SECRET_KEY
|
||||||
|
AUTHENTIK_TAG=
|
||||||
|
|
||||||
|
# PostgreSQL Configuration
|
||||||
|
PG_HOST=postgres
|
||||||
|
PG_PORT=5432
|
||||||
|
PG_USER=
|
||||||
|
PG_PASS=file:///run/secrets/DB_PASS
|
||||||
|
PG_DB=
|
||||||
|
|
||||||
|
# Redis Configuration
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
# Optional: Custom ports
|
||||||
|
COMPOSE_PORT_HTTP=9000
|
||||||
|
COMPOSE_PORT_HTTPS=9443
|
||||||
|
|
||||||
|
# Environment Variables for Docker Compose
|
||||||
|
AUTHENTIK_REDIS__HOST=$REDIS_HOST
|
||||||
|
AUTHENTIK_REDIS__PORT=$REDIS_PORT
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST=$PG_HOST
|
||||||
|
AUTHENTIK_POSTGRESQL__PORT=$PG_PORT
|
||||||
|
AUTHENTIK_POSTGRESQL__USER=$PG_USER
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME=$PG_DB
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD=$PG_PASS
|
||||||
|
AUTHENTIK_HOST_BROWSER="https://$SUBDOMAIN.$DOMAIN_NAME"
|
||||||
83
mgmt/authentik/compose.yml
Normal file
83
mgmt/authentik/compose.yml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
services:
|
||||||
|
server:
|
||||||
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG}
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
secrets:
|
||||||
|
- SECRET_KEY
|
||||||
|
- DB_PASS
|
||||||
|
volumes:
|
||||||
|
- ./media:/media
|
||||||
|
- ./custom-templates:/templates
|
||||||
|
networks:
|
||||||
|
- webapp
|
||||||
|
- db
|
||||||
|
# ports:
|
||||||
|
# - "${COMPOSE_PORT_HTTP:-9000}:9000"
|
||||||
|
# - "${COMPOSE_PORT_HTTPS:-9443}:9443"
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.tls=true
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.entrypoints=web,websecure
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.tls.certresolver=cloudflare
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.SSLRedirect=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSSeconds=315360000
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.browserXSSFilter=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.forceSTSHeader=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.SSLHost=${DOMAIN_NAME}
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSPreload=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.frameDeny=true
|
||||||
|
# - traefik.http.routers.$SUBDOMAIN.middlewares=$SUBDOMAIN@docker
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.service=$SUBDOMAIN
|
||||||
|
- traefik.http.services.$SUBDOMAIN.loadbalancer.server.port=9000
|
||||||
|
- traefik.docker.network=webapp
|
||||||
|
- "traefik.http.routers.authentik-output-rtr.rule=HostRegexp(`{subdomain:[a-z0-9-]+}.${DOMAIN_NAME}`) && PathPrefix(`/outpost.goauthentik.io/`)"
|
||||||
|
|
||||||
|
# ForwardAuth middleware definition
|
||||||
|
- "traefik.http.middlewares.authentik-forwardauth.forwardauth.address=http://authentik-server-1:9000/outpost.goauthentik.io/auth/traefik"
|
||||||
|
- "traefik.http.middlewares.authentik-forwardauth.forwardauth.trustForwardHeader=true"
|
||||||
|
- "traefik.http.middlewares.authentik-forwardauth.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version"
|
||||||
|
# Outpost router for /outpost.goauthentik.io paths
|
||||||
|
- "traefik.http.routers.$SUBDOMAIN-outpost.rule=Host(`authentik.jojops.com`) && PathPrefix(`/outpost.goauthentik.io/`)"
|
||||||
|
# - "traefik.http.routers.authentik-outpost.entrypoints=websecure"
|
||||||
|
# - "traefik.http.routers.authentik-outpost.tls=true"
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.priority=15
|
||||||
|
# - "traefik.http.routers.authentik-outpost.service=authentik-svc"
|
||||||
|
- "traefik.http.routers.authentik-outpost.rule=HostRegexp(`{$SUBDOMAIN:[a-z0-9-]+}.$DOMAIN_NAME`) && PathPrefix(`/outpost.goauthentik.io/`)"
|
||||||
|
- "traefik.http.routers.authentik-outpost.entrypoints=websecure"
|
||||||
|
- "traefik.http.routers.authentik-outpost.tls=true"
|
||||||
|
- "traefik.http.routers.authentik-outpost.priority=15"
|
||||||
|
- "traefik.http.routers.authentik-outpost.service=authentik"
|
||||||
|
|
||||||
|
worker:
|
||||||
|
image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG}
|
||||||
|
restart: unless-stopped
|
||||||
|
command: worker
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
secrets:
|
||||||
|
- SECRET_KEY
|
||||||
|
- DB_PASS
|
||||||
|
user: root
|
||||||
|
networks:
|
||||||
|
- db
|
||||||
|
volumes:
|
||||||
|
# - /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./media:/media
|
||||||
|
- ./certs:/certs
|
||||||
|
- ./custom-templates:/templates
|
||||||
|
networks:
|
||||||
|
webapp:
|
||||||
|
external: true
|
||||||
|
db:
|
||||||
|
external: true
|
||||||
|
secrets:
|
||||||
|
SECRET_KEY:
|
||||||
|
file: .secrets/SECRET_KEY
|
||||||
|
DB_PASS:
|
||||||
|
file: .secrets/DB_PASS
|
||||||
8
mgmt/gitea/.env.example
Normal file
8
mgmt/gitea/.env.example
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
DOMAIN_NAME=
|
||||||
|
SUBDOMAIN=
|
||||||
|
|
||||||
|
GITEA__database__DB_TYPE=
|
||||||
|
GITEA__database__HOST=
|
||||||
|
GITEA__database__NAME=
|
||||||
|
GITEA__database__USER=
|
||||||
|
GITEA__database__PASSWD__FILE=/run/secrets/DB_PASS
|
||||||
49
mgmt/gitea/compose.yml
Normal file
49
mgmt/gitea/compose.yml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
image: docker.gitea.com/gitea:1.24.6-rootless
|
||||||
|
container_name: gitea
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.gitea.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
|
||||||
|
- traefik.http.routers.gitea.tls=true
|
||||||
|
- traefik.http.routers.gitea.entrypoints=web,websecure
|
||||||
|
- traefik.http.routers.gitea.tls.certresolver=cloudflare
|
||||||
|
- traefik.http.middlewares.gitea.headers.SSLRedirect=true
|
||||||
|
- traefik.http.middlewares.gitea.headers.STSSeconds=315360000
|
||||||
|
- traefik.http.middlewares.gitea.headers.browserXSSFilter=true
|
||||||
|
- traefik.http.middlewares.gitea.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.gitea.headers.forceSTSHeader=true
|
||||||
|
- traefik.http.middlewares.gitea.headers.SSLHost=${DOMAIN_NAME}
|
||||||
|
- traefik.http.middlewares.gitea.headers.STSIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.gitea.headers.STSPreload=true
|
||||||
|
- traefik.http.middlewares.gitea.headers.frameDeny=true
|
||||||
|
- traefik.http.routers.gitea.middlewares=gitea@docker
|
||||||
|
- traefik.http.services.gitea.loadbalancer.server.port=3000
|
||||||
|
- traefik.docker.network=webapp
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
secrets:
|
||||||
|
- DB_PASS
|
||||||
|
volumes:
|
||||||
|
- gitea-data:/var/lib/gitea
|
||||||
|
- ./config:/etc/gitea
|
||||||
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
# ports:
|
||||||
|
# - "3000:3000"
|
||||||
|
# - "2222:2222"
|
||||||
|
networks:
|
||||||
|
- webapp
|
||||||
|
- db
|
||||||
|
volumes:
|
||||||
|
gitea-data:
|
||||||
|
name: gitea-data
|
||||||
|
networks:
|
||||||
|
webapp:
|
||||||
|
external: true
|
||||||
|
db:
|
||||||
|
external: true
|
||||||
|
secrets:
|
||||||
|
DB_PASS:
|
||||||
|
file: .secrets/DB_PASS
|
||||||
2
mgmt/portainer/.env.example
Normal file
2
mgmt/portainer/.env.example
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DOMAIN_NAME=
|
||||||
|
SUBDOMAIN=
|
||||||
35
mgmt/portainer/docker-compose.yml
Normal file
35
mgmt/portainer/docker-compose.yml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
services:
|
||||||
|
portainer:
|
||||||
|
image: portainer/portainer-ce:lts
|
||||||
|
container_name: portainer
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.portainer.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
|
||||||
|
- traefik.docker.network=webapp
|
||||||
|
- traefik.http.services.portainer.loadbalancer.server.port=9000
|
||||||
|
- traefik.http.routers.portainer.tls=true
|
||||||
|
- traefik.http.routers.portainer.entrypoints=web,websecure
|
||||||
|
- traefik.http.routers.portainer.tls.certresolver=cloudflare
|
||||||
|
- traefik.http.middlewares.portainer.headers.SSLRedirect=true
|
||||||
|
- traefik.http.middlewares.portainer.headers.STSSeconds=315360000
|
||||||
|
- traefik.http.middlewares.portainer.headers.browserXSSFilter=true
|
||||||
|
- traefik.http.middlewares.portainer.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.portainer.headers.forceSTSHeader=true
|
||||||
|
- traefik.http.middlewares.portainer.headers.SSLHost=${DOMAIN_NAME}
|
||||||
|
- traefik.http.middlewares.portainer.headers.STSIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.portainer.headers.STSPreload=true
|
||||||
|
- traefik.http.routers.portainer.middlewares=portainer@docker
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./data:/data
|
||||||
|
networks:
|
||||||
|
# - webapp
|
||||||
|
- mgmt
|
||||||
|
networks:
|
||||||
|
# webapp:
|
||||||
|
# external:
|
||||||
|
# true
|
||||||
|
mgmt:
|
||||||
|
external:
|
||||||
|
true
|
||||||
17
mgmt/redis-commander/compose.yml
Normal file
17
mgmt/redis-commander/compose.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
services:
|
||||||
|
redis-commander:
|
||||||
|
container_name: redis-commander
|
||||||
|
# hostname: redis-commander
|
||||||
|
image: ghcr.io/joeferner/redis-commander:latest
|
||||||
|
# build: .
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
- REDIS_HOSTS=local:redis:6379
|
||||||
|
# ports:
|
||||||
|
# - "8081:8081"
|
||||||
|
user: redis
|
||||||
|
networks:
|
||||||
|
db:
|
||||||
|
external: true
|
||||||
|
web:
|
||||||
|
external: true
|
||||||
4
mgmt/vaultwarden/.env.example
Normal file
4
mgmt/vaultwarden/.env.example
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
DOMAIN_NAME=
|
||||||
|
SUBDOMAIN=
|
||||||
|
DOMAIN=https://${SUBDOMAIN}.${DOMAIN_NAME}
|
||||||
|
# SIGNUPS_ALLOWED=false # Uncomment to disable signups
|
||||||
35
mgmt/vaultwarden/compose.yml
Normal file
35
mgmt/vaultwarden/compose.yml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
services:
|
||||||
|
vaultwarden:
|
||||||
|
image: vaultwarden/server:latest
|
||||||
|
container_name: vaultwarden
|
||||||
|
restart: always
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.vw.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
|
||||||
|
- traefik.http.routers.vw.tls=true
|
||||||
|
- traefik.http.routers.vw.entrypoints=web,websecure
|
||||||
|
- traefik.http.routers.vw.tls.certresolver=cloudflare
|
||||||
|
- traefik.http.middlewares.vw.headers.SSLRedirect=true
|
||||||
|
- traefik.http.middlewares.vw.headers.STSSeconds=315360000
|
||||||
|
- traefik.http.middlewares.vw.headers.browserXSSFilter=true
|
||||||
|
- traefik.http.middlewares.vw.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.vw.headers.forceSTSHeader=true
|
||||||
|
- traefik.http.middlewares.vw.headers.SSLHost=${DOMAIN_NAME}
|
||||||
|
- traefik.http.middlewares.vw.headers.STSIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.vw.headers.STSPreload=true
|
||||||
|
- traefik.http.middlewares.vw.headers.frameDeny=true
|
||||||
|
- traefik.http.routers.vw.middlewares=vw@docker
|
||||||
|
- traefik.http.services.vw.loadbalancer.server.port=80
|
||||||
|
volumes:
|
||||||
|
- vw-data:/data/
|
||||||
|
networks:
|
||||||
|
- mgmt
|
||||||
|
volumes:
|
||||||
|
vw-data:
|
||||||
|
name: vw-data
|
||||||
|
networks:
|
||||||
|
mgmt:
|
||||||
|
external:
|
||||||
|
true
|
||||||
0
templates/compose.yml
Normal file
0
templates/compose.yml
Normal file
2
webapp/it-tools/.env.example
Normal file
2
webapp/it-tools/.env.example
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
DOMAIN_NAME=
|
||||||
|
SUBDOMAIN=
|
||||||
26
webapp/it-tools/compose.yml
Normal file
26
webapp/it-tools/compose.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
services:
|
||||||
|
it-tools:
|
||||||
|
image: corentinth/it-tools
|
||||||
|
container_name: it-tools
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.tls=true
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.entrypoints=web,websecure
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.tls.certresolver=cloudflare
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.SSLRedirect=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSSeconds=315360000
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.browserXSSFilter=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.forceSTSHeader=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.SSLHost=${DOMAIN_NAME}
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.$SUBDOMAIN.headers.STSPreload=true
|
||||||
|
- traefik.http.routers.$SUBDOMAIN.middlewares=$SUBDOMAIN@docker
|
||||||
|
- traefik.http.services.$SUBDOMAIN.loadbalancer.server.port=433
|
||||||
|
networks:
|
||||||
|
- webapp
|
||||||
|
networks:
|
||||||
|
webapp:
|
||||||
|
external:
|
||||||
|
true
|
||||||
18
webapp/n8n/.env.example
Normal file
18
webapp/n8n/.env.example
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
DOMAIN_NAME=
|
||||||
|
SUBDOMAIN=
|
||||||
|
GENERIC_TIMEZONE=
|
||||||
|
SSL_EMAIL=
|
||||||
|
|
||||||
|
N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
|
||||||
|
N8N_RUNNERS_ENABLED=true
|
||||||
|
N8N_HOST=${SUBDOMAIN}.${DOMAIN_NAME}
|
||||||
|
|
||||||
|
DB_TYPE=postgresdb
|
||||||
|
DB_POSTGRESDB_HOST=
|
||||||
|
DB_POSTGRESDB_PORT=5432
|
||||||
|
DB_POSTGRESDB_DATABASE=
|
||||||
|
DB_POSTGRESDB_USER=
|
||||||
|
DB_POSTGRESDB_PASSWORD_FILE=/run/secrets/DB_PASS
|
||||||
|
|
||||||
|
WEBHOOK_URL=https://${SUBDOMAIN}.${DOMAIN_NAME}
|
||||||
|
N8N_GIT_NODE_DISABLE_BARE_REPOS=true
|
||||||
46
webapp/n8n/compose.yml
Normal file
46
webapp/n8n/compose.yml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
services:
|
||||||
|
n8n:
|
||||||
|
image: docker.n8n.io/n8nio/n8n
|
||||||
|
container_name: n8n
|
||||||
|
restart: always
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.n8n.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
|
||||||
|
- traefik.http.routers.n8n.tls=true
|
||||||
|
- traefik.http.routers.n8n.entrypoints=web,websecure
|
||||||
|
- traefik.http.routers.n8n.tls.certresolver=cloudflare
|
||||||
|
- traefik.http.middlewares.n8n.headers.SSLRedirect=true
|
||||||
|
- traefik.http.middlewares.n8n.headers.STSSeconds=315360000
|
||||||
|
- traefik.http.middlewares.n8n.headers.browserXSSFilter=true
|
||||||
|
- traefik.http.middlewares.n8n.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.n8n.headers.forceSTSHeader=true
|
||||||
|
- traefik.http.middlewares.n8n.headers.SSLHost=${DOMAIN_NAME}
|
||||||
|
- traefik.http.middlewares.n8n.headers.STSIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.n8n.headers.STSPreload=true
|
||||||
|
- traefik.http.middlewares.n8n.headers.frameDeny=true
|
||||||
|
- traefik.http.routers.n8n.middlewares=n8n@docker
|
||||||
|
- traefik.http.services.n8n.loadbalancer.server.port=5678
|
||||||
|
- traefik.docker.network=webapp
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
secrets:
|
||||||
|
- DB_PASS
|
||||||
|
volumes:
|
||||||
|
- n8n_data:/home/node/.n8n
|
||||||
|
- ./local-files:/files
|
||||||
|
networks:
|
||||||
|
- webapp
|
||||||
|
- db
|
||||||
|
secrets:
|
||||||
|
DB_PASS:
|
||||||
|
file: .secrets/DB_PASS
|
||||||
|
networks:
|
||||||
|
webapp:
|
||||||
|
external:
|
||||||
|
true
|
||||||
|
db:
|
||||||
|
external:
|
||||||
|
true
|
||||||
|
volumes:
|
||||||
|
n8n_data:
|
||||||
|
name: n8n_data
|
||||||
3
webapp/navidrome/.env.example
Normal file
3
webapp/navidrome/.env.example
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
DOMAIN_NAME=
|
||||||
|
SUBDOMAIN=
|
||||||
|
# GENERIC_TIMEZONE=
|
||||||
36
webapp/navidrome/compose.yml
Normal file
36
webapp/navidrome/compose.yml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
services:
|
||||||
|
navidrome:
|
||||||
|
image: deluan/navidrome:latest
|
||||||
|
container_name: navidrome
|
||||||
|
hostname: ${SUBDOMAIN}.${DOMAIN_NAME}
|
||||||
|
user: 1000:1000 # should be owner of volumes
|
||||||
|
labels:
|
||||||
|
- traefik.enable=true
|
||||||
|
- traefik.http.routers.nd.rule=Host(`${SUBDOMAIN}.${DOMAIN_NAME}`)
|
||||||
|
- traefik.http.routers.nd.tls=true
|
||||||
|
- traefik.http.routers.nd.entrypoints=web,websecure
|
||||||
|
- traefik.http.routers.nd.tls.certresolver=cloudflare
|
||||||
|
- traefik.http.middlewares.nd.headers.SSLRedirect=true
|
||||||
|
- traefik.http.middlewares.nd.headers.STSSeconds=315360000
|
||||||
|
- traefik.http.middlewares.nd.headers.browserXSSFilter=true
|
||||||
|
- traefik.http.middlewares.nd.headers.contentTypeNosniff=true
|
||||||
|
- traefik.http.middlewares.nd.headers.forceSTSHeader=true
|
||||||
|
- traefik.http.middlewares.nd.headers.SSLHost=${DOMAIN_NAME}
|
||||||
|
- traefik.http.middlewares.nd.headers.STSIncludeSubdomains=true
|
||||||
|
- traefik.http.middlewares.nd.headers.STSPreload=true
|
||||||
|
- traefik.http.middlewares.nd.headers.frameDeny=true
|
||||||
|
- traefik.http.routers.nd.middlewares=nd@docker
|
||||||
|
- traefik.http.services.nd.loadbalancer.server.port=4533
|
||||||
|
restart: always
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
# Optional: put your config options customization here. Examples:
|
||||||
|
# ND_LOGLEVEL: debug
|
||||||
|
volumes:
|
||||||
|
- ./data:/data
|
||||||
|
- ./music:/music:ro
|
||||||
|
networks:
|
||||||
|
webapp:
|
||||||
|
networks:
|
||||||
|
webapp:
|
||||||
|
external: true
|
||||||
5
webapp/qbittorrent/.env.example
Normal file
5
webapp/qbittorrent/.env.example
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
PUID=
|
||||||
|
PGID=
|
||||||
|
TZ=
|
||||||
|
WEBUI_PORT=
|
||||||
|
TORRENTING_PORT=
|
||||||
14
webapp/qbittorrent/compose.yml
Normal file
14
webapp/qbittorrent/compose.yml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
services:
|
||||||
|
qbittorrent:
|
||||||
|
image: lscr.io/linuxserver/qbittorrent:latest
|
||||||
|
container_name: qbittorrent
|
||||||
|
hostname: qbittorrent.jojo
|
||||||
|
volumes:
|
||||||
|
- ./config:/config
|
||||||
|
# - /mnt/c/Users/$USER/Downloads/:/downloads #optional
|
||||||
|
- ~/Downloads/:/downloads
|
||||||
|
ports:
|
||||||
|
- 5555:8080
|
||||||
|
- 6881:6881
|
||||||
|
- 6881:6881/udp
|
||||||
|
restart: unless-stopped
|
||||||
Reference in New Issue
Block a user