diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index f78d206a..46823ac1 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,12 +1 @@ -# These are supported funding model platforms - -github: [dargmuesli] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +github: [dargmuesli] \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22092f74..c4d9cb20 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,12 +20,31 @@ jobs: build: needs: ci-optimization if: needs.ci-optimization.outputs.continue == 'true' - name: dargstack rgen - uses: dargmuesli/github-actions/.github/workflows/dargstack-rgen.yml@7fbad16a13b7cbfe4f905498c71cd5e2c08751d8 # 5.5.2 + name: Update generated docs + runs-on: ubuntu-latest permissions: - contents: read - with: - APT_PACKAGES: mkcert + contents: write + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + ref: ${{ github.head_ref || github.ref_name }} + - name: Regenerate docs + run: | + go install github.com/dargstack/dargstack/v4/cmd/dargstack@v4.0.0-beta.16 + export PATH="$(go env GOPATH)/bin:$PATH" + dargstack document + - name: Commit and push updated docs + if: github.event_name == 'push' + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add artifacts/docs/ + if git diff --staged --quiet; then + echo "Docs are already up to date" + else + git commit -m "chore: update generated docs" + git push + fi release-semantic: needs: build name: Semantic Release diff --git a/.nvmrc b/.nvmrc deleted file mode 100644 index a45fd52c..00000000 --- a/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -24 diff --git a/.releaserc.json b/.releaserc.json index 2e162841..1f79157c 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -15,14 +15,7 @@ } ], "@semantic-release/changelog", - [ - "@semantic-release/exec", - { - "prepareCmd": "pnpm version ${nextRelease.version} --git-tag-version=false --no-git-checks" - } - ], "@semantic-release/github", "@semantic-release/git" - ], - "tagFormat": "${version}" + ] } diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..d1b2554a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,44 @@ +--- +applyTo: '**' +--- +# Project Instructions + +`stack` is the Docker Swarm configuration for [vibetype.app](https://vibetype.app/), an event community platform, managed with [dargstack](https://github.com/dargstack/dargstack/). + +## Documentation Map + +**For understanding the stack structure and deployment:** +- [README.md](README.md): Project overview, quick start +- [artifacts/docs/README.md](artifacts/docs/README.md): Auto-generated service, secret and volume reference (do not edit manually) + +**For contributing:** +- [CONTRIBUTING.md](CONTRIBUTING.md): Development setup, dargstack guidelines, code style, git workflow + +## Code Style + +- Do not use abbreviations in naming, except where omitting them would look unnatural +- Use natural language in any non-code text instead of referring to code directly, e.g. "the database's password" instead of "the `postgres_password`", except when a code reference is needed +- Use backticks in any non-code text to refer to code, e.g. "`postgres`" instead of "postgres" +- Sort YAML keys lexicographically except where order is semantically significant +- Code formatting is done by the editor via `.editorconfig` + +## Git + +- Work on branches other than the default branch + - Use this branch naming pattern: `//` +- Git commit titles must follow the Conventional Commits specification and be lowercase only + - The commit scope should not be repeated in the commit description, e.g. `feat(postgres): add role` instead of `feat(postgres): add postgres role` +- Git commit scopes must be chosen as follows (ordered by priority): + 1. service name, e.g. `postgres`, `traefik`, `vibetype` + 2. simplified dependency name, e.g. `dargstack`, `docker` + 3. area, e.g. `secrets`, `volumes`, `certificates` +- Commit bodies are only to be filled in when necessary, e.g. to mention a resolved issue link + +## Docker / dargstack + +- Each service lives under `src/development//compose.yaml` as a full Compose document and optionally `src/production//compose.yaml` as a delta-only override +- Lines annotated with `# dargstack:dev-only` are stripped from production compose +- Run `dargstack build ` after changing a service's source code to rebuild its development container image +- Run `dargstack validate` to check the stack configuration +- Run `dargstack document` to regenerate `artifacts/docs/README.md` (do not edit that file manually) +- Do not commit files from `artifacts/` unless they are tracked (e.g. `artifacts/docs/SERVICES_ADDITIONAL.md`) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..1f014396 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,116 @@ +# Contributing to stack + +Thank you for your interest in contributing! + +The fullstack environment composes several services, among those are the following first-party: + +| Repository | Required | Profile | Access | +|---|---|---|---| +| [maevsi/android](https://github.com/maevsi/android) | optional | — | public | +| [maevsi/ios](https://github.com/maevsi/ios) | optional | — | public | +| [maevsi/postgraphile](https://github.com/maevsi/postgraphile) | ✅ | `default` | public | +| [maevsi/reccoom](https://github.com/maevsi/reccoom) | optional | `recommendation` | private | +| [maevsi/sqitch](https://github.com/maevsi/sqitch) | ✅ | `default` | public | +| [maevsi/stack](https://github.com/maevsi/stack) | ✅ | — | public | +| [maevsi/vibetype](https://github.com/maevsi/vibetype) | ✅ | `default` | public | + +## Development Setup + +There are two development modes: + +| Mode | When to use | Setup | Where to start | +|---|---|---|---| +| **Frontend only** | Working on UI, i18n, or anything that doesn't require running backend services | Manual only | [Vibetype repository](https://github.com/maevsi/vibetype#development) | +| **Fullstack** | Working on backend services, the database, the API, or any cross-cutting concern | Automated or manual | This guide (continue reading) | + +> 🪟 **Windows users:** Set up [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) first and continue inside the Linux subsystem. +> If you use VS Code, see [VS Code + WSL](https://learn.microsoft.com/en-us/windows/wsl/tutorials/wsl-vscode). + +### Automated Setup + +```sh +dargstack init +``` + +### Manual Setup + +If you prefer to step through each action yourself: + +1. Install prerequisites + + 1. [Git](https://git-scm.com/): version control + 2. [Docker](https://docs.docker.com/engine/install/): container runtime + 3. [dargstack](https://github.com/dargstack/dargstack#install): stack management CLI + + +1. Create a parent directory and clone the sibling repositories into it: + + ```sh + mkdir vibetype && cd vibetype + git clone git@github.com:maevsi/android.git # optional + git clone git@github.com:maevsi/ios.git # optional + git clone git@github.com:maevsi/postgraphile.git + git clone git@github.com:maevsi/reccoom.git # optional, private + git clone git@github.com:maevsi/sqitch.git + git clone git@github.com:maevsi/stack.git + git clone git@github.com:maevsi/vibetype.git + ``` + +
+ Click here if you don't have SSH set up (you should!) to use HTTPS URLs instead + + + ```sh + mkdir vibetype && cd vibetype + git clone https://github.com/maevsi/android.git # optional + git clone https://github.com/maevsi/ios.git # optional + git clone https://github.com/maevsi/postgraphile.git + git clone https://github.com/maevsi/reccoom.git # optional, private + git clone https://github.com/maevsi/sqitch.git + git clone https://github.com/maevsi/stack.git + git clone https://github.com/maevsi/vibetype.git + ``` +
+ +2. Initialize all cloned projects for development according to their READMEs. + +3. Build development container images: + + ```sh + cd stack + dargstack build + ``` + + An interactive selection dialog will let you choose which services to build. + +4. Deploy: + + ```sh + dargstack deploy + ``` + +5. You should now be able to access Vibetype at [https://app.localhost](https://app.localhost) 🎉 + + +## Guidelines + +### Git & GitHub + +Follow [@dargmuesli's Contributing Guidelines](https://gist.github.com/dargmuesli/430b7d902a22df02d88d1969a22a81b5#contribution-workflow) for branch naming, commit formatting, and the pull request workflow. + +### Semantic Versioning + +Read [@dargmuesli's guide on Semantic Versioning](https://gist.github.com/dargmuesli/430b7d902a22df02d88d1969a22a81b5#file-semantic-versioning-md) for how to format PR, issue and commit titles. + +### dargstack + +- Service files live in `src/development//compose.yaml` (full Compose document) and `src/production//compose.yaml` (production delta only). +- Run `dargstack build` to interactively select and build development container images after making changes to a service's source code. +- Run `dargstack document` to regenerate `artifacts/docs/README.md` after adding or modifying services. +- Do not edit `artifacts/` files directly: they are generated or gitignored. + +### Code Style + +- Keep YAML keys sorted lexicographically where order is semantically irrelevant. +- Use natural language in comments; refer to code artifacts with backticks. +- Do not use abbreviations in names unless omitting them would look unnatural. diff --git a/Dockerfile.md b/Dockerfile.md new file mode 100644 index 00000000..65fb1158 --- /dev/null +++ b/Dockerfile.md @@ -0,0 +1,3 @@ +# +FROM ghcr.io/dargstack/dargstack:4.0.0-beta.16 +# diff --git a/README.md b/README.md index 579bc2b0..42493229 100644 --- a/README.md +++ b/README.md @@ -1,447 +1,26 @@ -# stack +[![ci status][ci-image]][ci-url] +[ci-image]: https://img.shields.io/github/actions/workflow/status/maevsi/stack/ci.yml +[ci-url]: https://github.com/maevsi/stack/actions/workflows/ci.yml -The Docker stack configuration for [vibetype.app](https://vibetype.app/). - -This project is deployed in accordance to the [DargStack template](https://github.com/dargstack/dargstack_template/) to make deployment a breeze. It is closely related to [Vibetype's source code](https://github.com/maevsi/vibetype/). - -## Table of Contents - - - 1. [x-shared](#x-shared) - - 2. [secrets](#secrets) - - 3. [services](#services) - - 4. [volumes](#volumes) - - -## x-shared - - - - ### `zammad-service` - - You can access the helpdesk at [zammad.app.localhost](https://zammad.app.localhost/). - - -## secrets +# @maevsi/stack +The Docker stack configuration for [vibetype.app](https://vibetype.app/). - - ### `elasticsearch-keystore_password` - - The search engine's password for the keystore. - - - ### `elasticsearch-password` - - The search engine's password for the default user. - - - ### `grafana_admin_email` - - The observation dashboard's admin email. - - - ### `grafana_admin_password` - - The observation dashboard's admin password. - - - ### `grafana_admin_user` - - The observation dashboard's admin user. - - - ### `grafana_discord_webhook` - - The observation dashboard's contact point for Discord. - - - ### `jobber_aliases` - - The job scheduler's SMTP client mail alias. - - - ### `jobber_aws-bucket` - - The job scheduler's AWS bucket name. - - - ### `jobber_aws-configuration` - - The job scheduler's AWS configuration. - - - ### `jobber_aws-credentials` - - The job scheduler's AWS credentials. - - - ### `jobber_msmtprc` - - The job scheduler's SMTP client configuration. - - - ### `portainer_admin-password` - - The container manager's admin password. - - - ### `postgraphile_connection` - - The GraphQL API's database URI. - - - ### `postgraphile_jwt-secret` - - The GraphQL API's JWT secret. - - - ### `postgraphile_owner-connection` - - The GraphQL API's database owner URI. - - - ### `postgres-backup_db` ![production](https://img.shields.io/badge/-production-informational.svg?style=flat-square) - - The database's name. - - - ### `postgres_db` - - The database's name. - - - ### `postgres_password` - - The database's password. - - - ### `postgres_role_service_grafana_password` - - The password of the observation dashboard's database role. - - - ### `postgres_role_service_grafana_username` - - The username of the observation dashboard's database role. - - - ### `postgres_role_service_postgraphile_password` - - The password of the GraphQL API database wrapper's database role. - - - ### `postgres_role_service_postgraphile_username` - - The username of the GraphQL API database wrapper's database role. - - - ### `postgres_role_service_reccoom_password` - - The password of the recommendation engine's database role. - - - ### `postgres_role_service_reccoom_username` - - The username of the recommendation engine's database role. - - - ### `postgres_role_service_vibetype_password` - - The `tusd` database role's password. - - - ### `postgres_role_service_vibetype_username` - - The `tusd` database role's password. - - - ### `postgres_role_service_zammad_password` - - The password of the customer service database role. - - - ### `postgres_role_service_zammad_username` - - The username of the customer service database role. - - - ### `postgres_user` - - The database's default user. - - - ### `reccoom_ingest-api-key` - - The AI provider's API key for the recommendation engine. - - - ### `reccoom_model-api-key` - - The AI model provider's API key. - - - ### `reccoom_openai-api-key` - - The AI provider's API key for the recommendation engine. - - - ### `reccoom_sentry-dsn` - - The Sentry DSN for the AI service. - - - ### `sqitch_target` - - The database change management application's database connection string. - - - ### `traefik_cf-dns-api-token` ![production](https://img.shields.io/badge/-production-informational.svg?style=flat-square) - - The DNS provider's DNS API token. - - - ### `traefik_cf-zone-api-token` ![production](https://img.shields.io/badge/-production-informational.svg?style=flat-square) - - The DNS provider's zone API token. - - - ### `tusd_aws` - - The upload service's s3 credentials file. - - - ### `vibetype_api-notification-secret` - - The notification endpoint's secret. - - - ### `vibetype_aws-credentials` - - The cloud computing provider's user credentials. - - - ### `vibetype_firebase-service-account-credentials` - - The notification provider's service account credentials. - - - ### `vibetype_openai-api-key` - - The AI provider's API key for the frontend. - - - ### `vibetype_turnstile-key` - - The captcha provider's application key. - - - ### `vibetype_zammad` - - The ticket system's configuration. - +This project is managed with [dargstack](https://github.com/dargstack/dargstack/) and is closely related to [Vibetype's source code](https://github.com/maevsi/vibetype/). -## services +## Documentation +To see which services, secrets and volumes this stack includes, head over to [`artifacts/docs/README.md`](artifacts/docs/README.md). - - ### `adminer` - - You can access the database's frontend at [adminer.app.localhost](https://adminer.app.localhost/). - This information is required for login: - - | | | - | -------- | ------------------- | - | System | PostgreSQL | - | Server | postgres | - | Username | [postgres_user] | - | Password | [postgres_password] | - | Database | [postgres_db] | - - Values in square brackets are [Docker secrets](https://docs.docker.com/engine/swarm/secrets/). - - - ### `cadvisor` - - You can access the container metrics at [cadvisor.app.localhost](https://cadvisor.app.localhost/). - - - ### `cloudflared` ![production](https://img.shields.io/badge/-production-informational.svg?style=flat-square) - - You can configure the secure tunnel at [dash.cloudflare.com](https://dash.cloudflare.com/). - - - ### `debezium` - - You can see how changes in the database end up in the event stream using `redpanda-console`. - - - ### `debezium-postgres-connector` - - You can check the database connector's setup logs using `portainer`. - - - ### `elasticsearch` - - You cannot access the search engine via a web interface. - - - ### `geoip` - - You cannot access the ip geolocator via a web interface. - - - ### `grafana` - - You can access the observation dashboard at [grafana.app.localhost](https://grafana.app.localhost/). - - - ### `jobber` - - You cannot access the jobber via a web interface. - - - ### `memcached` - - You cannot access the caching system via a web interface. - - - ### `minio` ![development](https://img.shields.io/badge/-development-informational.svg?style=flat-square) - - You can access the s3 console at [minio.app.localhost](https://minio.app.localhost/). - You can access the s3 api service at [s3.app.localhost](https://s3.app.localhost/) if you want to access via cli from outside the stack. - - - ### `node-exporter` - - You can view host metrics in the Grafana observation dashboard. - - - ### `portainer` - - You can access the container manager's frontend at [portainer.app.localhost](https://portainer.app.localhost/). - - - ### `portainer-agent` - - You cannot access the container manager's agent directly. - - - ### `postgraphile` - - You can access the GraphQL API for the PostgreSQL database at [postgraphile.app.localhost](https://postgraphile.app.localhost/). - - - ### `postgres` - - You can access the database via `adminer`. - - - ### `postgres_backup` ![production](https://img.shields.io/badge/-production-informational.svg?style=flat-square) - - You cannot access the database backup directly. - - - ### `prometheus` - - You can access the metrics monitoring at [prometheus.app.localhost](https://prometheus.app.localhost/). - - - ### `reccoom` - - You cannot access the recommendation service directly. - - - ### `reccoom_consumer` - - You can track the recommender's event streaming consumer using `redpanda-console`. - - - ### `reccoom_migration` - - You cannot access the recommender's database migration service directly. - - - ### `reccoom_postgres` - - You can access reccoom's database via `adminer`. - - - ### `redis` - - You cannot access the caching system via a web interface. - - - ### `redpanda` - - You can access the event streaming platform's ui as described under `redpanda-console`. - - - ### `redpanda-console` - - You can access the event streaming platform's ui at [redpanda.app.localhost](https://redpanda.app.localhost/). - - - ### `sqitch` - - You cannot access the database migrations directly. - - - ### `traefik` - - You can access the reverse proxy's dashboard at [traefik.app.localhost](https://traefik.app.localhost/). - - - ### `traefik_certs-dumper` ![production](https://img.shields.io/badge/-production-informational.svg?style=flat-square) - - You cannot access the reverse proxy's certificate helper directly. - - - ### `tusd` - - You can access the upload service at [tusd.app.localhost](https://tusd.app.localhost/). - - - ### `vibetype` - - You can access the main project's frontend at [app.localhost](https://app.localhost/). - - - ### `zammad-backup` - - You cannot access the helpdesk backup service via a web interface. - - - ### `zammad-init` - - You cannot access the helpdesk initialization service via a web interface. - - - ### `zammad-nginx` - - You can access the helpdesk at [zammad.app.localhost](https://zammad.app.localhost/). - - - ### `zammad-railsserver` - - You cannot access the helpdesk application server directly. - - - ### `zammad-scheduler` - - You cannot access the helpdesk scheduler directly. - - - ### `zammad-websocket` - - You cannot access the helpdesk websocket server directly. - +## Development Setup -## volumes +> 💡 **Windows users:** Run these steps inside [WSL](https://docs.microsoft.com/en-us/windows/wsl/install). +> 📖 **New to the project? Read [CONTRIBUTING.md](CONTRIBUTING.md) first** to understand the repository structure, the development modes, and what each component does. You will need this context to work effectively beyond the quick setup below. - - ### `acme_data` ![production](https://img.shields.io/badge/-production-informational.svg?style=flat-square) - - The reverse proxy's certificate data. - - - ### `debezium_kafka_configuration` - - The change data capture's configuration. - - - ### `debezium_kafka_data` - - The change data capture's data. - - - ### `debezium_kafka_logs` - - The change data capture's logs. - - - ### `elasticsearch-configuration` - - The search engine's configuration. - - - ### `elasticsearch_data` - - The search engine's data. - - - ### `grafana_data` - - The observation dashboard's data. - - - ### `minio_data` - - The s3 server's data. - - - ### `pnpm_data` - - The node package manager's data. - - - ### `portainer_data` - - The container manager's data. - - - ### `postgraphile_data` - - The GraphQL API's data. - - - ### `postgres_data` - - The database's data. - - - ### `prometheus_data` - - The metrics monitoring's data. - - - ### `reccoom_data` - - The recommender's model cache. - - - ### `reccoom_postgres_data` - - The recommendation database's data. - - - ### `redis_data` - - The caching system's data. - - - ### `redpanda_data` - - The message queue's data. - - - ### `vibetype_data` - - The frontend's data. - - - ### `zammad-backup_data` - - The helpdesk backup's data. - - - ### `zammad_data` - - The helpdesk's data. - +To start a local fullstack development environment, run the setup script from the directory where you want to clone the project: +```sh +dargstack init +``` diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..a0733052 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,57 @@ +# Vibetype Disclosure Policy + +## 1 Introduction + +The security of Vibetype is a top priority for our team. We believe in transparency and collaboration with the community to identify and address potential security vulnerabilities. This disclosure policy outlines the procedures for reporting security issues in Vibetype and how we handle such reports. + +## 2 Reporting a Security Issue + +If you discover a security vulnerability in Vibetype, we encourage you to report it to us promptly. To report a security issue, please follow these steps: + +Send an email to contact+security@maev.si with the subject line "Security Issue: [Brief Description]." Please provide a detailed description of the vulnerability, including the following: + +- A concise summary of the issue. +- A detailed explanation of the vulnerability and its potential impact. +- Steps to reproduce the vulnerability (if applicable). +- Any additional information that can help us understand and address the issue. + +## 3 Handling of Reports + +Upon receiving a security report, the Vibetype team will follow these steps: + +### 3.1 Acknowledgment + +We will acknowledge your report as soon as possible and provide an estimated timeline for the review and resolution process. + +### 3.2 Evaluation + +Our team will review the reported issue to assess its validity and severity. We may request additional information from you if necessary. + +### 3.3 Resolution + +Once we have confirmed and understood the vulnerability, we will develop and test a fix. We will try to resolve the issue as quickly as possible. + +### 3.4 Communication + +We will keep you informed of our progress throughout the process and notify you when a fix is available. If the issue affects multiple projects, we may coordinate with other project maintainers and vendors. + +## 4 Disclosure + +We believe in responsible disclosure to protect our users. + +If the issue is resolved, we will coordinate with you to establish a mutually agreed-upon release date for the fix. +We will issue a security advisory and update the project's documentation once the fix is publicly available. + +## 5 Credit and Recognition + +We highly value the contributions of the security community and will provide credit to individuals or organizations who responsibly report security vulnerabilities. However, if you prefer to remain anonymous, we will respect your wishes. + +## 6 Legal Protection + +Vibetype will not pursue legal action against security researchers who follow this disclosure policy and act in good faith. We appreciate your efforts to help us maintain the security of our project. + +## 7 Changes to this Policy + +This security disclosure policy may be updated or revised from time to time. + +Last Updated: 2026-04-03 diff --git a/artifacts/.gitignore b/artifacts/.gitignore new file mode 100644 index 00000000..87bd3818 --- /dev/null +++ b/artifacts/.gitignore @@ -0,0 +1,4 @@ +audit-log/ +certificates/ +secrets/ +.env.merged \ No newline at end of file diff --git a/artifacts/docs/README.md b/artifacts/docs/README.md new file mode 100644 index 00000000..0f890829 --- /dev/null +++ b/artifacts/docs/README.md @@ -0,0 +1,188 @@ +# vibetype + +The Docker stack configuration for [vibetype.app](https://vibetype.app/). See [maevsi](https://github.com/maevsi). + +## Profiles + +### analytics + +Services: cadvisor, grafana, node-exporter, prometheus + +### default + +Services: adminer, cloudflared, portainer, portainer-agent, postgraphile, postgres, sqitch, traefik, vibetype + +### event-streaming + +Services: debezium, debezium-postgres-connector, redpanda, redpanda-console + +### recommendation + +Services: reccoom, reccoom-consumer, reccoom-migration, reccoom-postgres + +### upload + +Services: minio, tusd + +### zammad + +Services: elasticsearch, memcached, redis, zammad-backup, zammad-init, zammad-nginx, zammad-railsserver, zammad-scheduler, zammad-websocket + +## Services + +### adminer + +You can access the database's frontend at [adminer.app.localhost](https://adminer.app.localhost/). +This information is required for login: + +| | | +| -------- | ------------------- | +| System | PostgreSQL | +| Server | postgres | +| Username | [postgres-user] | +| Password | [postgres-password] | +| Database | [postgres-db] | + +Values in square brackets are [Docker secrets](https://docs.docker.com/engine/swarm/secrets/). + +### cadvisor + +You can access the container metrics at [cadvisor.app.localhost](https://cadvisor.app.localhost/). + +### cloudflared *(production only)* + +You can configure the secure tunnel at [dash.cloudflare.com](https://dash.cloudflare.com/). + +### debezium + +You can see how changes in the database end up in the event stream using `redpanda-console`. + +### debezium-postgres-connector + +You can check the database connector's setup logs using `portainer`. + +### elasticsearch + +You cannot access the search engine via a web interface. + +### geoip + +You cannot access the ip geolocator via a web interface. + +### grafana + +You can access the observation dashboard at [grafana.app.localhost](https://grafana.app.localhost/). + +### jobber + +You cannot access the jobber via a web interface. + +### memcached + +You cannot access the caching system via a web interface. + +### minio + +You can access the s3 console at [minio.app.localhost](https://minio.app.localhost/). +You can access the s3 api service at [s3.app.localhost](https://s3.app.localhost/) if you want to access via cli from outside the stack. + +### node-exporter + +You can view host metrics in the Grafana observation dashboard. + +### portainer + +You can access the container manager's frontend at [portainer.app.localhost](https://portainer.app.localhost/). + +### portainer-agent + +You cannot access the container manager's agent directly. + +### postgraphile + +You can access the GraphQL API for the PostgreSQL database at [postgraphile.app.localhost](https://postgraphile.app.localhost/). + +### postgres + +You can access the database via `adminer`. + +### postgres-backup *(production only)* + +You cannot access the database backup directly. + +### prometheus + +You can access the metrics monitoring at [prometheus.app.localhost](https://prometheus.app.localhost/). + +### reccoom + +You cannot access the recommendation service directly. + +### reccoom-consumer + +You can track the recommender's event streaming consumer using `redpanda-console`. + +### reccoom-migration + +You cannot access the recommender's database migration service directly. + +### reccoom-postgres + +You can access reccoom's database via `adminer`. + +### redis + +You cannot access the caching system via a web interface. + +### redpanda + +You can access the event streaming platform's ui as described under `redpanda-console`. + +### redpanda-console + +You can access the event streaming platform's ui at [redpanda.app.localhost](https://redpanda.app.localhost/). + +### sqitch + +You cannot access the database migrations directly. + +### traefik + +You can access the reverse proxy's dashboard at [traefik.app.localhost](https://traefik.app.localhost/). + +### traefik-certs-dumper *(production only)* + +You cannot access the reverse proxy's certificate helper directly. + +### tusd + +You can access the upload service at [tusd.app.localhost](https://tusd.app.localhost/). + +### vibetype + +You can access the main project's frontend at [app.localhost](https://app.localhost/). + +### zammad-backup + +You cannot access the helpdesk backup service via a web interface. + +### zammad-init + +You cannot access the helpdesk initialization service via a web interface. + +### zammad-nginx + +You can access the helpdesk at [zammad.app.localhost](https://zammad.app.localhost/). + +### zammad-railsserver + +You cannot access the helpdesk application server directly. + +### zammad-scheduler + +You cannot access the helpdesk scheduler directly. + +### zammad-websocket + +You cannot access the helpdesk websocket server directly. + diff --git a/NOTES.md b/artifacts/docs/SERVICES_ADDITIONAL.md similarity index 91% rename from NOTES.md rename to artifacts/docs/SERVICES_ADDITIONAL.md index ce1846d5..3ac38388 100644 --- a/NOTES.md +++ b/artifacts/docs/SERVICES_ADDITIONAL.md @@ -1,4 +1,5 @@ # Additional Services + - ## `status` ![production](https://img.shields.io/badge/-production-informational.svg?style=flat-square) [![Website Uptime Monitoring](https://app.statuscake.com/button/index.php?Track=9CFPA32m2n&Days=1000&Design=6)](https://www.statuscake.com) - You can access the status dashboard at [status.vibetype.app](https://status.vibetype.app/) \ No newline at end of file + You can access the status dashboard at [status.vibetype.app](https://status.vibetype.app/) diff --git a/dargstack.env b/dargstack.env deleted file mode 100644 index aff39cd0..00000000 --- a/dargstack.env +++ /dev/null @@ -1 +0,0 @@ -PROJECT_NAME=vibetype \ No newline at end of file diff --git a/dargstack.yaml b/dargstack.yaml new file mode 100644 index 00000000..edaacb1c --- /dev/null +++ b/dargstack.yaml @@ -0,0 +1,28 @@ +# Dargstack configuration file + +environment: + # development: + # domain: app.localhost # optional, defaults to "app.localhost" + # certificate: + # include: [] # optional, domains added to TLS cert + # # - "*.app.localhost" + # exclude: [] # optional, domains removed from TLS cert + production: + domain: vibetype.app # optional, defaults to "app.localhost" + # branch: main # optional, defaults to "main" + # tag: latest # optional, defaults to "latest" + +metadata: + compatibility: ">=4.0.0-0 <5.0.0" + name: "vibetype" + source: + name: "maevsi" + url: "https://github.com/maevsi" + +runtime: + # deploy: + # volumes: + # prompt: true # optional, defaults to true + build: + mode: missing # optional, "always" | "missing" + # sudo: auto # optional, "auto" | "always" | "never" \ No newline at end of file diff --git a/package.json b/package.json deleted file mode 100644 index ad8c6c2c..00000000 --- a/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "author": "Jonas Thelemann ", - "description": "Dargstack configuration for Vibetype.", - "devDependencies": { - "dargstack": "3.0.0", - "dargstack_rgen": "0.9.92" - }, - "devEngines": { - "packageManager": { - "name": "pnpm", - "version": "11.0.8" - } - }, - "engines": { - "node": "24" - }, - "license": "GPL-3.0-only", - "name": "@maevsi/stack", - "private": true, - "repository": "https://github.com/maevsi/stack.git", - "scripts": { - "prepare": "./src/development/certificates/mkcert.sh" - }, - "type": "module", - "version": "18.5.3" -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index dda792f8..00000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,168 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - devDependencies: - dargstack: - specifier: 3.0.0 - version: 3.0.0 - dargstack_rgen: - specifier: 0.9.92 - version: 0.9.92 - -packages: - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@6.2.3: - resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} - engines: {node: '>=12'} - - cliui@9.0.1: - resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} - engines: {node: '>=20'} - - dargstack@3.0.0: - resolution: {integrity: sha512-hJn6NSEDiDvkH+3THlnLGHyvxagrm+t7f1snRSNER0u5A+manl2Wy1A7oFq6tWGtBIj0DDVoT0llpMlh8R9xQw==} - engines: {node: '24'} - - dargstack_rgen@0.9.92: - resolution: {integrity: sha512-VuVYJrmRA4GystTLH2f/+FKt9meiPbz6QToMBqgIWiMt+NQfIsZffIhnw1xVIogVTrPOPLZ3iqTmZAMYMxrEcA==} - engines: {node: '24'} - hasBin: true - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - diff@9.0.0: - resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==} - engines: {node: '>=0.3.1'} - - emoji-regex@10.6.0: - resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-east-asian-width@1.6.0: - resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} - engines: {node: '>=18'} - - indento@1.1.14: - resolution: {integrity: sha512-K4cK97v4M/ucCAbe3LUpg994folYL0WnEiCFxHXAIowKLbBb/Ahiazkz3Ao5gRar4i9pDr3imcpq4suOu0FbNw==} - - json2md@2.0.3: - resolution: {integrity: sha512-ZPzh6Djvqz8grJMxKllfCHo0p+p7BsbZ1J95KcCJgvvfdoy7myuKrrkUp80Kpy+wGauykC0dYljLqLY0kENaOw==} - - string-width@7.2.0: - resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} - engines: {node: '>=18'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - - wrap-ansi@9.0.2: - resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} - engines: {node: '>=18'} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} - engines: {node: '>= 14.6'} - hasBin: true - - yargs-parser@22.0.0: - resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - - yargs@18.0.0: - resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=23} - -snapshots: - - ansi-regex@6.2.2: {} - - ansi-styles@6.2.3: {} - - cliui@9.0.1: - dependencies: - string-width: 7.2.0 - strip-ansi: 7.2.0 - wrap-ansi: 9.0.2 - - dargstack@3.0.0: {} - - dargstack_rgen@0.9.92: - dependencies: - deepmerge: 4.3.1 - diff: 9.0.0 - json2md: 2.0.3 - yaml: 2.9.0 - yargs: 18.0.0 - - deepmerge@4.3.1: {} - - diff@9.0.0: {} - - emoji-regex@10.6.0: {} - - escalade@3.2.0: {} - - get-caller-file@2.0.5: {} - - get-east-asian-width@1.6.0: {} - - indento@1.1.14: {} - - json2md@2.0.3: - dependencies: - indento: 1.1.14 - - string-width@7.2.0: - dependencies: - emoji-regex: 10.6.0 - get-east-asian-width: 1.6.0 - strip-ansi: 7.2.0 - - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - - wrap-ansi@9.0.2: - dependencies: - ansi-styles: 6.2.3 - string-width: 7.2.0 - strip-ansi: 7.2.0 - - y18n@5.0.8: {} - - yaml@2.9.0: {} - - yargs-parser@22.0.0: {} - - yargs@18.0.0: - dependencies: - cliui: 9.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - string-width: 7.2.0 - y18n: 5.0.8 - yargs-parser: 22.0.0 diff --git a/src/.gitignore b/src/.gitignore deleted file mode 100644 index 71cda2dc..00000000 --- a/src/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -**/backups/*/** -**/production/secrets/**/*.secret -*.crt -*.csr -*.env -*.key -!**/README.md -!**/*.template -production/stack.yml diff --git a/src/development/adminer/compose.yaml b/src/development/adminer/compose.yaml new file mode 100644 index 00000000..cba210ae --- /dev/null +++ b/src/development/adminer/compose.yaml @@ -0,0 +1,34 @@ +services: + adminer: + # You can access the database's frontend at [adminer.app.localhost](https://adminer.app.localhost/). + # This information is required for login: + # + # | | | + # | -------- | ------------------- | + # | System | PostgreSQL | + # | Server | postgres | + # | Username | [postgres-user] | + # | Password | [postgres-password] | + # | Database | [postgres-db] | + # + # Values in square brackets are [Docker secrets](https://docs.docker.com/engine/swarm/secrets/). + deploy: + labels: + - dargstack.profiles=default + - traefik.enable=true + - traefik.http.routers.adminer.entryPoints=web + - traefik.http.routers.adminer.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.adminer.rule=Host(`adminer.${STACK_DOMAIN}`) + - traefik.http.routers.adminer-secure.entryPoints=web-secure + - traefik.http.routers.adminer-secure.rule=Host(`adminer.${STACK_DOMAIN}`) + - traefik.http.routers.adminer-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.adminer.loadbalancer.server.port=8080 + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + image: adminer:5.4.2-standalone + volumes: + - ./configurations/adminer.css:/var/www/html/adminer.css:ro diff --git a/src/development/adminer/configurations/adminer.css b/src/development/adminer/configurations/adminer.css new file mode 100755 index 00000000..3da66c8c --- /dev/null +++ b/src/development/adminer/configurations/adminer.css @@ -0,0 +1,7 @@ +a { + color: blue; +} + +a:visited { + color: blue; +} diff --git a/src/development/cadvisor/compose.yaml b/src/development/cadvisor/compose.yaml new file mode 100644 index 00000000..65527456 --- /dev/null +++ b/src/development/cadvisor/compose.yaml @@ -0,0 +1,25 @@ +services: + cadvisor: + # You can access the container metrics at [cadvisor.app.localhost](https://cadvisor.app.localhost/). + deploy: + labels: + - dargstack.profiles=analytics + - traefik.enable=true + - traefik.http.routers.cadvisor.entryPoints=web + - traefik.http.routers.cadvisor.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.cadvisor.rule=Host(`cadvisor.${STACK_DOMAIN}`) + - traefik.http.routers.cadvisor-secure.entryPoints=web-secure + - traefik.http.routers.cadvisor-secure.rule=Host(`cadvisor.${STACK_DOMAIN}`) + - traefik.http.routers.cadvisor-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.cadvisor.loadbalancer.server.port=8080 + mode: global + placement: + constraints: + - node.platform.os == linux + image: ghcr.io/google/cadvisor:v0.60.3 + volumes: + - /:/rootfs:ro + - /var/run:/var/run:ro + - /sys:/sys:ro + - /var/lib/docker/:/var/lib/docker:ro + - /dev/disk/:/dev/disk:ro diff --git a/src/development/certificates/mkcert.sh b/src/development/certificates/mkcert.sh deleted file mode 100755 index dcdb64cb..00000000 --- a/src/development/certificates/mkcert.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -THIS=$(dirname "$(readlink -f "$0")") - -create() { - NAME="$1" - shift - CONTENT=$* - - path="$THIS/$NAME" - certfile="$path.crt" - keyfile="$path.key" - - if [ "$CONTENT" != "" ]; then - # shellcheck disable=SC2086 - mkcert \ - -cert-file "$certfile" \ - -ecdsa \ - -key-file "$keyfile" $CONTENT - fi - - cat "$(mkcert -CAROOT)/rootCA.pem" >> "$certfile" -} - -echo "key crt" | tr ' ' '\n' | while read -r glob; do - if test -n "$(find "$THIS" -maxdepth 1 -name "*.$glob" -print -quit)"; then - rm "$THIS"/*."$glob" - fi -done - -create "root" -create "traefik" \ - `# adminer` "adminer.app.localhost" \ - `# cadvisor` "cadvisor.app.localhost" \ - `# grafana` "grafana.app.localhost" \ - `# minio` "minio.app.localhost" \ - `# portainer` "portainer.app.localhost" \ - `# postgraphile` "postgraphile.app.localhost" \ - `# prometheus` "prometheus.app.localhost" \ - `# reccoom` "reccoom.app.localhost" \ - `# redpanda` "redpanda.app.localhost" \ - `# traefik` "traefik.app.localhost" \ - `# tusd` "tusd.app.localhost" \ - `# vibetype` "app.localhost" "www.app.localhost" "127.0.0.1" "0.0.0.0" \ - `# zammad` "zammad.app.localhost" \ No newline at end of file diff --git a/src/development/compose.yaml b/src/development/compose.yaml new file mode 100644 index 00000000..f5dcf3b3 --- /dev/null +++ b/src/development/compose.yaml @@ -0,0 +1,4 @@ +volumes: + pnpm-data: + # The node package manager's data. + {} diff --git a/src/development/configurations/traefik/dynamic.yml b/src/development/configurations/traefik/dynamic.yml deleted file mode 100644 index 5fdce1e4..00000000 --- a/src/development/configurations/traefik/dynamic.yml +++ /dev/null @@ -1,7 +0,0 @@ -tls: - certificates: - - certFile: /etc/traefik/acme/traefik.crt - keyFile: /etc/traefik/acme/traefik.key - options: - mintls13: - minVersion: VersionTLS13 \ No newline at end of file diff --git a/src/development/debezium/compose.yaml b/src/development/debezium/compose.yaml new file mode 100644 index 00000000..c9f56a57 --- /dev/null +++ b/src/development/debezium/compose.yaml @@ -0,0 +1,49 @@ +services: + debezium: + # You can see how changes in the database end up in the event stream using `redpanda-console`. + deploy: + labels: + - dargstack.profiles=event-streaming + environment: + BOOTSTRAP_SERVERS: redpanda:9092 + CONFIG_STORAGE_TOPIC: connect_configs + GROUP_ID: 1 + OFFSET_STORAGE_TOPIC: connect_offsets + STATUS_STORAGE_TOPIC: connect_statuses + healthcheck: + test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://localhost:8083/connectors"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 90s + image: quay.io/debezium/connect:3.6 + volumes: + - debezium-kafka-configuration:/kafka/config + - debezium-kafka-data:/kafka/data + - debezium-kafka-logs:/kafka/logs + debezium-postgres-connector: + # You can check the database connector's setup logs using `portainer`. + command: /entrypoint.sh + deploy: + labels: + - dargstack.profiles=event-streaming + restart_policy: + condition: on-failure + entrypoint: sh + image: curlimages/curl:8.21.0 + secrets: + - postgres-db + - postgres-password + - postgres-user + volumes: + - ./configurations/entrypoint.sh:/entrypoint.sh:ro +volumes: + debezium-kafka-configuration: + # The change data capture's configuration. + {} + debezium-kafka-data: + # The change data capture's data. + {} + debezium-kafka-logs: + # The change data capture's logs. + {} diff --git a/src/production/configurations/debezium-postgres-connector/entrypoint.sh b/src/development/debezium/configurations/entrypoint.sh similarity index 88% rename from src/production/configurations/debezium-postgres-connector/entrypoint.sh rename to src/development/debezium/configurations/entrypoint.sh index d95c7c1e..4a61818f 100755 --- a/src/production/configurations/debezium-postgres-connector/entrypoint.sh +++ b/src/development/debezium/configurations/entrypoint.sh @@ -3,9 +3,9 @@ set -eu CONNECTOR_NAME="postgres-connector" DEBEZIUM_URL="http://debezium:8083/connectors" -POSTGRES_DB=$(cat /run/secrets/postgres_db) -POSTGRES_PASSWORD=$(cat /run/secrets/postgres_password) -POSTGRES_USER=$(cat /run/secrets/postgres_user) +POSTGRES_DB=$(cat /run/secrets/postgres-db) +POSTGRES_PASSWORD=$(cat /run/secrets/postgres-password) +POSTGRES_USER=$(cat /run/secrets/postgres-user) # Wait for Debezium to be healthy (REST API ready) echo "Waiting for Debezium to be ready..." diff --git a/src/development/elasticsearch/compose.yaml b/src/development/elasticsearch/compose.yaml new file mode 100644 index 00000000..a13b53bd --- /dev/null +++ b/src/development/elasticsearch/compose.yaml @@ -0,0 +1,60 @@ +secrets: + elasticsearch-keystore-password: + # The search engine's password for the keystore. + file: ~~/artifacts/secrets/elasticsearch-keystore-password.secret + elasticsearch-password: + # The search engine's password for the default user. + file: ~~/artifacts/secrets/elasticsearch-password.secret +services: + elasticsearch: + # You cannot access the search engine via a web interface. + deploy: + labels: + - dargstack.profiles=zammad + replicas: 0 # TODO: reenable once server setup is more fault tolerant + environment: + bootstrap.memory_lock: "true" + discovery.type: single-node + ELASTIC_PASSWORD_FILE: /run/secrets/elasticsearch-password + ES_JAVA_OPTS: -Xms1g -Xmx1g + KEYSTORE_PASSWORD_FILE: /run/secrets/elasticsearch-keystore-password + network.publish_host: elasticsearch + # healthcheck: + # test: ["CMD-SHELL", "NETRC=$(mktemp) && printf 'machine localhost\\nlogin elastic\\npassword %s\\n' \"$(cat /run/secrets/elasticsearch-password)\" > \"$NETRC\" && curl -fsS --netrc-file \"$NETRC\" --cacert /usr/share/elasticsearch/config/certs/http_ca.crt 'https://localhost:9200/_cluster/health?wait_for_status=yellow&timeout=5s' && rm -f \"$NETRC\" || { rm -f \"$NETRC\"; exit 1; }"] + # interval: 30s + # timeout: 10s + # retries: 3 + # start_period: 60s + image: elasticsearch:8.19.18 + secrets: + - source: elasticsearch-keystore-password + uid: "1000" + gid: "1000" + mode: 0o400 + - source: elasticsearch-password + uid: "1000" + gid: "1000" + mode: 0o400 + ulimits: + nofile: + soft: 65535 + hard: 65535 + memlock: + soft: -1 + hard: -1 + volumes: + - elasticsearch-configuration:/usr/share/elasticsearch/config + - elasticsearch-data:/usr/share/elasticsearch/data +volumes: + elasticsearch-configuration: + # The search engine's configuration. + {} + elasticsearch-data: + # The search engine's data. + {} +x-dargstack: + secrets: + elasticsearch-keystore-password: + type: random_string + elasticsearch-password: + type: random_string diff --git a/src/development/geoip/compose.yaml b/src/development/geoip/compose.yaml new file mode 100644 index 00000000..037c4314 --- /dev/null +++ b/src/development/geoip/compose.yaml @@ -0,0 +1,10 @@ +services: + geoip: + # You cannot access the ip geolocator via a web interface. + healthcheck: + test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://localhost:8080/actuator/health"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + image: ghcr.io/observabilitystack/geoip-api:2026-02 diff --git a/src/development/grafana/compose.yaml b/src/development/grafana/compose.yaml new file mode 100644 index 00000000..9c588da3 --- /dev/null +++ b/src/development/grafana/compose.yaml @@ -0,0 +1,71 @@ +secrets: + grafana-admin-email: + # The observation dashboard's admin email. + file: ~~/artifacts/secrets/grafana-admin-email.secret + grafana-admin-password: + # The observation dashboard's admin password. + file: ~~/artifacts/secrets/grafana-admin-password.secret + grafana-admin-user: + # The observation dashboard's admin user. + file: ~~/artifacts/secrets/grafana-admin-user.secret + grafana-discord-webhook: + # The observation dashboard's contact point for Discord. + file: ~~/artifacts/secrets/grafana-discord-webhook.secret +services: + grafana: + # You can access the observation dashboard at [grafana.app.localhost](https://grafana.app.localhost/). + deploy: + labels: + - dargstack.profiles=analytics + - traefik.enable=true + - traefik.http.routers.grafana.entryPoints=web + - traefik.http.routers.grafana.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.grafana.rule=Host(`grafana.${STACK_DOMAIN}`) + - traefik.http.routers.grafana-secure.entryPoints=web-secure + - traefik.http.routers.grafana-secure.rule=Host(`grafana.${STACK_DOMAIN}`) + - traefik.http.routers.grafana-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.grafana.loadbalancer.server.port=3000 + environment: + GF_DATABASE_HOST: postgres:5432 + GF_DATABASE_PASSWORD__FILE: /run/secrets/postgres-role-service-grafana-password + GF_DATABASE_TYPE: postgres + GF_DATABASE_USER__FILE: /run/secrets/postgres-role-service-grafana-username + GF_SECURITY_ADMIN_EMAIL__FILE: /run/secrets/grafana-admin-email + GF_SECURITY_ADMIN_PASSWORD__FILE: /run/secrets/grafana-admin-password + GF_SECURITY_ADMIN_USER__FILE: /run/secrets/grafana-admin-user + GF_SERVER_ROOT_URL: https://grafana.${STACK_DOMAIN}/ + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api/health"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 30s + image: grafana/grafana:12.4.5 + secrets: + - grafana-admin-email + - grafana-admin-password + - grafana-admin-user + - grafana-discord-webhook + - postgres-db + - postgres-role-service-grafana-password + - postgres-role-service-grafana-username + volumes: + - ./configurations/dashboards:/var/lib/grafana/dashboards:ro + - ./configurations/provisioning:/etc/grafana/provisioning:ro + - grafana-data:/var/lib/grafana +volumes: + grafana-data: + # The observation dashboard's data. + {} +x-dargstack: + secrets: + grafana-admin-email: + insecure_default: admin@localhost + type: insecure_default + grafana-admin-password: + type: random_string + grafana-admin-user: + type: wordlist_word + grafana-discord-webhook: + hint: https://discord.com/api/webhooks// + type: third_party diff --git a/src/production/configurations/grafana/dashboards/Infrastructure/Advanced/grafana.json b/src/development/grafana/configurations/dashboards/Infrastructure/Advanced/grafana.json similarity index 100% rename from src/production/configurations/grafana/dashboards/Infrastructure/Advanced/grafana.json rename to src/development/grafana/configurations/dashboards/Infrastructure/Advanced/grafana.json diff --git a/src/production/configurations/grafana/dashboards/Infrastructure/Advanced/prometheus-2.0.json b/src/development/grafana/configurations/dashboards/Infrastructure/Advanced/prometheus-2.0.json similarity index 100% rename from src/production/configurations/grafana/dashboards/Infrastructure/Advanced/prometheus-2.0.json rename to src/development/grafana/configurations/dashboards/Infrastructure/Advanced/prometheus-2.0.json diff --git a/src/production/configurations/grafana/dashboards/Infrastructure/cadvisor.json b/src/development/grafana/configurations/dashboards/Infrastructure/cadvisor.json similarity index 100% rename from src/production/configurations/grafana/dashboards/Infrastructure/cadvisor.json rename to src/development/grafana/configurations/dashboards/Infrastructure/cadvisor.json diff --git a/src/production/configurations/grafana/dashboards/Infrastructure/node-exporter.json b/src/development/grafana/configurations/dashboards/Infrastructure/node-exporter.json similarity index 100% rename from src/production/configurations/grafana/dashboards/Infrastructure/node-exporter.json rename to src/development/grafana/configurations/dashboards/Infrastructure/node-exporter.json diff --git a/src/production/configurations/grafana/dashboards/Infrastructure/operations.json b/src/development/grafana/configurations/dashboards/Infrastructure/operations.json similarity index 100% rename from src/production/configurations/grafana/dashboards/Infrastructure/operations.json rename to src/development/grafana/configurations/dashboards/Infrastructure/operations.json diff --git a/src/production/configurations/grafana/dashboards/Infrastructure/redpanda.json b/src/development/grafana/configurations/dashboards/Infrastructure/redpanda.json similarity index 100% rename from src/production/configurations/grafana/dashboards/Infrastructure/redpanda.json rename to src/development/grafana/configurations/dashboards/Infrastructure/redpanda.json diff --git a/src/production/configurations/grafana/dashboards/Management/kpis.json b/src/development/grafana/configurations/dashboards/Management/kpis.json similarity index 100% rename from src/production/configurations/grafana/dashboards/Management/kpis.json rename to src/development/grafana/configurations/dashboards/Management/kpis.json diff --git a/src/production/configurations/grafana/provisioning/alerting/alert-notifications-pending.yaml b/src/development/grafana/configurations/provisioning/alerting/alert-notifications-pending.yaml similarity index 100% rename from src/production/configurations/grafana/provisioning/alerting/alert-notifications-pending.yaml rename to src/development/grafana/configurations/provisioning/alerting/alert-notifications-pending.yaml diff --git a/src/production/configurations/grafana/provisioning/alerting/contact-points.yaml b/src/development/grafana/configurations/provisioning/alerting/contact-points.yaml similarity index 94% rename from src/production/configurations/grafana/provisioning/alerting/contact-points.yaml rename to src/development/grafana/configurations/provisioning/alerting/contact-points.yaml index cf88e5ce..832c0958 100644 --- a/src/production/configurations/grafana/provisioning/alerting/contact-points.yaml +++ b/src/development/grafana/configurations/provisioning/alerting/contact-points.yaml @@ -1,7 +1,7 @@ apiVersion: 1 contactPoints: - orgId: 1 - name: 'Discord' + name: Discord receivers: - uid: aen6t8xrd6pkwb type: discord @@ -25,6 +25,6 @@ contactPoints: {{ template "__alert_details" .Alerts.Resolved }}{{ end }}{{ end }}{{ template "default.message_custom" . }} <@&1377144332154572831> - url: $__file{/run/secrets/grafana_discord_webhook} + url: $__file{/run/secrets/grafana-discord-webhook} use_discord_username: false disableResolveMessage: false diff --git a/src/production/configurations/grafana/provisioning/dashboards/file.yml b/src/development/grafana/configurations/provisioning/dashboards/file.yml similarity index 89% rename from src/production/configurations/grafana/provisioning/dashboards/file.yml rename to src/development/grafana/configurations/provisioning/dashboards/file.yml index 7129ad74..c23fbd8b 100644 --- a/src/production/configurations/grafana/provisioning/dashboards/file.yml +++ b/src/development/grafana/configurations/provisioning/dashboards/file.yml @@ -2,13 +2,13 @@ apiVersion: 1 providers: # an unique provider name. Required - - name: 'File' + - name: "File" # Org id. Default to 1 orgId: 1 # name of the dashboard folder. - folder: '' + folder: "" # folder UID. will be automatically generated if not specified - folderUid: '' + folderUid: "" # provider type. Default to 'file' type: file # disable dashboard deletion @@ -21,4 +21,4 @@ providers: # path to dashboard files on disk. Required when using the 'file' type path: /var/lib/grafana/dashboards # use folder names from filesystem to create folders in Grafana - foldersFromFilesStructure: true \ No newline at end of file + foldersFromFilesStructure: true diff --git a/src/development/grafana/configurations/provisioning/datasources/postgres.yaml b/src/development/grafana/configurations/provisioning/datasources/postgres.yaml new file mode 100644 index 00000000..9d53b3fc --- /dev/null +++ b/src/development/grafana/configurations/provisioning/datasources/postgres.yaml @@ -0,0 +1,14 @@ +apiVersion: 1 + +datasources: + - access: proxy + jsonData: + database: $__file{/run/secrets/postgres-db} + postgresVersion: 1500 + sslmode: disable + name: PostgreSQL + secureJsonData: + password: $__file{/run/secrets/postgres-role-service-grafana-password} + type: grafana-postgresql-datasource + url: postgres:5432 + user: $__file{/run/secrets/postgres-role-service-grafana-username} diff --git a/src/production/configurations/grafana/provisioning/datasources/prometheus.yaml b/src/development/grafana/configurations/provisioning/datasources/prometheus.yaml similarity index 100% rename from src/production/configurations/grafana/provisioning/datasources/prometheus.yaml rename to src/development/grafana/configurations/provisioning/datasources/prometheus.yaml diff --git a/src/development/jobber/compose.yaml b/src/development/jobber/compose.yaml new file mode 100644 index 00000000..8b0ff062 --- /dev/null +++ b/src/development/jobber/compose.yaml @@ -0,0 +1,106 @@ +secrets: + jobber-aliases: + # The job scheduler's SMTP client mail alias. + file: ~~/artifacts/secrets/jobber-aliases.secret + jobber-aws-bucket: + # The job scheduler's AWS bucket name. + file: ~~/artifacts/secrets/jobber-aws-bucket.secret + jobber-aws-credentials: + # The job scheduler's AWS credentials. + file: ~~/artifacts/secrets/jobber-aws-credentials.secret + jobber-aws-configuration: + # The job scheduler's AWS configuration. + file: ~~/artifacts/secrets/jobber-aws-configuration.secret + jobber-msmtprc: + # The job scheduler's SMTP client configuration. + file: ~~/artifacts/secrets/jobber-msmtprc.secret +services: + jobber: + # You cannot access the jobber via a web interface. + environment: + AWS_SHARED_CREDENTIALS_FILE: /run/secrets/jobber-aws-credentials + image: ghcr.io/dargmuesli/jobber-aws-msmtp:1.3.0 + secrets: + - source: jobber-aliases + target: /etc/aliases + - jobber-aws-bucket + - jobber-aws-credentials + - source: jobber-aws-configuration + target: /home/jobberuser/.aws/config + - source: jobber-msmtprc + target: /etc/msmtprc + volumes: + - ./configurations/.jobber:/home/jobberuser/.jobber:ro + - ./configurations/sinks:/srv/sinks:ro +x-dargstack: + secrets: + jobber-aliases: + type: insecure_default + insecure_default: "default: mail@localhost" + jobber-aws-bucket: + type: wordlist_word + jobber-aws-credentials: + type: insecure_default + insecure_default: | + [default] + aws_access_key_id = s3user + aws_secret_access_key = s3password + jobber-aws-configuration: + type: template + template: | + [default] + region = {{secret:jobber-aws-configuration-region}} + + s3 = + endpoint_url = {{secret:jobber-aws-configuration-s3-endpoint}} + signature_version = s3v4 + max_concurrent_requests = 100 + max_queue_size = 1000 + multipart_threshold = 50MB + # Edit the multipart_chunksize value according to the file sizes that you want to upload. The present configuration allows to upload files up to 10 GB (100 requests * 10MB). For example setting it to 5GB allows you to upload files up to 5TB. + multipart_chunksize = 10MB + s3api = + endpoint_url = {{secret:jobber-aws-configuration-s3-endpoint}} + + [plugins] + endpoint = awscli_plugin_endpoint + jobber-aws-configuration-region: + type: third_party + jobber-aws-configuration-s3-endpoint: + type: third_party + jobber-msmtprc: + type: template + template: | + # Set default values for all following accounts. + defaults + auth on + tls on + tls_trust_file /etc/ssl/certs/ca-certificates.crt + syslog on + + # + account {{secret:jobber-msmtprc-account}} + from {{secret:jobber-msmtprc-from}} + host {{secret:jobber-msmtprc-host}} + password {{secret:jobber-msmtprc-password}} + port {{secret:jobber-msmtprc-port}} + user {{secret:jobber-msmtprc-user}} + # or + #auth off + #tls off + + # Set a default account + account default : + aliases /etc/aliases + jobber-msmtprc-account: + type: third_party + jobber-msmtprc-from: + type: third_party + jobber-msmtprc-host: + type: third_party + jobber-msmtprc-password: + type: third_party + jobber-msmtprc-port: + type: third_party + jobber-msmtprc-user: + type: third_party diff --git a/src/development/configurations/jobber/.jobber b/src/development/jobber/configurations/.jobber similarity index 76% rename from src/development/configurations/jobber/.jobber rename to src/development/jobber/configurations/.jobber index d9067df7..906ff841 100644 --- a/src/development/configurations/jobber/.jobber +++ b/src/development/jobber/configurations/.jobber @@ -2,7 +2,7 @@ version: 1.4 jobs: DBBackup: - cmd: aws s3 sync /backups s3://$(cat /run/secrets/jobber_aws-bucket)/backups + cmd: aws s3 sync /backups s3://$(cat /run/secrets/jobber-aws-bucket)/backups time: 0 0 0 * notifyOnSuccess: - type: system-email diff --git a/src/production/configurations/jobber/sinks/sentry/error.sh b/src/development/jobber/configurations/sinks/sentry/error.sh similarity index 100% rename from src/production/configurations/jobber/sinks/sentry/error.sh rename to src/development/jobber/configurations/sinks/sentry/error.sh diff --git a/src/production/configurations/jobber/sinks/sentry/in-progress.sh b/src/development/jobber/configurations/sinks/sentry/in-progress.sh similarity index 100% rename from src/production/configurations/jobber/sinks/sentry/in-progress.sh rename to src/development/jobber/configurations/sinks/sentry/in-progress.sh diff --git a/src/production/configurations/jobber/sinks/sentry/ok.sh b/src/development/jobber/configurations/sinks/sentry/ok.sh similarity index 100% rename from src/production/configurations/jobber/sinks/sentry/ok.sh rename to src/development/jobber/configurations/sinks/sentry/ok.sh diff --git a/src/development/memcached/compose.yaml b/src/development/memcached/compose.yaml new file mode 100644 index 00000000..62c7509b --- /dev/null +++ b/src/development/memcached/compose.yaml @@ -0,0 +1,14 @@ +services: + memcached: + # You cannot access the caching system via a web interface. + deploy: + labels: + - dargstack.profiles=zammad + healthcheck: + test: ["CMD-SHELL", "echo version | nc -w1 localhost 11211 | grep -q VERSION || exit 1"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 5s + image: memcached:1.6.44-alpine + # command: memcached -m 256M diff --git a/src/development/minio/compose.yaml b/src/development/minio/compose.yaml new file mode 100644 index 00000000..7f818715 --- /dev/null +++ b/src/development/minio/compose.yaml @@ -0,0 +1,43 @@ +services: + minio: + # You can access the s3 console at [minio.app.localhost](https://minio.app.localhost/). + # You can access the s3 api service at [s3.app.localhost](https://s3.app.localhost/) if you want to access via cli from outside the stack. + command: server /data --console-address ":9001" # dargstack:dev-only + deploy: + labels: + - dargstack.profiles=upload + - traefik.enable=true # dargstack:dev-only + # Minio Console + - traefik.http.routers.minio.entryPoints=web # dargstack:dev-only + - traefik.http.routers.minio.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.minio.rule=Host(`minio.${STACK_DOMAIN}`) # dargstack:dev-only + - traefik.http.routers.minio.service=minio # dargstack:dev-only + - traefik.http.routers.minio-secure.entryPoints=web-secure # dargstack:dev-only + - traefik.http.routers.minio-secure.rule=Host(`minio.${STACK_DOMAIN}`) # dargstack:dev-only + - traefik.http.routers.minio-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.routers.minio-secure.service=minio # dargstack:dev-only + - traefik.http.services.minio.loadbalancer.server.port=9001 # dargstack:dev-only + - traefik.http.services.minio.loadbalancer.passhostheader=true # dargstack:dev-only + # Minio itself + - traefik.http.routers.s3.entryPoints=web # dargstack:dev-only + - traefik.http.routers.s3.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.s3.rule=Host(`s3.${STACK_DOMAIN}`) # dargstack:dev-only + - traefik.http.routers.s3.service=s3 # dargstack:dev-only + - traefik.http.routers.s3-secure.entryPoints=web-secure # dargstack:dev-only + - traefik.http.routers.s3-secure.rule=Host(`s3.${STACK_DOMAIN}`) # dargstack:dev-only + - traefik.http.routers.s3-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.routers.s3-secure.service=s3 # dargstack:dev-only + - traefik.http.services.s3.loadbalancer.server.port=9000 # dargstack:dev-only + - traefik.http.services.s3.loadbalancer.passhostheader=true # dargstack:dev-only + entrypoint: /patched-entrypoint.sh # dargstack:dev-only + image: minio/minio # dargstack:dev-only + volumes: # dargstack:dev-only + - minio-data:/data # dargstack:dev-only + - ./configurations/entrypoint.sh:/patched-entrypoint.sh # dargstack:dev-only + environment: # dargstack:dev-only + MINIO_ROOT_PASSWORD: s3password # dargstack:dev-only + MINIO_ROOT_USER: s3user # dargstack:dev-only +volumes: + minio-data: + # The s3 server's data. + {} diff --git a/src/development/configurations/minio/entrypoint.sh b/src/development/minio/configurations/entrypoint.sh similarity index 100% rename from src/development/configurations/minio/entrypoint.sh rename to src/development/minio/configurations/entrypoint.sh diff --git a/src/development/node-exporter/compose.yaml b/src/development/node-exporter/compose.yaml new file mode 100644 index 00000000..bb7e410e --- /dev/null +++ b/src/development/node-exporter/compose.yaml @@ -0,0 +1,26 @@ +services: + node-exporter: + # You can view host metrics in the Grafana observation dashboard. + deploy: + labels: + - dargstack.profiles=analytics + mode: global + placement: + constraints: + - node.platform.os == linux + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:9100/metrics"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + image: quay.io/prometheus/node-exporter:v1.11.1 + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + command: + - --path.procfs=/host/proc + - --path.rootfs=/rootfs + - --path.sysfs=/host/sys + - --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/) diff --git a/src/development/portainer/compose.yaml b/src/development/portainer/compose.yaml new file mode 100644 index 00000000..30e75cf7 --- /dev/null +++ b/src/development/portainer/compose.yaml @@ -0,0 +1,55 @@ +secrets: + portainer-admin-password: + # The container manager's admin password. + file: ~~/artifacts/secrets/portainer-admin-password.secret +services: + portainer: + # You can access the container manager's frontend at [portainer.app.localhost](https://portainer.app.localhost/). + command: -H tcp://tasks.portainer-agent:9001 --tlsskipverify --admin-password-file '/run/secrets/portainer-admin-password' + deploy: + labels: + - dargstack.profiles=default + - traefik.enable=true + - traefik.http.routers.portainer.entryPoints=web + - traefik.http.routers.portainer.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.portainer.rule=Host(`portainer.${STACK_DOMAIN}`) + - traefik.http.routers.portainer-secure.entryPoints=web-secure + - traefik.http.routers.portainer-secure.rule=Host(`portainer.${STACK_DOMAIN}`) + - traefik.http.routers.portainer-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.portainer.loadbalancer.server.port=9000 + placement: + constraints: + - node.role == manager + replicas: 1 + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:9000/api/system/status"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 30s + image: portainer/portainer-ce:2.43.0-alpine + secrets: + - portainer-admin-password + volumes: + - portainer-data:/data + portainer-agent: + # You cannot access the container manager's agent directly. + deploy: + labels: + - dargstack.profiles=default + mode: global + placement: + constraints: + - node.platform.os == linux + image: portainer/agent:2.43.0 + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - /var/lib/docker/volumes:/var/lib/docker/volumes +volumes: + portainer-data: + # The container manager's data. + {} +x-dargstack: + secrets: + portainer-admin-password: + type: random_string diff --git a/src/development/postgraphile/compose.yaml b/src/development/postgraphile/compose.yaml new file mode 100644 index 00000000..733d84b5 --- /dev/null +++ b/src/development/postgraphile/compose.yaml @@ -0,0 +1,70 @@ +secrets: + postgraphile-connection: + # The GraphQL API's database URI. + file: ~~/artifacts/secrets/postgraphile-connection.secret + postgraphile-jwt-secret: + # The GraphQL API's JWT secret. + file: ~~/artifacts/secrets/postgraphile-jwt-secret.secret + postgraphile-owner-connection: + # The GraphQL API's database owner URI. + file: ~~/artifacts/secrets/postgraphile-owner-connection.secret + postgraphile-sentry-dsn: + # The GraphQL API's Sentry DSN. + file: ~~/artifacts/secrets/postgraphile-sentry-dsn.secret +services: + postgraphile: + # You can access the GraphQL API for the PostgreSQL database at [postgraphile.app.localhost](https://postgraphile.app.localhost/). + deploy: + labels: + - dargstack.development.git=git@github.com:maevsi/postgraphile.git + - dargstack.profiles=default + - traefik.enable=true + - traefik.http.middlewares.postgraphile-cors.headers.accessControlAllowCredentials=true + - traefik.http.middlewares.postgraphile-cors.headers.accessControlAllowHeaders=authorization + - traefik.http.middlewares.postgraphile-cors.headers.accessControlAllowOriginList=https://${STACK_DOMAIN},https://localhost:3000,https://app.localhost:3000 + - traefik.http.routers.postgraphile.entryPoints=web + - traefik.http.routers.postgraphile.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.postgraphile.rule=Host(`postgraphile.${STACK_DOMAIN}`) + - traefik.http.routers.postgraphile-secure.entryPoints=web-secure + - traefik.http.routers.postgraphile-secure.middlewares=postgraphile-cors + - traefik.http.routers.postgraphile-secure.rule=Host(`postgraphile.${STACK_DOMAIN}`) && Path(`/graphql`) + - traefik.http.routers.postgraphile-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.routers.postgraphile-secure-ruru.entryPoints=web-secure + - traefik.http.routers.postgraphile-secure-ruru.rule=Host(`postgraphile.${STACK_DOMAIN}`) + - traefik.http.routers.postgraphile-secure-ruru.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.postgraphile.loadbalancer.server.port=5678 + # # Use the DEBUG environment variable for extended debugging. + # environment: + # DEBUG: graphile-build:warn,graphile-build-pg:sql + image: vibetype/postgraphile:development + secrets: + - source: postgraphile-connection + target: /run/environment-variables/POSTGRAPHILE_CONNECTION + - source: postgraphile-jwt-secret + target: /run/environment-variables/POSTGRAPHILE_JWT_SECRET_KEY + - source: postgraphile-owner-connection + target: /run/environment-variables/POSTGRAPHILE_OWNER_CONNECTION + - source: postgraphile-sentry-dsn + target: /run/environment-variables/POSTGRAPHILE_SENTRY_DSN + volumes: + - ~~~/postgraphile/:/srv/app/ # dargstack:dev-only + - ./configurations/jwtES256.key.pub:/run/environment-variables/POSTGRAPHILE_JWT_PUBLIC_KEY:ro + - pnpm-data:/srv/.pnpm-store/ # dargstack:dev-only + - postgraphile-data:/srv/app/node_modules # dargstack:dev-only +volumes: + postgraphile-data: + # The GraphQL API's data. + {} +x-dargstack: + secrets: + postgraphile-connection: + type: template + template: postgres://{{secret:postgres-role-service-postgraphile-username}}:{{secret:postgres-role-service-postgraphile-password}}@postgres:5432/{{secret:postgres-db}} + postgraphile-jwt-secret: + type: private_key + key_type: ecdsa + postgraphile-owner-connection: + type: template + template: postgres://{{secret:postgres-user}}:{{secret:postgres-password}}@postgres:5432/{{secret:postgres-db}} + postgraphile-sentry-dsn: + type: third_party diff --git a/src/development/configurations/postgraphile/jwtES256.key.pub b/src/development/postgraphile/configurations/jwtES256.key.pub similarity index 100% rename from src/development/configurations/postgraphile/jwtES256.key.pub rename to src/development/postgraphile/configurations/jwtES256.key.pub diff --git a/src/development/postgres/compose.yaml b/src/development/postgres/compose.yaml new file mode 100644 index 00000000..83298b6c --- /dev/null +++ b/src/development/postgres/compose.yaml @@ -0,0 +1,109 @@ +secrets: + postgres-db: + # The database's name. + file: ~~/artifacts/secrets/postgres-db.secret + postgres-password: + # The database's password. + file: ~~/artifacts/secrets/postgres-password.secret + postgres-role-service-grafana-password: + # The password of the observation dashboard's database role. + file: ~~/artifacts/secrets/postgres-role-service-grafana-password.secret + postgres-role-service-grafana-username: + # The username of the observation dashboard's database role. + file: ~~/artifacts/secrets/postgres-role-service-grafana-username.secret + postgres-role-service-postgraphile-password: + # The password of the GraphQL API database wrapper's database role. + file: ~~/artifacts/secrets/postgres-role-service-postgraphile-password.secret + postgres-role-service-postgraphile-username: + # The username of the GraphQL API database wrapper's database role. + file: ~~/artifacts/secrets/postgres-role-service-postgraphile-username.secret + postgres-role-service-reccoom-password: + # The password of the recommendation engine's database role. + file: ~~/artifacts/secrets/postgres-role-service-reccoom-password.secret + postgres-role-service-reccoom-username: + # The username of the recommendation engine's database role. + file: ~~/artifacts/secrets/postgres-role-service-reccoom-username.secret + postgres-role-service-vibetype-password: + # The `vibetype` database role's password. + file: ~~/artifacts/secrets/postgres-role-service-vibetype-password.secret + postgres-role-service-vibetype-username: + # The `vibetype` database role's username. + file: ~~/artifacts/secrets/postgres-role-service-vibetype-username.secret + postgres-role-service-zammad-password: + # The password of the customer service database role. + file: ~~/artifacts/secrets/postgres-role-service-zammad-password.secret + postgres-role-service-zammad-username: + # The username of the customer service database role. + file: ~~/artifacts/secrets/postgres-role-service-zammad-username.secret + postgres-user: + # The database's default user. + file: ~~/artifacts/secrets/postgres-user.secret +services: + postgres: + # You can access the database via `adminer`. + command: -c vibetype.jwt_expiry_duration='1 month' -c wal_level=logical + deploy: + labels: + - dargstack.profiles=default + environment: + POSTGRES_DB_FILE: /run/secrets/postgres-db + POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password + POSTGRES_USER_FILE: /run/secrets/postgres-user + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$(cat /run/secrets/postgres-user) -d $$(cat /run/secrets/postgres-db)"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + image: postgis/postgis:18-3.6-alpine + ports: # dargstack:dev-only + - 5432:5432 # dargstack:dev-only + secrets: + - postgres-db + - postgres-password + - postgres-user + # sysctls: + # # Prevent Docker Swarm from killing connections (https://github.com/moby/moby/issues/31208) + # - net.ipv4.tcp_keepalive_time=600 + # - net.ipv4.tcp_keepalive_intvl=30 + # - net.ipv4.tcp_keepalive_probes=10 + volumes: + - postgres-data:/var/lib/postgresql/ +volumes: + postgres-data: + # The database's data. + {} +x-dargstack: + secrets: + postgres-db: + type: wordlist_word + postgres-password: + special_characters: false + type: random_string + postgres-role-service-grafana-password: + special_characters: false + type: random_string + postgres-role-service-grafana-username: + type: wordlist_word + postgres-role-service-postgraphile-password: + special_characters: false + type: random_string + postgres-role-service-postgraphile-username: + type: wordlist_word + postgres-role-service-reccoom-password: + special_characters: false + type: random_string + postgres-role-service-reccoom-username: + type: wordlist_word + postgres-role-service-vibetype-password: + special_characters: false + type: random_string + postgres-role-service-vibetype-username: + type: wordlist_word + postgres-role-service-zammad-password: + special_characters: false + type: random_string + postgres-role-service-zammad-username: + type: wordlist_word + postgres-user: + type: wordlist_word diff --git a/src/development/prometheus/compose.yaml b/src/development/prometheus/compose.yaml new file mode 100644 index 00000000..895a65ec --- /dev/null +++ b/src/development/prometheus/compose.yaml @@ -0,0 +1,28 @@ +services: + prometheus: + # You can access the metrics monitoring at [prometheus.app.localhost](https://prometheus.app.localhost/). + deploy: + labels: + - dargstack.profiles=analytics + - traefik.enable=true + - traefik.http.routers.prometheus.entryPoints=web + - traefik.http.routers.prometheus.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.prometheus.rule=Host(`prometheus.${STACK_DOMAIN}`) + - traefik.http.routers.prometheus-secure.entryPoints=web-secure + - traefik.http.routers.prometheus-secure.rule=Host(`prometheus.${STACK_DOMAIN}`) + - traefik.http.routers.prometheus-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.prometheus.loadbalancer.server.port=9090 + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:9090/-/healthy"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 15s + image: prom/prometheus:v3.13.0 + volumes: + - ./configurations/prometheus.yaml:/etc/prometheus/prometheus.yml:ro + - prometheus-data:/prometheus +volumes: + prometheus-data: + # The metrics monitoring's data. + {} diff --git a/src/production/configurations/prometheus/prometheus.yaml b/src/development/prometheus/configurations/prometheus.yaml similarity index 95% rename from src/production/configurations/prometheus/prometheus.yaml rename to src/development/prometheus/configurations/prometheus.yaml index 046e245a..5c499ac4 100644 --- a/src/production/configurations/prometheus/prometheus.yaml +++ b/src/development/prometheus/configurations/prometheus.yaml @@ -32,4 +32,4 @@ scrape_configs: static_configs: - targets: - redpanda:9644 - metrics_path: /public_metrics \ No newline at end of file + metrics_path: /public_metrics diff --git a/src/development/reccoom/compose.yaml b/src/development/reccoom/compose.yaml new file mode 100644 index 00000000..f046990d --- /dev/null +++ b/src/development/reccoom/compose.yaml @@ -0,0 +1,155 @@ +secrets: + reccoom-ingest-api-key: + # The recommendation engine's ingest API key. + file: ~~/artifacts/secrets/reccoom-ingest-api-key.secret + reccoom-model-api-key: + # The recommendation engine's model API key. + file: ~~/artifacts/secrets/reccoom-model-api-key.secret + reccoom-openai-api-key: + # The recommendation engine's OpenAI API key. + file: ~~/artifacts/secrets/reccoom-openai-api-key.secret + reccoom-sentry-dsn: + # The recommendation engine's Sentry DSN. + file: ~~/artifacts/secrets/reccoom-sentry-dsn.secret +services: + reccoom: + # You cannot access the recommendation service directly. + deploy: + labels: + - dargstack.development.git=git@github.com:maevsi/reccoom.git + - dargstack.profiles=recommendation + - traefik.enable=true # dargstack:dev-only + - traefik.http.routers.reccoom.entryPoints=web + - traefik.http.routers.reccoom.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.reccoom.rule=Host(`reccoom.${STACK_DOMAIN}`) + - traefik.http.routers.reccoom-secure.entryPoints=web-secure + - traefik.http.routers.reccoom-secure.rule=Host(`reccoom.${STACK_DOMAIN}`) + - traefik.http.routers.reccoom-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.reccoom.loadbalancer.server.port=5245 + environment: + POSTGRES_HOST: postgres + RECCOOM_POSTGRES_HOST: reccoom-postgres + image: vibetype/reccoom:development + secrets: + - source: postgres-db + target: /run/environment-variables/POSTGRES_DATABASE + - source: postgres-db + target: /run/environment-variables/RECCOOM_POSTGRES_DATABASE + - source: postgres-role-service-reccoom-username + target: /run/environment-variables/POSTGRES_USER + - source: postgres-user + target: /run/environment-variables/RECCOOM_POSTGRES_USER + - source: postgres-role-service-reccoom-password + target: /run/environment-variables/POSTGRES_PASSWORD + - source: postgres-password + target: /run/environment-variables/RECCOOM_POSTGRES_PASSWORD + - source: reccoom-ingest-api-key + target: /run/environment-variables/INGEST_API_KEY + - source: reccoom-model-api-key + target: /run/environment-variables/MODEL_API_KEY + - source: reccoom-openai-api-key + target: /run/environment-variables/OPENAI_API_KEY + - source: reccoom-sentry-dsn + target: /run/environment-variables/SENTRY_DSN + volumes: + - ~~~/reccoom/:/srv/app/ # dargstack:dev-only + - ../postgraphile/configurations/jwtES256.key.pub:/run/configurations/jwtES256.key.pub:ro + - reccoom-data:/home/python/.cache/ + reccoom-consumer: + # You can track the recommender's event streaming consumer using `redpanda-console`. + command: ["uv", "run", "python", "-m", "src.consumer"] + deploy: + labels: + - dargstack.development.git=git@github.com:maevsi/reccoom.git + - dargstack.profiles=recommendation + environment: + KAFKA_BOOTSTRAP_SERVERS: redpanda:9092 + POSTGRES_HOST: postgres + RECCOOM_POSTGRES_HOST: reccoom-postgres + healthcheck: + test: ["CMD-SHELL", "test -f /home/python/consumer-alive && [ $$(( $$(date +%s) - $$(date +%s -r /home/python/consumer-alive) )) -lt 60 ]"] + timeout: 5s + image: vibetype/reccoom:development + secrets: + - source: postgres-db + target: /run/environment-variables/POSTGRES_DATABASE + - source: postgres-db + target: /run/environment-variables/RECCOOM_POSTGRES_DATABASE + - source: postgres-role-service-reccoom-username + target: /run/environment-variables/POSTGRES_USER + - source: postgres-user + target: /run/environment-variables/RECCOOM_POSTGRES_USER + - source: postgres-role-service-reccoom-password + target: /run/environment-variables/POSTGRES_PASSWORD + - source: postgres-password + target: /run/environment-variables/RECCOOM_POSTGRES_PASSWORD + - source: reccoom-sentry-dsn + target: /run/environment-variables/SENTRY_DSN + volumes: + - ~~~/reccoom/:/srv/app/ + - reccoom-data:/home/python/.cache/ + reccoom-migration: + # You cannot access the recommender's database migration service directly. + command: ["uv", "run", "python", "-m", "src.migration"] + deploy: + labels: + - dargstack.development.git=git@github.com:maevsi/reccoom.git + - dargstack.profiles=recommendation + restart_policy: + condition: on-failure + environment: + RECCOOM_POSTGRES_HOST: reccoom-postgres + image: vibetype/reccoom:development + secrets: + - source: postgres-db + target: /run/environment-variables/RECCOOM_POSTGRES_DATABASE + - source: postgres-user + target: /run/environment-variables/RECCOOM_POSTGRES_USER + - source: postgres-password + target: /run/environment-variables/RECCOOM_POSTGRES_PASSWORD + - source: reccoom-sentry-dsn + target: /run/environment-variables/SENTRY_DSN + volumes: + - ~~~/reccoom/:/srv/app/ + - reccoom-data:/home/python/.cache/ + reccoom-postgres: + # You can access reccoom's database via `adminer`. + deploy: + labels: + - dargstack.profiles=recommendation + environment: + POSTGRES_DB_FILE: /run/secrets/postgres-db + POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password + POSTGRES_USER_FILE: /run/secrets/postgres-user + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$(cat /run/secrets/postgres-user) -d $$(cat /run/secrets/postgres-db)"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + image: pgvector/pgvector:0.8.5-pg18 + ports: # dargstack:dev-only + - 5433:5432 # dargstack:dev-only + secrets: + - postgres-db + - postgres-password + - postgres-user + volumes: + - reccoom-postgres-data:/var/lib/postgresql/ +volumes: + reccoom-data: + # The general cache data. + {} + reccoom-postgres-data: + # The recommendation database's data. + {} +x-dargstack: + secrets: + reccoom-ingest-api-key: + type: third_party + reccoom-model-api-key: + type: third_party + reccoom-openai-api-key: + type: third_party + reccoom-sentry-dsn: + type: third_party diff --git a/src/development/redis/compose.yaml b/src/development/redis/compose.yaml new file mode 100644 index 00000000..e1449fb5 --- /dev/null +++ b/src/development/redis/compose.yaml @@ -0,0 +1,19 @@ +services: + redis: + # You cannot access the caching system via a web interface. + deploy: + labels: + - dargstack.profiles=zammad + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 10s + image: redis:8.8.0-alpine + volumes: + - redis-data:/data +volumes: + redis-data: + # The caching system's data. + {} diff --git a/src/development/redpanda/compose.yaml b/src/development/redpanda/compose.yaml new file mode 100644 index 00000000..9e833bc7 --- /dev/null +++ b/src/development/redpanda/compose.yaml @@ -0,0 +1,51 @@ +services: + redpanda: + # You can access the event streaming platform's ui as described under `redpanda-console`. + command: + - redpanda start + - --mode dev-container # dargstack:dev-only + - --kafka-addr internal://0.0.0.0:9092,external://0.0.0.0:19092 + - --advertise-kafka-addr internal://redpanda:9092,external://localhost:19092 + - --pandaproxy-addr internal://0.0.0.0:8082,external://0.0.0.0:18082 + - --advertise-pandaproxy-addr internal://redpanda:8082,external://localhost:18082 + - --schema-registry-addr internal://0.0.0.0:8081,external://0.0.0.0:18081 + deploy: + labels: + - dargstack.profiles=event-streaming + healthcheck: + test: ["CMD", "rpk", "cluster", "health", "--exit-when-healthy"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 30s + image: redpandadata/redpanda:v26.1.12 + volumes: + - redpanda-data:/var/lib/redpanda/data + redpanda-console: + # You can access the event streaming platform's ui at [redpanda.app.localhost](https://redpanda.app.localhost/). + deploy: + labels: + - dargstack.profiles=event-streaming + - traefik.enable=true + - traefik.http.routers.redpanda.entryPoints=web + - traefik.http.routers.redpanda.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.redpanda.rule=Host(`redpanda.${STACK_DOMAIN}`) + - traefik.http.routers.redpanda-secure.entryPoints=web-secure + - traefik.http.routers.redpanda-secure.rule=Host(`redpanda.${STACK_DOMAIN}`) + - traefik.http.routers.redpanda-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.redpanda.loadbalancer.server.port=8080 + environment: + CONFIG_FILEPATH: /srv/app/redpanda-config.yaml + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/admin/health"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 15s + image: redpandadata/console:v3.8.0 + volumes: + - ./configurations/config.yaml:/srv/app/redpanda-config.yaml:ro +volumes: + redpanda-data: + # The message queue's data. + {} diff --git a/src/production/configurations/redpanda/config.yaml b/src/development/redpanda/configurations/config.yaml similarity index 58% rename from src/production/configurations/redpanda/config.yaml rename to src/development/redpanda/configurations/config.yaml index 26876a8a..93bf566c 100644 --- a/src/production/configurations/redpanda/config.yaml +++ b/src/development/redpanda/configurations/config.yaml @@ -1,12 +1,12 @@ kafka: brokers: - - redpanda:9092 + - redpanda:9092 redpanda: adminApi: enabled: true urls: - - http://redpanda:9644 + - http://redpanda:9644 schemaRegistry: enabled: true urls: - - http://redpanda:8081 + - http://redpanda:8081 diff --git a/src/development/secrets/elasticsearch/keystore_password.secret b/src/development/secrets/elasticsearch/keystore_password.secret deleted file mode 100644 index f3f85cae..00000000 --- a/src/development/secrets/elasticsearch/keystore_password.secret +++ /dev/null @@ -1 +0,0 @@ -elastic \ No newline at end of file diff --git a/src/development/secrets/elasticsearch/keystore_password.secret.template b/src/development/secrets/elasticsearch/keystore_password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/elasticsearch/keystore_password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/elasticsearch/password.secret b/src/development/secrets/elasticsearch/password.secret deleted file mode 100644 index f3f85cae..00000000 --- a/src/development/secrets/elasticsearch/password.secret +++ /dev/null @@ -1 +0,0 @@ -elastic \ No newline at end of file diff --git a/src/development/secrets/elasticsearch/password.secret.template b/src/development/secrets/elasticsearch/password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/elasticsearch/password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/grafana/admin_email.secret b/src/development/secrets/grafana/admin_email.secret deleted file mode 100644 index 06474a56..00000000 --- a/src/development/secrets/grafana/admin_email.secret +++ /dev/null @@ -1 +0,0 @@ -admin@localhost \ No newline at end of file diff --git a/src/development/secrets/grafana/admin_email.secret.template b/src/development/secrets/grafana/admin_email.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/grafana/admin_email.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/grafana/admin_password.secret b/src/development/secrets/grafana/admin_password.secret deleted file mode 100644 index 6da70038..00000000 --- a/src/development/secrets/grafana/admin_password.secret +++ /dev/null @@ -1 +0,0 @@ -grafana \ No newline at end of file diff --git a/src/development/secrets/grafana/admin_password.secret.template b/src/development/secrets/grafana/admin_password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/grafana/admin_password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/grafana/admin_user.secret b/src/development/secrets/grafana/admin_user.secret deleted file mode 100644 index 6da70038..00000000 --- a/src/development/secrets/grafana/admin_user.secret +++ /dev/null @@ -1 +0,0 @@ -grafana \ No newline at end of file diff --git a/src/development/secrets/grafana/admin_user.secret.template b/src/development/secrets/grafana/admin_user.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/grafana/admin_user.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/grafana/discord_webhook.secret b/src/development/secrets/grafana/discord_webhook.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/grafana/discord_webhook.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/grafana/discord_webhook.secret.template b/src/development/secrets/grafana/discord_webhook.secret.template deleted file mode 100644 index 3ad15b2a..00000000 --- a/src/development/secrets/grafana/discord_webhook.secret.template +++ /dev/null @@ -1 +0,0 @@ -https://discord.com/api/webhooks// \ No newline at end of file diff --git a/src/development/secrets/jobber/aliases.secret b/src/development/secrets/jobber/aliases.secret deleted file mode 100644 index 20df8a23..00000000 --- a/src/development/secrets/jobber/aliases.secret +++ /dev/null @@ -1 +0,0 @@ -default: mail@localhost diff --git a/src/development/secrets/jobber/aliases.secret.template b/src/development/secrets/jobber/aliases.secret.template deleted file mode 100644 index ff45006e..00000000 --- a/src/development/secrets/jobber/aliases.secret.template +++ /dev/null @@ -1 +0,0 @@ -default: diff --git a/src/development/secrets/jobber/aws-bucket.secret b/src/development/secrets/jobber/aws-bucket.secret deleted file mode 100644 index dc9cb35b..00000000 --- a/src/development/secrets/jobber/aws-bucket.secret +++ /dev/null @@ -1 +0,0 @@ -vibetype-backup \ No newline at end of file diff --git a/src/development/secrets/jobber/aws-bucket.secret.template b/src/development/secrets/jobber/aws-bucket.secret.template deleted file mode 100644 index 813cdeb1..00000000 --- a/src/development/secrets/jobber/aws-bucket.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/jobber/aws-configuration.secret b/src/development/secrets/jobber/aws-configuration.secret deleted file mode 100644 index 20ea0b02..00000000 --- a/src/development/secrets/jobber/aws-configuration.secret +++ /dev/null @@ -1,16 +0,0 @@ -[default] -region = auto - -s3 = - endpoint_url = http://minio:9000 - signature_version = s3v4 - max_concurrent_requests = 100 - max_queue_size = 1000 - multipart_threshold = 50MB - # Edit the multipart_chunksize value according to the file sizes that you want to upload. The present configuration allows to upload files up to 10 GB (100 requests * 10MB). For example setting it to 5GB allows you to upload files up to 5TB. - multipart_chunksize = 10MB -s3api = - endpoint_url = http://minio:9000 - -[plugins] -endpoint = awscli_plugin_endpoint \ No newline at end of file diff --git a/src/development/secrets/jobber/aws-configuration.secret.template b/src/development/secrets/jobber/aws-configuration.secret.template deleted file mode 100644 index 43cb79c8..00000000 --- a/src/development/secrets/jobber/aws-configuration.secret.template +++ /dev/null @@ -1,16 +0,0 @@ -[default] -region = - -s3 = - endpoint_url = - signature_version = s3v4 - max_concurrent_requests = 100 - max_queue_size = 1000 - multipart_threshold = 50MB - # Edit the multipart_chunksize value according to the file sizes that you want to upload. The present configuration allows to upload files up to 10 GB (100 requests * 10MB). For example setting it to 5GB allows you to upload files up to 5TB. - multipart_chunksize = 10MB -s3api = - endpoint_url = - -[plugins] -endpoint = awscli_plugin_endpoint \ No newline at end of file diff --git a/src/development/secrets/jobber/aws-credentials.secret b/src/development/secrets/jobber/aws-credentials.secret deleted file mode 100644 index a28cae87..00000000 --- a/src/development/secrets/jobber/aws-credentials.secret +++ /dev/null @@ -1,3 +0,0 @@ -[default] -aws_access_key_id = s3user -aws_secret_access_key = s3password diff --git a/src/development/secrets/jobber/aws-credentials.secret.template b/src/development/secrets/jobber/aws-credentials.secret.template deleted file mode 100644 index f652ea6f..00000000 --- a/src/development/secrets/jobber/aws-credentials.secret.template +++ /dev/null @@ -1,3 +0,0 @@ -[default] -aws_access_key_id = -aws_secret_access_key = diff --git a/src/development/secrets/jobber/msmtprc.secret b/src/development/secrets/jobber/msmtprc.secret deleted file mode 100644 index 84ceec08..00000000 --- a/src/development/secrets/jobber/msmtprc.secret +++ /dev/null @@ -1,17 +0,0 @@ -# Set default values for all following accounts. -defaults -auth off -tls off -tls_trust_file /etc/ssl/certs/ca-certificates.crt -syslog on - -# localhost -account localhost -host localhost -port 25 -from mail@localhost -user mail@localhost - -# Set a default account -account default : localhost -aliases /etc/aliases diff --git a/src/development/secrets/jobber/msmtprc.secret.template b/src/development/secrets/jobber/msmtprc.secret.template deleted file mode 100644 index 2bc06857..00000000 --- a/src/development/secrets/jobber/msmtprc.secret.template +++ /dev/null @@ -1,21 +0,0 @@ -# Set default values for all following accounts. -defaults -auth on -tls on -tls_trust_file /etc/ssl/certs/ca-certificates.crt -syslog on - -# -account -host -port -from -user -password -# or -#auth off -#tls off - -# Set a default account -account default : -aliases /etc/aliases diff --git a/src/development/secrets/portainer/admin-password.secret b/src/development/secrets/portainer/admin-password.secret deleted file mode 100644 index 45aee45f..00000000 --- a/src/development/secrets/portainer/admin-password.secret +++ /dev/null @@ -1 +0,0 @@ -123456123456 \ No newline at end of file diff --git a/src/development/secrets/portainer/admin-password.secret.template b/src/development/secrets/portainer/admin-password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/portainer/admin-password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgraphile/connection.secret b/src/development/secrets/postgraphile/connection.secret deleted file mode 100644 index f94cfa39..00000000 --- a/src/development/secrets/postgraphile/connection.secret +++ /dev/null @@ -1 +0,0 @@ -postgresql://postgraphile:postgraphile@postgres/vibetype \ No newline at end of file diff --git a/src/development/secrets/postgraphile/connection.secret.template b/src/development/secrets/postgraphile/connection.secret.template deleted file mode 100644 index 30d53aef..00000000 --- a/src/development/secrets/postgraphile/connection.secret.template +++ /dev/null @@ -1 +0,0 @@ -postgresql://:@/ \ No newline at end of file diff --git a/src/development/secrets/postgraphile/jwt-secret.secret b/src/development/secrets/postgraphile/jwt-secret.secret deleted file mode 100644 index 729ef18b..00000000 --- a/src/development/secrets/postgraphile/jwt-secret.secret +++ /dev/null @@ -1,5 +0,0 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIIDGfDCPfJsxMzMBBupP1pG7aL/xpYshE5qsXLqbDNWmoAoGCCqGSM49 -AwEHoUQDQgAEgIYyEMm+hZzEnXhJLGUx9lwr3cKsW2uJ+zLvei380CrUEPARnWQN -R/V0usS0EFypTQllniuCpbLG6un87kxh6w== ------END EC PRIVATE KEY----- diff --git a/src/development/secrets/postgraphile/jwt-secret.secret.template b/src/development/secrets/postgraphile/jwt-secret.secret.template deleted file mode 100644 index 86d1bb42..00000000 --- a/src/development/secrets/postgraphile/jwt-secret.secret.template +++ /dev/null @@ -1,5 +0,0 @@ - -# - -# Optional: convert to PKCS#8 (some libraries expect PKCS#8) -# \ No newline at end of file diff --git a/src/development/secrets/postgraphile/owner-connection.secret b/src/development/secrets/postgraphile/owner-connection.secret deleted file mode 100644 index 093bbed2..00000000 --- a/src/development/secrets/postgraphile/owner-connection.secret +++ /dev/null @@ -1 +0,0 @@ -postgresql://postgres:postgres@postgres/vibetype \ No newline at end of file diff --git a/src/development/secrets/postgraphile/owner-connection.secret.template b/src/development/secrets/postgraphile/owner-connection.secret.template deleted file mode 100644 index 279b3a1c..00000000 --- a/src/development/secrets/postgraphile/owner-connection.secret.template +++ /dev/null @@ -1 +0,0 @@ -postgresql://:@/ \ No newline at end of file diff --git a/src/development/secrets/postgres/db.secret b/src/development/secrets/postgres/db.secret deleted file mode 100644 index 9294c3d9..00000000 --- a/src/development/secrets/postgres/db.secret +++ /dev/null @@ -1 +0,0 @@ -vibetype \ No newline at end of file diff --git a/src/development/secrets/postgres/db.secret.template b/src/development/secrets/postgres/db.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/db.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/password.secret b/src/development/secrets/postgres/password.secret deleted file mode 100644 index f1349944..00000000 --- a/src/development/secrets/postgres/password.secret +++ /dev/null @@ -1 +0,0 @@ -postgres diff --git a/src/development/secrets/postgres/password.secret.template b/src/development/secrets/postgres/password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_grafana_password.secret b/src/development/secrets/postgres/role_service_grafana_password.secret deleted file mode 100644 index 6da70038..00000000 --- a/src/development/secrets/postgres/role_service_grafana_password.secret +++ /dev/null @@ -1 +0,0 @@ -grafana \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_grafana_password.secret.template b/src/development/secrets/postgres/role_service_grafana_password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_grafana_password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_grafana_username.secret b/src/development/secrets/postgres/role_service_grafana_username.secret deleted file mode 100644 index 6da70038..00000000 --- a/src/development/secrets/postgres/role_service_grafana_username.secret +++ /dev/null @@ -1 +0,0 @@ -grafana \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_grafana_username.secret.template b/src/development/secrets/postgres/role_service_grafana_username.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_grafana_username.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_postgraphile_password.secret b/src/development/secrets/postgres/role_service_postgraphile_password.secret deleted file mode 100644 index a4da12ec..00000000 --- a/src/development/secrets/postgres/role_service_postgraphile_password.secret +++ /dev/null @@ -1 +0,0 @@ -postgraphile \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_postgraphile_password.secret.template b/src/development/secrets/postgres/role_service_postgraphile_password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_postgraphile_password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_postgraphile_username.secret b/src/development/secrets/postgres/role_service_postgraphile_username.secret deleted file mode 100644 index a4da12ec..00000000 --- a/src/development/secrets/postgres/role_service_postgraphile_username.secret +++ /dev/null @@ -1 +0,0 @@ -postgraphile \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_postgraphile_username.secret.template b/src/development/secrets/postgres/role_service_postgraphile_username.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_postgraphile_username.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_reccoom_password.secret b/src/development/secrets/postgres/role_service_reccoom_password.secret deleted file mode 100644 index c848aa60..00000000 --- a/src/development/secrets/postgres/role_service_reccoom_password.secret +++ /dev/null @@ -1 +0,0 @@ -reccoom \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_reccoom_password.secret.template b/src/development/secrets/postgres/role_service_reccoom_password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_reccoom_password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_reccoom_username.secret b/src/development/secrets/postgres/role_service_reccoom_username.secret deleted file mode 100644 index c848aa60..00000000 --- a/src/development/secrets/postgres/role_service_reccoom_username.secret +++ /dev/null @@ -1 +0,0 @@ -reccoom \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_reccoom_username.secret.template b/src/development/secrets/postgres/role_service_reccoom_username.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_reccoom_username.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_vibetype_password.secret b/src/development/secrets/postgres/role_service_vibetype_password.secret deleted file mode 100644 index 9294c3d9..00000000 --- a/src/development/secrets/postgres/role_service_vibetype_password.secret +++ /dev/null @@ -1 +0,0 @@ -vibetype \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_vibetype_password.secret.template b/src/development/secrets/postgres/role_service_vibetype_password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_vibetype_password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_vibetype_username.secret b/src/development/secrets/postgres/role_service_vibetype_username.secret deleted file mode 100644 index 9294c3d9..00000000 --- a/src/development/secrets/postgres/role_service_vibetype_username.secret +++ /dev/null @@ -1 +0,0 @@ -vibetype \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_vibetype_username.secret.template b/src/development/secrets/postgres/role_service_vibetype_username.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_vibetype_username.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_zammad_password.secret b/src/development/secrets/postgres/role_service_zammad_password.secret deleted file mode 100644 index 70699eae..00000000 --- a/src/development/secrets/postgres/role_service_zammad_password.secret +++ /dev/null @@ -1 +0,0 @@ -zammad \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_zammad_password.secret.template b/src/development/secrets/postgres/role_service_zammad_password.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_zammad_password.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_zammad_username.secret b/src/development/secrets/postgres/role_service_zammad_username.secret deleted file mode 100644 index 70699eae..00000000 --- a/src/development/secrets/postgres/role_service_zammad_username.secret +++ /dev/null @@ -1 +0,0 @@ -zammad \ No newline at end of file diff --git a/src/development/secrets/postgres/role_service_zammad_username.secret.template b/src/development/secrets/postgres/role_service_zammad_username.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/role_service_zammad_username.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/postgres/user.secret b/src/development/secrets/postgres/user.secret deleted file mode 100644 index f1349944..00000000 --- a/src/development/secrets/postgres/user.secret +++ /dev/null @@ -1 +0,0 @@ -postgres diff --git a/src/development/secrets/postgres/user.secret.template b/src/development/secrets/postgres/user.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/postgres/user.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/reccoom/ingest-api-key.secret b/src/development/secrets/reccoom/ingest-api-key.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/reccoom/ingest-api-key.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/reccoom/ingest-api-key.secret.template b/src/development/secrets/reccoom/ingest-api-key.secret.template deleted file mode 100644 index 127df2bb..00000000 --- a/src/development/secrets/reccoom/ingest-api-key.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/reccoom/model-api-key.secret b/src/development/secrets/reccoom/model-api-key.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/reccoom/model-api-key.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/reccoom/model-api-key.secret.template b/src/development/secrets/reccoom/model-api-key.secret.template deleted file mode 100644 index 3553c666..00000000 --- a/src/development/secrets/reccoom/model-api-key.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/reccoom/openai-api-key.secret b/src/development/secrets/reccoom/openai-api-key.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/reccoom/openai-api-key.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/reccoom/openai-api-key.secret.template b/src/development/secrets/reccoom/openai-api-key.secret.template deleted file mode 100644 index 8ec50c4a..00000000 --- a/src/development/secrets/reccoom/openai-api-key.secret.template +++ /dev/null @@ -1 +0,0 @@ -sk-proj-<...> \ No newline at end of file diff --git a/src/development/secrets/reccoom/sentry-dsn.secret b/src/development/secrets/reccoom/sentry-dsn.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/reccoom/sentry-dsn.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/reccoom/sentry-dsn.secret.template b/src/development/secrets/reccoom/sentry-dsn.secret.template deleted file mode 100644 index b0cd0232..00000000 --- a/src/development/secrets/reccoom/sentry-dsn.secret.template +++ /dev/null @@ -1 +0,0 @@ -https://@.ingest.de.sentry.io/ \ No newline at end of file diff --git a/src/development/secrets/sqitch/target.secret b/src/development/secrets/sqitch/target.secret deleted file mode 100644 index 12789f3c..00000000 --- a/src/development/secrets/sqitch/target.secret +++ /dev/null @@ -1 +0,0 @@ -db:pg://postgres:postgres@postgres/vibetype \ No newline at end of file diff --git a/src/development/secrets/sqitch/target.secret.template b/src/development/secrets/sqitch/target.secret.template deleted file mode 100644 index 5fd02bec..00000000 --- a/src/development/secrets/sqitch/target.secret.template +++ /dev/null @@ -1 +0,0 @@ -db:pg://:@/ \ No newline at end of file diff --git a/src/development/secrets/tusd/aws.secret b/src/development/secrets/tusd/aws.secret deleted file mode 100644 index eed88684..00000000 --- a/src/development/secrets/tusd/aws.secret +++ /dev/null @@ -1,3 +0,0 @@ -[default] -aws_access_key_id = s3user -aws_secret_access_key = s3password \ No newline at end of file diff --git a/src/development/secrets/tusd/aws.secret.template b/src/development/secrets/tusd/aws.secret.template deleted file mode 100644 index 93deade4..00000000 --- a/src/development/secrets/tusd/aws.secret.template +++ /dev/null @@ -1,3 +0,0 @@ -[default] -aws_access_key_id = -aws_secret_access_key = \ No newline at end of file diff --git a/src/development/secrets/vibetype/api-notification.secret b/src/development/secrets/vibetype/api-notification.secret deleted file mode 100644 index 9294c3d9..00000000 --- a/src/development/secrets/vibetype/api-notification.secret +++ /dev/null @@ -1 +0,0 @@ -vibetype \ No newline at end of file diff --git a/src/development/secrets/vibetype/api-notification.secret.template b/src/development/secrets/vibetype/api-notification.secret.template deleted file mode 100644 index a6bb01c1..00000000 --- a/src/development/secrets/vibetype/api-notification.secret.template +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/development/secrets/vibetype/aws-credentials.secret b/src/development/secrets/vibetype/aws-credentials.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/vibetype/aws-credentials.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/vibetype/aws-credentials.secret.template b/src/development/secrets/vibetype/aws-credentials.secret.template deleted file mode 100644 index 96077989..00000000 --- a/src/development/secrets/vibetype/aws-credentials.secret.template +++ /dev/null @@ -1,3 +0,0 @@ -[stomper] -aws_access_key_id = -aws_secret_access_key = diff --git a/src/development/secrets/vibetype/firebase-service-account-credentials.secret b/src/development/secrets/vibetype/firebase-service-account-credentials.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/vibetype/firebase-service-account-credentials.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/vibetype/firebase-service-account-credentials.secret.template b/src/development/secrets/vibetype/firebase-service-account-credentials.secret.template deleted file mode 100644 index 49cf7a7b..00000000 --- a/src/development/secrets/vibetype/firebase-service-account-credentials.secret.template +++ /dev/null @@ -1,13 +0,0 @@ -{ - "type": "service_account", - "project_id": "maevsi-3f373", - "private_key_id": "", - "private_key": "", - "client_email": "firebase-adminsdk-fbsvc@maevsi-3f373.iam.gserviceaccount.com", - "client_id": "", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40maevsi-3f373.iam.gserviceaccount.com", - "universe_domain": "googleapis.com" -} diff --git a/src/development/secrets/vibetype/openai-api-key.secret b/src/development/secrets/vibetype/openai-api-key.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/vibetype/openai-api-key.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/vibetype/openai-api-key.secret.template b/src/development/secrets/vibetype/openai-api-key.secret.template deleted file mode 100644 index 8ec50c4a..00000000 --- a/src/development/secrets/vibetype/openai-api-key.secret.template +++ /dev/null @@ -1 +0,0 @@ -sk-proj-<...> \ No newline at end of file diff --git a/src/development/secrets/vibetype/turnstile-key.secret b/src/development/secrets/vibetype/turnstile-key.secret deleted file mode 100644 index d8c28c70..00000000 --- a/src/development/secrets/vibetype/turnstile-key.secret +++ /dev/null @@ -1 +0,0 @@ -1x0000000000000000000000000000000AA \ No newline at end of file diff --git a/src/development/secrets/vibetype/turnstile-key.secret.template b/src/development/secrets/vibetype/turnstile-key.secret.template deleted file mode 100644 index d8c28c70..00000000 --- a/src/development/secrets/vibetype/turnstile-key.secret.template +++ /dev/null @@ -1 +0,0 @@ -1x0000000000000000000000000000000AA \ No newline at end of file diff --git a/src/development/secrets/vibetype/zammad.secret b/src/development/secrets/vibetype/zammad.secret deleted file mode 100644 index 6075c4fb..00000000 --- a/src/development/secrets/vibetype/zammad.secret +++ /dev/null @@ -1 +0,0 @@ -UNSET THIRD PARTY SECRET \ No newline at end of file diff --git a/src/development/secrets/vibetype/zammad.template b/src/development/secrets/vibetype/zammad.template deleted file mode 100644 index 3858b4b0..00000000 --- a/src/development/secrets/vibetype/zammad.template +++ /dev/null @@ -1,5 +0,0 @@ -{ - "apiToken": "your-zammad-api-token", - "group": "Users", - "url": "https://support.example.com" -} diff --git a/src/development/sqitch/compose.yaml b/src/development/sqitch/compose.yaml new file mode 100644 index 00000000..dcc49ed5 --- /dev/null +++ b/src/development/sqitch/compose.yaml @@ -0,0 +1,33 @@ +secrets: + sqitch-target: + # The database change management application's database connection string. + file: ~~/artifacts/secrets/sqitch-target.secret +services: + sqitch: + # You cannot access the database migrations directly. + deploy: + labels: + - dargstack.development.git=git@github.com:maevsi/sqitch.git + - dargstack.profiles=default + restart_policy: + condition: on-failure + image: vibetype/sqitch:development + secrets: + - postgres-role-service-grafana-password + - postgres-role-service-grafana-username + - postgres-role-service-postgraphile-password + - postgres-role-service-postgraphile-username + - postgres-role-service-reccoom-password + - postgres-role-service-reccoom-username + - postgres-role-service-vibetype-password + - postgres-role-service-vibetype-username + - postgres-role-service-zammad-username + - postgres-role-service-zammad-password + - sqitch-target + volumes: + - ~~~/sqitch/:/srv/app/ +x-dargstack: + secrets: + sqitch-target: + type: template + template: db:pg://{{secret:postgres-user}}:{{secret:postgres-password}}@postgres:5432/{{secret:postgres-db}} diff --git a/src/development/stack.env.template b/src/development/stack.env.template deleted file mode 100644 index 261fdee5..00000000 --- a/src/development/stack.env.template +++ /dev/null @@ -1,8 +0,0 @@ -TUSD_BUCKET=vibetype-images -TUSD_ENDPOINT=http://minio:9000 -TUSD_MAX_SIZE=10485760 -TUSD_REGION=eu-central-1 -VIBETYPE_AWS_REGION=eu-central-1 -VIBETYPE_NUXT_PUBLIC_GTAG_ID=G-WMQ1JY99XH -VIBETYPE_NUXT_PUBLIC_TURNSTILE_SITE_KEY=1x00000000000000000000AA -VIBETYPE_NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H=100 \ No newline at end of file diff --git a/src/development/stack.yml b/src/development/stack.yml deleted file mode 100644 index 5c23f372..00000000 --- a/src/development/stack.yml +++ /dev/null @@ -1,967 +0,0 @@ -# vibetype.app -# https://vibetype.app/ -# Vibetype -# https://github.com/maevsi/vibetype/ ---- -x-shared: - zammad-service: - &zammad-service # You can access the helpdesk at [zammad.app.localhost](https://zammad.app.localhost/). - environment: &zammad-environment - ELASTICSEARCH_ENABLED: "false" - ELASTICSEARCH_HOST: elasticsearch - ELASTICSEARCH_SCHEMA: https - ELASTICSEARCH_USER: elastic - MEMCACHE_SERVERS: memcached:11211 - NGINX_SERVER_SCHEME: https - POSTGRESQL_DB: zammad - POSTGRESQL_DB_CREATE: "false" - POSTGRESQL_HOST: postgres - POSTGRESQL_OPTIONS: ?pool=50 - REDIS_URL: redis://redis:6379 - image: ghcr.io/zammad/zammad:6.5.2-90 - secrets: - - source: elasticsearch-password - target: /run/environment-variables/ELASTICSEARCH_PASS - - source: postgres_role_service_zammad_username - target: /run/environment-variables/POSTGRESQL_USER - - source: postgres_role_service_zammad_password - target: /run/environment-variables/POSTGRESQL_PASS - volumes: - - zammad_data:/opt/zammad/storage - - ../production/configurations/zammad/docker-entrypoint.sh:/docker-entrypoint.sh:ro -secrets: - elasticsearch-keystore_password: - # The search engine's password for the keystore. - file: ./secrets/elasticsearch/keystore_password.secret - elasticsearch-password: - # The search engine's password for the default user. - file: ./secrets/elasticsearch/password.secret - grafana_admin_email: - # The observation dashboard's admin email. - file: ./secrets/grafana/admin_email.secret - grafana_admin_password: - # The observation dashboard's admin password. - file: ./secrets/grafana/admin_password.secret - grafana_admin_user: - # The observation dashboard's admin user. - file: ./secrets/grafana/admin_user.secret - grafana_discord_webhook: - # The observation dashboard's contact point for Discord. - file: ./secrets/grafana/discord_webhook.secret - jobber_aliases: - # The job scheduler's SMTP client mail alias. - file: ./secrets/jobber/aliases.secret - jobber_aws-bucket: - # The job scheduler's AWS bucket name. - file: ./secrets/jobber/aws-bucket.secret - jobber_aws-credentials: - # The job scheduler's AWS credentials. - file: ./secrets/jobber/aws-credentials.secret - jobber_aws-configuration: - # The job scheduler's AWS configuration. - file: ./secrets/jobber/aws-configuration.secret - jobber_msmtprc: - # The job scheduler's SMTP client configuration. - file: ./secrets/jobber/msmtprc.secret - portainer_admin-password: - # The container manager's admin password. - file: ./secrets/portainer/admin-password.secret - postgraphile_connection: - # The GraphQL API's database URI. - file: ./secrets/postgraphile/connection.secret - postgraphile_jwt-secret: - # The GraphQL API's JWT secret. - file: ./secrets/postgraphile/jwt-secret.secret - postgraphile_owner-connection: - # The GraphQL API's database owner URI. - file: ./secrets/postgraphile/owner-connection.secret - postgres_db: - # The database's name. - file: ./secrets/postgres/db.secret - postgres_password: - # The database's password. - file: ./secrets/postgres/password.secret - postgres_role_service_grafana_password: - # The password of the observation dashboard's database role. - file: ./secrets/postgres/role_service_grafana_password.secret - postgres_role_service_grafana_username: - # The username of the observation dashboard's database role. - file: ./secrets/postgres/role_service_grafana_username.secret - postgres_role_service_postgraphile_password: - # The password of the GraphQL API database wrapper's database role. - file: ./secrets/postgres/role_service_postgraphile_password.secret - postgres_role_service_postgraphile_username: - # The username of the GraphQL API database wrapper's database role. - file: ./secrets/postgres/role_service_postgraphile_username.secret - postgres_role_service_reccoom_password: - # The password of the recommendation engine's database role. - file: ./secrets/postgres/role_service_reccoom_password.secret - postgres_role_service_reccoom_username: - # The username of the recommendation engine's database role. - file: ./secrets/postgres/role_service_reccoom_username.secret - postgres_role_service_vibetype_password: - # The `tusd` database role's password. - file: ./secrets/postgres/role_service_vibetype_password.secret - postgres_role_service_vibetype_username: - # The `tusd` database role's password. - file: ./secrets/postgres/role_service_vibetype_username.secret - postgres_role_service_zammad_password: - # The password of the customer service database role. - file: ./secrets/postgres/role_service_zammad_password.secret - postgres_role_service_zammad_username: - # The username of the customer service database role. - file: ./secrets/postgres/role_service_zammad_username.secret - postgres_user: - # The database's default user. - file: ./secrets/postgres/user.secret - reccoom_ingest-api-key: - # The AI provider's API key for the recommendation engine. - file: ./secrets/reccoom/ingest-api-key.secret - reccoom_model-api-key: - # The AI model provider's API key. - file: ./secrets/reccoom/model-api-key.secret - reccoom_openai-api-key: - # The AI provider's API key for the recommendation engine. - file: ./secrets/reccoom/openai-api-key.secret - reccoom_sentry-dsn: - # The Sentry DSN for the AI service. - file: ./secrets/reccoom/sentry-dsn.secret - sqitch_target: - # The database change management application's database connection string. - file: ./secrets/sqitch/target.secret - tusd_aws: - # The upload service's s3 credentials file. - file: ./secrets/tusd/aws.secret - vibetype_api-notification-secret: - # The notification endpoint's secret. - file: ./secrets/vibetype/api-notification.secret - vibetype_aws-credentials: - # The cloud computing provider's user credentials. - file: ./secrets/vibetype/aws-credentials.secret - vibetype_firebase-service-account-credentials: - # The notification provider's service account credentials. - file: ./secrets/vibetype/firebase-service-account-credentials.secret - vibetype_openai-api-key: - # The AI provider's API key for the frontend. - file: ./secrets/vibetype/openai-api-key.secret - vibetype_turnstile-key: - # The captcha provider's application key. - file: ./secrets/vibetype/turnstile-key.secret - vibetype_zammad: - # The ticket system's configuration. - file: ./secrets/vibetype/zammad.secret -services: - adminer: - # You can access the database's frontend at [adminer.app.localhost](https://adminer.app.localhost/). - # This information is required for login: - # - # | | | - # | -------- | ------------------- | - # | System | PostgreSQL | - # | Server | postgres | - # | Username | [postgres_user] | - # | Password | [postgres_password] | - # | Database | [postgres_db] | - # - # Values in square brackets are [Docker secrets](https://docs.docker.com/engine/swarm/secrets/). - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.adminer.entryPoints=web - - traefik.http.routers.adminer.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.adminer.rule=Host(`adminer.${STACK_DOMAIN}`) - - traefik.http.routers.adminer_secure.entryPoints=web-secure - - traefik.http.routers.adminer_secure.rule=Host(`adminer.${STACK_DOMAIN}`) - - traefik.http.routers.adminer_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.adminer.loadbalancer.server.port=8080 - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 10s - image: adminer:5.4.2-standalone - volumes: - - ../production/configurations/adminer/adminer.css:/var/www/html/adminer.css:ro - cadvisor: - # You can access the container metrics at [cadvisor.app.localhost](https://cadvisor.app.localhost/). - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.cadvisor.entryPoints=web - - traefik.http.routers.cadvisor.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.cadvisor.rule=Host(`cadvisor.${STACK_DOMAIN}`) - - traefik.http.routers.cadvisor_secure.entryPoints=web-secure - - traefik.http.routers.cadvisor_secure.rule=Host(`cadvisor.${STACK_DOMAIN}`) - - traefik.http.routers.cadvisor_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.cadvisor.loadbalancer.server.port=8080 - mode: global - placement: - constraints: - - node.platform.os == linux - image: ghcr.io/google/cadvisor:v0.60.3 - volumes: - - /:/rootfs:ro - - /var/run:/var/run:ro - - /sys:/sys:ro - - /var/lib/docker/:/var/lib/docker:ro - - /dev/disk/:/dev/disk:ro - debezium: - # You can see how changes in the database end up in the event stream using `redpanda-console`. - environment: - BOOTSTRAP_SERVERS: redpanda:9092 - CONFIG_STORAGE_TOPIC: connect_configs - GROUP_ID: 1 - OFFSET_STORAGE_TOPIC: connect_offsets - STATUS_STORAGE_TOPIC: connect_statuses - healthcheck: - test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://localhost:8083/connectors"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 90s - image: quay.io/debezium/connect:3.6 - volumes: - - debezium_kafka_configuration:/kafka/config - - debezium_kafka_data:/kafka/data - - debezium_kafka_logs:/kafka/logs - debezium-postgres-connector: - # You can check the database connector's setup logs using `portainer`. - command: /entrypoint.sh - deploy: - restart_policy: - condition: on-failure - entrypoint: sh - image: curlimages/curl:8.21.0 - secrets: - - postgres_db - - postgres_password - - postgres_user - volumes: - - ../production/configurations/debezium-postgres-connector/entrypoint.sh:/entrypoint.sh:ro - elasticsearch: - # You cannot access the search engine via a web interface. - deploy: - replicas: 0 # TODO: reenable once server setup is more fault tolerant - environment: - bootstrap.memory_lock: "true" - discovery.type: single-node - ELASTIC_PASSWORD_FILE: /run/secrets/elasticsearch-password - ES_JAVA_OPTS: -Xms1g -Xmx1g - KEYSTORE_PASSWORD_FILE: /run/secrets/elasticsearch-keystore_password - network.publish_host: elasticsearch - # healthcheck: - # test: ["CMD-SHELL", "NETRC=$(mktemp) && printf 'machine localhost\\nlogin elastic\\npassword %s\\n' \"$(cat /run/secrets/elasticsearch-password)\" > \"$NETRC\" && curl -fsS --netrc-file \"$NETRC\" --cacert /usr/share/elasticsearch/config/certs/http_ca.crt 'https://localhost:9200/_cluster/health?wait_for_status=yellow&timeout=5s' && rm -f \"$NETRC\" || { rm -f \"$NETRC\"; exit 1; }"] - # interval: 30s - # timeout: 10s - # retries: 3 - # start_period: 60s - image: elasticsearch:8.19.18 - secrets: - - source: elasticsearch-keystore_password - uid: "1000" - gid: "1000" - mode: 0o400 - - source: elasticsearch-password - uid: "1000" - gid: "1000" - mode: 0o400 - ulimits: - nofile: - soft: 65535 - hard: 65535 - memlock: - soft: -1 - hard: -1 - volumes: - - elasticsearch-configuration:/usr/share/elasticsearch/config - - elasticsearch_data:/usr/share/elasticsearch/data - geoip: - # You cannot access the ip geolocator via a web interface. - healthcheck: - test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://localhost:8080/actuator/health"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 10s - image: ghcr.io/observabilitystack/geoip-api:2026-02 - grafana: - # You can access the observation dashboard at [grafana.app.localhost](https://grafana.app.localhost/). - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.grafana.entryPoints=web - - traefik.http.routers.grafana.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.grafana.rule=Host(`grafana.${STACK_DOMAIN}`) - - traefik.http.routers.grafana_secure.entryPoints=web-secure - - traefik.http.routers.grafana_secure.rule=Host(`grafana.${STACK_DOMAIN}`) - - traefik.http.routers.grafana_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.grafana.loadbalancer.server.port=3000 - environment: - GF_DATABASE_HOST: postgres:5432 - GF_DATABASE_PASSWORD__FILE: /run/secrets/postgres_role_service_grafana_password - GF_DATABASE_TYPE: postgres - GF_DATABASE_USER__FILE: /run/secrets/postgres_role_service_grafana_username - GF_SECURITY_ADMIN_EMAIL__FILE: /run/secrets/grafana_admin_email - GF_SECURITY_ADMIN_PASSWORD__FILE: /run/secrets/grafana_admin_password - GF_SECURITY_ADMIN_USER__FILE: /run/secrets/grafana_admin_user - GF_SERVER_ROOT_URL: https://grafana.${STACK_DOMAIN}/ - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:3000/api/health"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 30s - image: grafana/grafana:12.4.5 - secrets: - - grafana_admin_email - - grafana_admin_password - - grafana_admin_user - - grafana_discord_webhook - - postgres_db - - postgres_role_service_grafana_password - - postgres_role_service_grafana_username - volumes: - - ../production/configurations/grafana/dashboards:/var/lib/grafana/dashboards:ro - - ../production/configurations/grafana/provisioning:/etc/grafana/provisioning:ro - - grafana_data:/var/lib/grafana - jobber: - # You cannot access the jobber via a web interface. - environment: - AWS_SHARED_CREDENTIALS_FILE: /run/secrets/jobber_aws-credentials - image: ghcr.io/dargmuesli/jobber-aws-msmtp:1.3.0 - secrets: - - source: jobber_aliases - target: /etc/aliases - - jobber_aws-bucket - - jobber_aws-credentials - - source: jobber_aws-configuration - target: /home/jobberuser/.aws/config - - source: jobber_msmtprc - target: /etc/msmtprc - volumes: - - ../production/backups/postgres/:/backups/ - - ./configurations/jobber/.jobber:/home/jobberuser/.jobber:ro - memcached: - # You cannot access the caching system via a web interface. - healthcheck: - test: ["CMD-SHELL", "echo version | nc -w1 localhost 11211 | grep -q VERSION || exit 1"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 5s - image: memcached:1.6.44-alpine - # command: memcached -m 256M - minio: #DARGSTACK-REMOVE - # You can access the s3 console at [minio.app.localhost](https://minio.app.localhost/). - # You can access the s3 api service at [s3.app.localhost](https://s3.app.localhost/) if you want to access via cli from outside the stack. - entrypoint: /patched-entrypoint.sh #DARGSTACK-REMOVE - command: server /data --console-address ":9001" #DARGSTACK-REMOVE - deploy: #DARGSTACK-REMOVE - labels: #DARGSTACK-REMOVE - - traefik.enable=true #DARGSTACK-REMOVE - # Minio Console - - traefik.http.routers.minio.entryPoints=web #DARGSTACK-REMOVE - - traefik.http.routers.minio.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.minio.rule=Host(`minio.${STACK_DOMAIN}`) #DARGSTACK-REMOVE - - traefik.http.routers.minio.service=minio #DARGSTACK-REMOVE - - traefik.http.routers.minio_secure.entryPoints=web-secure #DARGSTACK-REMOVE - - traefik.http.routers.minio_secure.rule=Host(`minio.${STACK_DOMAIN}`) #DARGSTACK-REMOVE - - traefik.http.routers.minio_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.routers.minio_secure.service=minio #DARGSTACK-REMOVE - - traefik.http.services.minio.loadbalancer.server.port=9001 #DARGSTACK-REMOVE - - traefik.http.services.minio.loadbalancer.passhostheader=true #DARGSTACK-REMOVE - # Minio itself - - traefik.http.routers.s3.entryPoints=web #DARGSTACK-REMOVE - - traefik.http.routers.s3.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.s3.rule=Host(`s3.${STACK_DOMAIN}`) #DARGSTACK-REMOVE - - traefik.http.routers.s3.service=s3 #DARGSTACK-REMOVE - - traefik.http.routers.s3_secure.entryPoints=web-secure #DARGSTACK-REMOVE - - traefik.http.routers.s3_secure.rule=Host(`s3.${STACK_DOMAIN}`) #DARGSTACK-REMOVE - - traefik.http.routers.s3_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.routers.s3_secure.service=s3 #DARGSTACK-REMOVE - - traefik.http.services.s3.loadbalancer.server.port=9000 #DARGSTACK-REMOVE - - traefik.http.services.s3.loadbalancer.passhostheader=true #DARGSTACK-REMOVE - image: minio/minio #DARGSTACK-REMOVE - volumes: #DARGSTACK-REMOVE - - minio_data:/data #DARGSTACK-REMOVE - - ./configurations/minio/entrypoint.sh:/patched-entrypoint.sh #DARGSTACK-REMOVE - environment: #DARGSTACK-REMOVE - MINIO_ROOT_PASSWORD: s3password #DARGSTACK-REMOVE - MINIO_ROOT_USER: s3user #DARGSTACK-REMOVE - node-exporter: - # You can view host metrics in the Grafana observation dashboard. - deploy: - mode: global - placement: - constraints: - - node.platform.os == linux - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:9100/metrics"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 10s - image: quay.io/prometheus/node-exporter:v1.11.1 - volumes: - - /proc:/host/proc:ro - - /sys:/host/sys:ro - - /:/rootfs:ro - command: - - --path.procfs=/host/proc - - --path.rootfs=/rootfs - - --path.sysfs=/host/sys - - --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/) - portainer: - # You can access the container manager's frontend at [portainer.app.localhost](https://portainer.app.localhost/). - command: -H tcp://tasks.portainer-agent:9001 --tlsskipverify --admin-password-file '/run/secrets/portainer_admin-password' - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.portainer.entryPoints=web - - traefik.http.routers.portainer.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.portainer.rule=Host(`portainer.${STACK_DOMAIN}`) - - traefik.http.routers.portainer_secure.entryPoints=web-secure - - traefik.http.routers.portainer_secure.rule=Host(`portainer.${STACK_DOMAIN}`) - - traefik.http.routers.portainer_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.portainer.loadbalancer.server.port=9000 - placement: - constraints: - - node.role == manager - replicas: 1 - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:9000/api/system/status"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 30s - image: portainer/portainer-ce:2.43.0-alpine - secrets: - - portainer_admin-password - volumes: - - portainer_data:/data - portainer-agent: - # You cannot access the container manager's agent directly. - deploy: - mode: global - placement: - constraints: - - node.platform.os == linux - image: portainer/agent:2.43.0 - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - /var/lib/docker/volumes:/var/lib/docker/volumes - postgraphile: - # You can access the GraphQL API for the PostgreSQL database at [postgraphile.app.localhost](https://postgraphile.app.localhost/). - deploy: - labels: - - traefik.enable=true - - traefik.http.middlewares.postgraphile_cors.headers.accessControlAllowCredentials=true - - traefik.http.middlewares.postgraphile_cors.headers.accessControlAllowHeaders=authorization - - traefik.http.middlewares.postgraphile_cors.headers.accessControlAllowOriginList=https://${STACK_DOMAIN},https://localhost:3000,https://app.localhost:3000 - - traefik.http.routers.postgraphile.entryPoints=web - - traefik.http.routers.postgraphile.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.postgraphile.rule=Host(`postgraphile.${STACK_DOMAIN}`) - - traefik.http.routers.postgraphile_secure.entryPoints=web-secure - - traefik.http.routers.postgraphile_secure.middlewares=postgraphile_cors - - traefik.http.routers.postgraphile_secure.rule=Host(`postgraphile.${STACK_DOMAIN}`) && Path(`/graphql`) - - traefik.http.routers.postgraphile_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.routers.postgraphile_secure_ruru.entryPoints=web-secure - - traefik.http.routers.postgraphile_secure_ruru.rule=Host(`postgraphile.${STACK_DOMAIN}`) - - traefik.http.routers.postgraphile_secure_ruru.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.postgraphile.loadbalancer.server.port=5678 - # # Use the DEBUG environment variable for extended debugging. - # environment: - # DEBUG: graphile-build:warn,graphile-build-pg:sql - image: maevsi/postgraphile:dev - secrets: - - source: postgraphile_connection - target: /run/environment-variables/POSTGRAPHILE_CONNECTION - - source: postgraphile_jwt-secret - target: /run/environment-variables/POSTGRAPHILE_JWT_SECRET_KEY - - source: postgraphile_owner-connection - target: /run/environment-variables/POSTGRAPHILE_OWNER_CONNECTION - volumes: - - ../../../postgraphile/:/srv/app/ #DARGSTACK-REMOVE - - ./configurations/postgraphile/jwtES256.key.pub:/run/environment-variables/POSTGRAPHILE_JWT_PUBLIC_KEY:ro - - pnpm_data:/srv/.pnpm-store/ #DARGSTACK-REMOVE - - postgraphile_data:/srv/app/node_modules #DARGSTACK-REMOVE - postgres: - # You can access the database via `adminer`. - command: -c vibetype.jwt_expiry_duration='1 month' -c wal_level=logical - environment: - POSTGRES_DB_FILE: /run/secrets/postgres_db - POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password - POSTGRES_USER_FILE: /run/secrets/postgres_user - healthcheck: - test: ["CMD-SHELL", "pg_isready -U $$(cat /run/secrets/postgres_user) -d $$(cat /run/secrets/postgres_db)"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - image: postgis/postgis:18-3.6-alpine - ports: #DARGSTACK-REMOVE - - 5432:5432 #DARGSTACK-REMOVE - secrets: - - postgres_db - - postgres_password - - postgres_user - # sysctls: - # # Prevent Docker Swarm from killing connections (https://github.com/moby/moby/issues/31208) - # - net.ipv4.tcp_keepalive_time=600 - # - net.ipv4.tcp_keepalive_intvl=30 - # - net.ipv4.tcp_keepalive_probes=10 - volumes: - - postgres_data:/var/lib/postgresql/ - prometheus: - # You can access the metrics monitoring at [prometheus.app.localhost](https://prometheus.app.localhost/). - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.prometheus.entryPoints=web - - traefik.http.routers.prometheus.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.prometheus.rule=Host(`prometheus.${STACK_DOMAIN}`) - - traefik.http.routers.prometheus_secure.entryPoints=web-secure - - traefik.http.routers.prometheus_secure.rule=Host(`prometheus.${STACK_DOMAIN}`) - - traefik.http.routers.prometheus_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.prometheus.loadbalancer.server.port=9090 - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:9090/-/healthy"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 15s - image: prom/prometheus:v3.13.0 - volumes: - - ../production/configurations/prometheus/prometheus.yaml:/etc/prometheus/prometheus.yml:ro - - prometheus_data:/prometheus - reccoom: - # You cannot access the recommendation service directly. - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.reccoom.entryPoints=web - - traefik.http.routers.reccoom.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.reccoom.rule=Host(`reccoom.${STACK_DOMAIN}`) - - traefik.http.routers.reccoom_secure.entryPoints=web-secure - - traefik.http.routers.reccoom_secure.rule=Host(`reccoom.${STACK_DOMAIN}`) - - traefik.http.routers.reccoom_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.reccoom.loadbalancer.server.port=5245 - environment: - POSTGRES_HOST: postgres - RECCOOM_POSTGRES_HOST: reccoom_postgres - image: maevsi/reccoom:dev - secrets: - - source: postgres_db - target: /run/environment-variables/POSTGRES_DATABASE - - source: postgres_db - target: /run/environment-variables/RECCOOM_POSTGRES_DATABASE - - source: postgres_role_service_reccoom_username - target: /run/environment-variables/POSTGRES_USER - - source: postgres_user - target: /run/environment-variables/RECCOOM_POSTGRES_USER - - source: postgres_role_service_reccoom_password - target: /run/environment-variables/POSTGRES_PASSWORD - - source: postgres_password - target: /run/environment-variables/RECCOOM_POSTGRES_PASSWORD - - source: reccoom_ingest-api-key - target: /run/environment-variables/INGEST_API_KEY - - source: reccoom_model-api-key - target: /run/environment-variables/MODEL_API_KEY - - source: reccoom_openai-api-key - target: /run/environment-variables/OPENAI_API_KEY - - source: reccoom_sentry-dsn - target: /run/environment-variables/SENTRY_DSN - volumes: - - ../../../reccoom/:/srv/app/ #DARGSTACK-REMOVE - - ./configurations/postgraphile/jwtES256.key.pub:/run/configurations/jwtES256.key.pub:ro - - reccoom_data:/home/python/.cache/ - reccoom_consumer: - # You can track the recommender's event streaming consumer using `redpanda-console`. - command: ["uv", "run", "python", "-m", "src.consumer"] - environment: - KAFKA_BOOTSTRAP_SERVERS: redpanda:9092 - POSTGRES_HOST: postgres - RECCOOM_POSTGRES_HOST: reccoom_postgres - healthcheck: - test: ["CMD-SHELL", "test -f /home/python/consumer-alive && [ $$(( $$(date +%s) - $$(date +%s -r /home/python/consumer-alive) )) -lt 60 ]"] - timeout: 5s - image: maevsi/reccoom:dev - secrets: - - source: postgres_db - target: /run/environment-variables/POSTGRES_DATABASE - - source: postgres_db - target: /run/environment-variables/RECCOOM_POSTGRES_DATABASE - - source: postgres_role_service_reccoom_username - target: /run/environment-variables/POSTGRES_USER - - source: postgres_user - target: /run/environment-variables/RECCOOM_POSTGRES_USER - - source: postgres_role_service_reccoom_password - target: /run/environment-variables/POSTGRES_PASSWORD - - source: postgres_password - target: /run/environment-variables/RECCOOM_POSTGRES_PASSWORD - - source: reccoom_sentry-dsn - target: /run/environment-variables/SENTRY_DSN - volumes: - - reccoom_fastembed_data:/tmp/fastembed_cache/ - - reccoom_data:/home/python/.cache/ - reccoom_migration: - # You cannot access the recommender's database migration service directly. - command: ["uv", "run", "python", "-m", "src.migration"] - deploy: - restart_policy: - condition: on-failure - environment: - RECCOOM_POSTGRES_HOST: reccoom_postgres - image: maevsi/reccoom:dev - secrets: - - source: postgres_db - target: /run/environment-variables/RECCOOM_POSTGRES_DATABASE - - source: postgres_user - target: /run/environment-variables/RECCOOM_POSTGRES_USER - - source: postgres_password - target: /run/environment-variables/RECCOOM_POSTGRES_PASSWORD - - source: reccoom_sentry-dsn - target: /run/environment-variables/SENTRY_DSN - volumes: - - ../../../reccoom/:/srv/app/ - - reccoom_data:/home/python/.cache/ - reccoom_postgres: - # You can access reccoom's database via `adminer`. - environment: - POSTGRES_DB_FILE: /run/secrets/postgres_db - POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password - POSTGRES_USER_FILE: /run/secrets/postgres_user - healthcheck: - test: ["CMD-SHELL", "pg_isready -U $$(cat /run/secrets/postgres_user) -d $$(cat /run/secrets/postgres_db)"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - image: pgvector/pgvector:0.8.5-pg18 - ports: #DARGSTACK-REMOVE - - 5433:5432 #DARGSTACK-REMOVE - secrets: - - postgres_db - - postgres_password - - postgres_user - volumes: - - reccoom_postgres_data:/var/lib/postgresql/ - redis: - # You cannot access the caching system via a web interface. - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 5s - retries: 5 - start_period: 10s - image: redis:8.8.0-alpine - volumes: - - redis_data:/data - redpanda: - # You can access the event streaming platform's ui as described under `redpanda-console`. - command: - - redpanda start - - --mode dev-container #DARGSTACK-REMOVE - - --kafka-addr internal://0.0.0.0:9092,external://0.0.0.0:19092 - - --advertise-kafka-addr internal://redpanda:9092,external://localhost:19092 - - --pandaproxy-addr internal://0.0.0.0:8082,external://0.0.0.0:18082 - - --advertise-pandaproxy-addr internal://redpanda:8082,external://localhost:18082 - - --schema-registry-addr internal://0.0.0.0:8081,external://0.0.0.0:18081 - healthcheck: - test: ["CMD", "rpk", "cluster", "health", "--exit-when-healthy"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 30s - image: redpandadata/redpanda:v26.1.12 - volumes: - - redpanda_data:/var/lib/redpanda/data - redpanda-console: - # You can access the event streaming platform's ui at [redpanda.app.localhost](https://redpanda.app.localhost/). - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.redpanda.entryPoints=web - - traefik.http.routers.redpanda.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.redpanda.rule=Host(`redpanda.${STACK_DOMAIN}`) - - traefik.http.routers.redpanda_secure.entryPoints=web-secure - - traefik.http.routers.redpanda_secure.rule=Host(`redpanda.${STACK_DOMAIN}`) - - traefik.http.routers.redpanda_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.redpanda.loadbalancer.server.port=8080 - environment: - CONFIG_FILEPATH: /srv/app/redpanda-config.yaml - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/admin/health"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 15s - image: redpandadata/console:v3.8.0 - volumes: - - ../production/configurations/redpanda/config.yaml:/srv/app/redpanda-config.yaml:ro - sqitch: - # You cannot access the database migrations directly. - deploy: - restart_policy: - condition: on-failure - image: maevsi/sqitch:dev - secrets: - - postgres_role_service_grafana_password - - postgres_role_service_grafana_username - - postgres_role_service_postgraphile_password - - postgres_role_service_postgraphile_username - - postgres_role_service_reccoom_password - - postgres_role_service_reccoom_username - - postgres_role_service_vibetype_password - - postgres_role_service_vibetype_username - - postgres_role_service_zammad_username - - postgres_role_service_zammad_password - - sqitch_target - volumes: - - ../../../sqitch/:/srv/app/ - traefik: - # You can access the reverse proxy's dashboard at [traefik.app.localhost](https://traefik.app.localhost/). - command: - - --api=true - - --entryPoints.web.address=:80 - - --entryPoints.web-secure.address=:443 - - --entryPoints.web-secure.http.encodedCharacters.allowEncodedSlash=true #DARGSTACK-REMOVE # required for Nuxt's virtual imports - - --ping=true - - --providers.swarm=true - - --providers.swarm.endpoint=unix:///var/run/docker.sock - - --providers.swarm.exposedByDefault=false - - --providers.file.filename=/dynamic.yml #DARGSTACK-REMOVE - - --providers.file.watch=true #DARGSTACK-REMOVE - - --log.level=DEBUG #DARGSTACK-REMOVE - deploy: - labels: - - traefik.enable=true - - traefik.http.middlewares.redirectscheme.redirectscheme.scheme=https #DARGSTACK-REMOVE - - traefik.http.routers.traefik.entryPoints=web - - traefik.http.routers.traefik.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.traefik.rule=Host(`traefik.${STACK_DOMAIN}`) - - traefik.http.routers.traefik.service=api@internal - - traefik.http.routers.traefik_secure.entryPoints=web-secure - - traefik.http.routers.traefik_secure.rule=Host(`traefik.${STACK_DOMAIN}`) - - traefik.http.routers.traefik_secure.service=api@internal - - traefik.http.routers.traefik_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.traefik.loadbalancer.server.port=8080 - mode: global - placement: - constraints: - - node.role == manager - healthcheck: - test: ["CMD", "traefik", "healthcheck", "--ping"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 15s - image: traefik:v3.7.7 - ports: #DARGSTACK-REMOVE - - mode: host #DARGSTACK-REMOVE - protocol: tcp #DARGSTACK-REMOVE - published: 80 #DARGSTACK-REMOVE - target: 80 #DARGSTACK-REMOVE - - mode: host #DARGSTACK-REMOVE - protocol: tcp #DARGSTACK-REMOVE - published: 443 #DARGSTACK-REMOVE - target: 443 #DARGSTACK-REMOVE - volumes: - - /var/run/docker.sock:/var/run/docker.sock - - ./certificates/:/etc/traefik/acme/ - - ./configurations/traefik/dynamic.yml:/dynamic.yml:ro #DARGSTACK-REMOVE - tusd: - # You can access the upload service at [tusd.app.localhost](https://tusd.app.localhost/). - command: -behind-proxy --hooks-enabled-events pre-create,pre-finish,pre-terminate --hooks-http http://vibetype:3000/api/internal/service/tusd -max-size ${TUSD_MAX_SIZE} -s3-bucket ${TUSD_BUCKET} -s3-endpoint ${TUSD_ENDPOINT} - deploy: - labels: - - traefik.enable=true - - traefik.http.middlewares.tusd_cors.headers.customresponseheaders.Cross-Origin-Resource-Policy=cross-origin - - traefik.http.routers.tusd.entryPoints=web - - traefik.http.routers.tusd.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.tusd.rule=Host(`tusd.${STACK_DOMAIN}`) - - traefik.http.routers.tusd_secure.entryPoints=web-secure - - traefik.http.routers.tusd_secure.middlewares=tusd_cors - - traefik.http.routers.tusd_secure.rule=Host(`tusd.${STACK_DOMAIN}`) && (Method(`GET`) || Method(`HEAD`) || Method(`OPTIONS`) || Method(`POST`) || Method(`PUT`) || Method(`PATCH`)) - - traefik.http.routers.tusd_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.tusd.loadbalancer.server.port=8080 - environment: - AWS_REGION: ${TUSD_REGION} - healthcheck: - test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 10s - image: tusproject/tusd:v2.10.0 - secrets: - - source: tusd_aws - target: /home/tusd/.aws/credentials - vibetype: - # You can access the main project's frontend at [app.localhost](https://app.localhost/). - deploy: - labels: - - traefik.enable=true - - traefik.http.middlewares.vibetype_cors.headers.accessControlAllowHeaders=authorization,content-type,hook-name,x-csrf-token,x-turnstile-key - - traefik.http.middlewares.vibetype_cors.headers.accessControlAllowMethods=GET,POST,PUT,DELETE - - traefik.http.middlewares.vibetype_cors.headers.accessControlAllowOriginList=https://localhost:3000,https://app.localhost:3000 - - traefik.http.middlewares.vibetype_redirectregex.redirectregex.regex=^https?:\/\/www\.${STACK_DOMAIN}\/(.*) - - traefik.http.middlewares.vibetype_redirectregex.redirectregex.replacement=https://${STACK_DOMAIN}/$${2} - - traefik.http.routers.vibetype.entryPoints=web - - traefik.http.routers.vibetype.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.vibetype.rule=(Host(`${STACK_DOMAIN}`) || Host(`www.${STACK_DOMAIN}`)) && !PathPrefix(`/api/internal`) - - traefik.http.routers.vibetype_secure.entryPoints=web-secure - - traefik.http.routers.vibetype_secure.middlewares=vibetype_cors,vibetype_redirectregex - - traefik.http.routers.vibetype_secure.rule=(Host(`${STACK_DOMAIN}`) || Host(`www.${STACK_DOMAIN}`)) && !PathPrefix(`/api/internal`) - - traefik.http.routers.vibetype_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.vibetype.loadbalancer.server.port=3000 - environment: - AWS_REGION: ${VIBETYPE_AWS_REGION} - NUXT_PUBLIC_GTAG_ID: ${VIBETYPE_NUXT_PUBLIC_GTAG_ID} - NUXT_PUBLIC_I18N_BASE_URL: https://${STACK_DOMAIN} - NUXT_PUBLIC_SITE_URL: https://${STACK_DOMAIN} - NUXT_PUBLIC_TURNSTILE_SITE_KEY: ${VIBETYPE_NUXT_PUBLIC_TURNSTILE_SITE_KEY} - NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H: ${VIBETYPE_NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H} - PGHOST: postgres - image: maevsi/vibetype:dev - secrets: - - source: vibetype_api-notification-secret - target: /run/environment-variables/NUXT_API_NOTIFICATION_SECRET - - source: vibetype_aws-credentials - target: /home/node/.aws/credentials - - source: vibetype_firebase-service-account-credentials - target: /run/environment-variables/FIREBASE_SERVICE_ACCOUNT_CREDENTIALS - - source: vibetype_openai-api-key - target: /run/environment-variables/NUXT_OPENAI_API_KEY - - source: vibetype_turnstile-key - target: /run/environment-variables/NUXT_TURNSTILE_SECRET_KEY - - source: vibetype_zammad - target: /run/environment-variables/NUXT_VIBETYPE_ZAMMAD - - source: postgres_db - target: /run/environment-variables/PGDATABASE - - source: postgres_role_service_vibetype_password - target: /run/environment-variables/PGPASSWORD - - source: postgres_role_service_vibetype_username - target: /run/environment-variables/PGUSER - user: node:node # files created inside a docker container, like node_modules by pnpm, gain correct permissions by setting the user to `node` - volumes: - - pnpm_data:/srv/.pnpm-store/ #DARGSTACK-REMOVE - - ./certificates/:/srv/certificates/ #DARGSTACK-REMOVE - - ../../../vibetype/:/srv/app/ #DARGSTACK-REMOVE - - vibetype_data:/srv/app/node_modules #DARGSTACK-REMOVE - - ./configurations/postgraphile/jwtES256.key.pub:/run/environment-variables/NUXT_PUBLIC_VIO_AUTH_JWT_PUBLIC_KEY:ro - zammad-backup: - # You cannot access the helpdesk backup service via a web interface. - <<: *zammad-service - command: ["zammad-backup"] - user: 0:0 - volumes: - - zammad-backup_data:/var/tmp/zammad - - zammad_data:/opt/zammad/storage:ro - - ../production/configurations/zammad/docker-entrypoint.sh:/docker-entrypoint.sh:ro - zammad-init: - # You cannot access the helpdesk initialization service via a web interface. - <<: *zammad-service - command: ["zammad-init"] - deploy: - restart_policy: - condition: on-failure - user: 0:0 - zammad-nginx: - # You can access the helpdesk at [zammad.app.localhost](https://zammad.app.localhost/). - <<: *zammad-service - command: ["zammad-nginx"] - deploy: - labels: - - traefik.enable=true - - traefik.http.routers.zammad.entryPoints=web - - traefik.http.routers.zammad.middlewares=redirectscheme #DARGSTACK-REMOVE - - traefik.http.routers.zammad.rule=Host(`zammad.${STACK_DOMAIN}`) - - traefik.http.routers.zammad_secure.entryPoints=web-secure - - traefik.http.routers.zammad_secure.rule=Host(`zammad.${STACK_DOMAIN}`) - - traefik.http.routers.zammad_secure.tls.options=mintls13@file #DARGSTACK-REMOVE - - traefik.http.services.zammad.loadbalancer.server.port=8080 - healthcheck: - test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://127.0.0.1:8080/"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 30s - zammad-railsserver: - # You cannot access the helpdesk application server directly. - <<: *zammad-service - command: ["zammad-railsserver"] - healthcheck: - test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://127.0.0.1:3000/"] - interval: 30s - timeout: 5s - retries: 3 - start_period: 60s - zammad-scheduler: - # You cannot access the helpdesk scheduler directly. - <<: *zammad-service - command: ["zammad-scheduler"] - zammad-websocket: - # You cannot access the helpdesk websocket server directly. - <<: *zammad-service - command: ["zammad-websocket"] -version: "3.7" -volumes: - debezium_kafka_configuration: - # The change data capture's configuration. - {} - debezium_kafka_data: - # The change data capture's data. - {} - debezium_kafka_logs: - # The change data capture's logs. - {} - elasticsearch-configuration: - # The search engine's configuration. - {} - elasticsearch_data: - # The search engine's data. - {} - grafana_data: - # The observation dashboard's data. - {} - minio_data: - # The s3 server's data. - {} - pnpm_data: - # The node package manager's data. - {} - portainer_data: - # The container manager's data. - {} - postgraphile_data: - # The GraphQL API's data. - {} - postgres_data: - # The database's data. - {} - prometheus_data: - # The metrics monitoring's data. - {} - reccoom_data: - # The recommender's model cache. - {} - reccoom_postgres_data: - # The recommendation database's data. - {} - redis_data: - # The caching system's data. - {} - redpanda_data: - # The message queue's data. - {} - vibetype_data: - # The frontend's data. - {} - zammad-backup_data: - # The helpdesk backup's data. - {} - zammad_data: - # The helpdesk's data. - {} diff --git a/src/development/traefik/compose.yaml b/src/development/traefik/compose.yaml new file mode 100644 index 00000000..5ecd920c --- /dev/null +++ b/src/development/traefik/compose.yaml @@ -0,0 +1,53 @@ +services: + traefik: + # You can access the reverse proxy's dashboard at [traefik.app.localhost](https://traefik.app.localhost/). + command: + - --api=true + - --entryPoints.web.address=:80 + - --entryPoints.web-secure.address=:443 + - --entryPoints.web-secure.http.encodedCharacters.allowEncodedSlash=true # dargstack:dev-only # required for Nuxt's virtual imports + - --ping=true + - --providers.swarm=true + - --providers.swarm.endpoint=unix:///var/run/docker.sock + - --providers.swarm.exposedByDefault=false + - --providers.file.filename=/dynamic.yml # dargstack:dev-only + - --providers.file.watch=true # dargstack:dev-only + - --log.level=DEBUG # dargstack:dev-only + deploy: + labels: + - dargstack.profiles=default + - traefik.enable=true + - traefik.http.middlewares.redirectscheme.redirectscheme.scheme=https # dargstack:dev-only + - traefik.http.routers.traefik.entryPoints=web + - traefik.http.routers.traefik.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.traefik.rule=Host(`traefik.${STACK_DOMAIN}`) + - traefik.http.routers.traefik.service=api@internal + - traefik.http.routers.traefik-secure.entryPoints=web-secure + - traefik.http.routers.traefik-secure.rule=Host(`traefik.${STACK_DOMAIN}`) + - traefik.http.routers.traefik-secure.service=api@internal + - traefik.http.routers.traefik-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.traefik.loadbalancer.server.port=8080 + mode: global + placement: + constraints: + - node.role == manager + healthcheck: + test: ["CMD", "traefik", "healthcheck", "--ping"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 15s + image: traefik:v3.7.7 + ports: # dargstack:dev-only + - mode: host # dargstack:dev-only + protocol: tcp # dargstack:dev-only + published: 80 # dargstack:dev-only + target: 80 # dargstack:dev-only + - mode: host # dargstack:dev-only + protocol: tcp # dargstack:dev-only + published: 443 # dargstack:dev-only + target: 443 # dargstack:dev-only + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ~~/artifacts/certificates/:/etc/traefik/acme/ + - ./configurations/dynamic.yml:/dynamic.yml:ro # dargstack:dev-only diff --git a/src/development/traefik/configurations/dynamic.yml b/src/development/traefik/configurations/dynamic.yml new file mode 100644 index 00000000..705f4828 --- /dev/null +++ b/src/development/traefik/configurations/dynamic.yml @@ -0,0 +1,7 @@ +tls: + certificates: + - certFile: /etc/traefik/acme/localhost.pem + keyFile: /etc/traefik/acme/localhost-key.pem + options: + mintls13: + minVersion: VersionTLS13 diff --git a/src/development/tusd/compose.yaml b/src/development/tusd/compose.yaml new file mode 100644 index 00000000..6a8c4c25 --- /dev/null +++ b/src/development/tusd/compose.yaml @@ -0,0 +1,41 @@ +secrets: + tusd-aws: + # The upload service's s3 credentials file. + file: ~~/artifacts/secrets/tusd-aws.secret +services: + tusd: + # You can access the upload service at [tusd.app.localhost](https://tusd.app.localhost/). + command: -behind-proxy --hooks-enabled-events pre-create,pre-finish,pre-terminate --hooks-http http://vibetype:3000/api/internal/service/tusd -max-size ${TUSD_MAX_SIZE} -s3-bucket ${TUSD_BUCKET} -s3-endpoint ${TUSD_ENDPOINT} + deploy: + labels: + - dargstack.profiles=upload + - traefik.enable=true + - traefik.http.middlewares.tusd-cors.headers.customresponseheaders.Cross-Origin-Resource-Policy=cross-origin + - traefik.http.routers.tusd.entryPoints=web + - traefik.http.routers.tusd.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.tusd.rule=Host(`tusd.${STACK_DOMAIN}`) + - traefik.http.routers.tusd-secure.entryPoints=web-secure + - traefik.http.routers.tusd-secure.middlewares=tusd-cors + - traefik.http.routers.tusd-secure.rule=Host(`tusd.${STACK_DOMAIN}`) && (Method(`GET`) || Method(`HEAD`) || Method(`OPTIONS`) || Method(`POST`) || Method(`PUT`) || Method(`PATCH`)) + - traefik.http.routers.tusd-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.tusd.loadbalancer.server.port=8080 + environment: + AWS_REGION: ${TUSD_REGION} + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8080/"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 10s + image: tusproject/tusd:v2.10.0 + secrets: + - source: tusd-aws + target: /home/tusd/.aws/credentials +x-dargstack: + secrets: + tusd-aws: + insecure_default: | + [default] + aws_access_key_id = s3user + aws_secret_access_key = s3password + type: insecure_default diff --git a/src/development/vibetype/compose.yaml b/src/development/vibetype/compose.yaml new file mode 100644 index 00000000..d2f7a782 --- /dev/null +++ b/src/development/vibetype/compose.yaml @@ -0,0 +1,125 @@ +secrets: + vibetype-api-notification-secret: + # The notification endpoint's secret. + file: ~~/artifacts/secrets/vibetype-api-notification.secret + vibetype-aws-credentials: + # The cloud computing provider's user credentials. + file: ~~/artifacts/secrets/vibetype-aws-credentials.secret + vibetype-firebase-service-account-credentials: + # The notification provider's service account credentials. + file: ~~/artifacts/secrets/vibetype-firebase-service-account-credentials.secret + vibetype-openai-api-key: + # The AI provider's API key for the frontend. + file: ~~/artifacts/secrets/vibetype-openai-api-key.secret + vibetype-turnstile-key: + # The captcha provider's application key. + file: ~~/artifacts/secrets/vibetype-turnstile-key.secret + vibetype-zammad: + # The ticket system's configuration. + file: ~~/artifacts/secrets/vibetype-zammad.secret +services: + vibetype: + # You can access the main project's frontend at [app.localhost](https://app.localhost/). + deploy: + labels: + - dargstack.development.git=git@github.com:maevsi/vibetype.git + - dargstack.profiles=default + - traefik.enable=true + - traefik.http.middlewares.vibetype-cors.headers.accessControlAllowHeaders=authorization,content-type,hook-name,x-csrf-token,x-turnstile-key + - traefik.http.middlewares.vibetype-cors.headers.accessControlAllowMethods=GET,POST,PUT,DELETE + - traefik.http.middlewares.vibetype-cors.headers.accessControlAllowOriginList=https://localhost:3000,https://app.localhost:3000 + - traefik.http.middlewares.vibetype-redirectregex.redirectregex.regex=^https?:\/\/www\.${STACK_DOMAIN}\/(.*) + - traefik.http.middlewares.vibetype-redirectregex.redirectregex.replacement=https://${STACK_DOMAIN}/$${1} + - traefik.http.routers.vibetype.entryPoints=web + - traefik.http.routers.vibetype.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.vibetype.rule=(Host(`${STACK_DOMAIN}`) || Host(`www.${STACK_DOMAIN}`)) && !PathPrefix(`/api/internal`) + - traefik.http.routers.vibetype-secure.entryPoints=web-secure + - traefik.http.routers.vibetype-secure.middlewares=vibetype-cors,vibetype-redirectregex + - traefik.http.routers.vibetype-secure.rule=(Host(`${STACK_DOMAIN}`) || Host(`www.${STACK_DOMAIN}`)) && !PathPrefix(`/api/internal`) + - traefik.http.routers.vibetype-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.vibetype.loadbalancer.server.port=3000 + environment: + AWS_REGION: ${VIBETYPE_AWS_REGION} + NUXT_PUBLIC_GTAG_ID: ${VIBETYPE_NUXT_PUBLIC_GTAG_ID} + NUXT_PUBLIC_I18N_BASE_URL: https://${STACK_DOMAIN} + NUXT_PUBLIC_SITE_URL: https://${STACK_DOMAIN} + NUXT_PUBLIC_TURNSTILE_SITE_KEY: ${VIBETYPE_NUXT_PUBLIC_TURNSTILE_SITE_KEY} + NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H: ${VIBETYPE_NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H} + PGHOST: postgres + image: vibetype/vibetype:development + secrets: + - source: vibetype-api-notification-secret + target: /run/environment-variables/NUXT_API_NOTIFICATION_SECRET + - source: vibetype-aws-credentials + target: /home/node/.aws/credentials + - source: vibetype-firebase-service-account-credentials + target: /run/environment-variables/FIREBASE_SERVICE_ACCOUNT_CREDENTIALS + - source: vibetype-openai-api-key + target: /run/environment-variables/NUXT_OPENAI_API_KEY + - source: vibetype-turnstile-key + target: /run/environment-variables/NUXT_TURNSTILE_SECRET_KEY + - source: vibetype-zammad + target: /run/environment-variables/NUXT_VIBETYPE_ZAMMAD + - source: postgres-db + target: /run/environment-variables/PGDATABASE + - source: postgres-role-service-vibetype-password + target: /run/environment-variables/PGPASSWORD + - source: postgres-role-service-vibetype-username + target: /run/environment-variables/PGUSER + volumes: + - pnpm-data:/srv/.pnpm-store/ # dargstack:dev-only + - ~~/artifacts/certificates/:/srv/certificates/ # dargstack:dev-only + - ~~~/vibetype/:/srv/app/ # dargstack:dev-only + - vibetype-data:/srv/app/node_modules # dargstack:dev-only + - ../postgraphile/configurations/jwtES256.key.pub:/run/environment-variables/NUXT_PUBLIC_VIO_AUTH_JWT_PUBLIC_KEY:ro +volumes: + vibetype-data: + # The frontend's data. + {} +x-dargstack: + secrets: + vibetype-api-notification-secret: + type: random_string + vibetype-aws-credentials: + template: | + [stomper] + aws_access_key_id = {{secret:vibetype-aws-credentials-access-key-id}} + aws_secret_access_key = {{secret:vibetype-aws-credentials-access-key}} + vibetype-aws-credentials-access-key: + type: third_party + vibetype-aws-credentials-access-key-id: + type: third_party + vibetype-firebase-service-account-credentials: + template: | + { + "type": "service_account", + "project_id": "maevsi-3f373", + "private_key_id": "{{secret:vibetype-firebase-service-account-credentials-private-key-id}}", + "private_key": "{{secret:vibetype-firebase-service-account-credentials-private-key}}", + "client_email": "firebase-adminsdk-fbsvc@maevsi-3f373.iam.gserviceaccount.com", + "client_id": "{{secret:vibetype-firebase-service-account-credentials-client-id}}", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40maevsi-3f373.iam.gserviceaccount.com", + "universe_domain": "googleapis.com" + } + vibetype-firebase-service-account-credentials-client-id: + type: third_party + vibetype-firebase-service-account-credentials-private-key-id: + type: third_party + vibetype-firebase-service-account-credentials-private-key: + type: third_party + vibetype-openai-api-key: + type: third_party + vibetype-turnstile-key: + insecure_default: 1x0000000000000000000000000000000AA + vibetype-zammad: + template: | + { + "apiToken": "{{secret:vibetype-zammad-api-token}}", + "group": "Users", + "url": "https://support.example.com" + } + vibetype-zammad-api-token: + type: third_party diff --git a/src/development/zammad/compose.yaml b/src/development/zammad/compose.yaml new file mode 100644 index 00000000..10aafac1 --- /dev/null +++ b/src/development/zammad/compose.yaml @@ -0,0 +1,95 @@ +x-shared: + zammad-service: + &zammad-service # You can access the helpdesk at [zammad.app.localhost](https://zammad.app.localhost/). + deploy: + labels: + - dargstack.profiles=zammad + environment: &zammad-environment + ELASTICSEARCH_ENABLED: "false" + ELASTICSEARCH_HOST: elasticsearch + ELASTICSEARCH_SCHEMA: https + ELASTICSEARCH_USER: elastic + MEMCACHE_SERVERS: memcached:11211 + NGINX_SERVER_SCHEME: https + POSTGRESQL_DB: zammad + POSTGRESQL_DB_CREATE: "false" + POSTGRESQL_HOST: postgres + POSTGRESQL_OPTIONS: ?pool=50 + REDIS_URL: redis://redis:6379 + image: ghcr.io/zammad/zammad:6.5.2-90 + secrets: + - source: elasticsearch-password + target: /run/environment-variables/ELASTICSEARCH_PASS + - source: postgres-role-service-zammad-username + target: /run/environment-variables/POSTGRESQL_USER + - source: postgres-role-service-zammad-password + target: /run/environment-variables/POSTGRESQL_PASS + volumes: + - zammad-data:/opt/zammad/storage + - ./configurations/docker-entrypoint.sh:/docker-entrypoint.sh:ro +services: + zammad-backup: + # You cannot access the helpdesk backup service via a web interface. + <<: *zammad-service + command: ["zammad-backup"] + user: 0:0 + volumes: + - zammad-backup-data:/var/tmp/zammad + - zammad-data:/opt/zammad/storage:ro + - ./configurations/docker-entrypoint.sh:/docker-entrypoint.sh:ro + zammad-init: + # You cannot access the helpdesk initialization service via a web interface. + <<: *zammad-service + command: ["zammad-init"] + deploy: + labels: + - dargstack.profiles=zammad + restart_policy: + condition: on-failure + user: 0:0 + zammad-nginx: + # You can access the helpdesk at [zammad.app.localhost](https://zammad.app.localhost/). + <<: *zammad-service + command: ["zammad-nginx"] + deploy: + labels: + - dargstack.profiles=zammad + - traefik.enable=true + - traefik.http.routers.zammad.entryPoints=web + - traefik.http.routers.zammad.middlewares=redirectscheme # dargstack:dev-only + - traefik.http.routers.zammad.rule=Host(`zammad.${STACK_DOMAIN}`) + - traefik.http.routers.zammad-secure.entryPoints=web-secure + - traefik.http.routers.zammad-secure.rule=Host(`zammad.${STACK_DOMAIN}`) + - traefik.http.routers.zammad-secure.tls.options=mintls13@file # dargstack:dev-only + - traefik.http.services.zammad.loadbalancer.server.port=8080 + healthcheck: + test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://127.0.0.1:8080/"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 30s + zammad-railsserver: + # You cannot access the helpdesk application server directly. + <<: *zammad-service + command: ["zammad-railsserver"] + healthcheck: + test: ["CMD", "curl", "--fail", "--silent", "--show-error", "http://127.0.0.1:3000/"] + interval: 30s + timeout: 5s + retries: 3 + start_period: 60s + zammad-scheduler: + # You cannot access the helpdesk scheduler directly. + <<: *zammad-service + command: ["zammad-scheduler"] + zammad-websocket: + # You cannot access the helpdesk websocket server directly. + <<: *zammad-service + command: ["zammad-websocket"] +volumes: + zammad-backup-data: + # The helpdesk backup's data. + {} + zammad-data: + # The helpdesk's data. + {} diff --git a/src/production/configurations/zammad/docker-entrypoint.sh b/src/development/zammad/configurations/docker-entrypoint.sh similarity index 99% rename from src/production/configurations/zammad/docker-entrypoint.sh rename to src/development/zammad/configurations/docker-entrypoint.sh index 1459d9b7..9d364edd 100755 --- a/src/production/configurations/zammad/docker-entrypoint.sh +++ b/src/development/zammad/configurations/docker-entrypoint.sh @@ -7,7 +7,7 @@ ENVIRONMENT_VARIABLES_PATH="/run/environment-variables" is_valid_var_name() { case "$1" in - *[!a-zA-Z0-9_]*|'') return 1 ;; + ''|[!a-zA-Z_]*|*[!a-zA-Z0-9_]*) return 1 ;; *) return 0 ;; esac } @@ -16,7 +16,7 @@ load_env_file() { file="$1" name=$(basename "$file") is_valid_var_name "$name" || return 0 - value="$(cat "$file")" + value=$(cat "$file") export "$name=$value" } diff --git a/src/production/adminer/compose.yaml b/src/production/adminer/compose.yaml new file mode 100644 index 00000000..c471fc93 --- /dev/null +++ b/src/production/adminer/compose.yaml @@ -0,0 +1,8 @@ +services: + adminer: + deploy: + labels: + - (( append )) + - traefik.http.routers.adminer-secure.tls.certresolver=default + update_config: + order: start-first diff --git a/src/production/backups/postgres/README.md b/src/production/backups/postgres/README.md deleted file mode 100644 index a78acebf..00000000 --- a/src/production/backups/postgres/README.md +++ /dev/null @@ -1,3 +0,0 @@ - - -This directory contains backups created by [prodrigestivill/postgres-backup-local](https://github.com/prodrigestivill/docker-postgres-backup-local). diff --git a/src/production/cadvisor/compose.yaml b/src/production/cadvisor/compose.yaml new file mode 100644 index 00000000..4ebd6218 --- /dev/null +++ b/src/production/cadvisor/compose.yaml @@ -0,0 +1,8 @@ +services: + cadvisor: + deploy: + labels: + - (( append )) + - traefik.http.routers.cadvisor-secure.tls.certresolver=default + update_config: + order: start-first diff --git a/src/production/cloudflared/compose.yaml b/src/production/cloudflared/compose.yaml new file mode 100644 index 00000000..cfddd0ee --- /dev/null +++ b/src/production/cloudflared/compose.yaml @@ -0,0 +1,12 @@ +services: + cloudflared: + # You can configure the secure tunnel at [dash.cloudflare.com](https://dash.cloudflare.com/). + command: tunnel run + deploy: + labels: + - dargstack.profiles=default + update_config: + order: start-first + environment: + TUNNEL_TOKEN: ${CLOUDFLARED_TUNNEL_TOKEN} + image: cloudflare/cloudflared:2026.7.1 diff --git a/src/production/compose.yaml b/src/production/compose.yaml new file mode 100644 index 00000000..adefef00 --- /dev/null +++ b/src/production/compose.yaml @@ -0,0 +1,2 @@ +volumes: + pnpm-data: (( prune )) diff --git a/src/production/configurations/adminer/adminer.css b/src/production/configurations/adminer/adminer.css deleted file mode 100755 index c77609cb..00000000 --- a/src/production/configurations/adminer/adminer.css +++ /dev/null @@ -1,7 +0,0 @@ -a { - color: blue; -} - -a:visited { - color: blue; -} diff --git a/src/production/configurations/grafana/provisioning/datasources/postgres.yaml b/src/production/configurations/grafana/provisioning/datasources/postgres.yaml deleted file mode 100644 index f39d522b..00000000 --- a/src/production/configurations/grafana/provisioning/datasources/postgres.yaml +++ /dev/null @@ -1,14 +0,0 @@ -apiVersion: 1 - -datasources: - - access: proxy - jsonData: - database: $__file{/run/secrets/postgres_db} - postgresVersion: 1500 - sslmode: 'disable' - name: PostgreSQL - secureJsonData: - password: $__file{/run/secrets/postgres_role_service_grafana_password} - type: grafana-postgresql-datasource - url: postgres:5432 - user: $__file{/run/secrets/postgres_role_service_grafana_username} diff --git a/src/production/debezium/compose.yaml b/src/production/debezium/compose.yaml new file mode 100644 index 00000000..484d03e5 --- /dev/null +++ b/src/production/debezium/compose.yaml @@ -0,0 +1,9 @@ +services: + debezium: + deploy: + update_config: + order: stop-first + debezium-postgres-connector: + deploy: + update_config: + order: stop-first diff --git a/src/production/elasticsearch/compose.yaml b/src/production/elasticsearch/compose.yaml new file mode 100644 index 00000000..b48924b3 --- /dev/null +++ b/src/production/elasticsearch/compose.yaml @@ -0,0 +1,5 @@ +services: + elasticsearch: + deploy: + update_config: + order: stop-first diff --git a/src/production/geoip/compose.yaml b/src/production/geoip/compose.yaml new file mode 100644 index 00000000..fc5fc9a9 --- /dev/null +++ b/src/production/geoip/compose.yaml @@ -0,0 +1,5 @@ +services: + geoip: + deploy: + update_config: + order: start-first diff --git a/src/production/grafana/compose.yaml b/src/production/grafana/compose.yaml new file mode 100644 index 00000000..b28ce288 --- /dev/null +++ b/src/production/grafana/compose.yaml @@ -0,0 +1,8 @@ +services: + grafana: + deploy: + labels: + - (( append )) + - traefik.http.routers.grafana-secure.tls.certresolver=default + update_config: + order: start-first diff --git a/src/production/jobber/compose.yaml b/src/production/jobber/compose.yaml new file mode 100644 index 00000000..063fbc2f --- /dev/null +++ b/src/production/jobber/compose.yaml @@ -0,0 +1,10 @@ +services: + jobber: + deploy: + update_config: + order: stop-first + environment: + SENTRY_CRONS: ${SENTRY_CRONS} + volumes: + - (( append )) + - postgres-backup-data:/backups/ diff --git a/src/production/configurations/jobber/.jobber b/src/production/jobber/configurations/.jobber similarity index 86% rename from src/production/configurations/jobber/.jobber rename to src/production/jobber/configurations/.jobber index 7613d3e6..162ba232 100644 --- a/src/production/configurations/jobber/.jobber +++ b/src/production/jobber/configurations/.jobber @@ -5,7 +5,7 @@ jobs: cmd: | /srv/sinks/sentry/in-progress.sh source .venv/bin/activate - aws s3 sync /backups s3://$(cat /run/secrets/jobber_aws-bucket)/backups + aws s3 sync /backups s3://$(cat /run/secrets/jobber-aws-bucket)/backups deactivate sleep 3 time: 0 0 0 * diff --git a/src/production/memcached/compose.yaml b/src/production/memcached/compose.yaml new file mode 100644 index 00000000..c448c776 --- /dev/null +++ b/src/production/memcached/compose.yaml @@ -0,0 +1,5 @@ +services: + memcached: + deploy: + update_config: + order: start-first diff --git a/src/production/minio/compose.yaml b/src/production/minio/compose.yaml new file mode 100644 index 00000000..afb70a8c --- /dev/null +++ b/src/production/minio/compose.yaml @@ -0,0 +1,4 @@ +# services: +# minio: (( prune )) # breaks renovate +volumes: + minio_data: (( prune )) diff --git a/src/production/portainer-agent/compose.yaml b/src/production/portainer-agent/compose.yaml new file mode 100644 index 00000000..601a15a3 --- /dev/null +++ b/src/production/portainer-agent/compose.yaml @@ -0,0 +1,5 @@ +services: + portainer-agent: + deploy: + update_config: + order: start-first diff --git a/src/production/portainer/compose.yaml b/src/production/portainer/compose.yaml new file mode 100644 index 00000000..d443dc3b --- /dev/null +++ b/src/production/portainer/compose.yaml @@ -0,0 +1,8 @@ +services: + portainer: + deploy: + labels: + - (( append )) + - traefik.http.routers.portainer-secure.tls.certresolver=default + update_config: + order: stop-first diff --git a/src/production/postgraphile/compose.yaml b/src/production/postgraphile/compose.yaml new file mode 100644 index 00000000..02fb237a --- /dev/null +++ b/src/production/postgraphile/compose.yaml @@ -0,0 +1,11 @@ +services: + postgraphile: + deploy: + labels: + - (( append )) + - traefik.http.routers.postgraphile.middlewares=postgraphile-cors,redirectscheme + - traefik.http.routers.postgraphile-secure.tls.certresolver=default + - traefik.http.routers.postgraphile-secure-ruru.tls.certresolver=default + update_config: + order: start-first + image: ghcr.io/maevsi/postgraphile:2.1.7 diff --git a/src/production/configurations/postgraphile/jwtES256.key.pub b/src/production/postgraphile/configurations/jwtES256.key.pub similarity index 100% rename from src/production/configurations/postgraphile/jwtES256.key.pub rename to src/production/postgraphile/configurations/jwtES256.key.pub diff --git a/src/production/postgraphile/configurations/jwtRS256.key.pub b/src/production/postgraphile/configurations/jwtRS256.key.pub new file mode 100644 index 00000000..e7ddc5d9 --- /dev/null +++ b/src/production/postgraphile/configurations/jwtRS256.key.pub @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuxhUva8Nwcd88mUjNKa5 +OZqrhskSvWqsWRqVlyqSCVygblcEjV5PyT0CQ+41eTlAS/it61QWcR4Bk6OZW3ga +XQ739/2yuDCqgeXZ7VX0PXUZG+biaeA7BiiK2hB7Ve9YB0l72et0nNCFuQChAqjl +dSr4HvPJBQaofZ8CCRd29gue04uWDYj0hjzorHtQvj/AvmUQxw0vTUMpVPNfjeed ++4V0vciZJsyhRe1BoFqGrLrTVqvk+9AvFHInIjGXVUoR4JlVcE6CJQcLj+Sv6rIN +F5pk4fDJLc0/B5GTtXwuW4+A88Fl+765bvaMl2okfbaTS8V7FjXpZqr7BcGaRmCj +lSsiKDVOZGWXfIjiKoyCVT9M343PsLvTl2FKJQEwQ0svie9OgPx7qG1dNj+FJXzz +KdkwCwy0urQse2071vgAq10FUoTRiWk5ul9DPa75S8VrGuKu4/tA3kIx/qxAopGP +/px/MDIIsQBYMu5Lv6VMe3nY3bKrm0WYLwXvJDwHnQgMLjv0oblecu+SPm3ax7Ok +VLjdyMhM3TRkNJqC3vhAasmCGMBNShRtK4+EgoCKscFSxhvzokWUZEA6WTxDmMkF +l9dmKLjYbNL9ct3mAP/iG/Sa4xj/T0Qt/AKEH8zM5KXWpQ0m1mu8C9PjAfZF5d8u +pg1jBKql11Zp143eJg37WbkCAwEAAQ== +-----END PUBLIC KEY----- diff --git a/src/production/postgres/compose.yaml b/src/production/postgres/compose.yaml new file mode 100644 index 00000000..daeab7be --- /dev/null +++ b/src/production/postgres/compose.yaml @@ -0,0 +1,31 @@ +secrets: + postgres-backup-db: + # The database's name. + external: true +services: + postgres: + deploy: + update_config: + order: stop-first + postgres-backup: + # You cannot access the database backup directly. + deploy: + update_config: + order: stop-first + environment: + POSTGRES_DB_FILE: /run/secrets/postgres-backup-db + POSTGRES_HOST: postgres + POSTGRES_PASSWORD_FILE: /run/secrets/postgres-password + POSTGRES_USER_FILE: /run/secrets/postgres-user + image: prodrigestivill/postgres-backup-local:18-alpine + secrets: + - postgres-backup-db + - postgres-password + - postgres-user + volumes: + - postgres-data:/var/lib/postgresql/ + - postgres-backup-data:/backups/ +volumes: + postgres-backup-data: + # The database backup's data. + {} diff --git a/src/production/production.env.template b/src/production/production.env.template deleted file mode 100644 index 8ffc032b..00000000 --- a/src/production/production.env.template +++ /dev/null @@ -1,5 +0,0 @@ -CLOUDFLARED_TUNNEL_TOKEN= -SENTRY_CRONS= -STACK_DOMAIN= -TRAEFIK_ACME_EMAIL= -TRAEFIK_ACME_PROVIDER= \ No newline at end of file diff --git a/src/production/production.yml b/src/production/production.yml deleted file mode 100644 index 6b7c1cec..00000000 --- a/src/production/production.yml +++ /dev/null @@ -1,192 +0,0 @@ -secrets: - postgres-backup_db: - # The database's name. - external: true - traefik_cf-dns-api-token: - # The DNS provider's DNS API token. - external: true - traefik_cf-zone-api-token: - # The DNS provider's zone API token. - external: true -services: - adminer: - deploy: - labels: - - (( append )) - - traefik.http.routers.adminer_secure.tls.certresolver=default - cadvisor: - deploy: - labels: (( prune )) - cloudflared: - # You can configure the secure tunnel at [dash.cloudflare.com](https://dash.cloudflare.com/). - command: tunnel run - environment: - TUNNEL_TOKEN: ${CLOUDFLARED_TUNNEL_TOKEN} - image: cloudflare/cloudflared - grafana: - deploy: - labels: - - (( append )) - - traefik.http.routers.grafana_secure.tls.certresolver=default - jobber: - environment: - SENTRY_CRONS: ${SENTRY_CRONS} - volumes: - - (( append )) - - ./configurations/jobber/sinks:/srv/sinks:ro - # minio: (( prune )) # breaks renovate - portainer: - deploy: - labels: - - (( append )) - - traefik.http.routers.portainer_secure.tls.certresolver=default - postgraphile: - deploy: - labels: - - (( append )) - - traefik.http.routers.postgraphile.middlewares=postgraphile_cors,redirectscheme - - traefik.http.routers.postgraphile_secure.tls.certresolver=default - - traefik.http.routers.postgraphile_secure_ruru.tls.certresolver=default - image: ghcr.io/maevsi/postgraphile:2.1.6 - postgres_backup: - # You cannot access the database backup directly. - environment: - POSTGRES_DB_FILE: /run/secrets/postgres-backup_db - POSTGRES_HOST: postgres - POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password - POSTGRES_USER_FILE: /run/secrets/postgres_user - image: prodrigestivill/postgres-backup-local:18-alpine - secrets: - - postgres-backup_db - - postgres_password - - postgres_user - volumes: - - postgres_data:/var/lib/postgresql/ - - ../production/backups/postgres/:/backups/ - prometheus: - deploy: - labels: - - (( append )) - - traefik.http.routers.prometheus_secure.tls.certresolver=default - reccoom: - deploy: (( prune )) - environment: - SENTRY_TRACES_SAMPLE_RATE: "0.1" - image: ghcr.io/maevsi/reccoom:0.18.9 - reccoom_consumer: - environment: - SENTRY_TRACES_SAMPLE_RATE: "0.1" - image: ghcr.io/maevsi/reccoom:0.18.9 - reccoom_migration: - environment: - SENTRY_TRACES_SAMPLE_RATE: "0.1" - image: ghcr.io/maevsi/reccoom:0.18.9 - volumes: (( prune )) - redpanda-console: - deploy: - labels: - - (( append )) - - traefik.http.routers.redpanda_secure.tls.certresolver=default - sqitch: - image: ghcr.io/maevsi/sqitch:11.1.8 - volumes: (( prune )) - traefik: - command: - - (( prepend )) - - --certificatesResolvers.default.acme.email=${TRAEFIK_ACME_EMAIL} - - --certificatesResolvers.default.acme.storage=/etc/traefik/acme/acme.json - - --certificatesResolvers.default.acme.dnsChallenge.provider=${TRAEFIK_ACME_PROVIDER} - deploy: - labels: - - (( append )) - - traefik.http.routers.traefik_secure.tls.certresolver=default - environment: - CF_DNS_API_TOKEN_FILE: /run/secrets/traefik_cf-dns-api-token - CF_ZONE_API_TOKEN_FILE: /run/secrets/traefik_cf-zone-api-token - secrets: - - traefik_cf-dns-api-token - - traefik_cf-zone-api-token - traefik_certs-dumper: - # You cannot access the reverse proxy's certificate helper directly. - command: - - file - - --clean=false - - --crt-name="$STACK_DOMAIN" - - --dest=/etc/traefik/acme/ - - --key-name="$STACK_DOMAIN" - - --source=/etc/traefik/acme/acme.json - - --version=v2 - - --watch - environment: - STACK_DOMAIN: ${STACK_DOMAIN} - image: ldez/traefik-certs-dumper:v2.11.4 - volumes: - - acme_data:/etc/traefik/acme/ - tusd: - deploy: - labels: - - (( append )) - - traefik.http.routers.tusd.middlewares=tusd_cors - - traefik.http.routers.tusd_secure.tls.certresolver=default - vibetype: - deploy: - labels: - - (( append )) - - traefik.http.routers.vibetype.middlewares=vibetype_cors,vibetype_redirectregex - - traefik.http.routers.vibetype_secure.tls.certresolver=default - image: ghcr.io/maevsi/vibetype:15.1.10 - user: (( prune )) - # vibetype_beta: - # # You can access the main project frontend's beta version at [beta.app.localhost](https://beta.app.localhost/). - # deploy: - # labels: - # - traefik.enable=true - # - traefik.http.routers.vibetype_beta.entryPoints=web - # - traefik.http.routers.vibetype_beta.middlewares=vibetype_cors,vibetype_redirectregex - # - traefik.http.routers.vibetype_beta.rule=Host(`beta.${STACK_DOMAIN}`) - # - traefik.http.routers.vibetype_beta_secure.entryPoints=web-secure - # - traefik.http.routers.vibetype_beta_secure.middlewares=vibetype_cors,vibetype_redirectregex - # - traefik.http.routers.vibetype_beta_secure.rule=Host(`beta.${STACK_DOMAIN}`) - # - traefik.http.services.vibetype_beta.loadbalancer.server.port=3000 - # - traefik.http.routers.vibetype_beta_secure.tls.certresolver=default - # environment: - # AWS_REGION: ${VIBETYPE_AWS_REGION} - # NUXT_PUBLIC_GTAG_ID: ${VIBETYPE_NUXT_PUBLIC_GTAG_ID} - # NUXT_PUBLIC_I18N_BASE_URL: https://${STACK_DOMAIN} - # NUXT_PUBLIC_SITE_URL: https://${STACK_DOMAIN} - # NUXT_PUBLIC_TURNSTILE_SITE_KEY: ${VIBETYPE_NUXT_PUBLIC_TURNSTILE_SITE_KEY} - # NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H: ${VIBETYPE_NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H} - # NUXT_PUBLIC_VIO_ENVIRONMENT: beta - # PGHOST: postgres - # image: ghcr.io/maevsi/vibetype:11.0.2 - # secrets: - # - source: vibetype_api-notification-secret - # target: /run/environment-variables/NUXT_API_NOTIFICATION_SECRET - # - source: vibetype_aws-credentials - # target: /home/node/.aws/credentials # TODO: switch to user `node` - # - source: vibetype_firebase-service-account-credentials - # target: /run/environment-variables/FIREBASE_SERVICE_ACCOUNT_CREDENTIALS - # - source: vibetype_openai-api-key - # target: /run/environment-variables/NUXT_OPENAI_API_KEY - # - source: vibetype_turnstile-key - # target: /run/environment-variables/NUXT_TURNSTILE_SECRET_KEY - # - source: postgres_db - # target: /run/environment-variables/PGDATABASE - # - source: postgres_role_service_vibetype_password - # target: /run/environment-variables/PGPASSWORD - # - source: postgres_role_service_vibetype_username - # target: /run/environment-variables/PGUSER - # volumes: - # - ./configurations/postgraphile/jwtES256.key.pub:/run/environment-variables/NUXT_PUBLIC_VIO_AUTH_JWT_PUBLIC_KEY:ro - zammad-nginx: - deploy: - labels: - - (( append )) - - traefik.http.routers.zammad_secure.tls.certresolver=default -version: "3.7" -volumes: - acme_data: - # The reverse proxy's certificate data. - {} - minio_data: (( prune )) - vibetype_data: (( prune )) diff --git a/src/production/prometheus/compose.yaml b/src/production/prometheus/compose.yaml new file mode 100644 index 00000000..502d2ee7 --- /dev/null +++ b/src/production/prometheus/compose.yaml @@ -0,0 +1,8 @@ +services: + prometheus: + deploy: + labels: + - (( append )) + - traefik.http.routers.prometheus-secure.tls.certresolver=default + update_config: + order: stop-first diff --git a/src/production/reccoom/compose.yaml b/src/production/reccoom/compose.yaml new file mode 100644 index 00000000..d765bf75 --- /dev/null +++ b/src/production/reccoom/compose.yaml @@ -0,0 +1,27 @@ +services: + reccoom: + deploy: + update_config: + order: start-first + environment: + SENTRY_TRACES_SAMPLE_RATE: "0.1" + image: ghcr.io/maevsi/reccoom:0.18.9 + reccoom-consumer: + deploy: + update_config: + order: start-first + environment: + SENTRY_TRACES_SAMPLE_RATE: "0.1" + image: ghcr.io/maevsi/reccoom:0.18.9 + reccoom-migration: + deploy: + update_config: + order: start-first + environment: + SENTRY_TRACES_SAMPLE_RATE: "0.1" + image: ghcr.io/maevsi/reccoom:0.18.9 + volumes: (( prune )) + reccoom-postgres: + deploy: + update_config: + order: stop-first diff --git a/src/production/redis/compose.yaml b/src/production/redis/compose.yaml new file mode 100644 index 00000000..2220d16c --- /dev/null +++ b/src/production/redis/compose.yaml @@ -0,0 +1,5 @@ +services: + redis: + deploy: + update_config: + order: stop-first diff --git a/src/production/redpanda/compose.yaml b/src/production/redpanda/compose.yaml new file mode 100644 index 00000000..8d384353 --- /dev/null +++ b/src/production/redpanda/compose.yaml @@ -0,0 +1,12 @@ +services: + redpanda: + deploy: + update_config: + order: stop-first + redpanda-console: + deploy: + labels: + - (( append )) + - traefik.http.routers.redpanda-secure.tls.certresolver=default + update_config: + order: start-first diff --git a/src/production/sqitch/compose.yaml b/src/production/sqitch/compose.yaml new file mode 100644 index 00000000..08b9c44d --- /dev/null +++ b/src/production/sqitch/compose.yaml @@ -0,0 +1,7 @@ +services: + sqitch: + deploy: + update_config: + order: stop-first + image: ghcr.io/maevsi/sqitch:11.1.8 + volumes: (( prune )) diff --git a/src/production/traefik/compose.yaml b/src/production/traefik/compose.yaml new file mode 100644 index 00000000..8d430c9c --- /dev/null +++ b/src/production/traefik/compose.yaml @@ -0,0 +1,49 @@ +secrets: + traefik-cf-dns-api-token: + # The DNS provider's DNS API token. + external: true + traefik-cf-zone-api-token: + # The DNS provider's zone API token. + external: true +services: + traefik: + command: + - (( prepend )) + - --certificatesResolvers.default.acme.email=${TRAEFIK_ACME_EMAIL} + - --certificatesResolvers.default.acme.storage=/etc/traefik/acme/acme.json + - --certificatesResolvers.default.acme.dnsChallenge.provider=${TRAEFIK_ACME_PROVIDER} + deploy: + labels: + - (( append )) + - traefik.http.routers.traefik-secure.tls.certresolver=default + update_config: + order: start-first + environment: + CF_DNS_API_TOKEN_FILE: /run/secrets/traefik-cf-dns-api-token + CF_ZONE_API_TOKEN_FILE: /run/secrets/traefik-cf-zone-api-token + secrets: + - traefik-cf-dns-api-token + - traefik-cf-zone-api-token + traefik-certs-dumper: + # You cannot access the reverse proxy's certificate helper directly. + command: + - file + - --clean=false + - --crt-name="$STACK_DOMAIN" + - --dest=/etc/traefik/acme/ + - --key-name="$STACK_DOMAIN" + - --source=/etc/traefik/acme/acme.json + - --version=v2 + - --watch + deploy: + update_config: + order: stop-first + environment: + STACK_DOMAIN: ${STACK_DOMAIN} + image: ldez/traefik-certs-dumper:v2.11.4 + volumes: + - acme-data:/etc/traefik/acme/ +volumes: + acme-data: + # The reverse proxy's certificate data. + {} diff --git a/src/production/tusd/compose.yaml b/src/production/tusd/compose.yaml new file mode 100644 index 00000000..54e38bba --- /dev/null +++ b/src/production/tusd/compose.yaml @@ -0,0 +1,9 @@ +services: + tusd: + deploy: + labels: + - (( append )) + - traefik.http.routers.tusd.middlewares=tusd-cors + - traefik.http.routers.tusd-secure.tls.certresolver=default + update_config: + order: start-first diff --git a/src/production/vibetype/compose.yaml b/src/production/vibetype/compose.yaml new file mode 100644 index 00000000..bacbf1c5 --- /dev/null +++ b/src/production/vibetype/compose.yaml @@ -0,0 +1,54 @@ +services: + vibetype: + deploy: + labels: + - (( append )) + - traefik.http.routers.vibetype.middlewares=vibetype_cors,vibetype_redirectregex + - traefik.http.routers.vibetype-secure.tls.certresolver=default + update_config: + order: start-first + image: ghcr.io/maevsi/vibetype:15.1.10 + # vibetype-beta: + # # You can access the main project frontend's beta version at [beta.app.localhost](https://beta.app.localhost/). + # deploy: + # labels: + # - traefik.enable=true + # - traefik.http.routers.vibetype-beta.entryPoints=web + # - traefik.http.routers.vibetype-beta.middlewares=vibetype_cors,vibetype_redirectregex + # - traefik.http.routers.vibetype-beta.rule=Host(`beta.${STACK_DOMAIN}`) + # - traefik.http.routers.vibetype-beta-secure.entryPoints=web-secure + # - traefik.http.routers.vibetype-beta-secure.middlewares=vibetype_cors,vibetype_redirectregex + # - traefik.http.routers.vibetype-beta-secure.rule=Host(`beta.${STACK_DOMAIN}`) + # - traefik.http.services.vibetype-beta.loadbalancer.server.port=3000 + # - traefik.http.routers.vibetype-beta-secure.tls.certresolver=default + # environment: + # AWS_REGION: ${VIBETYPE_AWS_REGION} + # NUXT_PUBLIC_GTAG_ID: ${VIBETYPE_NUXT_PUBLIC_GTAG_ID} + # NUXT_PUBLIC_I18N_BASE_URL: https://${STACK_DOMAIN} + # NUXT_PUBLIC_SITE_URL: https://${STACK_DOMAIN} + # NUXT_PUBLIC_TURNSTILE_SITE_KEY: ${VIBETYPE_NUXT_PUBLIC_TURNSTILE_SITE_KEY} + # NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H: ${VIBETYPE_NUXT_PUBLIC_VIBETYPE_EMAIL_LIMIT24H} + # NUXT_PUBLIC_VIO_ENVIRONMENT: beta + # PGHOST: postgres + # image: ghcr.io/maevsi/vibetype:11.0.2 + # secrets: + # - source: vibetype-api-notification-secret + # target: /run/environment-variables/NUXT_API_NOTIFICATION_SECRET + # - source: vibetype-aws-credentials + # target: /home/node/.aws/credentials # TODO: switch to user `node` + # - source: vibetype-firebase-service-account-credentials + # target: /run/environment-variables/FIREBASE_SERVICE_ACCOUNT_CREDENTIALS + # - source: vibetype-openai-api-key + # target: /run/environment-variables/NUXT_OPENAI_API_KEY + # - source: vibetype-turnstile-key + # target: /run/environment-variables/NUXT_TURNSTILE_SECRET_KEY + # - source: postgres-db + # target: /run/environment-variables/PGDATABASE + # - source: postgres-role-service-vibetype-password + # target: /run/environment-variables/PGPASSWORD + # - source: postgres-role-service-vibetype-username + # target: /run/environment-variables/PGUSER + # volumes: + # - ./configurations/postgraphile/jwtES256.key.pub:/run/environment-variables/NUXT_PUBLIC_VIO_AUTH_JWT_PUBLIC_KEY:ro +volumes: + vibetype_data: (( prune )) diff --git a/src/production/zammad/compose.yaml b/src/production/zammad/compose.yaml new file mode 100644 index 00000000..e610980c --- /dev/null +++ b/src/production/zammad/compose.yaml @@ -0,0 +1,28 @@ +services: + zammad-backup: + deploy: + update_config: + order: stop-first + zammad-init: + deploy: + update_config: + order: stop-first + zammad-nginx: + deploy: + labels: + - (( append )) + - traefik.http.routers.zammad-secure.tls.certresolver=default + update_config: + order: start-first + zammad-railsserver: + deploy: + update_config: + order: start-first + zammad-scheduler: + deploy: + update_config: + order: stop-first + zammad-websocket: + deploy: + update_config: + order: start-first