first commit

This commit is contained in:
Aykhan Shahsuvarov 2024-12-06 00:08:43 +00:00
commit 5768c9c54d
25 changed files with 728 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/private
.env

32
caddy/.env.example Normal file
View File

@ -0,0 +1,32 @@
############# Gitea #############
GITEA_DOMAIN=
GITEA_CRT=
GITEA_KEY=
############# Slash #############
SLASH_DOMAIN=
SLASH_CRT=
SLASH_KEY=
############# Memos #############
MEMOS_DOMAIN=
MEMOS_CRT=
MEMOS_KEY=
############# WG easy #############
WG_EASY_DOMAIN=
WG_EASY_CRT=
WG_EASY_KEY=
############# VaultWarden #############
VAULTWARDEN_DOMAIN=
VAULTWARDEN_CRT=
VAULTWARDEN_KEY=
############# Sftpgo #############
SFTPGO_DOMAIN=
############# Searxng #############
SEARXNG_DOMAIN=
SEARXNG_CRT=
SEARXNG_KEY=

1
caddy/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/ssl/*

196
caddy/Caddyfile Normal file
View File

@ -0,0 +1,196 @@
{
admin off
}
############## gitea ##############
{$GITEA_DOMAIN} {
tls /etc/ssl/custom/{$GITEA_CRT} /etc/ssl/custom/{$GITEA_KEY}
request_body {
max_size 512MB
}
reverse_proxy http://gitea:3000 {
header_up X-Real-IP {http.request.header.Cf-Connecting-Ip}
header_up X-Forwarded-For {http.request.header.Cf-Connecting-Ip}
header_up X-Country-Code {http.request.header.Cf-Ipcountry}
header_up -CF-*
}
}
############## slash ##############
{$SLASH_DOMAIN} {
tls /etc/ssl/custom/{$SLASH_CRT} /etc/ssl/custom/{$SLASH_KEY}
request_body {
max_size 10MB
}
reverse_proxy http://slash:5231 {
header_up X-Real-IP {http.request.header.Cf-Connecting-Ip}
header_up X-Forwarded-For {http.request.header.Cf-Connecting-Ip}
header_up X-Country-Code {http.request.header.Cf-Ipcountry}
header_up -CF-*
}
}
############## memos ##############
{$MEMOS_DOMAIN} {
tls /etc/ssl/custom/{$MEMOS_CRT} /etc/ssl/custom/{$MEMOS_KEY}
request_body {
max_size 128MB
}
reverse_proxy http://memos:5230 {
header_up X-Real-IP {http.request.header.Cf-Connecting-Ip}
header_up X-Forwarded-For {http.request.header.Cf-Connecting-Ip}
header_up X-Country-Code {http.request.header.Cf-Ipcountry}
header_up -CF-*
}
}
############## wg-easy ##############
{$WG_EASY_DOMAIN} {
tls /etc/ssl/custom/{$WG_EASY_CRT} /etc/ssl/custom/{$WG_EASY_KEY}
request_body {
max_size 10MB
}
reverse_proxy http://wg-easy:51821 {
header_up X-Real-IP {http.request.header.Cf-Connecting-Ip}
header_up X-Forwarded-For {http.request.header.Cf-Connecting-Ip}
header_up X-Country-Code {http.request.header.Cf-Ipcountry}
header_up -CF-*
}
}
############## vaultwarden ##############
{$VAULTWARDEN_DOMAIN} {
tls /etc/ssl/custom/{$VAULTWARDEN_CRT} /etc/ssl/custom/{$VAULTWARDEN_KEY}
request_body {
max_size 128MB
}
reverse_proxy http://vaultwarden {
header_up X-Real-IP {http.request.header.Cf-Connecting-Ip}
header_up X-Forwarded-For {http.request.header.Cf-Connecting-Ip}
header_up X-Country-Code {http.request.header.Cf-Ipcountry}
header_up -CF-*
}
}
############## sftpgo ##############
{$SFTPGO_DOMAIN} {
request_body {
max_size 5120MB
}
reverse_proxy http://sftpgo:8080 {
header_up X-Real-IP {http.request.header.Cf-Connecting-Ip}
header_up X-Forwarded-For {http.request.header.Cf-Connecting-Ip}
header_up X-Country-Code {http.request.header.Cf-Ipcountry}
header_up -CF-*
}
}
############## searxng ##############
{$SEARXNG_DOMAIN} {
tls /etc/ssl/custom/{$SEARXNG_CRT} /etc/ssl/custom/{$SEARXNG_KEY}
request_body {
max_size 128MB
}
@api {
path /config
path /healthz
path /stats/errors
path /stats/checker
}
@static {
path /static/*
}
@notstatic {
not path /static/*
}
@imageproxy {
path /image_proxy
}
@notimageproxy {
not path /image_proxy
}
header {
# Enable HTTP Strict Transport Security (HSTS) to force clients to always connect via HTTPS
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
# Enable cross-site filter (XSS) and tell browser to block detected attacks
X-XSS-Protection "1; mode=block"
# Prevent some browsers from MIME-sniffing a response away from the declared Content-Type
X-Content-Type-Options "nosniff"
# Disable some features
Permissions-Policy "accelerometer=(),ambient-light-sensor=(),autoplay=(),camera=(),encrypted-media=(),focus-without-user-activation=(),geolocation=(),gyroscope=(),magnetometer=(),microphone=(),midi=(),payment=(),picture-in-picture=(),speaker=(),sync-xhr=(),usb=(),vr=()"
# Disable some features (legacy)
Feature-Policy "accelerometer 'none';ambient-light-sensor 'none'; autoplay 'none';camera 'none';encrypted-media 'none';focus-without-user-activation 'none'; geolocation 'none';gyroscope 'none';magnetometer 'none';microphone 'none';midi 'none';payment 'none';picture-in-picture 'none'; speaker 'none';sync-xhr 'none';usb 'none';vr 'none'"
# Referer
Referrer-Policy "no-referrer"
# X-Robots-Tag
X-Robots-Tag "noindex, noarchive, nofollow"
# Remove Server header
-Server
}
header @api {
Access-Control-Allow-Methods "GET, OPTIONS"
Access-Control-Allow-Origin "*"
}
# Cache
header @static {
# Cache
Cache-Control "public, max-age=31536000"
defer
}
header @notstatic {
# No Cache
Cache-Control "no-cache, no-store"
Pragma "no-cache"
}
# CSP (see http://content-security-policy.com/ )
header @imageproxy {
Content-Security-Policy "default-src 'none'; img-src 'self' data:"
}
header @notimageproxy {
Content-Security-Policy "upgrade-insecure-requests; default-src 'none'; script-src 'self'; style-src 'self' 'unsafe-inline'; form-action 'self' https://github.com/searxng/searxng/issues/new; font-src 'self'; frame-ancestors 'self'; base-uri 'self'; connect-src 'self' https://overpass-api.de; img-src 'self' data: https://*.tile.openstreetmap.org; frame-src https://www.youtube-nocookie.com https://player.vimeo.com https://www.dailymotion.com https://www.deezer.com https://www.mixcloud.com https://w.soundcloud.com https://embed.spotify.com"
}
# SearXNG
handle {
encode zstd gzip
reverse_proxy searxng:8080 {
header_up X-Forwarded-Port {http.request.port}
header_up X-Forwarded-Proto {http.request.scheme}
header_up X-Real-IP {http.request.header.Cf-Connecting-Ip}
header_up X-Forwarded-For {http.request.header.Cf-Connecting-Ip}
header_up X-Country-Code {http.request.header.Cf-Ipcountry}
header_up -CF-*
}
}
}

22
caddy/docker-compose.yml Normal file
View File

@ -0,0 +1,22 @@
services:
caddy:
image: caddy:2.8.4
container_name: caddy
restart: unless-stopped
networks:
- caddy
ports:
- "443:443"
- "80:80"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- ./ssl:/etc/ssl/custom/
env_file:
- ./.env
networks:
caddy:
name: caddy
driver: bridge
external: true

9
gitea/.env.example Normal file
View File

@ -0,0 +1,9 @@
# URL of the Gitea instance (e.g. https://gitea.example.com)
GITEA_INSTANCE_URL=
# How to get the token: https://docs.gitea.com/usage/actions/act-runner#obtain-a-registration-token
GITEA_RUNNER_REGISTRATION_TOKEN=
# UID and GID of the user that should run the runner (e.g. USER_UID=1000, USER_GID=1000)
USER_UID=
USER_GID=
# Name of the runner (e.g. runner-1)
GITEA_RUNNER_NAME=

2
gitea/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/data/*
/act-data/*

37
gitea/docker-compose.yml Normal file
View File

@ -0,0 +1,37 @@
networks:
gitea:
external: false
caddy:
name: caddy
driver: bridge
external: true
services:
server:
image: gitea/gitea:1.22.3
container_name: gitea
environment:
- USER_UID=${USER_UID}
- USER_GID=${USER_GID}
restart: unless-stopped
networks:
- gitea
- caddy
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
act:
image: gitea/act_runner:0.2.11
container_name: gitea_act
restart: unless-stopped
environment:
- GITEA_INSTANCE_URL=${GITEA_INSTANCE_URL}
- GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_REGISTRATION_TOKEN}
- GITEA_RUNNER_NAME=${GITEA_RUNNER_NAME}
networks:
- gitea
volumes:
- ./act-data:/data
- /var/run/docker.sock:/var/run/docker.sock

217
main.sh Executable file
View File

@ -0,0 +1,217 @@
#!/bin/bash
BLACK="\033[30m"
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
BLUE="\033[34m"
MAGENTA="\033[35m"
CYAN="\033[36m"
WHITE="\033[37m"
RESET="\033[0m"
colored() {
echo -e "$1$2$RESET"
}
print_error() {
echo "$(colored $RED "Error:") $1" >&2
}
print_success() {
colored $GREEN "$1"
}
print_usage() {
echo -e "Usage: $0 [command]\n"
echo "Commands:"
echo " start: Start all services"
echo " stop: Stop all services"
echo " generate-env: Generate .env files for all services"
echo " help: Show this help message"
}
generate_env_files() {
cp --update=none ./gitea/.env.example ./gitea/.env
# cp --update=none ./memos/.env.example ./memos/.env
cp --update=none ./searxng/.env.example ./searxng/.env
cp --update=none ./sftpgo/.env.example ./sftpgo/.env
# cp --update=none ./slash/.env.example ./slash/.env
cp --update=none ./vaultwarden/.env.example ./vaultwarden/.env
cp --update=none ./wg_easy/.env.example ./wg_easy/.env
cp --update=none ./caddy/.env.example ./caddy/.env
print_success ".env files generated."
}
start_services() {
echo "Starting gitea..."
docker compose -f ./gitea/docker-compose.yml up -d
if [ $? -eq 0 ]; then
print_success "Gitea started successfully."
else
print_error "failed to start Gitea!"
exit 1
fi
echo "Starting memos..."
docker compose -f ./memos/docker-compose.yml up -d
if [ $? -eq 0 ]; then
print_success "Memos started successfully."
else
print_error "failed to start Memos!"
exit 1
fi
echo "Starting searxng..."
docker compose -f ./searxng/docker-compose.yml up -d
if [ $? -eq 0 ]; then
print_success "Searxng started successfully."
else
print_error "failed to start Searxng!"
exit 1
fi
echo "Starting sftpgo..."
docker compose -f ./sftpgo/docker-compose.yml up -d
if [ $? -eq 0 ]; then
print_success "Sftpgo started successfully."
else
print_error "failed to start Sftpgo!"
exit 1
fi
echo "Starting slash..."
docker compose -f ./slash/docker-compose.yml up -d
if [ $? -eq 0 ]; then
print_success "Slash started successfully."
else
print_error "failed to start Slash!"
exit 1
fi
echo "Starting vaultwarden..."
docker compose -f ./vaultwarden/docker-compose.yml up -d
if [ $? -eq 0 ]; then
print_success "Vaultwarden started successfully."
else
print_error "failed to start Vaultwarden!"
exit 1
fi
echo "Starting wg-easy..."
docker compose -f ./wg_easy/docker-compose.yml up -d
if [ $? -eq 0 ]; then
print_success "Wg-easy started successfully."
else
print_error "failed to start Wg-easy!"
exit 1
fi
echo "Starting caddy..."
docker compose -f ./caddy/docker-compose.yml up -d
if [ $? -eq 0 ]; then
print_success "Caddy started successfully."
else
print_error "failed to start Caddy!"
exit 1
fi
}
stop_services() {
echo "Stopping gitea..."
docker compose -f ./gitea/docker-compose.yml down
if [ $? -eq 0 ]; then
print_success "Gitea stopped successfully."
else
print_error "failed to stop Gitea!"
exit 1
fi
echo "Stopping memos..."
docker compose -f ./memos/docker-compose.yml down
if [ $? -eq 0 ]; then
print_success "Memos stopped successfully."
else
print_error "failed to stop Memos!"
exit 1
fi
echo "Stopping searxng..."
docker compose -f ./searxng/docker-compose.yml down
if [ $? -eq 0 ]; then
print_success "Searxng stopped successfully."
else
print_error "failed to stop Searxng!"
exit 1
fi
echo "Stopping sftpgo..."
docker compose -f ./sftpgo/docker-compose.yml down
if [ $? -eq 0 ]; then
print_success "Sftpgo stopped successfully."
else
print_error "failed to stop Sftpgo!"
exit 1
fi
echo "Stopping slash..."
docker compose -f ./slash/docker-compose.yml down
if [ $? -eq 0 ]; then
print_success "Slash stopped successfully."
else
print_error "failed to stop Slash!"
exit 1
fi
echo "Stopping vaultwarden..."
docker compose -f ./vaultwarden/docker-compose.yml down
if [ $? -eq 0 ]; then
print_success "Vaultwarden stopped successfully."
else
print_error "failed to stop Vaultwarden!"
exit 1
fi
echo "Stopping wg-easy..."
docker compose -f ./wg_easy/docker-compose.yml down
if [ $? -eq 0 ]; then
print_success "Wg-easy stopped successfully."
else
print_error "failed to stop Wg-easy!"
exit 1
fi
echo "Stopping caddy..."
docker compose -f ./caddy/docker-compose.yml down
if [ $? -eq 0 ]; then
print_success "Caddy stopped successfully."
else
print_error "failed to stop Caddy!"
exit 1
fi
}
if [ $# -lt 1 ]; then
print_usage
exit 1
fi
case $1 in
start)
start_services
;;
stop)
stop_services
;;
generate-env)
generate_env_files
;;
help)
print_usage
;;
*)
print_error "Invalid command: $1"
print_usage
exit 1
;;
esac

1
memos/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/data/*

18
memos/docker-compose.yml Normal file
View File

@ -0,0 +1,18 @@
networks:
memos:
external: false
caddy:
name: caddy
driver: bridge
external: true
services:
server:
image: neosmemo/memos:0.23.0-pre
container_name: memos
restart: unless-stopped
networks:
- memos
- caddy
volumes:
- ./data/:/var/opt/memos

14
searxng/.env.example Normal file
View File

@ -0,0 +1,14 @@
# By default listen on https://localhost
# To change this:
# * uncomment SEARXNG_HOSTNAME, and replace <host> by the SearXNG hostname
# * uncomment LETSENCRYPT_EMAIL, and replace <email> by your email (require to create a Let's Encrypt certificate)
SEARXNG_HOSTNAME=
# LETSENCRYPT_EMAIL=<email>
# Optional:
# If you run a very small or a very large instance, you might want to change the amount of used uwsgi workers and threads per worker
# More workers (= processes) means that more search requests can be handled at the same time, but it also causes more resource usage
# SEARXNG_UWSGI_WORKERS=4
# SEARXNG_UWSGI_THREADS=4

2
searxng/data/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/searxng/*
/valkey-data2/*

View File

@ -0,0 +1,42 @@
networks:
searxng:
external: false
caddy:
name: caddy
driver: bridge
external: true
services:
redis:
container_name: searxng_redis
image: docker.io/valkey/valkey:8-alpine
command: valkey-server --save 30 1 --loglevel warning
restart: unless-stopped
networks:
- searxng
volumes:
- ./data/valkey-data2:/data
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"
searxng:
container_name: searxng
image: docker.io/searxng/searxng:2024.12.1-0245e82bd
restart: unless-stopped
networks:
- searxng
- caddy
volumes:
- ./data/searxng:/etc/searxng:rw
environment:
- SEARXNG_BASE_URL=https://${SEARXNG_HOSTNAME:-localhost}/
- UWSGI_WORKERS=${SEARXNG_UWSGI_WORKERS:-4}
- UWSGI_THREADS=${SEARXNG_UWSGI_THREADS:-4}
logging:
driver: "json-file"
options:
max-size: "1m"
max-file: "1"

6
sftpgo/.env.example Normal file
View File

@ -0,0 +1,6 @@
# https://docs.sftpgo.com/latest/config-file/ (Common > idle_timeout)
SFTPGO_COMMON_IDLE_TIMEOUT=15
# https://docs.sftpgo.com/latest/config-file/ (Common > upload_mode)
SFTPGO_COMMON_UPLOAD_MODE=0
# https://docs.sftpgo.com/latest/config-file/ (HTTP server > bindings > ip_proxy_header)
SFTPGO_HTTPD__BINDINGS__0__CLIENT_IP_PROXY_HEADER=X-Real-IP

2
sftpgo/data/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/data/*
/home/*

20
sftpgo/docker-compose.yml Normal file
View File

@ -0,0 +1,20 @@
networks:
caddy:
name: caddy
driver: bridge
external: true
services:
server:
image: drakkan/sftpgo:v2
container_name: sftpgo
restart: unless-stopped
environment:
- SFTPGO_COMMON_IDLE_TIMEOUT=${SFTPGO_COMMON_IDLE_TIMEOUT}
- SFTPGO_COMMON_UPLOAD_MODE=${SFTPGO_COMMON_UPLOAD_MODE}
- SFTPGO_HTTPD__BINDINGS__0__CLIENT_IP_PROXY_HEADER=${SFTPGO_HTTPD__BINDINGS__0__CLIENT_IP_PROXY_HEADER}
networks:
- caddy
volumes:
- ./data/data:/srv/sftpgo
- ./data/home:/var/lib/sftpgo

1
slash/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/data/*

16
slash/docker-compose.yml Normal file
View File

@ -0,0 +1,16 @@
networks:
caddy:
name: caddy
driver: bridge
external: true
services:
server:
# image: yourselfhosted/slash:latest
image: aykhans/slash:1.0.0-rc.0-e
container_name: slash
restart: unless-stopped
networks:
- caddy
volumes:
- ./data/:/var/opt/slash

4
vaultwarden/.env.example Normal file
View File

@ -0,0 +1,4 @@
# Domain name of the server (e.g. https://example.com)
DOMAIN=
# Admin token (if you want to use admin features)
ADMIN_TOKEN=

1
vaultwarden/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/data/*

View File

@ -0,0 +1,18 @@
networks:
caddy:
name: caddy
driver: bridge
external: true
services:
server:
image: vaultwarden/server:1.32.5
container_name: vaultwarden
restart: unless-stopped
environment:
- DOMAIN=${DOMAIN}
- ADMIN_TOKEN=${ADMIN_TOKEN}
networks:
- caddy
volumes:
- ./data:/data/

7
wg_easy/.env.example Normal file
View File

@ -0,0 +1,7 @@
# Language of web page (e.g. en)
LANG=
# The public hostname or IP of your VPN server (e.g. vpn.example.com, 1.1.1.1)
WG_HOST=
# (Optional) When set, requires a password when logging in to the Web UI.
# See How to generate a hash: https://github.com/wg-easy/wg-easy/blob/master/How_to_generate_an_bcrypt_hash.md
PASSWORD_HASH=

1
wg_easy/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/data/*

View File

@ -0,0 +1,57 @@
# volumes:
# etc_wireguard:
networks:
caddy:
name: caddy
driver: bridge
external: true
services:
wg-easy:
environment:
# Change Language:
# (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th, hi, ja)
- LANG=${LANG:-en}
# ⚠️ Required:
# Change this to your host's public address
- WG_HOST=${WG_HOST}
# Optional:
- PASSWORD_HASH=${PASSWORD_HASH}
# - PORT=51821
# - WG_PORT=51820
# - WG_CONFIG_PORT=92820
# - WG_DEFAULT_ADDRESS=10.8.0.x
# - WG_DEFAULT_DNS=1.1.1.1
# - WG_MTU=1420
# - WG_ALLOWED_IPS=192.168.15.0/24, 10.0.1.0/24
# - WG_PERSISTENT_KEEPALIVE=25
# - WG_PRE_UP=echo "Pre Up" > /etc/wireguard/pre-up.txt
# - WG_POST_UP=echo "Post Up" > /etc/wireguard/post-up.txt
# - WG_PRE_DOWN=echo "Pre Down" > /etc/wireguard/pre-down.txt
# - WG_POST_DOWN=echo "Post Down" > /etc/wireguard/post-down.txt
# - UI_TRAFFIC_STATS=true
# - UI_CHART_TYPE=0 # (0 Charts disabled, 1 # Line chart, 2 # Area chart, 3 # Bar chart)
# - WG_ENABLE_ONE_TIME_LINKS=true
# - UI_ENABLE_SORT_CLIENTS=true
# - WG_ENABLE_EXPIRES_TIME=true
# - ENABLE_PROMETHEUS_METRICS=false
# - PROMETHEUS_METRICS_PASSWORD=$$2a$$12$$vkvKpeEAHD78gasyawIod.1leBMKg8sBwKW.pQyNsq78bXV3INf2G # (needs double $$, hash of 'prometheus_password'; see "How_to_generate_an_bcrypt_hash.md" for generate the hash)
image: ghcr.io/wg-easy/wg-easy:14
container_name: wg-easy
volumes:
- ./data:/etc/wireguard
networks:
- caddy
ports:
- "51820:51820/udp"
# - "51821:51821/tcp"
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
# - NET_RAW # ⚠️ Uncomment if using Podman
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1