commit 1cd9af500c285f167206d30855508547ffb7c288 Author: Iurii Tatishchev Date: Thu Jul 14 23:13:34 2022 -0700 Add initial templates for docker-compose services (gitea, nextcloud, traefik) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f0b8ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,304 @@ +# Created by https://www.toptal.com/developers/gitignore/api/python,pycharm,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=python,pycharm,visualstudiocode + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +# Azure Toolkit for IntelliJ plugin +# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij +.idea/**/azureSettings.xml + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# Support for Project snippet scope +.vscode/*.code-snippets + +# Ignore code-workspaces +*.code-workspace + +# End of https://www.toptal.com/developers/gitignore/api/python,pycharm,visualstudiocode diff --git a/.idea/alpina.iml b/.idea/alpina.iml new file mode 100644 index 0000000..c440309 --- /dev/null +++ b/.idea/alpina.iml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..456eeb6 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/jsonSchemas.xml b/.idea/jsonSchemas.xml new file mode 100644 index 0000000..3fa3264 --- /dev/null +++ b/.idea/jsonSchemas.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..987187e --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..92f2d47 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..e69de29 diff --git a/contrib/rbw-client.sh b/contrib/rbw-client.sh new file mode 100755 index 0000000..2a0baf9 --- /dev/null +++ b/contrib/rbw-client.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash + +while [[ $# -gt 0 ]]; do + case $1 in + --vault-id) + vault_id="$2" + shift # past argument + shift # past value + ;; + -*) + echo "Unknown option $1" + exit 1 + ;; + esac +done + +# rbw adds a newline which has to be trimmed +/usr/bin/env rbw get --folder Keyring "$vault_id" ansible_vault | tr -d '\n' diff --git a/group_vars/docker_hosts.yml b/group_vars/docker_hosts.yml new file mode 100644 index 0000000..2da0437 --- /dev/null +++ b/group_vars/docker_hosts.yml @@ -0,0 +1,2 @@ +--- +my_svc_path: ~/services diff --git a/inventories/prod/hosts b/inventories/prod/hosts new file mode 100644 index 0000000..483f02b --- /dev/null +++ b/inventories/prod/hosts @@ -0,0 +1,2 @@ +[docker_hosts] +root@alpina.lab.home diff --git a/inventories/staging/hosts b/inventories/staging/hosts new file mode 100644 index 0000000..abac7a9 --- /dev/null +++ b/inventories/staging/hosts @@ -0,0 +1,2 @@ +[docker_hosts] +root@etapp.lab.home diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..9e788b5 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +ansible==6.0.0 diff --git a/roles/common/tasks/main.yml b/roles/common/tasks/main.yml new file mode 100644 index 0000000..13c323c --- /dev/null +++ b/roles/common/tasks/main.yml @@ -0,0 +1,43 @@ +- name: Upgrade alpine packages + community.general.apk: + upgrade: yes + update_cache: yes + register: apk_upgrades + +- name: Install alpine packages + community.general.apk: + name: + - qemu-guest-agent + - dhcpcd + - python3 + - fish + - docker + - docker-compose + - docker-fish-completion + - docker-compose-fish-completion + - zfs + state: latest + update_cache: yes + register: apk_installs + +- name: Enable qemu-guest-agent service + service: + name: qemu-guest-agent + runlevel: boot + enabled: yes + +- name: Enable zfs-import service + service: + name: zfs-import + runlevel: sysinit + enabled: yes + +- name: Enable zfs-mount service + service: + name: zfs-mount + runlevel: sysinit + enabled: yes + +- name: Reboot if needed + reboot: + when: apk_upgrades.changed or apk_installs.changed diff --git a/roles/docker_host/tasks/main.yml b/roles/docker_host/tasks/main.yml new file mode 100644 index 0000000..08fc74d --- /dev/null +++ b/roles/docker_host/tasks/main.yml @@ -0,0 +1,5 @@ +- name: Create my service directory + file: + state: directory + path: "{{ my_svc_path }}" + mode: "700" diff --git a/roles/gitea/tasks/main.yml b/roles/gitea/tasks/main.yml new file mode 100644 index 0000000..1a48913 --- /dev/null +++ b/roles/gitea/tasks/main.yml @@ -0,0 +1,33 @@ +# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories + +- name: Ensure service directory exists + file: + path: "{{ current_svc_path }}" + state: directory + mode: "500" + +- name: Ensure directory structure exists + file: + path: "{{ current_svc_path }}/{{ item.path }}" + state: directory + mode: "500" + with_community.general.filetree: "{{ templates_source }}" + when: item.state == "directory" + + +- name: Include app config variables + include_vars: + file: "{{ role_path }}/vars/app_config.yml" + +- name: Generate {{ current_svc_name }} deployment from templates + template: + src: "{{ item.src }}" + dest: "{{ current_svc_path }}/{{ item.path | regex_replace('\\.j2$', '') }}" + mode: "400" + with_community.general.filetree: "{{ templates_source }}" + when: item.state == "file" + +- name: Deploy docker-compose for {{ current_svc_name }} + community.docker.docker_compose: + project_src: "{{ current_svc_path }}" + state: present diff --git a/roles/gitea/templates/.env.db.j2 b/roles/gitea/templates/.env.db.j2 new file mode 100644 index 0000000..59eb7f9 --- /dev/null +++ b/roles/gitea/templates/.env.db.j2 @@ -0,0 +1,3 @@ +POSTGRES_USER=gitea +POSTGRES_DB=gitea +POSTGRES_PASSWORD="{{ db_password }}" diff --git a/roles/gitea/templates/.env.gitea.j2 b/roles/gitea/templates/.env.gitea.j2 new file mode 100644 index 0000000..9f3cbc0 --- /dev/null +++ b/roles/gitea/templates/.env.gitea.j2 @@ -0,0 +1,25 @@ +GITEA____APP_NAME=CazGitea + +# Database +GITEA__database__DB_TYPE=postgres +GITEA__database__HOST=db:5432 +GITEA__database__NAME="{{ db_user }}" +GITEA__database__USER="{{ db_name }}" +GITEA__database__PASSWD="{{ db_password }}" + +# Server +GITEA__server__ROOT_URL=https://gitea.cazzzer.com/ +GITEA__server__DISABLE_SSH=true + +# Mail +GITEA__mailer__ENABLED=true +GITEA__mailer__HOST=smtp.sendgrid.net:587 +GITEA__mailer__FROM=gitea@cazzzer.com +GITEA__mailer__USER=apikey +GITEA__mailer__PASSWD="{{ sendgrid_api_key }}" + +# Security +GITEA__security__SECRET_KEY="{{ secret_key }}" +GITEA__security__INTERNAL_TOKEN="{{ internal_token }}" + +GITEA__oauth2__JWT_SECRET="{{ jwt_secret }}" diff --git a/roles/gitea/templates/docker-compose.yml.j2 b/roles/gitea/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..817e980 --- /dev/null +++ b/roles/gitea/templates/docker-compose.yml.j2 @@ -0,0 +1,41 @@ +version: "3.9" + +networks: + default: + traefik_traefik: + external: true + +volumes: + gitea: + postgres: + +services: + server: + image: gitea/gitea:1.16.9 + container_name: gitea_server + labels: + - traefik.enable=true + - traefik.http.routers.gitea.rule=Host(`gitea.lab.cazzzer.com`) + - traefik.http.services.gitea.loadbalancer.server.port=3000 + restart: unless-stopped + env_file: + - .env.gitea + networks: + - default + - traefik_traefik + volumes: + - gitea:/data + ports: + - "8011:3000" + depends_on: + - db + db: + image: postgres:14-alpine + container_name: gitea_db + restart: unless-stopped + env_file: + - .env.db + networks: + - default + volumes: + - postgres:/var/lib/postgresql/data diff --git a/roles/gitea/vars/app_config.yml b/roles/gitea/vars/app_config.yml new file mode 100644 index 0000000..02af00c --- /dev/null +++ b/roles/gitea/vars/app_config.yml @@ -0,0 +1,27 @@ +$ANSIBLE_VAULT;1.2;AES256;alpina +35303032386566343430633238343936366234333434343763666231666232633539303232383534 +3035346233346162373939333531613535353232626531640a646537616163353736653161326265 +31336530316335623335353661373834613264326436303933326135396166346562343136353931 +6439383039346465300a366266393130356630316630333336616565366562613038393239623738 +65626664643630353236333932373337333363626337386163613464306638633964663264363964 +30373661393531306662323134626664656233323762393037356434353066343830333033316365 +65616636613437663737306263373066306361376630616331663031346434336663393862316464 +62343339663461353934323063653566303932656264363562333136353665336263646230323832 +35376666303531383961646234663230663634393135326664386665633538616233613866373965 +64363361313232316336376631646662376565353536316438306361306261663532386564616566 +61663534393035343233326562303863646165346538393761326335376165623964396130393831 +64333665313461666335383134613831376138393061343238643661366439636534626265323865 +35393035336632653038623438626366373733626331633866373935616531623664303063376562 +31356332346164663364636235333461383437623161343338643839323765336237633266633864 +64363234646533616439313638363865373364623637636537623666383664656630333533303233 +64383734366666633832393230663739333435666138636462336332373061346239306136336263 +39643666303863303035313738343664636536663939616335303834333834363739303938646665 +66303637633239373461393434313036316563313132356432633337666537616363373830313034 +61313538633663653230643262613333306361666131663036643162343966313365653566393235 +36623832663034373734653664613038363137366437326565373761663963636336393536386435 +30393831326134376639366661653439616138643438646363343632346131306532663439396534 +32383661306539306635336262383563376561303862396532633362666266313562623336383235 +36366565633734633639653239306331333237353233326563653930653739316230666362323931 +39663931376562653530323434656436353166393836643238643632396430353034333034333665 +62323338373839383132323537353431636537616366393965643463316164323034316536383961 +6164333537633631646663333463306236613038326339643439 diff --git a/roles/gitea/vars/main.yml b/roles/gitea/vars/main.yml new file mode 100644 index 0000000..57a15ea --- /dev/null +++ b/roles/gitea/vars/main.yml @@ -0,0 +1,5 @@ +--- +current_svc_name: gitea +current_svc_path: "{{ my_svc_path }}/{{ current_svc_name }}" + +templates_source: "{{ role_path }}/templates" diff --git a/roles/nextcloud/tasks/main.yml b/roles/nextcloud/tasks/main.yml new file mode 100644 index 0000000..1a48913 --- /dev/null +++ b/roles/nextcloud/tasks/main.yml @@ -0,0 +1,33 @@ +# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories + +- name: Ensure service directory exists + file: + path: "{{ current_svc_path }}" + state: directory + mode: "500" + +- name: Ensure directory structure exists + file: + path: "{{ current_svc_path }}/{{ item.path }}" + state: directory + mode: "500" + with_community.general.filetree: "{{ templates_source }}" + when: item.state == "directory" + + +- name: Include app config variables + include_vars: + file: "{{ role_path }}/vars/app_config.yml" + +- name: Generate {{ current_svc_name }} deployment from templates + template: + src: "{{ item.src }}" + dest: "{{ current_svc_path }}/{{ item.path | regex_replace('\\.j2$', '') }}" + mode: "400" + with_community.general.filetree: "{{ templates_source }}" + when: item.state == "file" + +- name: Deploy docker-compose for {{ current_svc_name }} + community.docker.docker_compose: + project_src: "{{ current_svc_path }}" + state: present diff --git a/roles/nextcloud/templates/.env.db.j2 b/roles/nextcloud/templates/.env.db.j2 new file mode 100644 index 0000000..b921070 --- /dev/null +++ b/roles/nextcloud/templates/.env.db.j2 @@ -0,0 +1,3 @@ +POSTGRES_USER=nextcloud +POSTGRES_DB=nextcloud +POSTGRES_PASSWORD="{{ db_password }}" diff --git a/roles/nextcloud/templates/.env.nextcloud.j2 b/roles/nextcloud/templates/.env.nextcloud.j2 new file mode 100644 index 0000000..16536ae --- /dev/null +++ b/roles/nextcloud/templates/.env.nextcloud.j2 @@ -0,0 +1,18 @@ +POSTGRES_DB=nextcloud +POSTGRES_USER=nextcloud +POSTGRES_PASSWORD="{{ db_password }}" +POSTGRES_HOST=db + +NEXTCLOUD_TRUSTED_DOMAINS=nc.cazzzer.com + +REDIS_HOST=redis +REDIS_HOST_PASSWORD="{{ redis_password }}" + +SMTP_HOST=smtp.sendgrid.net +SMTP_SECURE=tls +SMTP_PORT=587 +SMTP_AUTHTYPE=LOGIN +SMTP_NAME=apikey +SMTP_PASSWORD="{{ sendgrid_api_key }}" +MAIL_FROM_ADDRESS=nc +MAIL_DOMAIN=cazzzer.com diff --git a/roles/nextcloud/templates/.env.redis.j2 b/roles/nextcloud/templates/.env.redis.j2 new file mode 100644 index 0000000..a8a0212 --- /dev/null +++ b/roles/nextcloud/templates/.env.redis.j2 @@ -0,0 +1 @@ +REDIS_PASSWORD="{{ redis_password }}" diff --git a/roles/nextcloud/templates/docker-compose.yml.j2 b/roles/nextcloud/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..1fabc01 --- /dev/null +++ b/roles/nextcloud/templates/docker-compose.yml.j2 @@ -0,0 +1,98 @@ +version: "3.9" + +networks: + default: + traefik_traefik: + external: true + +volumes: + nextcloud: + nextcloud_config: + nextcloud_data: + db: + +services: + app: + image: nextcloud:24-fpm-alpine + container_name: nextcloud_app + restart: unless-stopped + depends_on: + - db + - redis + env_file: + - .env.nextcloud + networks: + - default + volumes: + - nextcloud:/var/www/html + - nextcloud_config:/var/www/html/config + - nextcloud_data:/var/www/html/data + + cron: + image: nextcloud:24-fpm-alpine + container_name: nextcloud_cron + restart: unless-stopped + depends_on: + - app + entrypoint: /cron.sh + networks: + - default + volumes_from: + - app + + notify_push: + image: nextcloud:24-fpm-alpine + container_name: nextcloud_notify_push + restart: unless-stopped + depends_on: + - app + entrypoint: + - /var/www/html/custom_apps/notify_push/bin/x86_64/notify_push + - /var/www/html/config/config.php + networks: + - default + volumes_from: + - app + + db: + image: postgres:13-alpine + container_name: nextcloud_db + restart: unless-stopped + env_file: + - .env.db + networks: + - default + volumes: + - db:/var/lib/postgresql/data + + redis: + image: redis:7-alpine + container_name: nextcloud_redis + restart: unless-stopped + env_file: + - .env.redis + networks: + - default + command: + - sh + - -c + - redis-server --requirepass $$REDIS_PASSWORD + + web: + image: nginx:1.23-alpine + container_name: nextcloud_web + labels: + - traefik.enable=true + - traefik.http.routers.nextcloud.rule=Host(`nc.lab.cazzzer.com`) + restart: unless-stopped + links: + - app + ports: + - "8012:80" + networks: + - traefik_traefik + - default + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf + volumes_from: + - app diff --git a/roles/nextcloud/templates/nginx.conf.j2 b/roles/nextcloud/templates/nginx.conf.j2 new file mode 100644 index 0000000..75deb05 --- /dev/null +++ b/roles/nextcloud/templates/nginx.conf.j2 @@ -0,0 +1,182 @@ +# https://github.com/nextcloud/docker/blob/master/.examples/docker-compose/with-nginx-proxy/postgres/fpm/web/nginx.conf + +worker_processes auto; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + # Prevent nginx HTTP Server Detection + server_tokens off; + + keepalive_timeout 65; + + upstream php-handler { + server app:9000; + } + + server { + listen 80; + + # HSTS settings + # WARNING: Only add the preload option once you read about + # the consequences in https://hstspreload.org/. This option + # will add the domain to a hardcoded list that is shipped + # in all major browsers and getting removed from this list + # could take several months. + #add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always; + + # set max upload size + client_max_body_size 512M; + fastcgi_buffers 64 4K; + + # Enable gzip but do not remove ETag headers + gzip on; + gzip_vary on; + gzip_comp_level 4; + gzip_min_length 256; + gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; + gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy; + + # Pagespeed is not supported by Nextcloud, so if your server is built + # with the `ngx_pagespeed` module, uncomment this line to disable it. + #pagespeed off; + + # HTTP response headers borrowed from Nextcloud `.htaccess` + add_header Referrer-Policy "no-referrer" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-Download-Options "noopen" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Permitted-Cross-Domain-Policies "none" always; + add_header X-Robots-Tag "none" always; + add_header X-XSS-Protection "1; mode=block" always; + + # Remove X-Powered-By, which is an information leak + fastcgi_hide_header X-Powered-By; + + # Path to the root of your installation + root /var/www/html; + + # Specify how to handle directories -- specifying `/index.php$request_uri` + # here as the fallback means that Nginx always exhibits the desired behaviour + # when a client requests a path that corresponds to a directory that exists + # on the server. In particular, if that directory contains an index.php file, + # that file is correctly served; if it doesn't, then the request is passed to + # the front-end controller. This consistent behaviour means that we don't need + # to specify custom rules for certain paths (e.g. images and other assets, + # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus + # `try_files $uri $uri/ /index.php$request_uri` + # always provides the desired behaviour. + index index.php index.html /index.php$request_uri; + + # Rule borrowed from `.htaccess` to handle Microsoft DAV clients + location = / { + if ( $http_user_agent ~ ^DavClnt ) { + return 302 /remote.php/webdav/$is_args$args; + } + } + + location = /robots.txt { + allow all; + log_not_found off; + access_log off; + } + + # Make a regex exception for `/.well-known` so that clients can still + # access it despite the existence of the regex rule + # `location ~ /(\.|autotest|...)` which would otherwise handle requests + # for `/.well-known`. + location ^~ /.well-known { + # The rules in this block are an adaptation of the rules + # in `.htaccess` that concern `/.well-known`. + + location = /.well-known/carddav { return 301 /remote.php/dav/; } + location = /.well-known/caldav { return 301 /remote.php/dav/; } + + location /.well-known/acme-challenge { try_files $uri $uri/ =404; } + location /.well-known/pki-validation { try_files $uri $uri/ =404; } + + # Let Nextcloud's API for `/.well-known` URIs handle all other + # requests by passing them to the front-end controller. + return 301 /index.php$request_uri; + } + + # Rules borrowed from `.htaccess` to hide certain paths from clients + location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/) { return 404; } + location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) { return 404; } + + # Ensure this block, which passes PHP files to the PHP process, is above the blocks + # which handle static assets (as seen below). If this block is not declared first, + # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php` + # to the URI, resulting in a HTTP 500 error response. + location ~ \.php(?:$|/) { + # Required for legacy support + rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri; + + fastcgi_split_path_info ^(.+?\.php)(/.*)$; + set $path_info $fastcgi_path_info; + + try_files $fastcgi_script_name =404; + + include fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param PATH_INFO $path_info; + #fastcgi_param HTTPS on; + + fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice + fastcgi_param front_controller_active true; # Enable pretty urls + fastcgi_pass php-handler; + + fastcgi_intercept_errors on; + fastcgi_request_buffering off; + } + + location ~ \.(?:css|js|svg|gif)$ { + try_files $uri /index.php$request_uri; + expires 6M; # Cache-Control policy borrowed from `.htaccess` + access_log off; # Optional: Don't log access to assets + } + + location ~ \.woff2?$ { + try_files $uri /index.php$request_uri; + expires 7d; # Cache-Control policy borrowed from `.htaccess` + access_log off; # Optional: Don't log access to assets + } + + # Rule borrowed from `.htaccess` + location /remote { + return 301 /remote.php$request_uri; + } + + location / { + try_files $uri $uri/ /index.php$request_uri; + } + + location ^~ /push/ { + proxy_pass http://notify_push:7867/; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "Upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } +} diff --git a/roles/nextcloud/vars/app_config.yml b/roles/nextcloud/vars/app_config.yml new file mode 100644 index 0000000..2fed906 --- /dev/null +++ b/roles/nextcloud/vars/app_config.yml @@ -0,0 +1,14 @@ +$ANSIBLE_VAULT;1.2;AES256;alpina +65313636646233613364363933616361346639653939346337303832646339316632383966666237 +3766396134383434613534373937663162393134306536300a626139373732393037346630333838 +63663439353238643532316231623866396434303034313130386635623363353263626362376334 +3933346434633662320a386432373465646432343338666561366161646335636232353133393933 +65313364666564353039626238383033343765323730316633356139326666623135326131353864 +32386237643538636538356261393164633137636235346564393930346539623731386633336339 +31303466653936343166366164383134306232613236663735623834393963306331376435616365 +31313866383730393063353335626164303632636331303830636530656131636139376633623439 +63663639323964623231343066373538633336353561646230363363643762393634643435306164 +31366364326237636365336363343264343562353337303235633034383635373934376334353336 +61373065386639643064303431623162373665363937353832313561386134613834613935653964 +64656339316165313936333736643030356366663162316462636662326134396539356262666536 +64336133393937396330353234316563356337623733326264363333373536633833 diff --git a/roles/nextcloud/vars/main.yml b/roles/nextcloud/vars/main.yml new file mode 100644 index 0000000..0009816 --- /dev/null +++ b/roles/nextcloud/vars/main.yml @@ -0,0 +1,6 @@ +--- +# vars file for roles/nextcloud/ +current_svc_name: nextcloud +current_svc_path: "{{ my_svc_path }}/{{ current_svc_name }}" + +templates_source: "{{ role_path }}/templates" \ No newline at end of file diff --git a/roles/traefik/tasks/main.yml b/roles/traefik/tasks/main.yml new file mode 100644 index 0000000..4268e66 --- /dev/null +++ b/roles/traefik/tasks/main.yml @@ -0,0 +1,33 @@ +# https://stackoverflow.com/questions/41667864/can-the-templates-module-handle-multiple-templates-directories + +- name: Ensure service directory exists + file: + path: "{{ current_svc_path }}" + state: directory + mode: "500" + +- name: Ensure directory structure exists + file: + path: "{{ current_svc_path }}/{{ item.path }}" + state: directory + mode: "500" + with_community.general.filetree: "{{ templates_source }}" + when: item.state == "directory" + + +#- name: Include app config variables +# include_vars: +# file: "{{ role_path }}/vars/app_config.yml" + +- name: Generate {{ current_svc_name }} deployment from templates + template: + src: "{{ item.src }}" + dest: "{{ current_svc_path }}/{{ item.path | regex_replace('\\.j2$', '') }}" + mode: "400" + with_community.general.filetree: "{{ templates_source }}" + when: item.state == "file" + +- name: Deploy docker-compose for {{ current_svc_name }} + community.docker.docker_compose: + project_src: "{{ current_svc_path }}" + state: present diff --git a/roles/traefik/templates/.env.traefik.j2 b/roles/traefik/templates/.env.traefik.j2 new file mode 100644 index 0000000..e69de29 diff --git a/roles/traefik/templates/docker-compose.yml.j2 b/roles/traefik/templates/docker-compose.yml.j2 new file mode 100644 index 0000000..867f315 --- /dev/null +++ b/roles/traefik/templates/docker-compose.yml.j2 @@ -0,0 +1,20 @@ +version: "3.9" + +networks: + traefik: + +services: + traefik: + image: traefik:v2.8 + container_name: traefik + restart: unless-stopped + ports: + - "80:80" + - "8080:8080" + env_file: + - .env.traefik + networks: + - traefik + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./traefik.yml:/etc/traefik/traefik.yml:ro diff --git a/roles/traefik/templates/traefik.yml.j2 b/roles/traefik/templates/traefik.yml.j2 new file mode 100644 index 0000000..7b71e70 --- /dev/null +++ b/roles/traefik/templates/traefik.yml.j2 @@ -0,0 +1,7 @@ +api: + insecure: true + +providers: + docker: + exposedByDefault: false + network: traefik_traefik diff --git a/roles/traefik/vars/app_config.yml b/roles/traefik/vars/app_config.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/traefik/vars/main.yml b/roles/traefik/vars/main.yml new file mode 100644 index 0000000..85e13a0 --- /dev/null +++ b/roles/traefik/vars/main.yml @@ -0,0 +1,5 @@ +--- +current_svc_name: traefik +current_svc_path: "{{ my_svc_path }}/{{ current_svc_name }}" + +templates_source: "{{ role_path }}/templates" diff --git a/services.yml b/services.yml new file mode 100644 index 0000000..9b9fb27 --- /dev/null +++ b/services.yml @@ -0,0 +1,7 @@ +- hosts: docker_hosts + roles: + - docker_host + - traefik + - nextcloud + - role: gitea + diff --git a/site.yml b/site.yml new file mode 100644 index 0000000..373825e --- /dev/null +++ b/site.yml @@ -0,0 +1,6 @@ +- hosts: all + roles: + - common + +- name: Install services + import_playbook: services.yml