Compare commits
4 Commits
a74909be25
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ea638c0eae | |||
| 3f94ced9ea | |||
| a81aa80161 | |||
| a9a758d332 |
@@ -35,20 +35,20 @@ SilverLinux is the primary self-hosted platform for Silver Solutions and hosts s
|
|||||||
* Gitea Actions Runner
|
* Gitea Actions Runner
|
||||||
* DbGate
|
* DbGate
|
||||||
* Xray
|
* Xray
|
||||||
|
* Sentry
|
||||||
* Prometheus
|
* Prometheus
|
||||||
* Grafana
|
* Grafana
|
||||||
* Node Exporter
|
* Node Exporter
|
||||||
* cAdvisor
|
* cAdvisor
|
||||||
* Alertmanager
|
* Alertmanager
|
||||||
|
* Nextcloud
|
||||||
|
|
||||||
### Planned
|
### Planned
|
||||||
|
|
||||||
* Nextcloud
|
|
||||||
* Loki
|
* Loki
|
||||||
* Redis
|
* Redis
|
||||||
* Authelia
|
* Authelia
|
||||||
* CrowdSec
|
* CrowdSec
|
||||||
* Sentry
|
|
||||||
* Restic
|
* Restic
|
||||||
* Harbor
|
* Harbor
|
||||||
* SonarQube
|
* SonarQube
|
||||||
@@ -62,6 +62,49 @@ See [docs/roadmap.md](docs/roadmap.md) for the phased infrastructure roadmap.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Service Orchestration
|
||||||
|
|
||||||
|
All Docker services on SilverLinux are managed through the **slcompose orchestrator** (`slcompose`), a bash wrapper that:
|
||||||
|
|
||||||
|
1. **Injects Secrets** — Uses Infisical CLI to load environment variables from Infisical and inject them into each service at runtime
|
||||||
|
2. **Boots All Services** — Automatically starts all services at system startup via systemd
|
||||||
|
3. **Manages Services** — Provides CLI commands to start, stop, restart, and view logs for individual services
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Load secrets from Infisical and start all services
|
||||||
|
slcompose boot
|
||||||
|
|
||||||
|
# Manage individual services
|
||||||
|
slcompose up gitea # Start gitea
|
||||||
|
slcompose down gitea # Stop gitea
|
||||||
|
slcompose restart gitea # Restart gitea
|
||||||
|
slcompose logs gitea # Stream live logs
|
||||||
|
slcompose logs-tail gitea 200 # View last 200 lines
|
||||||
|
slcompose list # List all services
|
||||||
|
|
||||||
|
# View injected environment variables
|
||||||
|
slcompose env gitea # Show env vars for gitea
|
||||||
|
slcompose env-all # Show env vars for all services
|
||||||
|
```
|
||||||
|
|
||||||
|
**Service Auto-Boot:** The systemd service `slcompose.service` automatically runs `slcompose boot` on system startup, ensuring all services recover after server reboot.
|
||||||
|
|
||||||
|
**Secrets Flow:**
|
||||||
|
```
|
||||||
|
System Boot → systemd slcompose.service → slcompose boot
|
||||||
|
↓
|
||||||
|
For each service in /srv/docker/:
|
||||||
|
- Load INFISICAL_TOKEN from /etc/infisical/token
|
||||||
|
- Use Infisical CLI to inject secrets from path: /[SERVICE_NAME]
|
||||||
|
- Run: docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
See [docs/orchestration.md](docs/orchestration.md) and [docs/slcompose.sh](docs/slcompose.sh) for complete details.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Shared Infrastructure
|
## Shared Infrastructure
|
||||||
|
|
||||||
The following components are shared across multiple services:
|
The following components are shared across multiple services:
|
||||||
@@ -73,13 +116,9 @@ The following components are shared across multiple services:
|
|||||||
* Isolated Docker Networks
|
* Isolated Docker Networks
|
||||||
* Monitoring Docker Stack
|
* Monitoring Docker Stack
|
||||||
* Automated Backup System
|
* Automated Backup System
|
||||||
* Shared Secrets Management
|
* Shared Secrets Management (Infisical + slcompose)
|
||||||
|
|
||||||
Secrets are stored outside the repository:
|
Secrets are managed centrally through Infisical and injected at runtime by the slcompose wrapper.
|
||||||
|
|
||||||
```text
|
|
||||||
/srv/secrets/company.env
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -89,6 +128,7 @@ Secrets are stored outside the repository:
|
|||||||
baget/
|
baget/
|
||||||
dbgate/
|
dbgate/
|
||||||
docs/
|
docs/
|
||||||
|
docs/nextcloud.md
|
||||||
gitea/
|
gitea/
|
||||||
jitsi/
|
jitsi/
|
||||||
mssql/
|
mssql/
|
||||||
@@ -136,7 +176,8 @@ Never commit:
|
|||||||
* SSL Private Keys
|
* SSL Private Keys
|
||||||
* Database Credentials
|
* Database Credentials
|
||||||
* Real `.env` files
|
* Real `.env` files
|
||||||
* `/srv/secrets/company.env`
|
* Infisical tokens
|
||||||
|
* Sentry upstream installer secrets
|
||||||
|
|
||||||
Use example files whenever possible.
|
Use example files whenever possible.
|
||||||
|
|
||||||
|
|||||||
+77
-9
@@ -1,6 +1,6 @@
|
|||||||
# SilverLinux Infrastructure Summary
|
# SilverLinux Infrastructure Summary
|
||||||
|
|
||||||
Last Updated: 2026-06-25
|
Last Updated: 2026-07-08
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@@ -22,6 +22,8 @@ Monitoring, alerting, automated backups and restore validation are now productio
|
|||||||
| Jitsi Meet | https://meet.silveressence.net |
|
| Jitsi Meet | https://meet.silveressence.net |
|
||||||
| BaGet | https://nuget.silveressence.net |
|
| BaGet | https://nuget.silveressence.net |
|
||||||
| DbGate | https://dbgate.silveressence.net |
|
| DbGate | https://dbgate.silveressence.net |
|
||||||
|
| Sentry | https://sentry.silveressence.net |
|
||||||
|
| Nextcloud | https://cloud.silveressence.net |
|
||||||
| Xray | Public tunneling endpoint |
|
| Xray | Public tunneling endpoint |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -259,6 +261,62 @@ Status:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Nextcloud
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Private cloud storage
|
||||||
|
* File sharing
|
||||||
|
* Team document storage
|
||||||
|
|
||||||
|
Access:
|
||||||
|
|
||||||
|
* https://cloud.silveressence.net
|
||||||
|
* HTTPS through Nginx Proxy Manager
|
||||||
|
* Nextcloud user authentication required
|
||||||
|
|
||||||
|
Runtime:
|
||||||
|
|
||||||
|
* `nextcloud:29-apache`
|
||||||
|
* `postgres:16`
|
||||||
|
* `redis:7-alpine`
|
||||||
|
* Data volume `nextcloud_nextcloud_data`
|
||||||
|
* Database volume `nextcloud_nextcloud_db`
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
* Operational
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Sentry
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Centralized error tracking
|
||||||
|
* Application exception diagnostics
|
||||||
|
* Release health and performance visibility
|
||||||
|
|
||||||
|
Access:
|
||||||
|
|
||||||
|
* https://sentry.silveressence.net
|
||||||
|
* HTTPS through Nginx Proxy Manager
|
||||||
|
|
||||||
|
Deployment:
|
||||||
|
|
||||||
|
* Installed with upstream Sentry self-hosted `install.sh`
|
||||||
|
* Compose project `sentry-self-hosted`
|
||||||
|
* Install directory `/srv/docker/sentry`
|
||||||
|
* Public entry container `sentry-self-hosted-nginx-1`
|
||||||
|
* Nginx Proxy Manager forwards to `sentry-self-hosted-nginx-1:80`
|
||||||
|
* Exception to the normal `slcompose` and Infisical service pattern
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
* Operational
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Xray
|
### Xray
|
||||||
|
|
||||||
Purpose:
|
Purpose:
|
||||||
@@ -307,10 +365,10 @@ Purpose:
|
|||||||
|
|
||||||
### Shared Secrets
|
### Shared Secrets
|
||||||
|
|
||||||
Location:
|
Primary source:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Contains:
|
Contains:
|
||||||
@@ -319,10 +377,19 @@ Contains:
|
|||||||
* PostgreSQL passwords
|
* PostgreSQL passwords
|
||||||
* MSSQL SA password
|
* MSSQL SA password
|
||||||
* OpenProject secrets
|
* OpenProject secrets
|
||||||
* Future DbGate password
|
* DbGate password
|
||||||
|
* Nextcloud secrets
|
||||||
* Future OAuth secrets
|
* Future OAuth secrets
|
||||||
|
|
||||||
This file must never be committed to Git.
|
Secrets are injected into standard SilverLinux Compose stacks at runtime through `slcompose`.
|
||||||
|
|
||||||
|
Exception:
|
||||||
|
|
||||||
|
* Sentry follows its upstream self-hosted installer pattern because it is a much larger multi-service application.
|
||||||
|
|
||||||
|
Legacy note:
|
||||||
|
|
||||||
|
* `/srv/secrets/company.env` is no longer part of the active secret model and should be removed if it still exists on the server.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -338,12 +405,14 @@ Plane.so was removed to reduce maintenance complexity and duplicate functionalit
|
|||||||
|
|
||||||
### Centralized Secrets
|
### Centralized Secrets
|
||||||
|
|
||||||
All shared credentials are stored in:
|
All standard service credentials are stored in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
|
They are injected by `slcompose` at runtime. Sentry is the exception and follows the default self-hosted Sentry installation model.
|
||||||
|
|
||||||
### Xray Connectivity Layer
|
### Xray Connectivity Layer
|
||||||
|
|
||||||
Xray is classified as a tunneling and connectivity layer rather than an application backend.
|
Xray is classified as a tunneling and connectivity layer rather than an application backend.
|
||||||
@@ -380,7 +449,6 @@ Completed:
|
|||||||
### Phase 2 - Security And Stability
|
### Phase 2 - Security And Stability
|
||||||
|
|
||||||
* CrowdSec
|
* CrowdSec
|
||||||
* Sentry
|
|
||||||
* Fail2Ban upgrade
|
* Fail2Ban upgrade
|
||||||
* Cloudflare rate limiting and WAF
|
* Cloudflare rate limiting and WAF
|
||||||
|
|
||||||
@@ -388,13 +456,13 @@ Completed:
|
|||||||
|
|
||||||
* Backup v5.3 automation
|
* Backup v5.3 automation
|
||||||
* Restore validation
|
* Restore validation
|
||||||
|
* Sentry
|
||||||
|
|
||||||
### Phase 3 - Scale And Enterprise Services
|
### Phase 3 - Scale And Enterprise Services
|
||||||
|
|
||||||
* SonarQube
|
* SonarQube
|
||||||
* Harbor Docker registry
|
* Harbor Docker registry
|
||||||
* Backstage portal
|
* Backstage portal
|
||||||
* Nextcloud
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -72,12 +72,12 @@ It is stored under **Repository Settings -> Actions -> Secrets** and must never
|
|||||||
|
|
||||||
The end-to-end Gitea Actions to BaGet publishing pipeline is operational.
|
The end-to-end Gitea Actions to BaGet publishing pipeline is operational.
|
||||||
|
|
||||||
### Future Improvement
|
### Secret Management
|
||||||
|
|
||||||
BaGet configuration should eventually be migrated to:
|
BaGet runtime secrets should be managed through:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
to centralize secret management across SilverLinux services.
|
This keeps BaGet aligned with the standard SilverLinux `slcompose` deployment pattern. The repository must not contain the real BaGet API key.
|
||||||
|
|||||||
+6
-6
@@ -55,13 +55,13 @@ Only DbGate is publicly accessible. MSSQL port `1433` and PostgreSQL port `5432`
|
|||||||
|
|
||||||
DbGate requires a username and password before granting access. The initial unauthenticated deployment was corrected by configuring `LOGIN` and `PASSWORD`.
|
DbGate requires a username and password before granting access. The initial unauthenticated deployment was corrected by configuring `LOGIN` and `PASSWORD`.
|
||||||
|
|
||||||
The running server currently stores the DbGate credentials directly in its Compose configuration. The repository intentionally does not contain the password; its Compose definition resolves `DBGATE_PASSWORD` from the deployment environment.
|
The DbGate password is supplied through Infisical at runtime. The repository intentionally does not contain the password; its Compose definition resolves `DBGATE_PASSWORD` from the deployment environment.
|
||||||
|
|
||||||
Planned improvement:
|
Operational requirement:
|
||||||
|
|
||||||
* Add `DBGATE_PASSWORD` to `/srv/secrets/company.env`.
|
* Keep `DBGATE_PASSWORD` in the DbGate Infisical path.
|
||||||
* Deploy with `docker compose --env-file /srv/secrets/company.env up -d`.
|
* Deploy through `slcompose` so the value is injected before Docker Compose evaluates the environment.
|
||||||
* Remove the credential from the server-side Compose file.
|
* Remove any legacy plaintext credential from the server-side Compose file if it still exists.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ Back up:
|
|||||||
/srv/docker/dbgate/data
|
/srv/docker/dbgate/data
|
||||||
```
|
```
|
||||||
|
|
||||||
Also retain the Compose definition, Nginx Proxy Manager configuration and DbGate credential through the centralized secrets backup after migration.
|
Also retain the Compose definition, Nginx Proxy Manager configuration and DbGate credential through Infisical recovery.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+50
-7
@@ -29,11 +29,13 @@ Public IP: 51.255.83.140
|
|||||||
* Gitea Actions Runner (`silverlinux-runner`)
|
* Gitea Actions Runner (`silverlinux-runner`)
|
||||||
* DbGate
|
* DbGate
|
||||||
* Xray
|
* Xray
|
||||||
|
* Sentry (Error Tracking & Observability)
|
||||||
* Prometheus
|
* Prometheus
|
||||||
* Grafana
|
* Grafana
|
||||||
* Node Exporter
|
* Node Exporter
|
||||||
* cAdvisor
|
* cAdvisor
|
||||||
* Alertmanager
|
* Alertmanager
|
||||||
|
* Nextcloud
|
||||||
|
|
||||||
## Domains
|
## Domains
|
||||||
|
|
||||||
@@ -49,17 +51,50 @@ nuget.silveressence.net -> BaGet (through Nginx Proxy Manager)
|
|||||||
|
|
||||||
dbgate.silveressence.net -> DbGate (through Nginx Proxy Manager)
|
dbgate.silveressence.net -> DbGate (through Nginx Proxy Manager)
|
||||||
|
|
||||||
|
sentry.silveressence.net -> Sentry (through Nginx Proxy Manager)
|
||||||
|
|
||||||
|
cloud.silveressence.net -> Nextcloud (through Nginx Proxy Manager)
|
||||||
|
|
||||||
Xray -> Public tunneling endpoint through proxy network
|
Xray -> Public tunneling endpoint through proxy network
|
||||||
|
|
||||||
## Secrets
|
## Secrets
|
||||||
|
|
||||||
Secrets are stored in:
|
Secrets are stored in Infisical and injected at runtime via the **slcompose orchestrator**.
|
||||||
|
|
||||||
/srv/secrets/company.env
|
Never hardcode credentials. Standard SilverLinux services receive environment variables through Infisical's secret injection at container startup.
|
||||||
|
|
||||||
Never hardcode credentials.
|
Sentry is the exception because it is a much larger upstream self-hosted application and follows the default Sentry installation pattern.
|
||||||
|
|
||||||
Always use env_file.
|
Legacy note: `/srv/secrets/company.env` is no longer part of the active secret model and should be removed if it still exists on the server.
|
||||||
|
|
||||||
|
### Secret Injection Flow
|
||||||
|
|
||||||
|
The `slcompose` service orchestrator manages all Docker services with automated secret injection:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose boot # Boots all services with secrets injected
|
||||||
|
slcompose up <service> # Start a service with secrets injected
|
||||||
|
slcompose down <service> # Stop a service
|
||||||
|
slcompose restart <service> # Restart a service
|
||||||
|
slcompose logs <service> # Stream logs
|
||||||
|
slcompose logs-tail <service> [lines] # View last N lines
|
||||||
|
slcompose list # List all available services
|
||||||
|
```
|
||||||
|
|
||||||
|
**System Startup:** The systemd service `slcompose.service` automatically runs `slcompose boot` on server reboot.
|
||||||
|
|
||||||
|
**Implementation:** See [docs/slcompose.sh](slcompose.sh) and [docs/slcompose.service](slcompose.service).
|
||||||
|
|
||||||
|
## Service Orchestration
|
||||||
|
|
||||||
|
All Docker services are managed through **slcompose**, which:
|
||||||
|
|
||||||
|
1. **Loads Infisical Token** from `/etc/infisical/token`
|
||||||
|
2. **Discovers Services** by scanning `/srv/docker/` for directories with `docker-compose.yml`
|
||||||
|
3. **Injects Secrets** using `infisical run --path=/[SERVICE_NAME]` before executing docker compose commands
|
||||||
|
4. **Manages Lifecycle** with up, down, restart, and logs commands
|
||||||
|
|
||||||
|
Each service directory name (e.g., `/srv/docker/gitea`) becomes the Infisical path (e.g., `/gitea`) for secret lookup.
|
||||||
|
|
||||||
## Docker Networks
|
## Docker Networks
|
||||||
|
|
||||||
@@ -71,6 +106,10 @@ gitea-runner_default
|
|||||||
|
|
||||||
MSSQL is attached only to `internal`. DbGate is attached to both `internal` and `proxy`.
|
MSSQL is attached only to `internal`. DbGate is attached to both `internal` and `proxy`.
|
||||||
|
|
||||||
|
Nextcloud is attached to `proxy` and `nextcloud_nextcloud_internal`. Its PostgreSQL and Redis containers are attached only to `nextcloud_nextcloud_internal`.
|
||||||
|
|
||||||
|
Sentry was installed using the upstream self-hosted `install.sh` workflow in `/srv/docker/sentry`, is available at `sentry.silveressence.net`, and uses the `sentry-self-hosted_default` network for internal services. Nginx Proxy Manager forwards to `sentry-self-hosted-nginx-1:80`. It is not a normal `slcompose` service.
|
||||||
|
|
||||||
Jitsi uses `jitsi-docker-jitsi-meet-aa76415_meet.jitsi` for its internal cluster and `proxy` for web access. Xray is currently attached to `proxy`; `xray_default` exists but had no running containers attached in the 2026-06-24 runtime snapshot.
|
Jitsi uses `jitsi-docker-jitsi-meet-aa76415_meet.jitsi` for its internal cluster and `proxy` for web access. Xray is currently attached to `proxy`; `xray_default` exists but had no running containers attached in the 2026-06-24 runtime snapshot.
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
@@ -94,7 +133,7 @@ The global self-hosted runner is operational at `/srv/docker/gitea-runner` with
|
|||||||
|
|
||||||
Silver 2.0 uses `.gitea/workflows/package.yml` to publish NuGet packages to BaGet when a push to `net-8-version` has a commit message containing `[Package]`.
|
Silver 2.0 uses `.gitea/workflows/package.yml` to publish NuGet packages to BaGet when a push to `net-8-version` has a commit message containing `[Package]`.
|
||||||
|
|
||||||
The runner registration token is stored in `/srv/secrets/company.env`. The BaGet publishing key is stored as the repository Actions secret `BAGET_API_KEY`.
|
The runner registration token is stored in Infisical. The BaGet publishing key is stored as the repository Actions secret `BAGET_API_KEY`.
|
||||||
|
|
||||||
## Databases
|
## Databases
|
||||||
|
|
||||||
@@ -179,8 +218,10 @@ Roadmap:
|
|||||||
* Phase 1 completed: Grafana, Prometheus, Node Exporter, cAdvisor, Alertmanager, backup metrics integration, incident intelligence
|
* Phase 1 completed: Grafana, Prometheus, Node Exporter, cAdvisor, Alertmanager, backup metrics integration, incident intelligence
|
||||||
* Phase 1 remaining: Loki, Redis, Authelia
|
* Phase 1 remaining: Loki, Redis, Authelia
|
||||||
* Phase 2 completed: Backup v5.3 automation, restore validation
|
* Phase 2 completed: Backup v5.3 automation, restore validation
|
||||||
* Phase 2 remaining: CrowdSec, Sentry, Fail2Ban upgrade, Cloudflare rate limiting and WAF
|
* Phase 2 completed: Sentry
|
||||||
* Phase 3: SonarQube, Harbor, Backstage, Nextcloud
|
* Phase 2 remaining: CrowdSec, Fail2Ban upgrade, Cloudflare rate limiting and WAF
|
||||||
|
* Phase 3 completed: Nextcloud
|
||||||
|
* Phase 3 remaining: SonarQube, Harbor, Backstage
|
||||||
|
|
||||||
See:
|
See:
|
||||||
|
|
||||||
@@ -201,3 +242,5 @@ docs/roadmap.md
|
|||||||
* DbGate selected as the database administration portal
|
* DbGate selected as the database administration portal
|
||||||
* Xray introduced as a tunneling and connectivity layer
|
* Xray introduced as a tunneling and connectivity layer
|
||||||
* Multi-network segmentation formalized: internal, proxy and isolated infrastructure networks
|
* Multi-network segmentation formalized: internal, proxy and isolated infrastructure networks
|
||||||
|
* Nextcloud deployed as the private cloud storage service at cloud.silveressence.net
|
||||||
|
* Sentry deployed using upstream self-hosted install.sh and exposed at sentry.silveressence.net
|
||||||
|
|||||||
+153
-8
@@ -120,7 +120,7 @@ Required:
|
|||||||
|
|
||||||
* Native SQL Server database backups
|
* Native SQL Server database backups
|
||||||
* MSSQL Compose configuration
|
* MSSQL Compose configuration
|
||||||
* `MSSQL_SA_PASSWORD` from the shared secrets backup
|
* `MSSQL_SA_PASSWORD` from Infisical recovery data
|
||||||
* Runtime MSSQL data included by the v1.5+ backup structure
|
* Runtime MSSQL data included by the v1.5+ backup structure
|
||||||
|
|
||||||
Importance:
|
Importance:
|
||||||
@@ -174,10 +174,10 @@ Critical
|
|||||||
|
|
||||||
#### Shared Secrets
|
#### Shared Secrets
|
||||||
|
|
||||||
Location:
|
Source:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Contains:
|
Contains:
|
||||||
@@ -186,14 +186,99 @@ Contains:
|
|||||||
* PostgreSQL passwords
|
* PostgreSQL passwords
|
||||||
* MSSQL SA password
|
* MSSQL SA password
|
||||||
* OpenProject secrets
|
* OpenProject secrets
|
||||||
* Future DbGate password
|
* DbGate password
|
||||||
* Future OAuth secrets
|
* Future OAuth secrets
|
||||||
|
|
||||||
Importance:
|
Importance:
|
||||||
|
|
||||||
Critical
|
Critical
|
||||||
|
|
||||||
Without this file applications may not start correctly.
|
Without Infisical recovery and `/etc/infisical/token` reauthorization, applications may not start correctly.
|
||||||
|
|
||||||
|
Legacy note:
|
||||||
|
|
||||||
|
* `/srv/secrets/company.env` is no longer part of the active secret model and should be removed if it still exists.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Nextcloud
|
||||||
|
|
||||||
|
Volumes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
nextcloud_nextcloud_data
|
||||||
|
nextcloud_nextcloud_db
|
||||||
|
```
|
||||||
|
|
||||||
|
Compose location:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/docker/nextcloud
|
||||||
|
```
|
||||||
|
|
||||||
|
Contains:
|
||||||
|
|
||||||
|
* Uploaded files and user data
|
||||||
|
* Nextcloud application configuration
|
||||||
|
* Installed apps and themes
|
||||||
|
* PostgreSQL metadata database
|
||||||
|
* Compose configuration and environment references
|
||||||
|
|
||||||
|
Required:
|
||||||
|
|
||||||
|
* Logical PostgreSQL dump from `nextcloud-db`
|
||||||
|
* Archive of `nextcloud_nextcloud_data`
|
||||||
|
* Archive or cold snapshot of `nextcloud_nextcloud_db`
|
||||||
|
* `/srv/docker/nextcloud/docker-compose.yml`
|
||||||
|
* `/srv/docker/nextcloud/.env` only if it contains non-secret runtime configuration
|
||||||
|
* Infisical `/nextcloud` secrets
|
||||||
|
|
||||||
|
Importance:
|
||||||
|
|
||||||
|
Critical
|
||||||
|
|
||||||
|
The 2026-07-08 runtime snapshot verified `nextcloud_nextcloud_data` and `nextcloud_nextcloud_db` as Docker-managed named volumes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Sentry
|
||||||
|
|
||||||
|
Deployment model:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Upstream Sentry self-hosted install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Contains:
|
||||||
|
|
||||||
|
* `/srv/docker/sentry`
|
||||||
|
* Generated Sentry configuration
|
||||||
|
* PostgreSQL metadata
|
||||||
|
* ClickHouse event data
|
||||||
|
* Redis cache and coordination data
|
||||||
|
* Kafka data if persistence is enabled
|
||||||
|
* SeaweedFS attachments and object storage
|
||||||
|
|
||||||
|
Required:
|
||||||
|
|
||||||
|
* Backup of `/srv/docker/sentry`
|
||||||
|
* Backup of Sentry generated config and secret files
|
||||||
|
* Backup of persistent Sentry Docker volumes
|
||||||
|
* Nginx Proxy Manager route and certificate state for `sentry.silveressence.net`
|
||||||
|
|
||||||
|
Importance:
|
||||||
|
|
||||||
|
Critical
|
||||||
|
|
||||||
|
Sentry is not a normal SilverLinux `slcompose` service. Preserve its upstream self-hosted installer layout and restore it as one deployment unit.
|
||||||
|
|
||||||
|
Verified configuration files:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/docker/sentry/.env
|
||||||
|
/srv/docker/sentry/docker-compose.yml
|
||||||
|
/srv/docker/sentry/sentry/sentry.conf.py
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -293,7 +378,7 @@ Contains:
|
|||||||
* Runner deployment configuration
|
* Runner deployment configuration
|
||||||
* Runner state
|
* Runner state
|
||||||
|
|
||||||
The registration token is stored separately in `/srv/secrets/company.env`.
|
The registration token is stored in Infisical.
|
||||||
|
|
||||||
Importance:
|
Importance:
|
||||||
|
|
||||||
@@ -393,6 +478,60 @@ Keep:
|
|||||||
7 days
|
7 days
|
||||||
```
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Nextcloud Backup Recipe
|
||||||
|
|
||||||
|
This recipe shows practical commands to back up the operational Nextcloud PostgreSQL database and application data volume. Run these on the host where Docker runs. Adjust paths, filenames and the backup target directory as needed.
|
||||||
|
|
||||||
|
1) Backup PostgreSQL (from running `nextcloud-db` container). This creates a compressed SQL dump:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backup directory on host
|
||||||
|
BACKUP_DIR=/srv/backups/nextcloud
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
docker exec -t nextcloud-db pg_dump -U nextcloud nextcloud | gzip > "$BACKUP_DIR/nextcloud_db_$(date +%F).sql.gz"
|
||||||
|
```
|
||||||
|
|
||||||
|
If the DB user or DB name differ from the example, use the values from the Nextcloud Infisical path or sanitized Compose config. For a full cluster dump, use `pg_dumpall` with the appropriate PostgreSQL user.
|
||||||
|
|
||||||
|
2) Backup application data volume (`nextcloud_nextcloud_data`):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
BACKUP_DIR=/srv/backups/nextcloud
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
docker run --rm -v nextcloud_nextcloud_data:/data -v "$BACKUP_DIR":/backup alpine \
|
||||||
|
sh -c "cd /data && tar czf /backup/nextcloud_data_$(date +%F).tar.gz ."
|
||||||
|
```
|
||||||
|
|
||||||
|
3) Backup `docker-compose.yml` and `.env` if the `.env` file contains only non-secret runtime configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp /srv/docker/nextcloud/docker-compose.yml "$BACKUP_DIR/docker-compose.yml.$(date +%F)"
|
||||||
|
if [ -f /srv/docker/nextcloud/.env ]; then
|
||||||
|
cp /srv/docker/nextcloud/.env "$BACKUP_DIR/.env.$(date +%F)"
|
||||||
|
fi
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not preserve plaintext passwords from `.env`; migrate them to Infisical and remove them from the file.
|
||||||
|
|
||||||
|
4) Optional: Export Postgres data directory snapshot (cold snapshot required — stop DB or use filesystem snapshot):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stop DB to take a consistent file-level snapshot (or use LVM/ZFS snapshot instead)
|
||||||
|
docker compose -f /srv/docker/nextcloud/docker-compose.yml stop nextcloud-db
|
||||||
|
tar czf "$BACKUP_DIR/nextcloud_db_files_$(date +%F).tar.gz" -C /var/lib/docker/volumes/nextcloud_nextcloud_db/_data .
|
||||||
|
docker compose -f /srv/docker/nextcloud/docker-compose.yml start nextcloud-db
|
||||||
|
```
|
||||||
|
|
||||||
|
5) Retention and verification
|
||||||
|
|
||||||
|
- Keep backups in `/srv/backups/nextcloud` with rolling retention (e.g., daily 7, weekly 4, monthly 6).
|
||||||
|
- Verify SQL dumps by restoring to a staging DB and checking the Nextcloud application with `occ status` and a login test.
|
||||||
|
|
||||||
|
Security note: backups contain secrets (DB passwords stored in config, mail credentials in `config.php`). Protect backups with appropriate filesystem permissions and store them encrypted if possible.
|
||||||
|
|
||||||
|
|
||||||
### Weekly
|
### Weekly
|
||||||
|
|
||||||
Keep:
|
Keep:
|
||||||
@@ -427,6 +566,8 @@ Restore order:
|
|||||||
10. Gitea Actions Runner
|
10. Gitea Actions Runner
|
||||||
11. DbGate
|
11. DbGate
|
||||||
12. Xray
|
12. Xray
|
||||||
|
13. Nextcloud
|
||||||
|
14. Sentry
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -449,6 +590,10 @@ Verified:
|
|||||||
* OpenProject assets
|
* OpenProject assets
|
||||||
* Docker configuration
|
* Docker configuration
|
||||||
|
|
||||||
|
Nextcloud restore validation is pending after its 2026-07-08 operational documentation update.
|
||||||
|
|
||||||
|
Sentry restore validation is pending after its upstream `install.sh` deployment documentation update.
|
||||||
|
|
||||||
Validation results:
|
Validation results:
|
||||||
|
|
||||||
* MSSQL backup integrity verified
|
* MSSQL backup integrity verified
|
||||||
@@ -542,10 +687,10 @@ Install:
|
|||||||
|
|
||||||
### Step 2
|
### Step 2
|
||||||
|
|
||||||
Restore:
|
Restore or reauthorize:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical access and service secret paths
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 3
|
### Step 3
|
||||||
|
|||||||
+7
-2
@@ -95,10 +95,15 @@ The complete workflow has been tested successfully and is operational.
|
|||||||
Runner registration token:
|
Runner registration token:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
|
||||||
GITEA_RUNNER_REGISTRATION_TOKEN
|
GITEA_RUNNER_REGISTRATION_TOKEN
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Source:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Infisical
|
||||||
|
```
|
||||||
|
|
||||||
BaGet publishing credential:
|
BaGet publishing credential:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -106,7 +111,7 @@ Repository Settings -> Actions -> Secrets
|
|||||||
BAGET_API_KEY
|
BAGET_API_KEY
|
||||||
```
|
```
|
||||||
|
|
||||||
No credentials are stored in repositories. Infrastructure-level secrets belong in `company.env`; repository workflow secrets belong in Gitea Actions Secrets.
|
No credentials are stored in repositories. Infrastructure-level secrets belong in Infisical; repository workflow secrets belong in Gitea Actions Secrets.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+80
-10
@@ -161,12 +161,12 @@ Implemented
|
|||||||
|
|
||||||
Decision:
|
Decision:
|
||||||
|
|
||||||
Store shared credentials in a single secrets file.
|
Originally store shared credentials in a single secrets file.
|
||||||
|
|
||||||
Location:
|
Location:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Legacy local secrets file
|
||||||
```
|
```
|
||||||
|
|
||||||
Reason:
|
Reason:
|
||||||
@@ -178,7 +178,14 @@ Reason:
|
|||||||
|
|
||||||
Status:
|
Status:
|
||||||
|
|
||||||
Implemented
|
Superseded by Infisical and `slcompose`
|
||||||
|
|
||||||
|
Current state:
|
||||||
|
|
||||||
|
* Standard SilverLinux service secrets are stored in Infisical.
|
||||||
|
* `slcompose` injects secrets into Compose stacks at runtime.
|
||||||
|
* The legacy local secrets file should be removed if it still exists.
|
||||||
|
* Sentry is the exception and follows the upstream self-hosted Sentry installation pattern.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -235,7 +242,7 @@ Decision:
|
|||||||
* Replace GitHub Actions with self-hosted Gitea Actions.
|
* Replace GitHub Actions with self-hosted Gitea Actions.
|
||||||
* Execute package publishing on SilverLinux using the global `silverlinux-runner`.
|
* Execute package publishing on SilverLinux using the global `silverlinux-runner`.
|
||||||
* Publish internal NuGet packages to BaGet.
|
* Publish internal NuGet packages to BaGet.
|
||||||
* Store the runner registration token in `/srv/secrets/company.env` and publishing credentials in Gitea Actions Secrets.
|
* Store the runner registration token in Infisical and publishing credentials in Gitea Actions Secrets.
|
||||||
* Use `[Package]` in commit messages to request commit-driven package publishing.
|
* Use `[Package]` in commit messages to request commit-driven package publishing.
|
||||||
|
|
||||||
Reason:
|
Reason:
|
||||||
@@ -262,15 +269,15 @@ Reason:
|
|||||||
|
|
||||||
* Simplicity during initial deployment.
|
* Simplicity during initial deployment.
|
||||||
|
|
||||||
Future Plan:
|
Current Plan:
|
||||||
|
|
||||||
Move the API key into the centralized SilverLinux secrets management system located at:
|
Move the API key into the centralized SilverLinux secrets management system:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
when additional services begin consuming the same secret management approach.
|
when the BaGet deployment is fully aligned with the standard `slcompose` pattern.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -281,7 +288,7 @@ Decision:
|
|||||||
* Run Microsoft SQL Server 2022 Express alongside PostgreSQL.
|
* Run Microsoft SQL Server 2022 Express alongside PostgreSQL.
|
||||||
* Attach MSSQL only to the `internal` Docker network.
|
* Attach MSSQL only to the `internal` Docker network.
|
||||||
* Do not publish port `1433` or route MSSQL through the reverse proxy.
|
* Do not publish port `1433` or route MSSQL through the reverse proxy.
|
||||||
* Store `MSSQL_SA_PASSWORD` in `/srv/secrets/company.env`.
|
* Store `MSSQL_SA_PASSWORD` in Infisical.
|
||||||
|
|
||||||
Reason:
|
Reason:
|
||||||
|
|
||||||
@@ -312,7 +319,7 @@ Reason:
|
|||||||
|
|
||||||
Follow-up:
|
Follow-up:
|
||||||
|
|
||||||
Move the DbGate password from the server-side Compose configuration to `/srv/secrets/company.env`.
|
Move the DbGate password from any legacy server-side Compose configuration to Infisical.
|
||||||
|
|
||||||
Status:
|
Status:
|
||||||
|
|
||||||
@@ -447,6 +454,10 @@ Status:
|
|||||||
Accepted
|
Accepted
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Current status:
|
||||||
|
|
||||||
|
* Sentry is now implemented and documented as the exception to the standard `slcompose` + Infisical service pattern.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2026-06-25 - Select Prometheus And Grafana Monitoring Stack
|
## 2026-06-25 - Select Prometheus And Grafana Monitoring Stack
|
||||||
@@ -583,6 +594,65 @@ Implemented
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-08 - Deploy Nextcloud For Private Cloud Storage
|
||||||
|
|
||||||
|
Decision:
|
||||||
|
|
||||||
|
Deploy Nextcloud as the SilverLinux private cloud storage and file sharing service at `cloud.silveressence.net`.
|
||||||
|
|
||||||
|
Implementation:
|
||||||
|
|
||||||
|
* Run `nextcloud:29-apache` as the web application container.
|
||||||
|
* Run `postgres:16` as the stack-local Nextcloud database.
|
||||||
|
* Run `redis:7-alpine` as the stack-local cache and locking backend.
|
||||||
|
* Attach only the web container to `proxy`.
|
||||||
|
* Keep PostgreSQL and Redis on `nextcloud_nextcloud_internal`.
|
||||||
|
* Persist data in `nextcloud_nextcloud_data` and `nextcloud_nextcloud_db`.
|
||||||
|
* Manage the stack from `/srv/docker/nextcloud` with `slcompose` and Infisical secret injection.
|
||||||
|
|
||||||
|
Reason:
|
||||||
|
|
||||||
|
* Provide self-hosted file storage and document sharing.
|
||||||
|
* Keep user files inside SilverLinux infrastructure.
|
||||||
|
* Avoid exposing database or cache ports publicly.
|
||||||
|
* Reuse the standard Nginx Proxy Manager routing model.
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Implemented
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2026-07-08 - Document Sentry As Upstream Self-Hosted Deployment
|
||||||
|
|
||||||
|
Decision:
|
||||||
|
|
||||||
|
Run Sentry using the upstream self-hosted `install.sh` workflow and expose it at `sentry.silveressence.net` through Nginx Proxy Manager.
|
||||||
|
|
||||||
|
Implementation:
|
||||||
|
|
||||||
|
* Use the upstream Sentry self-hosted installer layout.
|
||||||
|
* Treat `sentry-self-hosted` as one atomic deployment unit.
|
||||||
|
* Keep Sentry backing services isolated on `sentry-self-hosted_default`.
|
||||||
|
* Route public access through the Sentry nginx or web entry layer.
|
||||||
|
* Do not force Sentry into the standard SilverLinux `slcompose` and Infisical pattern.
|
||||||
|
|
||||||
|
Reason:
|
||||||
|
|
||||||
|
* Sentry is a large distributed application with many tightly coupled services.
|
||||||
|
* The upstream self-hosted installer manages required configuration and generated secrets.
|
||||||
|
* Preserving the upstream layout reduces maintenance risk during upgrades.
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Implemented
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Future Decisions
|
## Future Decisions
|
||||||
|
|
||||||
Document future decisions using the following template:
|
Document future decisions using the following template:
|
||||||
|
|||||||
+165
-2
@@ -9,7 +9,7 @@ All public services are routed through Nginx Proxy Manager.
|
|||||||
Verified proxy-host snapshot:
|
Verified proxy-host snapshot:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
2026-06-24
|
2026-06-24, with Nextcloud and Sentry evidence added from 2026-07-08 server output
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -38,6 +38,8 @@ Used for:
|
|||||||
| 5 | `team.silveressence.net` | `http://openproject:80` | enabled | enabled | disabled | enabled | none | enabled |
|
| 5 | `team.silveressence.net` | `http://openproject:80` | enabled | enabled | disabled | enabled | none | enabled |
|
||||||
| 6 | `nuget.silveressence.net` | `http://baget:80` | disabled | disabled | disabled | disabled | none | enabled |
|
| 6 | `nuget.silveressence.net` | `http://baget:80` | disabled | disabled | disabled | disabled | none | enabled |
|
||||||
| 8 | `dbgate.silveressence.net` | `http://dbgate:3000` | disabled | disabled | disabled | enabled | none | enabled |
|
| 8 | `dbgate.silveressence.net` | `http://dbgate:3000` | disabled | disabled | disabled | enabled | none | enabled |
|
||||||
|
| 12 | `sentry.silveressence.net` | `http://sentry-self-hosted-nginx-1:80` | enabled | enabled | disabled | enabled | none | enabled |
|
||||||
|
| 13 | `cloud.silveressence.net` | `http://nextcloud:80` | disabled | disabled | disabled | enabled | none | enabled |
|
||||||
|
|
||||||
All listed active inventory hosts have Block Exploits enabled.
|
All listed active inventory hosts have Block Exploits enabled.
|
||||||
|
|
||||||
@@ -72,9 +74,11 @@ Nginx Proxy Manager findings from the 2026-06-24 snapshot:
|
|||||||
|
|
||||||
* `portainer.silveressence.net` has SSL Force, HTTP/2 and HSTS enabled.
|
* `portainer.silveressence.net` has SSL Force, HTTP/2 and HSTS enabled.
|
||||||
* `team.silveressence.net` has SSL Force and HTTP/2 enabled.
|
* `team.silveressence.net` has SSL Force and HTTP/2 enabled.
|
||||||
* `git.silveressence.net`, `meet.silveressence.net`, `nuget.silveressence.net` and `dbgate.silveressence.net` do not have SSL Force enabled.
|
* `sentry.silveressence.net` has SSL Force, HTTP/2, WebSocket and Block Exploits enabled; HSTS is disabled.
|
||||||
|
* `git.silveressence.net`, `meet.silveressence.net`, `nuget.silveressence.net`, `dbgate.silveressence.net` and `cloud.silveressence.net` do not have SSL Force enabled.
|
||||||
* No listed proxy host uses an Nginx Proxy Manager access list.
|
* No listed proxy host uses an Nginx Proxy Manager access list.
|
||||||
* DbGate is a high-sensitivity database administration interface and should be prioritized for SSL Force and an access restriction policy.
|
* DbGate is a high-sensitivity database administration interface and should be prioritized for SSL Force and an access restriction policy.
|
||||||
|
* Nextcloud stores private files and should be prioritized for SSL Force, HTTP/2 and HSTS.
|
||||||
* Plane.so has been removed from containers, Nginx Proxy Manager and server certificate storage.
|
* Plane.so has been removed from containers, Nginx Proxy Manager and server certificate storage.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -202,6 +206,89 @@ Active
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Exact Syncer Demo
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
exactsyncer.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Demo `.NET 9` Blazor application for Exact Online integration
|
||||||
|
* Provides a UI for connecting Exact webhooks and observing sync behavior
|
||||||
|
* Syncs main division changes to dependent sub-divisions
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
* When the main division record (Relation 1) changes, divisions 2–10 add or update the same relation data
|
||||||
|
* Demonstrates how Exact Online master/sub-division sync works in practice
|
||||||
|
|
||||||
|
Container:
|
||||||
|
|
||||||
|
```text
|
||||||
|
exact-syncer
|
||||||
|
```
|
||||||
|
|
||||||
|
Routing:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Nginx Proxy Manager -> exact-syncer:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* Demo version intended for client evaluation
|
||||||
|
* Can be recreated as a bespoke customer instance on request
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Operational demo
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### BobAutoWas Exact Syncer Instance
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cicd.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Client-specific Exact Syncer instance for BobAutoWas
|
||||||
|
* Customer recreation of the Exact Syncer demo application
|
||||||
|
* Provides the same webhook-driven division sync behavior
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
* Mirrors Exact Syncer demo functionality for BobAutoWas
|
||||||
|
* Supports client evaluation and live preview of the integration
|
||||||
|
|
||||||
|
Container:
|
||||||
|
|
||||||
|
```text
|
||||||
|
bobsAutowas
|
||||||
|
```
|
||||||
|
|
||||||
|
Routing:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Nginx Proxy Manager -> bobsAutowas:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Active client instance
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### DbGate
|
### DbGate
|
||||||
|
|
||||||
Domain:
|
Domain:
|
||||||
@@ -234,6 +321,82 @@ Active
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Sentry
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sentry.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Error tracking and observability
|
||||||
|
* Event ingestion endpoint
|
||||||
|
* Sentry web UI
|
||||||
|
|
||||||
|
Container:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sentry-self-hosted-nginx-1
|
||||||
|
```
|
||||||
|
|
||||||
|
Routing:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Nginx Proxy Manager -> sentry-self-hosted-nginx-1:80
|
||||||
|
```
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Active
|
||||||
|
```
|
||||||
|
|
||||||
|
Runtime note:
|
||||||
|
|
||||||
|
Sentry was installed through the upstream self-hosted `install.sh` and is available at `https://sentry.silveressence.net`. Nginx Proxy Manager proxy host 12 forwards the domain to `http://sentry-self-hosted-nginx-1:80`. The 2026-07-08 database query showed SSL Force enabled, HTTP/2 enabled, HSTS disabled, HSTS subdomains disabled, WebSocket enabled, Block Exploits enabled and no access list.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Nextcloud
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cloud.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Private cloud storage
|
||||||
|
* File sharing
|
||||||
|
* Team document storage
|
||||||
|
|
||||||
|
Container:
|
||||||
|
|
||||||
|
```text
|
||||||
|
nextcloud
|
||||||
|
```
|
||||||
|
|
||||||
|
Routing:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Nginx Proxy Manager -> nextcloud:80
|
||||||
|
```
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Active
|
||||||
|
```
|
||||||
|
|
||||||
|
Runtime note:
|
||||||
|
|
||||||
|
Nginx Proxy Manager proxy host 13 is enabled and forwards `cloud.silveressence.net` to `http://nextcloud:80`. The 2026-07-08 database query showed SSL Force disabled, HTTP/2 disabled, HSTS disabled, WebSocket enabled, Block Exploits enabled and no access list.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## DNS
|
## DNS
|
||||||
|
|
||||||
DNS records should point to:
|
DNS records should point to:
|
||||||
|
|||||||
+31
-3
@@ -68,7 +68,7 @@ Login
|
|||||||
SMTP credentials are stored in:
|
SMTP credentials are stored in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Variables:
|
Variables:
|
||||||
@@ -147,6 +147,34 @@ Configured and validated
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Nextcloud
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* User notifications
|
||||||
|
* File sharing notifications
|
||||||
|
* Password and account emails where enabled
|
||||||
|
|
||||||
|
Sender:
|
||||||
|
|
||||||
|
```text
|
||||||
|
noreply@silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Observed runtime settings:
|
||||||
|
|
||||||
|
```text
|
||||||
|
smtp.gmail.com
|
||||||
|
port 465
|
||||||
|
ssl
|
||||||
|
```
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
Configured
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Alertmanager
|
### Alertmanager
|
||||||
|
|
||||||
Purpose:
|
Purpose:
|
||||||
@@ -221,7 +249,7 @@ docker logs gitea
|
|||||||
Verify:
|
Verify:
|
||||||
|
|
||||||
* App password is valid
|
* App password is valid
|
||||||
* SMTP credentials match company.env
|
* SMTP credentials match the Infisical values injected by `slcompose`
|
||||||
* STARTTLS is enabled
|
* STARTTLS is enabled
|
||||||
* Port 587 is used
|
* Port 587 is used
|
||||||
|
|
||||||
@@ -240,7 +268,7 @@ Verify:
|
|||||||
|
|
||||||
* Use Gmail App Passwords.
|
* Use Gmail App Passwords.
|
||||||
* Never use personal Gmail passwords.
|
* Never use personal Gmail passwords.
|
||||||
* Store SMTP credentials only in company.env.
|
* Store SMTP credentials only in Infisical.
|
||||||
* Rotate credentials if they become exposed.
|
* Rotate credentials if they become exposed.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
+102
-2
@@ -8,12 +8,12 @@ Current model:
|
|||||||
|
|
||||||
* `internal` for private databases and backend service traffic
|
* `internal` for private databases and backend service traffic
|
||||||
* `proxy` for HTTP and HTTPS services routed by Nginx Proxy Manager
|
* `proxy` for HTTP and HTTPS services routed by Nginx Proxy Manager
|
||||||
* Isolated stack networks for specialized infrastructure such as Jitsi, Xray, monitoring and CI/CD runners
|
* Isolated stack networks for specialized infrastructure such as Jitsi, Xray, monitoring, Sentry and CI/CD runners
|
||||||
|
|
||||||
Verified runtime snapshot:
|
Verified runtime snapshot:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
2026-06-24 10:15 CEST
|
2026-06-24 10:15 CEST, with Nextcloud and Sentry evidence added from 2026-07-08 server output
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -73,6 +73,8 @@ Public services:
|
|||||||
* Xray
|
* Xray
|
||||||
* Jitsi Web
|
* Jitsi Web
|
||||||
* BaGet
|
* BaGet
|
||||||
|
* Nextcloud
|
||||||
|
* Sentry
|
||||||
|
|
||||||
Internal monitoring services:
|
Internal monitoring services:
|
||||||
|
|
||||||
@@ -110,6 +112,7 @@ jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
|||||||
xray_default
|
xray_default
|
||||||
gitea-runner_default
|
gitea-runner_default
|
||||||
monitoring stack network
|
monitoring stack network
|
||||||
|
sentry-self-hosted_default
|
||||||
```
|
```
|
||||||
|
|
||||||
#### jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
#### jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
||||||
@@ -158,6 +161,29 @@ Verified subnet:
|
|||||||
172.22.0.0/16
|
172.22.0.0/16
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Gluetun PIA VPN Gateway
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Containerized VPN gateway for Private Internet Access (PIA)
|
||||||
|
* Isolate VPN traffic from host networking and production services
|
||||||
|
|
||||||
|
Services:
|
||||||
|
|
||||||
|
* `gluetun-pia`
|
||||||
|
* `xray-pia` (via `container:gluetun-pia` network mode)
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* `gluetun-pia` routes selected container traffic through PIA WireGuard
|
||||||
|
* `xray-pia` is a secondary VLESS endpoint that uses the Gluetun VPN gateway
|
||||||
|
* Production `xray` remains isolated on the direct OVH path
|
||||||
|
|
||||||
|
Verified isolation:
|
||||||
|
|
||||||
|
* VPN traffic is contained inside the `gluetun-pia` container namespace
|
||||||
|
* Host routing remains unchanged by VPN activity
|
||||||
|
|
||||||
#### gitea-runner_default
|
#### gitea-runner_default
|
||||||
|
|
||||||
Purpose:
|
Purpose:
|
||||||
@@ -200,6 +226,59 @@ Validated:
|
|||||||
* Grafana connects to Prometheus
|
* Grafana connects to Prometheus
|
||||||
* Alertmanager routes monitoring alerts
|
* Alertmanager routes monitoring alerts
|
||||||
|
|
||||||
|
#### nextcloud_nextcloud_internal
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Private Nextcloud application, database and cache traffic
|
||||||
|
* Keep Nextcloud PostgreSQL and Redis away from the public proxy layer
|
||||||
|
|
||||||
|
Services:
|
||||||
|
|
||||||
|
* `nextcloud`
|
||||||
|
* `nextcloud-db`
|
||||||
|
* `nextcloud-redis`
|
||||||
|
|
||||||
|
Public attachment:
|
||||||
|
|
||||||
|
* Only the `nextcloud` web container also attaches to `proxy`.
|
||||||
|
* `nextcloud-db` and `nextcloud-redis` are internal-only.
|
||||||
|
|
||||||
|
Verified subnet:
|
||||||
|
|
||||||
|
```text
|
||||||
|
172.27.0.0/16
|
||||||
|
```
|
||||||
|
|
||||||
|
#### sentry-self-hosted_default
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Internal Sentry event processing, storage and worker communication
|
||||||
|
* Keep Sentry backing services isolated from shared application networks
|
||||||
|
|
||||||
|
Services:
|
||||||
|
|
||||||
|
* Sentry web, relay, worker, cron and consumer services
|
||||||
|
* Kafka
|
||||||
|
* Snuba
|
||||||
|
* ClickHouse
|
||||||
|
* PostgreSQL
|
||||||
|
* Redis
|
||||||
|
* SeaweedFS
|
||||||
|
|
||||||
|
Public attachment:
|
||||||
|
|
||||||
|
* Public access is through Nginx Proxy Manager at `sentry.silveressence.net`.
|
||||||
|
* The public entry container is `sentry-self-hosted-nginx-1`.
|
||||||
|
* Sentry databases, queues and workers must remain internal to the Sentry deployment.
|
||||||
|
|
||||||
|
Verified subnet:
|
||||||
|
|
||||||
|
```text
|
||||||
|
172.25.0.0/16
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Runtime-Published Ports
|
## Runtime-Published Ports
|
||||||
@@ -215,6 +294,14 @@ The current Docker runtime includes these host-published ports.
|
|||||||
| Jitsi Web | `8000`, `8443` | `80`, `443` | `8443` allowed; `8000` not listed | Direct HTTP and HTTPS ports also published |
|
| Jitsi Web | `8000`, `8443` | `80`, `443` | `8443` allowed; `8000` not listed | Direct HTTP and HTTPS ports also published |
|
||||||
| Jitsi JVB | `10000/udp` | `10000/udp` | Allowed | Required media bridge traffic |
|
| Jitsi JVB | `10000/udp` | `10000/udp` | Allowed | Required media bridge traffic |
|
||||||
| Xray | `32443` | `8080` | Allowed | Public tunneling endpoint |
|
| Xray | `32443` | `8080` | Allowed | Public tunneling endpoint |
|
||||||
|
| Sentry nginx | `9000` | `80` | Not listed as allowed | Nginx Proxy Manager forwards to `sentry-self-hosted-nginx-1:80`; direct host port should be reviewed |
|
||||||
|
|
||||||
|
Nextcloud runtime exposure from the 2026-07-08 snapshot:
|
||||||
|
|
||||||
|
* `nextcloud` exposes `80/tcp` only inside Docker and is routed through Nginx Proxy Manager.
|
||||||
|
* `nextcloud-db` exposes `5432/tcp` only inside Docker.
|
||||||
|
* `nextcloud-redis` exposes `6379/tcp` only inside Docker.
|
||||||
|
* No host-published ports were shown for the Nextcloud stack.
|
||||||
|
|
||||||
Additional UFW allowed ports with no matching Docker-published service in the 2026-06-24 Docker snapshot:
|
Additional UFW allowed ports with no matching Docker-published service in the 2026-06-24 Docker snapshot:
|
||||||
|
|
||||||
@@ -228,6 +315,12 @@ Database ports:
|
|||||||
* MSSQL exposes `1433/tcp` only inside Docker.
|
* MSSQL exposes `1433/tcp` only inside Docker.
|
||||||
* DbGate exposes `3000/tcp` only inside Docker.
|
* DbGate exposes `3000/tcp` only inside Docker.
|
||||||
|
|
||||||
|
Sentry runtime exposure:
|
||||||
|
|
||||||
|
* `sentry.silveressence.net` is routed through Nginx Proxy Manager to `sentry-self-hosted-nginx-1:80`.
|
||||||
|
* `sentry-self-hosted-nginx-1` publishes `0.0.0.0:9000 -> 80/tcp`.
|
||||||
|
* Sentry backing services should not publish host ports.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Topology Summary
|
## Topology Summary
|
||||||
@@ -243,6 +336,8 @@ Internet
|
|||||||
-> Xray
|
-> Xray
|
||||||
-> Jitsi Web
|
-> Jitsi Web
|
||||||
-> BaGet
|
-> BaGet
|
||||||
|
-> Nextcloud
|
||||||
|
-> Sentry
|
||||||
|
|
||||||
internal network
|
internal network
|
||||||
-> PostgreSQL
|
-> PostgreSQL
|
||||||
@@ -254,6 +349,8 @@ isolated networks
|
|||||||
-> xray_default
|
-> xray_default
|
||||||
-> gitea-runner_default
|
-> gitea-runner_default
|
||||||
-> monitoring stack network
|
-> monitoring stack network
|
||||||
|
-> nextcloud_nextcloud_internal
|
||||||
|
-> sentry-self-hosted_default
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -284,9 +381,12 @@ Periodically verify:
|
|||||||
* Jitsi internal components remain attached to `jitsi-docker-jitsi-meet-aa76415_meet.jitsi`
|
* Jitsi internal components remain attached to `jitsi-docker-jitsi-meet-aa76415_meet.jitsi`
|
||||||
* The desired Xray attachment is reconciled with the fact that `xray_default` currently has no running containers
|
* The desired Xray attachment is reconciled with the fact that `xray_default` currently has no running containers
|
||||||
* Direct host-published ports are intentional and protected by firewall policy
|
* Direct host-published ports are intentional and protected by firewall policy
|
||||||
|
* Sentry host-published port `9000` has a documented owner and firewall policy
|
||||||
* UFW-only allowed ports have documented owners
|
* UFW-only allowed ports have documented owners
|
||||||
* Prometheus targets remain healthy
|
* Prometheus targets remain healthy
|
||||||
* Grafana datasource connection remains healthy
|
* Grafana datasource connection remains healthy
|
||||||
|
* Nextcloud remains routed through Nginx Proxy Manager without host-published database or Redis ports
|
||||||
|
* Sentry remains routed through Nginx Proxy Manager with internal backing services isolated
|
||||||
* Unused Docker networks are removed only after confirming they are not active dependencies
|
* Unused Docker networks are removed only after confirming they are not active dependencies
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -0,0 +1,338 @@
|
|||||||
|
# Nextcloud
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Nextcloud is deployed on SilverLinux as the private cloud storage and file sharing service for Silver Solutions.
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Operational
|
||||||
|
```
|
||||||
|
|
||||||
|
Public URL:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://cloud.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Verified runtime snapshot:
|
||||||
|
|
||||||
|
```text
|
||||||
|
2026-07-08 13:21:13 +02:00
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Runtime Stack
|
||||||
|
|
||||||
|
Location:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/docker/nextcloud
|
||||||
|
```
|
||||||
|
|
||||||
|
Files present on the server:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/docker/nextcloud/docker-compose.yml
|
||||||
|
/srv/docker/nextcloud/.env
|
||||||
|
```
|
||||||
|
|
||||||
|
The `.env` file was present in the 2026-07-08 snapshot, but passwords should come from Infisical through `slcompose`. Remove any secret values from this file if they still exist.
|
||||||
|
|
||||||
|
Management:
|
||||||
|
|
||||||
|
* Docker Compose stack name: `nextcloud`
|
||||||
|
* Managed by `slcompose`
|
||||||
|
* Secrets injected at runtime through Infisical
|
||||||
|
* Restart policy: `unless-stopped`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Containers
|
||||||
|
|
||||||
|
| Container | Image | Purpose | Status at snapshot |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `nextcloud` | `nextcloud:29-apache` | Web UI, file storage and application runtime | Up 6 days |
|
||||||
|
| `nextcloud-db` | `postgres:16` | Nextcloud PostgreSQL database | Up 6 days |
|
||||||
|
| `nextcloud-redis` | `redis:7-alpine` | Redis cache and locking backend | Up 6 days |
|
||||||
|
|
||||||
|
Nextcloud application status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
installed: true
|
||||||
|
version: 29.0.16
|
||||||
|
maintenance: false
|
||||||
|
needsDbUpgrade: false
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Networking
|
||||||
|
|
||||||
|
Networks:
|
||||||
|
|
||||||
|
* `proxy`
|
||||||
|
* `nextcloud_nextcloud_internal`
|
||||||
|
|
||||||
|
Network roles:
|
||||||
|
|
||||||
|
* `proxy` connects `nextcloud` to Nginx Proxy Manager.
|
||||||
|
* `nextcloud_nextcloud_internal` connects `nextcloud`, `nextcloud-db` and `nextcloud-redis`.
|
||||||
|
* `nextcloud-db` and `nextcloud-redis` are internal-only and are not attached to `proxy`.
|
||||||
|
|
||||||
|
Verified subnet:
|
||||||
|
|
||||||
|
```text
|
||||||
|
nextcloud_nextcloud_internal: 172.27.0.0/16
|
||||||
|
```
|
||||||
|
|
||||||
|
Port exposure:
|
||||||
|
|
||||||
|
* `nextcloud` exposes `80/tcp` only inside Docker.
|
||||||
|
* `nextcloud-db` exposes `5432/tcp` only inside Docker.
|
||||||
|
* `nextcloud-redis` exposes `6379/tcp` only inside Docker.
|
||||||
|
* No Nextcloud stack ports were published to the host in the runtime snapshot.
|
||||||
|
|
||||||
|
Routing:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Internet
|
||||||
|
-> Nginx Proxy Manager
|
||||||
|
-> proxy network
|
||||||
|
-> nextcloud:80
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Domain And Proxy
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cloud.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Nextcloud trusted domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cloud.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Reverse proxy settings observed in the application configuration:
|
||||||
|
|
||||||
|
```text
|
||||||
|
overwritehost: cloud.silveressence.net
|
||||||
|
overwriteprotocol: https
|
||||||
|
trusted_proxies: 172.16.0.0/12
|
||||||
|
```
|
||||||
|
|
||||||
|
Nginx Proxy Manager proxy host 13 forwards requests to `nextcloud`.
|
||||||
|
|
||||||
|
Proxy host settings from the 2026-07-08 Nginx Proxy Manager database query:
|
||||||
|
|
||||||
|
| Setting | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Forward scheme | `http` |
|
||||||
|
| Forward host | `nextcloud` |
|
||||||
|
| Forward port | `80` |
|
||||||
|
| SSL Force | disabled |
|
||||||
|
| HTTP/2 | disabled |
|
||||||
|
| HSTS | disabled |
|
||||||
|
| HSTS subdomains | disabled |
|
||||||
|
| Block Exploits | enabled |
|
||||||
|
| WebSocket | enabled |
|
||||||
|
| Access List | none |
|
||||||
|
| Status | enabled |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Persistent Data
|
||||||
|
|
||||||
|
Docker volumes:
|
||||||
|
|
||||||
|
| Volume | Mount point | Purpose |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `nextcloud_nextcloud_data` | `/var/www/html` | Nextcloud application files, config, apps and user data directory |
|
||||||
|
| `nextcloud_nextcloud_db` | `/var/lib/next-cloud-postgresDb/data` | PostgreSQL data for Nextcloud |
|
||||||
|
|
||||||
|
Host mountpoints:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/var/lib/docker/volumes/nextcloud_nextcloud_data/_data
|
||||||
|
/var/lib/docker/volumes/nextcloud_nextcloud_db/_data
|
||||||
|
```
|
||||||
|
|
||||||
|
Application data directory:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/var/www/html/data
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Database
|
||||||
|
|
||||||
|
Database type:
|
||||||
|
|
||||||
|
```text
|
||||||
|
pgsql
|
||||||
|
```
|
||||||
|
|
||||||
|
Database host:
|
||||||
|
|
||||||
|
```text
|
||||||
|
nextcloud-db
|
||||||
|
```
|
||||||
|
|
||||||
|
Database image:
|
||||||
|
|
||||||
|
```text
|
||||||
|
postgres:16
|
||||||
|
```
|
||||||
|
|
||||||
|
Operational note:
|
||||||
|
|
||||||
|
PostgreSQL is pinned to version 16 for this stack. During initial deployment, the database volume was initialized with PostgreSQL 16 and therefore must not be started with PostgreSQL 17 without a proper PostgreSQL major-version upgrade.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Redis
|
||||||
|
|
||||||
|
Redis host:
|
||||||
|
|
||||||
|
```text
|
||||||
|
nextcloud-redis
|
||||||
|
```
|
||||||
|
|
||||||
|
Port:
|
||||||
|
|
||||||
|
```text
|
||||||
|
6379
|
||||||
|
```
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Cache backend
|
||||||
|
* File locking support
|
||||||
|
* Internal application performance support
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Email
|
||||||
|
|
||||||
|
Nextcloud SMTP is configured.
|
||||||
|
|
||||||
|
Observed application mail settings:
|
||||||
|
|
||||||
|
```text
|
||||||
|
mail_smtphost: smtp.gmail.com
|
||||||
|
mail_smtpport: 465
|
||||||
|
mail_smtpsecure: ssl
|
||||||
|
mail_from_address: noreply
|
||||||
|
mail_domain: silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Sender:
|
||||||
|
|
||||||
|
```text
|
||||||
|
noreply@silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Credentials must remain in Infisical and must not be committed.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
|
||||||
|
Required secret values include:
|
||||||
|
|
||||||
|
* `NEXTCLOUD_ADMIN_USER`
|
||||||
|
* `NEXTCLOUD_ADMIN_PASSWORD`
|
||||||
|
* `POSTGRES_DB`
|
||||||
|
* `POSTGRES_USER`
|
||||||
|
* `POSTGRES_PASSWORD`
|
||||||
|
* SMTP credentials if not inherited from shared mail configuration
|
||||||
|
|
||||||
|
Security note:
|
||||||
|
|
||||||
|
Nextcloud `config.php` contains sensitive values such as `secret`, `passwordsalt`, database credentials and SMTP credentials. Do not paste the raw file into public channels and rotate any exposed credentials.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Backup Requirements
|
||||||
|
|
||||||
|
Back up these items:
|
||||||
|
|
||||||
|
* `nextcloud_nextcloud_data`
|
||||||
|
* `nextcloud_nextcloud_db`
|
||||||
|
* `/srv/docker/nextcloud/docker-compose.yml`
|
||||||
|
* `/srv/docker/nextcloud/.env` only if it contains non-secret runtime configuration
|
||||||
|
* Infisical secrets for the `/nextcloud` path
|
||||||
|
|
||||||
|
The `nextcloud_nextcloud_data` volume includes the application config and user uploaded files. The `nextcloud_nextcloud_db` volume contains the metadata database and should also be backed up with a logical PostgreSQL dump where possible.
|
||||||
|
|
||||||
|
See [docs/backups.md](backups.md) for the backup recipe and restore order.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Operational Commands
|
||||||
|
|
||||||
|
Check stack status:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker ps --filter "name=nextcloud"
|
||||||
|
```
|
||||||
|
|
||||||
|
Check Nextcloud application status:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud php -f /var/www/html/occ status
|
||||||
|
```
|
||||||
|
|
||||||
|
Check selected config values:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -u www-data nextcloud php -f /var/www/html/occ config:system:get trusted_domains
|
||||||
|
docker exec -u www-data nextcloud php -f /var/www/html/occ config:system:get overwritehost
|
||||||
|
docker exec -u www-data nextcloud php -f /var/www/html/occ config:system:get overwriteprotocol
|
||||||
|
```
|
||||||
|
|
||||||
|
Manage through slcompose:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose up nextcloud
|
||||||
|
slcompose restart nextcloud
|
||||||
|
slcompose logs nextcloud
|
||||||
|
slcompose logs-tail nextcloud 200
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification Evidence
|
||||||
|
|
||||||
|
The 2026-07-08 server output verified:
|
||||||
|
|
||||||
|
* Hostname `silverlinux`
|
||||||
|
* Containers `nextcloud`, `nextcloud-db` and `nextcloud-redis` running
|
||||||
|
* Compose files present under `/srv/docker/nextcloud`
|
||||||
|
* Public domain `cloud.silveressence.net`
|
||||||
|
* Nextcloud version `29.0.16`
|
||||||
|
* Maintenance mode disabled
|
||||||
|
* Database upgrade not required
|
||||||
|
* PostgreSQL backend at `nextcloud-db`
|
||||||
|
* Redis backend at `nextcloud-redis`
|
||||||
|
* Docker volumes `nextcloud_nextcloud_data` and `nextcloud_nextcloud_db`
|
||||||
|
* No host-published ports for the Nextcloud stack
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
* [docs/services.md](services.md)
|
||||||
|
* [docs/domains.md](domains.md)
|
||||||
|
* [docs/network.md](network.md)
|
||||||
|
* [docs/security.md](security.md)
|
||||||
|
* [docs/backups.md](backups.md)
|
||||||
|
* [docs/secrets.md](secrets.md)
|
||||||
@@ -0,0 +1,392 @@
|
|||||||
|
# Service Orchestration: slcompose
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
**slcompose** is the central service orchestrator for SilverLinux. It manages all Docker services in `/srv/docker/` with automated secret injection from Infisical.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
System Boot
|
||||||
|
↓
|
||||||
|
systemd: slcompose.service
|
||||||
|
↓
|
||||||
|
/usr/local/bin/slcompose boot
|
||||||
|
↓
|
||||||
|
For each service in /srv/docker/:
|
||||||
|
├─ Load Infisical Token from /etc/infisical/token
|
||||||
|
├─ Discover docker-compose.yml
|
||||||
|
├─ Extract service name from directory (e.g., gitea)
|
||||||
|
├─ Inject secrets: infisical run --path=/gitea
|
||||||
|
└─ Execute: docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Copy `slcompose.sh` to `/usr/local/bin/slcompose` and make executable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo cp docs/slcompose.sh /usr/local/bin/slcompose
|
||||||
|
sudo chmod +x /usr/local/bin/slcompose
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy systemd service file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo cp docs/slcompose.service /etc/systemd/system/slcompose.service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable slcompose.service
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### List Services
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose list
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
```
|
||||||
|
Available services:
|
||||||
|
====================
|
||||||
|
- gitea
|
||||||
|
- portainer
|
||||||
|
- postgres
|
||||||
|
- mssql
|
||||||
|
- openproject
|
||||||
|
- jitsi
|
||||||
|
- nginx-proxy-manager
|
||||||
|
- postgres
|
||||||
|
- baget
|
||||||
|
- dbgate
|
||||||
|
- nextcloud
|
||||||
|
```
|
||||||
|
|
||||||
|
### Boot All Services
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose boot
|
||||||
|
```
|
||||||
|
|
||||||
|
This is automatically called by systemd on server startup.
|
||||||
|
|
||||||
|
### Start a Service
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose up gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
- Loads Infisical token
|
||||||
|
- Injects secrets from Infisical path: `/gitea`
|
||||||
|
- Runs: `docker compose up -d` in `/srv/docker/gitea`
|
||||||
|
|
||||||
|
### Stop a Service
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose down gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restart a Service
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose restart gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
|
||||||
|
Stream live logs (Ctrl+C to exit):
|
||||||
|
```bash
|
||||||
|
slcompose logs gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
View last N lines (default 200):
|
||||||
|
```bash
|
||||||
|
slcompose logs-tail gitea
|
||||||
|
slcompose logs-tail gitea 500
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Injected Environment Variables
|
||||||
|
|
||||||
|
View all environment variables injected into a specific service from Infisical:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose env gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
Output (color-coded):
|
||||||
|
```
|
||||||
|
========================================
|
||||||
|
Environment Variables for: gitea
|
||||||
|
========================================
|
||||||
|
DB_HOST = postgres
|
||||||
|
DB_NAME = gitea_db
|
||||||
|
DB_PASSWD = secure_password_123
|
||||||
|
DB_TYPE = postgres
|
||||||
|
DB_USER = gitea
|
||||||
|
DOMAIN = git.silveressence.net
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
*(Blue: variable names | Green: values)*
|
||||||
|
|
||||||
|
View injected environment variables for ALL services:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
slcompose env-all
|
||||||
|
```
|
||||||
|
|
||||||
|
Output (color-coded):
|
||||||
|
```
|
||||||
|
========================================
|
||||||
|
All Services and Their Environment Variables
|
||||||
|
========================================
|
||||||
|
|
||||||
|
--- gitea ---
|
||||||
|
DB_HOST = postgres
|
||||||
|
DB_NAME = gitea_db
|
||||||
|
...
|
||||||
|
|
||||||
|
--- portainer ---
|
||||||
|
ADMIN_PASSWORD = secure_password
|
||||||
|
...
|
||||||
|
|
||||||
|
--- postgres ---
|
||||||
|
POSTGRES_DB = main_db
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
*(Blue: variable names | Green: values)*
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Verify secrets are properly injected
|
||||||
|
- Debug missing or incorrect environment variables
|
||||||
|
- Audit which services have access to which secrets
|
||||||
|
- Troubleshoot authentication or configuration issues
|
||||||
|
|
||||||
|
## How Secret Injection Works
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
1. **Infisical Token**: Stored at `/etc/infisical/token`
|
||||||
|
2. **Infisical Domain** (optional): Stored at `/etc/infisical/domain`
|
||||||
|
3. **Secrets Path**: Each service has secrets at path `/<SERVICE_NAME>` in Infisical
|
||||||
|
|
||||||
|
Example: For `gitea` service, secrets must be at `/gitea` in Infisical.
|
||||||
|
|
||||||
|
### Injection Process
|
||||||
|
|
||||||
|
For each service, slcompose executes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
infisical run \
|
||||||
|
--token "$INFISICAL_TOKEN" \
|
||||||
|
--env prod \
|
||||||
|
--path="/$SERVICE_NAME" \
|
||||||
|
--recursive \
|
||||||
|
-- docker compose "$@"
|
||||||
|
```
|
||||||
|
|
||||||
|
This:
|
||||||
|
1. Authenticates with Infisical using the token
|
||||||
|
2. Fetches all secrets from the specified path
|
||||||
|
3. Recursively includes nested secrets
|
||||||
|
4. Sets them as environment variables
|
||||||
|
5. Passes them to the docker compose command
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
All secrets from Infisical are available as environment variables inside the docker compose execution context and are used by `docker-compose.yml` files.
|
||||||
|
|
||||||
|
Example `docker-compose.yml`:
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:latest
|
||||||
|
environment:
|
||||||
|
DB_TYPE: postgres
|
||||||
|
DB_HOST: postgres
|
||||||
|
DB_NAME: ${DB_NAME} # Injected from Infisical
|
||||||
|
DB_USER: ${DB_USER} # Injected from Infisical
|
||||||
|
DB_PASSWD: ${DB_PASSWD} # Injected from Infisical
|
||||||
|
```
|
||||||
|
|
||||||
|
## Service Directory Structure
|
||||||
|
|
||||||
|
Each service is a subdirectory in `/srv/docker/` containing:
|
||||||
|
|
||||||
|
```
|
||||||
|
/srv/docker/gitea/
|
||||||
|
├── docker-compose.yml
|
||||||
|
├── README.md (optional)
|
||||||
|
└── app.ini (optional, service-specific config)
|
||||||
|
```
|
||||||
|
|
||||||
|
Services are discovered by the presence of `docker-compose.yml`.
|
||||||
|
|
||||||
|
## Systemd Integration
|
||||||
|
|
||||||
|
### Service File: `/etc/systemd/system/slcompose.service`
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=SilverLinux Docker Orchestrator (slCompose)
|
||||||
|
After=docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/slcompose boot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
User=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Details:**
|
||||||
|
- `Type=oneshot` — Runs once and exits (doesn't stay running)
|
||||||
|
- `RemainAfterExit=yes` — Systemd remembers the service as "active" after boot completes
|
||||||
|
- `After=docker.service` — Waits for Docker to start first
|
||||||
|
- `Requires=docker.service` — Fails if Docker is not available
|
||||||
|
- `WantedBy=multi-user.target` — Starts during normal multi-user boot
|
||||||
|
|
||||||
|
### Enable Auto-Boot
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl enable slcompose.service
|
||||||
|
```
|
||||||
|
|
||||||
|
### Check Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl status slcompose.service
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Boot Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo journalctl -u slcompose.service -n 100
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Missing Infisical Token
|
||||||
|
|
||||||
|
If `/etc/infisical/token` doesn't exist, slcompose exits with:
|
||||||
|
```
|
||||||
|
ERROR: Missing Infisical token at /etc/infisical/token
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service Not Found
|
||||||
|
|
||||||
|
If you try to manage a non-existent service:
|
||||||
|
```bash
|
||||||
|
slcompose up nonexistent
|
||||||
|
```
|
||||||
|
|
||||||
|
Output:
|
||||||
|
```
|
||||||
|
ERROR: Service 'nonexistent' not found at /srv/docker/nonexistent
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Not Running
|
||||||
|
|
||||||
|
If Docker isn't available, slcompose waits and retries:
|
||||||
|
```
|
||||||
|
Waiting for Docker...
|
||||||
|
Waiting for Docker...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Services not starting on boot
|
||||||
|
|
||||||
|
1. Check if systemd service is enabled:
|
||||||
|
```bash
|
||||||
|
sudo systemctl is-enabled slcompose.service
|
||||||
|
```
|
||||||
|
|
||||||
|
2. View boot logs:
|
||||||
|
```bash
|
||||||
|
sudo journalctl -u slcompose.service -n 50
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Test slcompose manually:
|
||||||
|
```bash
|
||||||
|
slcompose boot
|
||||||
|
```
|
||||||
|
|
||||||
|
### Secrets not injected
|
||||||
|
|
||||||
|
1. Verify Infisical token exists:
|
||||||
|
```bash
|
||||||
|
cat /etc/infisical/token
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Test Infisical access:
|
||||||
|
```bash
|
||||||
|
infisical run --token "$(cat /etc/infisical/token)" --env prod --path=/gitea -- env | grep -v '^_'
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Check service paths in Infisical match service directory names
|
||||||
|
|
||||||
|
### Service fails to start
|
||||||
|
|
||||||
|
1. View detailed logs:
|
||||||
|
```bash
|
||||||
|
slcompose logs gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Check docker-compose.yml for syntax errors:
|
||||||
|
```bash
|
||||||
|
cd /srv/docker/gitea && docker-compose config
|
||||||
|
```
|
||||||
|
|
||||||
|
3. View full docker compose output:
|
||||||
|
```bash
|
||||||
|
cd /srv/docker/gitea && infisical run --token "$(cat /etc/infisical/token)" --env prod --path=/gitea -- docker compose up
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding New Services
|
||||||
|
|
||||||
|
1. Create service directory:
|
||||||
|
```bash
|
||||||
|
mkdir -p /srv/docker/myservice
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Add `docker-compose.yml`:
|
||||||
|
```bash
|
||||||
|
cp template/docker-compose.yml /srv/docker/myservice/
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Create secrets in Infisical at path `/myservice`
|
||||||
|
|
||||||
|
4. Test:
|
||||||
|
```bash
|
||||||
|
slcompose up myservice
|
||||||
|
slcompose logs myservice
|
||||||
|
slcompose down myservice
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Service will automatically boot on next system startup
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- **Boot Time**: ~2 minutes for all 10+ services (includes Docker startup)
|
||||||
|
- **Per-Service**: ~5-10 seconds per service startup
|
||||||
|
- **Memory Overhead**: Minimal (orchestrator is bash script)
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
- **Secrets**: Never logged or displayed (only injected into containers)
|
||||||
|
- **Tokens**: Read from files with appropriate permissions
|
||||||
|
- **Docker Access**: Requires root/docker group membership
|
||||||
|
- **Service Isolation**: Uses Docker networks to isolate services
|
||||||
|
|
||||||
|
## Related Files
|
||||||
|
|
||||||
|
- [slcompose.sh](slcompose.sh) — Orchestrator script
|
||||||
|
- [slcompose.service](slcompose.service) — Systemd service file
|
||||||
|
- [AI_CONTEXT.md](AI_CONTEXT.md) — Infrastructure context
|
||||||
|
- [../README.md](../README.md) — Repository overview
|
||||||
+40
-3
@@ -23,9 +23,19 @@ Purpose:
|
|||||||
Status:
|
Status:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Planned
|
Completed
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Deployment:
|
||||||
|
|
||||||
|
* Docker Compose project: `nextcloud`
|
||||||
|
* Management: `slcompose` with Infisical secret injection
|
||||||
|
* External access: `cloud.silveressence.net` through Nginx Proxy Manager
|
||||||
|
* Internal networking: `nextcloud_nextcloud_internal`
|
||||||
|
* Runtime services: `nextcloud`, `nextcloud-db`, `nextcloud-redis`
|
||||||
|
|
||||||
|
See [docs/nextcloud.md](nextcloud.md) for complete deployment documentation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Observability
|
### Observability
|
||||||
@@ -97,9 +107,33 @@ Purpose:
|
|||||||
Status:
|
Status:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Planned
|
Completed
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Completed components:
|
||||||
|
|
||||||
|
* Sentry self-hosted distributed deployment (70+ services)
|
||||||
|
* Relay for event ingestion
|
||||||
|
* Kafka for event streaming
|
||||||
|
* ClickHouse for high-performance event storage
|
||||||
|
* PostgreSQL for metadata storage
|
||||||
|
* Snuba for event processing and query engine
|
||||||
|
* Redis for caching and coordination
|
||||||
|
* SeaweedFS for object/file storage
|
||||||
|
* Web UI and API layer
|
||||||
|
* Background workers (taskworker, cron, cleanup, etc.)
|
||||||
|
* Nginx proxy integration at sentry.silveressence.net
|
||||||
|
|
||||||
|
Deployment:
|
||||||
|
|
||||||
|
* Docker Compose project: sentry-self-hosted
|
||||||
|
* Management: upstream Sentry self-hosted `install.sh` workflow
|
||||||
|
* External access: sentry.silveressence.net (Nginx Proxy Manager)
|
||||||
|
* Internal networking: Isolated sentry-self-hosted_default network
|
||||||
|
* Exception to the standard SilverLinux `slcompose` and Infisical service pattern
|
||||||
|
|
||||||
|
See [docs/sentry.md](sentry.md) for complete deployment documentation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Identity And Access
|
### Identity And Access
|
||||||
@@ -312,7 +346,6 @@ Completed:
|
|||||||
Items:
|
Items:
|
||||||
|
|
||||||
* CrowdSec
|
* CrowdSec
|
||||||
* Sentry
|
|
||||||
* Fail2Ban upgrade
|
* Fail2Ban upgrade
|
||||||
* Cloudflare rate limiting and WAF
|
* Cloudflare rate limiting and WAF
|
||||||
|
|
||||||
@@ -320,6 +353,7 @@ Completed:
|
|||||||
|
|
||||||
* Backup v5.3 automation
|
* Backup v5.3 automation
|
||||||
* Restore validation
|
* Restore validation
|
||||||
|
* Sentry
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -330,6 +364,9 @@ Items:
|
|||||||
* SonarQube
|
* SonarQube
|
||||||
* Harbor Docker registry
|
* Harbor Docker registry
|
||||||
* Backstage portal
|
* Backstage portal
|
||||||
|
|
||||||
|
Completed:
|
||||||
|
|
||||||
* Nextcloud
|
* Nextcloud
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
+64
-44
@@ -2,21 +2,17 @@
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
SilverLinux uses a centralized secrets file for shared credentials and sensitive configuration.
|
SilverLinux uses Infisical for centralized secret management. Secrets are injected into standard Compose stacks at runtime by `slcompose`, which wraps `infisical run`.
|
||||||
|
|
||||||
Location:
|
This repository no longer depends on a local `/srv/secrets/company.env` file for deployed services. If that file still exists on the server, remove it after confirming all required values are present in Infisical.
|
||||||
|
|
||||||
```text
|
Sentry is the only documented exception to the standard pattern. It follows the upstream self-hosted Sentry installation model because it is a much larger multi-service application.
|
||||||
/srv/secrets/company.env
|
|
||||||
```
|
|
||||||
|
|
||||||
This file is stored on the server and is never committed to Git.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
The secrets file provides a single location for:
|
The Infisical deployment flow provides a single source of truth for:
|
||||||
|
|
||||||
* SMTP credentials
|
* SMTP credentials
|
||||||
* Database passwords
|
* Database passwords
|
||||||
@@ -24,11 +20,12 @@ The secrets file provides a single location for:
|
|||||||
* OAuth client secrets
|
* OAuth client secrets
|
||||||
* Future API keys
|
* Future API keys
|
||||||
|
|
||||||
Applications should load secrets using:
|
Applications should load secrets using Infisical injection at deployment time through `slcompose`.
|
||||||
|
|
||||||
```yaml
|
Example:
|
||||||
env_file:
|
|
||||||
- /srv/secrets/company.env
|
```bash
|
||||||
|
slcompose up gitea
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -124,6 +121,40 @@ Used by:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Nextcloud
|
||||||
|
|
||||||
|
```text
|
||||||
|
NEXTCLOUD_ADMIN_USER
|
||||||
|
NEXTCLOUD_ADMIN_PASSWORD
|
||||||
|
POSTGRES_DB
|
||||||
|
POSTGRES_USER
|
||||||
|
POSTGRES_PASSWORD
|
||||||
|
SMTP_HOST
|
||||||
|
SMTP_PORT
|
||||||
|
SMTP_USERNAME
|
||||||
|
SMTP_PASSWORD
|
||||||
|
```
|
||||||
|
|
||||||
|
Used by:
|
||||||
|
|
||||||
|
* Nextcloud
|
||||||
|
* Nextcloud PostgreSQL
|
||||||
|
* Nextcloud notification email
|
||||||
|
|
||||||
|
Infisical path:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/nextcloud
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* The 2026-07-08 runtime snapshot showed `/srv/docker/nextcloud/.env` present on the server.
|
||||||
|
* Do not commit the raw `.env` file or `config.php`.
|
||||||
|
* `config.php` includes high-sensitivity values such as `secret`, `passwordsalt`, database credentials and SMTP credentials.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Future OAuth
|
### Future OAuth
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -145,22 +176,21 @@ Future use:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### DbGate Credential Migration
|
### Sentry Exception
|
||||||
|
|
||||||
The running DbGate deployment currently has its login credential in the server-side Compose configuration. Move the password to:
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Sentry self-hosted installer secrets
|
||||||
DBGATE_PASSWORD
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The repository Compose definition already references `DBGATE_PASSWORD` and contains no real password.
|
Used by:
|
||||||
|
|
||||||
Status:
|
* Sentry
|
||||||
|
|
||||||
```text
|
Notes:
|
||||||
Migration pending
|
|
||||||
```
|
* Sentry does not follow the same simple `slcompose` + Infisical pattern as the other SilverLinux services.
|
||||||
|
* Keep Sentry secrets out of this repository.
|
||||||
|
* Document any Sentry-specific backup or restore requirements in [docs/sentry.md](sentry.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -168,7 +198,7 @@ Migration pending
|
|||||||
|
|
||||||
* Never commit secrets to Git.
|
* Never commit secrets to Git.
|
||||||
* Never store passwords directly in docker-compose files.
|
* Never store passwords directly in docker-compose files.
|
||||||
* Never share the contents of company.env.
|
* Never share Infisical exports, tokens or raw service `.env` files.
|
||||||
* Use environment variables whenever possible.
|
* Use environment variables whenever possible.
|
||||||
* Use `.env.example` files for documentation.
|
* Use `.env.example` files for documentation.
|
||||||
* Rotate credentials immediately if exposure is suspected.
|
* Rotate credentials immediately if exposure is suspected.
|
||||||
@@ -177,13 +207,13 @@ Migration pending
|
|||||||
|
|
||||||
## Backup Requirements
|
## Backup Requirements
|
||||||
|
|
||||||
The following file must be included in server backups:
|
Backups must preserve the ability to recover Infisical-managed secrets.
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical project data and service secret paths
|
||||||
```
|
```
|
||||||
|
|
||||||
Loss of this file may prevent applications from starting correctly.
|
Loss of the Infisical secret source may prevent applications from starting correctly.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -191,32 +221,22 @@ Loss of this file may prevent applications from starting correctly.
|
|||||||
|
|
||||||
If the server must be rebuilt:
|
If the server must be rebuilt:
|
||||||
|
|
||||||
1. Restore `/srv/secrets/company.env`
|
1. Restore or reauthorize Infisical access.
|
||||||
2. Verify file permissions
|
2. Verify `/etc/infisical/token` and any required Infisical domain configuration.
|
||||||
3. Deploy Docker stacks
|
3. Deploy Docker stacks through `slcompose`.
|
||||||
4. Verify services can access required variables
|
4. Verify services can access required variables.
|
||||||
5. Verify SMTP functionality
|
5. Verify SMTP functionality.
|
||||||
6. Verify database connectivity
|
6. Verify database connectivity.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Security Notes
|
## Security Notes
|
||||||
|
|
||||||
The secrets file contains credentials for multiple services.
|
Infisical contains credentials for multiple services.
|
||||||
|
|
||||||
Access should be restricted to system administrators only.
|
Access should be restricted to system administrators only.
|
||||||
|
|
||||||
Recommended permissions:
|
The local Infisical token under `/etc/infisical/token` must be protected with root-only permissions.
|
||||||
|
|
||||||
```bash
|
|
||||||
chmod 600 /srv/secrets/company.env
|
|
||||||
```
|
|
||||||
|
|
||||||
Recommended ownership:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
root:root
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+27
-6
@@ -101,7 +101,7 @@ Planned improvements:
|
|||||||
Shared secrets are stored in:
|
Shared secrets are stored in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@@ -117,6 +117,7 @@ Rules:
|
|||||||
* Never commit secrets to Git
|
* Never commit secrets to Git
|
||||||
* Never share secrets in documentation
|
* Never share secrets in documentation
|
||||||
* Never hardcode passwords in Docker Compose files
|
* Never hardcode passwords in Docker Compose files
|
||||||
|
* Remove `/srv/secrets/company.env` if it still exists after confirming all values are present in Infisical
|
||||||
|
|
||||||
See:
|
See:
|
||||||
|
|
||||||
@@ -149,12 +150,16 @@ Publicly exposed services:
|
|||||||
* Xray
|
* Xray
|
||||||
* Jitsi Web
|
* Jitsi Web
|
||||||
* BaGet
|
* BaGet
|
||||||
|
* Nextcloud
|
||||||
|
* Sentry
|
||||||
|
|
||||||
High-sensitivity exposure:
|
High-sensitivity exposure:
|
||||||
|
|
||||||
* DbGate exposes a database administration interface and must always require authentication and HTTPS.
|
* DbGate exposes a database administration interface and must always require authentication and HTTPS.
|
||||||
* Xray exposes tunneling capability and must be monitored for abuse, unexpected traffic and unauthorized use.
|
* Xray exposes tunneling capability and must be monitored for abuse, unexpected traffic and unauthorized use.
|
||||||
* Portainer exposes Docker management and must be restricted to trusted administrators.
|
* Portainer exposes Docker management and must be restricted to trusted administrators.
|
||||||
|
* Nextcloud exposes private file storage and must require strong user authentication, HTTPS and prompt security updates.
|
||||||
|
* Sentry exposes application error data and must require strong authentication, HTTPS and careful project/token management.
|
||||||
|
|
||||||
Nginx Proxy Manager findings from the 2026-06-24 proxy-host snapshot:
|
Nginx Proxy Manager findings from the 2026-06-24 proxy-host snapshot:
|
||||||
|
|
||||||
@@ -164,12 +169,16 @@ Nginx Proxy Manager findings from the 2026-06-24 proxy-host snapshot:
|
|||||||
* Plane.so has been removed from containers, Nginx Proxy Manager and server certificate storage.
|
* Plane.so has been removed from containers, Nginx Proxy Manager and server certificate storage.
|
||||||
* `cicd.silveressence.net` is intentionally enabled as a frequently changing prototype deployment endpoint.
|
* `cicd.silveressence.net` is intentionally enabled as a frequently changing prototype deployment endpoint.
|
||||||
* `exactsyncer.silveressence.net` is intentionally enabled as a client-facing Exact Online syncer demo endpoint.
|
* `exactsyncer.silveressence.net` is intentionally enabled as a client-facing Exact Online syncer demo endpoint.
|
||||||
|
* `cloud.silveressence.net` is enabled for Nextcloud with WebSocket and Block Exploits enabled, but SSL Force, HTTP/2 and HSTS disabled and no access list.
|
||||||
|
* `sentry.silveressence.net` is enabled for Sentry with SSL Force, HTTP/2, WebSocket and Block Exploits enabled; HSTS is disabled and no access list is assigned.
|
||||||
|
|
||||||
Priority hardening:
|
Priority hardening:
|
||||||
|
|
||||||
1. Enable SSL Force for all HTTPS public service routes unless there is a documented exception.
|
1. Enable SSL Force for all HTTPS public service routes unless there is a documented exception.
|
||||||
2. Add an access list or equivalent restriction for DbGate and Portainer.
|
2. Enable SSL Force, HTTP/2 and HSTS for Nextcloud unless there is a documented exception.
|
||||||
3. Define explicit exposure and authentication expectations for prototype and demo endpoints.
|
3. Enable HSTS for Sentry unless there is a documented exception.
|
||||||
|
4. Add an access list or equivalent restriction for DbGate and Portainer.
|
||||||
|
5. Define explicit exposure and authentication expectations for prototype and demo endpoints.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -180,7 +189,7 @@ Outgoing email is provided through Gmail SMTP.
|
|||||||
Credentials are stored in:
|
Credentials are stored in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
@@ -214,7 +223,7 @@ Future OAuth providers:
|
|||||||
|
|
||||||
Requirements:
|
Requirements:
|
||||||
|
|
||||||
* Store client secrets in company.env
|
* Store client secrets in Infisical
|
||||||
* Use least-privilege scopes
|
* Use least-privilege scopes
|
||||||
* Disable unused authentication providers
|
* Disable unused authentication providers
|
||||||
|
|
||||||
@@ -259,6 +268,10 @@ Applications and DbGate communicate with the database containers through the `in
|
|||||||
|
|
||||||
DbGate is the public administration entry point and must require authentication and HTTPS. Its web interface is routed through Nginx Proxy Manager; database ports `5432` and `1433` remain private.
|
DbGate is the public administration entry point and must require authentication and HTTPS. Its web interface is routed through Nginx Proxy Manager; database ports `5432` and `1433` remain private.
|
||||||
|
|
||||||
|
Nextcloud uses a stack-local PostgreSQL container named `nextcloud-db` on `nextcloud_nextcloud_internal`. Its `5432/tcp` port is not published to the host and is not routed through Nginx Proxy Manager.
|
||||||
|
|
||||||
|
Nextcloud Redis uses `nextcloud-redis` on `nextcloud_nextcloud_internal`. Its `6379/tcp` port is not published to the host.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Connectivity Layer Security
|
## Connectivity Layer Security
|
||||||
@@ -292,6 +305,7 @@ Networks:
|
|||||||
* jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
* jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
||||||
* xray_default
|
* xray_default
|
||||||
* gitea-runner_default
|
* gitea-runner_default
|
||||||
|
* nextcloud_nextcloud_internal
|
||||||
|
|
||||||
Network model:
|
Network model:
|
||||||
|
|
||||||
@@ -299,6 +313,8 @@ Network model:
|
|||||||
* `proxy` is for public HTTP and HTTPS services controlled by Nginx Proxy Manager.
|
* `proxy` is for public HTTP and HTTPS services controlled by Nginx Proxy Manager.
|
||||||
* Isolated stack networks are used for Jitsi, Xray and CI/CD runner separation.
|
* Isolated stack networks are used for Jitsi, Xray and CI/CD runner separation.
|
||||||
* `xray_default` currently exists without a running container attached; the active `xray` container is attached to `proxy`.
|
* `xray_default` currently exists without a running container attached; the active `xray` container is attached to `proxy`.
|
||||||
|
* `nextcloud_nextcloud_internal` isolates Nextcloud database and Redis traffic from the public proxy layer.
|
||||||
|
* `sentry-self-hosted_default` isolates Sentry databases, queues, workers and event processing services from shared application networks.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -345,6 +361,11 @@ Periodically verify:
|
|||||||
* DbGate login is enforced
|
* DbGate login is enforced
|
||||||
* DbGate proxy route has SSL Force and an access restriction policy
|
* DbGate proxy route has SSL Force and an access restriction policy
|
||||||
* Xray exposure policy is still valid
|
* Xray exposure policy is still valid
|
||||||
|
* Nextcloud security advisories are reviewed and the image is updated promptly
|
||||||
|
* Nextcloud database and Redis ports remain internal-only
|
||||||
|
* Nextcloud proxy route uses HTTPS with SSL Force, HTTP/2 and HSTS enabled unless there is a documented exception
|
||||||
|
* Sentry upstream self-hosted release notes are reviewed before updates
|
||||||
|
* Sentry internal services remain inaccessible except through the public Sentry web or nginx entry layer
|
||||||
* Public services are still routed only through Nginx Proxy Manager
|
* Public services are still routed only through Nginx Proxy Manager
|
||||||
* Removed proxy hosts and unused certificates stay removed unless explicitly approved
|
* Removed proxy hosts and unused certificates stay removed unless explicitly approved
|
||||||
* Prototype and demo proxy hosts have documented owners and exposure expectations
|
* Prototype and demo proxy hosts have documented owners and exposure expectations
|
||||||
@@ -362,7 +383,7 @@ Periodically verify:
|
|||||||
If a credential is exposed:
|
If a credential is exposed:
|
||||||
|
|
||||||
1. Rotate the credential immediately.
|
1. Rotate the credential immediately.
|
||||||
2. Update `/srv/secrets/company.env`.
|
2. Rotate or update the value in Infisical.
|
||||||
3. Restart affected services.
|
3. Restart affected services.
|
||||||
4. Review logs for unauthorized access.
|
4. Review logs for unauthorized access.
|
||||||
5. Update documentation if required.
|
5. Update documentation if required.
|
||||||
|
|||||||
+293
@@ -0,0 +1,293 @@
|
|||||||
|
# Sentry
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Sentry is the centralized error tracking and observability platform for SilverLinux-hosted applications.
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Operational
|
||||||
|
```
|
||||||
|
|
||||||
|
Public URL:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://sentry.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Deployment model:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Upstream Sentry self-hosted install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Sentry is intentionally documented as an exception to the standard SilverLinux `slcompose` and Infisical pattern. It is a much larger upstream self-hosted application and should be maintained according to the Sentry self-hosted project workflow.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Runtime Stack
|
||||||
|
|
||||||
|
Compose project:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sentry-self-hosted
|
||||||
|
```
|
||||||
|
|
||||||
|
Install directory:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/docker/sentry
|
||||||
|
```
|
||||||
|
|
||||||
|
Deployment method:
|
||||||
|
|
||||||
|
* Installed with Sentry self-hosted `install.sh`.
|
||||||
|
* Managed as one upstream Sentry self-hosted deployment unit.
|
||||||
|
* Not managed as a normal SilverLinux `slcompose` service.
|
||||||
|
* Not expected to use the standard per-service Infisical path pattern used by smaller SilverLinux services.
|
||||||
|
|
||||||
|
Runtime shape:
|
||||||
|
|
||||||
|
* 70+ containers
|
||||||
|
* Multiple internal queues, stores, workers and processing services
|
||||||
|
* One public web entry path through Nginx Proxy Manager
|
||||||
|
|
||||||
|
Key runtime containers from the 2026-07-08 snapshot:
|
||||||
|
|
||||||
|
| Container | Image | Role | Exposure |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `sentry-self-hosted-nginx-1` | `nginx:1.31.0-alpine` | Public Sentry entry proxy | Publishes `0.0.0.0:9000 -> 80/tcp`; NPM forwards to `80` |
|
||||||
|
| `sentry-self-hosted-web-1` | `sentry-self-hosted-local` | Sentry web UI and API | Internal `9000/tcp` |
|
||||||
|
| `sentry-self-hosted-relay-1` | `ghcr.io/getsentry/relay:nightly` | Event ingestion relay | Internal `3000/tcp` |
|
||||||
|
| `sentry-self-hosted-postgres-1` | `postgres:14.23-bookworm` | Metadata database | Internal `5432/tcp` |
|
||||||
|
| `sentry-self-hosted-clickhouse-1` | `clickhouse-self-hosted-local` | Event storage | Internal `8123/tcp`, `9000/tcp`, `9009/tcp` |
|
||||||
|
| `sentry-self-hosted-redis-1` | `redis:6.2.20-alpine` | Cache and coordination | Internal `6379/tcp` |
|
||||||
|
| `sentry-self-hosted-kafka-1` | `confluentinc/cp-kafka:7.6.6` | Event stream buffer | Internal `9092/tcp` |
|
||||||
|
| `sentry-self-hosted-seaweedfs-1` | `chrislusf/seaweedfs:4.17_large_disk` | Object and attachment storage | Internal ports only |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Public Access
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sentry.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Public route:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Internet
|
||||||
|
-> Nginx Proxy Manager
|
||||||
|
-> sentry-self-hosted-nginx-1
|
||||||
|
-> Sentry web/API services
|
||||||
|
```
|
||||||
|
|
||||||
|
Nginx Proxy Manager host:
|
||||||
|
|
||||||
|
| Setting | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Proxy host ID | `12` |
|
||||||
|
| Forward scheme | `http` |
|
||||||
|
| Forward host | `sentry-self-hosted-nginx-1` |
|
||||||
|
| Forward port | `80` |
|
||||||
|
| SSL Force | enabled |
|
||||||
|
| HTTP/2 | enabled |
|
||||||
|
| HSTS | disabled |
|
||||||
|
| HSTS subdomains | disabled |
|
||||||
|
| Block Exploits | enabled |
|
||||||
|
| WebSocket | enabled |
|
||||||
|
| Access List | none |
|
||||||
|
| Status | enabled |
|
||||||
|
|
||||||
|
Only the Sentry web or nginx entry layer should be public. Internal services such as PostgreSQL, ClickHouse, Redis, Kafka, Snuba and workers must stay internal to the Sentry deployment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Sentry is a distributed event processing pipeline.
|
||||||
|
|
||||||
|
```text
|
||||||
|
Applications
|
||||||
|
-> Sentry SDK
|
||||||
|
-> Relay
|
||||||
|
-> Kafka
|
||||||
|
-> Snuba
|
||||||
|
-> ClickHouse
|
||||||
|
-> Web UI and API
|
||||||
|
```
|
||||||
|
|
||||||
|
Core components:
|
||||||
|
|
||||||
|
* Web UI and API
|
||||||
|
* Relay
|
||||||
|
* Kafka
|
||||||
|
* Snuba
|
||||||
|
* ClickHouse
|
||||||
|
* PostgreSQL
|
||||||
|
* Redis
|
||||||
|
* SeaweedFS
|
||||||
|
* Task workers
|
||||||
|
* Cron and cleanup jobs
|
||||||
|
* Consumer and metrics processor services
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Networking
|
||||||
|
|
||||||
|
Internal network:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sentry-self-hosted_default
|
||||||
|
```
|
||||||
|
|
||||||
|
Verified subnet:
|
||||||
|
|
||||||
|
```text
|
||||||
|
172.25.0.0/16
|
||||||
|
```
|
||||||
|
|
||||||
|
Public proxy attachment:
|
||||||
|
|
||||||
|
* Sentry is reachable at `https://sentry.silveressence.net` through Nginx Proxy Manager.
|
||||||
|
* The public route should terminate at the Sentry nginx or web entry container.
|
||||||
|
* Internal Sentry infrastructure containers must not be exposed directly.
|
||||||
|
|
||||||
|
Security boundary:
|
||||||
|
|
||||||
|
* Treat Sentry as its own upstream-managed application cluster.
|
||||||
|
* Do not attach Sentry databases or queues to shared application database networks unless there is a documented operational need.
|
||||||
|
* Keep Sentry credentials, generated secrets and upstream `.env` files out of this repository.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Data Storage
|
||||||
|
|
||||||
|
Sentry stores data across multiple backing services:
|
||||||
|
|
||||||
|
| Component | Data role |
|
||||||
|
| --- | --- |
|
||||||
|
| PostgreSQL | Sentry metadata and relational state |
|
||||||
|
| ClickHouse | Event and analytics storage |
|
||||||
|
| Kafka | Event stream buffer |
|
||||||
|
| Redis | Cache and coordination |
|
||||||
|
| SeaweedFS | Attachments, files and object storage |
|
||||||
|
|
||||||
|
The upstream self-hosted installation directory and its Docker volumes are part of the recovery surface.
|
||||||
|
|
||||||
|
Verified configuration files:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/docker/sentry/.env
|
||||||
|
/srv/docker/sentry/docker-compose.yml
|
||||||
|
/srv/docker/sentry/sentry/sentry.conf.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Backup Requirements
|
||||||
|
|
||||||
|
Back up:
|
||||||
|
|
||||||
|
* `/srv/docker/sentry`
|
||||||
|
* Sentry `.env` and generated configuration files
|
||||||
|
* PostgreSQL volume
|
||||||
|
* ClickHouse volume
|
||||||
|
* Redis volume if persistence is enabled
|
||||||
|
* Kafka data if persistence is enabled
|
||||||
|
* SeaweedFS data
|
||||||
|
* Nginx Proxy Manager route and certificate state for `sentry.silveressence.net`
|
||||||
|
|
||||||
|
Secrets:
|
||||||
|
|
||||||
|
* Sentry generated secrets must stay out of Git.
|
||||||
|
* Do not move Sentry into the normal Infisical pattern unless the upstream deployment is intentionally redesigned.
|
||||||
|
* Preserve the upstream Sentry secret files through secure server backup and restore procedures.
|
||||||
|
|
||||||
|
Restore validation:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Pending
|
||||||
|
```
|
||||||
|
|
||||||
|
Restore validation should include:
|
||||||
|
|
||||||
|
* Web UI login
|
||||||
|
* Project list visibility
|
||||||
|
* DSN availability
|
||||||
|
* Ingesting a test event
|
||||||
|
* Viewing the test event in the UI
|
||||||
|
* Confirming background consumers are healthy
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Operations
|
||||||
|
|
||||||
|
Use the upstream Sentry self-hosted commands from the installation directory.
|
||||||
|
|
||||||
|
Typical command pattern:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /srv/docker/sentry
|
||||||
|
sudo docker compose ps
|
||||||
|
sudo docker compose logs --tail=200
|
||||||
|
sudo docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not operate Sentry with `slcompose` unless the deployment is intentionally converted away from the upstream installer model.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Updates
|
||||||
|
|
||||||
|
Use the upstream Sentry self-hosted update workflow.
|
||||||
|
|
||||||
|
Before updating:
|
||||||
|
|
||||||
|
* Back up configuration and volumes.
|
||||||
|
* Review upstream release notes.
|
||||||
|
* Confirm available disk space.
|
||||||
|
* Verify the current deployment is healthy.
|
||||||
|
|
||||||
|
After updating:
|
||||||
|
|
||||||
|
* Confirm all containers are healthy.
|
||||||
|
* Verify `https://sentry.silveressence.net`.
|
||||||
|
* Send a test event from an application or SDK test client.
|
||||||
|
* Review worker, consumer, Kafka, Snuba and ClickHouse logs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
Known verified facts:
|
||||||
|
|
||||||
|
* Sentry was installed using the upstream self-hosted `install.sh`.
|
||||||
|
* Sentry is available at `https://sentry.silveressence.net`.
|
||||||
|
* Sentry install directory is `/srv/docker/sentry`.
|
||||||
|
* Sentry nginx entry container is `sentry-self-hosted-nginx-1`.
|
||||||
|
* Nginx Proxy Manager forwards `sentry.silveressence.net` to `http://sentry-self-hosted-nginx-1:80`.
|
||||||
|
* `sentry-self-hosted-nginx-1` publishes `0.0.0.0:9000 -> 80/tcp`.
|
||||||
|
* `sentry-self-hosted_default` subnet is `172.25.0.0/16`.
|
||||||
|
* Sentry is treated as the exception to the standard SilverLinux `slcompose` and Infisical service pattern.
|
||||||
|
|
||||||
|
Recommended next runtime capture:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker ps --filter "name=sentry" --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}"
|
||||||
|
docker network inspect proxy sentry-self-hosted_default --format 'network={{.Name}} containers={{range $id,$c := .Containers}}{{$c.Name}} {{end}}'
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
* [docs/services.md](services.md)
|
||||||
|
* [docs/domains.md](domains.md)
|
||||||
|
* [docs/network.md](network.md)
|
||||||
|
* [docs/security.md](security.md)
|
||||||
|
* [docs/backups.md](backups.md)
|
||||||
|
* [docs/secrets.md](secrets.md)
|
||||||
+78
-3
@@ -168,6 +168,8 @@ Examples:
|
|||||||
* Grafana
|
* Grafana
|
||||||
* Node Exporter
|
* Node Exporter
|
||||||
* cAdvisor
|
* cAdvisor
|
||||||
|
* Sentry
|
||||||
|
* Nextcloud
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -194,6 +196,8 @@ Contains:
|
|||||||
/srv/docker/dbgate
|
/srv/docker/dbgate
|
||||||
/srv/docker/xray
|
/srv/docker/xray
|
||||||
/srv/docker/monitoring
|
/srv/docker/monitoring
|
||||||
|
/srv/docker/nextcloud
|
||||||
|
/srv/docker/sentry
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -201,7 +205,7 @@ Contains:
|
|||||||
### Shared Secrets
|
### Shared Secrets
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Contains:
|
Contains:
|
||||||
@@ -210,9 +214,13 @@ Contains:
|
|||||||
* Database passwords
|
* Database passwords
|
||||||
* Application secrets
|
* Application secrets
|
||||||
* MSSQL SA password
|
* MSSQL SA password
|
||||||
* Future DbGate password
|
* DbGate password
|
||||||
* Future OAuth credentials
|
* Future OAuth credentials
|
||||||
|
|
||||||
|
Legacy note:
|
||||||
|
|
||||||
|
* `/srv/secrets/company.env` is no longer part of the active secret model and should be removed if it still exists.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Backups
|
### Backups
|
||||||
@@ -342,6 +350,70 @@ The `xray_default` network exists, but the running `xray` container was attached
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Nextcloud
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/docker/nextcloud
|
||||||
|
```
|
||||||
|
|
||||||
|
Volumes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
nextcloud_nextcloud_data
|
||||||
|
nextcloud_nextcloud_db
|
||||||
|
```
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
cloud.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Runtime note:
|
||||||
|
|
||||||
|
The 2026-07-08 runtime snapshot showed `nextcloud`, `nextcloud-db` and `nextcloud-redis` running with no host-published ports. The web container is routed through Nginx Proxy Manager on the `proxy` network; PostgreSQL and Redis stay on `nextcloud_nextcloud_internal`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Sentry
|
||||||
|
|
||||||
|
Deployment:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Upstream Sentry self-hosted install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Install directory:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/srv/docker/sentry
|
||||||
|
```
|
||||||
|
|
||||||
|
Domain:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sentry.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Network:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sentry-self-hosted_default
|
||||||
|
```
|
||||||
|
|
||||||
|
Public entry:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sentry-self-hosted-nginx-1
|
||||||
|
0.0.0.0:9000 -> 80/tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
Runtime note:
|
||||||
|
|
||||||
|
Sentry is available through Nginx Proxy Manager at `https://sentry.silveressence.net`. It is maintained as an upstream self-hosted Sentry deployment and is the exception to the standard SilverLinux `slcompose` and Infisical service model.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
### Monitoring Stack
|
### Monitoring Stack
|
||||||
|
|
||||||
```text
|
```text
|
||||||
@@ -390,6 +462,8 @@ Implemented:
|
|||||||
* SSL certificates managed through Nginx Proxy Manager
|
* SSL certificates managed through Nginx Proxy Manager
|
||||||
* PostgreSQL not exposed publicly
|
* PostgreSQL not exposed publicly
|
||||||
* MSSQL port 1433 not exposed publicly
|
* MSSQL port 1433 not exposed publicly
|
||||||
|
* Nextcloud PostgreSQL and Redis not exposed publicly
|
||||||
|
* Sentry backing services not exposed publicly
|
||||||
* Database administration is available only through authenticated HTTPS access to DbGate
|
* Database administration is available only through authenticated HTTPS access to DbGate
|
||||||
* Xray is not attached to the private database network and is monitored as a tunneling endpoint
|
* Xray is not attached to the private database network and is monitored as a tunneling endpoint
|
||||||
* OpenID disabled in Gitea
|
* OpenID disabled in Gitea
|
||||||
@@ -407,13 +481,14 @@ noreply@silveressence.net
|
|||||||
SMTP credentials are stored in:
|
SMTP credentials are stored in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Used by:
|
Used by:
|
||||||
|
|
||||||
* Gitea
|
* Gitea
|
||||||
* OpenProject
|
* OpenProject
|
||||||
|
* Nextcloud
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+265
-9
@@ -363,6 +363,69 @@ Operational
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### Exact Syncer Demo
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Demo `.NET 9` Blazor application for Exact Online integration
|
||||||
|
* Provides a user interface for connecting Exact webhooks
|
||||||
|
* Syncs changes from a main division to dependent sub-divisions
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
* When the main division relation changes, the app updates related sub-divisions with Exact data
|
||||||
|
* Example: a change in main division Relation 1 propagates to divisions 2–10
|
||||||
|
|
||||||
|
Runtime:
|
||||||
|
|
||||||
|
* Hostname: `exactsyncer.silveressence.net`
|
||||||
|
* Container: `exact-syncer`
|
||||||
|
* Port: `8080`
|
||||||
|
|
||||||
|
Deployment notes:
|
||||||
|
|
||||||
|
* Demo version for clients to evaluate Exact Online sync behavior
|
||||||
|
* Can be recreated as a dedicated instance for new customers
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Operational demo
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### BobAutoWas Exact Syncer Instance
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Client-specific Exact Syncer instance for BobAutoWas
|
||||||
|
* Recreated from the Exact Syncer demo for customer delivery
|
||||||
|
* Provides the same webhook-driven and division-sync workflow
|
||||||
|
|
||||||
|
Behavior:
|
||||||
|
|
||||||
|
* Uses the same Exact Online master/sub-division sync model as the demo
|
||||||
|
* Intended for client preview and delivery use
|
||||||
|
|
||||||
|
Runtime:
|
||||||
|
|
||||||
|
* Hostname: `cicd.silveressence.net`
|
||||||
|
* Container: `bobsAutowas`
|
||||||
|
* Port: `8080`
|
||||||
|
|
||||||
|
Deployment notes:
|
||||||
|
|
||||||
|
* Dedicated customer-facing instance of Exact Syncer
|
||||||
|
* Managed as an active demo/product instance
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Active client instance
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
### DbGate
|
### DbGate
|
||||||
|
|
||||||
URL:
|
URL:
|
||||||
@@ -398,18 +461,131 @@ Operational
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Xray
|
### Nextcloud
|
||||||
|
|
||||||
|
URL:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://cloud.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
Purpose:
|
Purpose:
|
||||||
|
|
||||||
* Connectivity and tunneling layer
|
* Private cloud storage
|
||||||
* Improve long-distance connectivity stability to SilverLinux
|
* File sharing
|
||||||
* Maintain secure routing paths when direct connectivity is limited
|
* Team document storage
|
||||||
|
* Nextcloud notification email
|
||||||
|
|
||||||
|
Runtime:
|
||||||
|
|
||||||
|
* `nextcloud` using `nextcloud:29-apache`
|
||||||
|
* `nextcloud-db` using `postgres:16`
|
||||||
|
* `nextcloud-redis` using `redis:7-alpine`
|
||||||
|
|
||||||
|
Networks:
|
||||||
|
|
||||||
|
* `proxy` for Nginx Proxy Manager access to the web container
|
||||||
|
* `nextcloud_nextcloud_internal` for private Nextcloud, PostgreSQL and Redis traffic
|
||||||
|
|
||||||
|
Storage:
|
||||||
|
|
||||||
|
* `nextcloud_nextcloud_data`
|
||||||
|
* `nextcloud_nextcloud_db`
|
||||||
|
|
||||||
|
Exposure:
|
||||||
|
|
||||||
|
* Routed through Nginx Proxy Manager
|
||||||
|
* No Nextcloud stack ports were published to the host in the 2026-07-08 runtime snapshot
|
||||||
|
* Database and Redis containers are internal-only
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Operational
|
||||||
|
```
|
||||||
|
|
||||||
|
See [docs/nextcloud.md](nextcloud.md) for complete deployment documentation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Sentry
|
||||||
|
|
||||||
|
URL:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://sentry.silveressence.net
|
||||||
|
```
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Centralized error tracking and observability
|
||||||
|
* Application exception diagnostics
|
||||||
|
* Release health visibility
|
||||||
|
* Performance monitoring
|
||||||
|
|
||||||
|
Architecture:
|
||||||
|
|
||||||
|
* Distributed system with 70+ services
|
||||||
|
* Components: Relay, Kafka, Snuba, ClickHouse, PostgreSQL, Redis, SeaweedFS
|
||||||
|
* Self-hosted deployment
|
||||||
|
|
||||||
|
Entry container:
|
||||||
|
|
||||||
|
* `sentry-self-hosted-nginx-1` using `nginx:1.31.0-alpine`
|
||||||
|
* Publishes `0.0.0.0:9000 -> 80/tcp`
|
||||||
|
* Nginx Proxy Manager forwards to `sentry-self-hosted-nginx-1:80`
|
||||||
|
|
||||||
|
Networks:
|
||||||
|
|
||||||
|
* `proxy` for Nginx Proxy Manager access
|
||||||
|
* `sentry-self-hosted_default` for internal service communication
|
||||||
|
|
||||||
|
Management:
|
||||||
|
|
||||||
|
* Installed with upstream Sentry self-hosted `install.sh`
|
||||||
|
* Install directory: `/srv/docker/sentry`
|
||||||
|
* Managed according to the upstream Sentry self-hosted workflow
|
||||||
|
* Exception to the standard SilverLinux `slcompose` and Infisical pattern
|
||||||
|
* Single atomic upstream deployment unit
|
||||||
|
|
||||||
|
Data Storage:
|
||||||
|
|
||||||
|
* PostgreSQL for metadata
|
||||||
|
* ClickHouse for high-performance event storage
|
||||||
|
* Redis for caching and coordination
|
||||||
|
* SeaweedFS for attachments and objects
|
||||||
|
|
||||||
|
Backup Requirements:
|
||||||
|
|
||||||
|
* `/srv/docker/sentry`
|
||||||
|
* PostgreSQL database volume
|
||||||
|
* ClickHouse data volume
|
||||||
|
* Sentry configuration files
|
||||||
|
* SeaweedFS data
|
||||||
|
* Persistent Kafka data (if enabled)
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Running
|
||||||
|
```
|
||||||
|
|
||||||
|
See [docs/sentry.md](sentry.md) for complete deployment documentation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Xray (Direct Production)
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Primary production VLESS endpoint
|
||||||
|
* Direct OVH internet routing for stable public access
|
||||||
|
* Separate from VPN-routed traffic to protect production stability
|
||||||
|
|
||||||
Classification:
|
Classification:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
Network tunneling / connectivity layer
|
Primary production connectivity layer
|
||||||
```
|
```
|
||||||
|
|
||||||
Networks:
|
Networks:
|
||||||
@@ -430,6 +606,7 @@ ghcr.io/xtls/xray-core:latest
|
|||||||
|
|
||||||
Runtime note:
|
Runtime note:
|
||||||
|
|
||||||
|
* Direct production Xray is unmodified and isolated from the VPN routing setup.
|
||||||
* The `xray_default` network exists, but the running `xray` container was attached only to `proxy` in the 2026-06-24 runtime snapshot.
|
* The `xray_default` network exists, but the running `xray` container was attached only to `proxy` in the 2026-06-24 runtime snapshot.
|
||||||
|
|
||||||
Security:
|
Security:
|
||||||
@@ -446,6 +623,83 @@ Operational
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### VPN Gateway (Gluetun PIA)
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Containerized VPN gateway for Private Internet Access (PIA)
|
||||||
|
* Routes selected containers through WireGuard without affecting host networking
|
||||||
|
* Provides an isolated VPN execution layer for safe experimentation
|
||||||
|
|
||||||
|
Container:
|
||||||
|
|
||||||
|
```text
|
||||||
|
gluetun-pia
|
||||||
|
```
|
||||||
|
|
||||||
|
VPN Provider:
|
||||||
|
|
||||||
|
* Private Internet Access (PIA)
|
||||||
|
|
||||||
|
Mode:
|
||||||
|
|
||||||
|
* Custom WireGuard configuration generated by PIA
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* No VPN software runs on the host
|
||||||
|
* Prevents SSH lockout and host routing table override issues
|
||||||
|
* Only selected services use this VPN gateway
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Operational VPN gateway
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### VPN-Routed Xray (xray-pia)
|
||||||
|
|
||||||
|
Purpose:
|
||||||
|
|
||||||
|
* Secondary VLESS endpoint routed through the PIA VPN gateway
|
||||||
|
* Maintains a separate service path from the direct production Xray endpoint
|
||||||
|
|
||||||
|
Container:
|
||||||
|
|
||||||
|
```text
|
||||||
|
xray-pia
|
||||||
|
```
|
||||||
|
|
||||||
|
Runtime ports:
|
||||||
|
|
||||||
|
```text
|
||||||
|
0.0.0.0:32444 -> 32444/tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
Network mode:
|
||||||
|
|
||||||
|
* `container:gluetun-pia`
|
||||||
|
|
||||||
|
Routing:
|
||||||
|
|
||||||
|
* Client -> `xray-pia` (32444) -> `gluetun-pia` -> PIA WireGuard VPN -> Internet
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
* Fully isolated from host networking
|
||||||
|
* Does not impact the direct production Xray endpoint
|
||||||
|
* Supports future multiple VPN exit points
|
||||||
|
|
||||||
|
Status:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Operational secondary VPN endpoint
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Shared Infrastructure
|
## Shared Infrastructure
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
@@ -515,10 +769,10 @@ Running
|
|||||||
|
|
||||||
### Shared Secrets
|
### Shared Secrets
|
||||||
|
|
||||||
Location:
|
Source:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Purpose:
|
Purpose:
|
||||||
@@ -533,6 +787,10 @@ Status:
|
|||||||
Active
|
Active
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Legacy note:
|
||||||
|
|
||||||
|
* `/srv/secrets/company.env` is no longer part of the active secret model and should be removed if it still exists.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Removed Services
|
## Removed Services
|
||||||
@@ -554,7 +812,6 @@ Phase 1:
|
|||||||
Phase 2:
|
Phase 2:
|
||||||
|
|
||||||
* CrowdSec
|
* CrowdSec
|
||||||
* Sentry
|
|
||||||
* Restic
|
* Restic
|
||||||
* Fail2Ban upgrade
|
* Fail2Ban upgrade
|
||||||
* Cloudflare rate limiting and WAF
|
* Cloudflare rate limiting and WAF
|
||||||
@@ -564,7 +821,6 @@ Phase 3:
|
|||||||
* SonarQube
|
* SonarQube
|
||||||
* Harbor
|
* Harbor
|
||||||
* Backstage
|
* Backstage
|
||||||
* Nextcloud
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# /etc/systemd/system/slcompose.service
|
||||||
|
[Unit]
|
||||||
|
Description=SilverLinux Docker Orchestrator (slCompose)
|
||||||
|
After=docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/slcompose boot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
User=root
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
BASE_DIR="/srv/docker"
|
||||||
|
INFISICAL_TOKEN_FILE="/etc/infisical/token"
|
||||||
|
INFISICAL_DOMAIN_FILE="/etc/infisical/domain"
|
||||||
|
|
||||||
|
function load_infisical() {
|
||||||
|
if [ ! -f "$INFISICAL_TOKEN_FILE" ]; then
|
||||||
|
echo "ERROR: Missing Infisical token at $INFISICAL_TOKEN_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export INFISICAL_TOKEN=$(cat "$INFISICAL_TOKEN_FILE")
|
||||||
|
|
||||||
|
if [ -f "$INFISICAL_DOMAIN_FILE" ]; then
|
||||||
|
export INFISICAL_DOMAIN=$(cat "$INFISICAL_DOMAIN_FILE")
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function exec_with_infisical() {
|
||||||
|
local service_name="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
infisical run \
|
||||||
|
--token "$INFISICAL_TOKEN" \
|
||||||
|
--env prod \
|
||||||
|
--path="/$service_name" \
|
||||||
|
--recursive \
|
||||||
|
-- "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_service() {
|
||||||
|
SERVICE_DIR="$1"
|
||||||
|
shift
|
||||||
|
|
||||||
|
SERVICE_NAME=$(basename "$SERVICE_DIR")
|
||||||
|
|
||||||
|
cd "$SERVICE_DIR"
|
||||||
|
|
||||||
|
echo "-----------------------------------"
|
||||||
|
echo "Booting: $SERVICE_DIR"
|
||||||
|
|
||||||
|
until docker info >/dev/null 2>&1; do
|
||||||
|
echo "Waiting for Docker..."
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
|
||||||
|
load_infisical
|
||||||
|
|
||||||
|
echo "Using Infisical path: /$SERVICE_NAME"
|
||||||
|
|
||||||
|
exec_with_infisical "$SERVICE_NAME" docker compose "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
function list_services() {
|
||||||
|
echo "Available services:"
|
||||||
|
echo "===================="
|
||||||
|
for dir in "$BASE_DIR"/*; do
|
||||||
|
if [ -f "$dir/docker-compose.yml" ]; then
|
||||||
|
SERVICE_NAME=$(basename "$dir")
|
||||||
|
echo " - $SERVICE_NAME"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function boot_all() {
|
||||||
|
echo "==================================="
|
||||||
|
echo "SilverLinux Boot Orchestrator START"
|
||||||
|
echo "==================================="
|
||||||
|
|
||||||
|
load_infisical
|
||||||
|
|
||||||
|
for dir in "$BASE_DIR"/*; do
|
||||||
|
if [ -f "$dir/docker-compose.yml" ]; then
|
||||||
|
SERVICE_NAME=$(basename "$dir")
|
||||||
|
echo "Booting: $SERVICE_NAME"
|
||||||
|
run_service "$dir" up -d || {
|
||||||
|
echo "FAILED: $SERVICE_NAME"
|
||||||
|
}
|
||||||
|
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "==================================="
|
||||||
|
echo "Boot orchestration finished"
|
||||||
|
echo "==================================="
|
||||||
|
}
|
||||||
|
|
||||||
|
function service_up() {
|
||||||
|
SERVICE_NAME="$1"
|
||||||
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
||||||
|
|
||||||
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
||||||
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Starting service: $SERVICE_NAME"
|
||||||
|
run_service "$SERVICE_DIR" up -d
|
||||||
|
}
|
||||||
|
|
||||||
|
function service_down() {
|
||||||
|
SERVICE_NAME="$1"
|
||||||
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
||||||
|
|
||||||
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
||||||
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Stopping service: $SERVICE_NAME"
|
||||||
|
run_service "$SERVICE_DIR" down
|
||||||
|
}
|
||||||
|
|
||||||
|
function service_restart() {
|
||||||
|
SERVICE_NAME="$1"
|
||||||
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
||||||
|
|
||||||
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
||||||
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Restarting service: $SERVICE_NAME"
|
||||||
|
run_service "$SERVICE_DIR" restart
|
||||||
|
}
|
||||||
|
|
||||||
|
function service_logs() {
|
||||||
|
SERVICE_NAME="$1"
|
||||||
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
||||||
|
|
||||||
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
||||||
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Tailing logs for: $SERVICE_NAME (Ctrl+C to exit)"
|
||||||
|
run_service "$SERVICE_DIR" logs -f
|
||||||
|
}
|
||||||
|
|
||||||
|
function service_logs_tail() {
|
||||||
|
SERVICE_NAME="$1"
|
||||||
|
NUM_LINES="${2:-200}"
|
||||||
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
||||||
|
|
||||||
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
||||||
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Last $NUM_LINES lines of logs for: $SERVICE_NAME"
|
||||||
|
run_service "$SERVICE_DIR" logs --tail "$NUM_LINES"
|
||||||
|
}
|
||||||
|
|
||||||
|
function service_env() {
|
||||||
|
SERVICE_NAME="$1"
|
||||||
|
SERVICE_DIR="$BASE_DIR/$SERVICE_NAME"
|
||||||
|
|
||||||
|
if [ ! -d "$SERVICE_DIR" ] || [ ! -f "$SERVICE_DIR/docker-compose.yml" ]; then
|
||||||
|
echo "ERROR: Service '$SERVICE_NAME' not found at $SERVICE_DIR"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
load_infisical
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo "Environment Variables for: $SERVICE_NAME"
|
||||||
|
echo "========================================"
|
||||||
|
|
||||||
|
exec_with_infisical "$SERVICE_NAME" env | grep -v "^_" | sort | while IFS='=' read -r name value; do
|
||||||
|
printf "\033[34m%-50s\033[0m = \033[32m%s\033[0m\n" "$name" "$value"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function service_env_all() {
|
||||||
|
load_infisical
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo "All Services and Their Environment Variables"
|
||||||
|
echo "========================================"
|
||||||
|
|
||||||
|
for dir in "$BASE_DIR"/*; do
|
||||||
|
if [ -f "$dir/docker-compose.yml" ]; then
|
||||||
|
SERVICE_NAME=$(basename "$dir")
|
||||||
|
echo ""
|
||||||
|
echo "--- $SERVICE_NAME ---"
|
||||||
|
exec_with_infisical "$SERVICE_NAME" env | grep -v "^_" | sort | while IFS='=' read -r name value; do
|
||||||
|
printf "\033[34m%-50s\033[0m = \033[32m%s\033[0m\n" "$name" "$value"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_usage() {
|
||||||
|
cat <<EOF
|
||||||
|
SilverLinux Service Orchestrator
|
||||||
|
|
||||||
|
Usage: $0 <command> [service_name] [options]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
boot Boot all services at startup
|
||||||
|
list List all available services
|
||||||
|
up <service> Start a service
|
||||||
|
down <service> Stop a service
|
||||||
|
restart <service> Restart a service
|
||||||
|
logs <service> Tail logs for a service (Ctrl+C to exit)
|
||||||
|
logs-tail <service> [lines] Show last N lines of logs (default: 200)
|
||||||
|
env <service> Show injected environment variables for a service
|
||||||
|
env-all Show injected environment variables for all services
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
$0 boot
|
||||||
|
$0 list
|
||||||
|
$0 up gitea
|
||||||
|
$0 down gitea
|
||||||
|
$0 restart gitea
|
||||||
|
$0 logs gitea
|
||||||
|
$0 logs-tail gitea
|
||||||
|
$0 logs-tail gitea 500
|
||||||
|
$0 env gitea
|
||||||
|
$0 env-all
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
boot)
|
||||||
|
boot_all
|
||||||
|
;;
|
||||||
|
list)
|
||||||
|
list_services
|
||||||
|
;;
|
||||||
|
up)
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "ERROR: Service name required"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
service_up "$2"
|
||||||
|
;;
|
||||||
|
down)
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "ERROR: Service name required"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
service_down "$2"
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "ERROR: Service name required"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
service_restart "$2"
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "ERROR: Service name required"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
service_logs "$2"
|
||||||
|
;;
|
||||||
|
logs-tail)
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "ERROR: Service name required"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
service_logs_tail "$2" "$3"
|
||||||
|
;;
|
||||||
|
env)
|
||||||
|
if [ -z "$2" ]; then
|
||||||
|
echo "ERROR: Service name required"
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
service_env "$2"
|
||||||
|
;;
|
||||||
|
env-all)
|
||||||
|
service_env_all
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
show_usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
+7
-9
@@ -90,7 +90,7 @@ POSTGRES_ROOT_PASSWORD
|
|||||||
Stored in:
|
Stored in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Future improvement:
|
Future improvement:
|
||||||
@@ -114,11 +114,9 @@ Purpose:
|
|||||||
* Repository notifications
|
* Repository notifications
|
||||||
* User invitations
|
* User invitations
|
||||||
|
|
||||||
SMTP configuration is loaded from:
|
SMTP secrets are provided by Infisical at runtime.
|
||||||
|
|
||||||
```text
|
These values are resolved during deployment by `infisical run`.
|
||||||
/srv/secrets/company.env
|
|
||||||
```
|
|
||||||
|
|
||||||
Variables:
|
Variables:
|
||||||
|
|
||||||
@@ -231,7 +229,7 @@ Labels:
|
|||||||
* `ubuntu-24.04`
|
* `ubuntu-24.04`
|
||||||
* `ubuntu-22.04`
|
* `ubuntu-22.04`
|
||||||
|
|
||||||
The runner registration token is loaded from `GITEA_RUNNER_REGISTRATION_TOKEN` in `/srv/secrets/company.env`.
|
The runner registration token is loaded from `GITEA_RUNNER_REGISTRATION_TOKEN` in Infisical through `slcompose`.
|
||||||
|
|
||||||
### Package Publishing
|
### Package Publishing
|
||||||
|
|
||||||
@@ -246,7 +244,7 @@ The publishing credential is stored as the repository Actions secret `BAGET_API_
|
|||||||
Gitea and its Actions runner use infrastructure secrets stored in:
|
Gitea and its Actions runner use infrastructure secrets stored in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Variables:
|
Variables:
|
||||||
@@ -342,7 +340,7 @@ gitea
|
|||||||
### Secrets
|
### Secrets
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical service paths for Gitea and the Gitea runner
|
||||||
```
|
```
|
||||||
|
|
||||||
Without these items, a complete restoration is not possible.
|
Without these items, a complete restoration is not possible.
|
||||||
@@ -355,7 +353,7 @@ To restore Gitea:
|
|||||||
|
|
||||||
1. Restore PostgreSQL database.
|
1. Restore PostgreSQL database.
|
||||||
2. Restore Gitea data directory.
|
2. Restore Gitea data directory.
|
||||||
3. Restore company.env secrets.
|
3. Restore or reauthorize Infisical access and service secret paths.
|
||||||
4. Deploy Docker Compose stack.
|
4. Deploy Docker Compose stack.
|
||||||
5. Verify SMTP configuration.
|
5. Verify SMTP configuration.
|
||||||
6. Verify SSH access.
|
6. Verify SSH access.
|
||||||
|
|||||||
+2
-2
@@ -36,7 +36,7 @@ Configuration stored in:
|
|||||||
|
|
||||||
Stored in:
|
Stored in:
|
||||||
|
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
|
|
||||||
Variables:
|
Variables:
|
||||||
|
|
||||||
@@ -71,4 +71,4 @@ Configuration:
|
|||||||
|
|
||||||
- docs/server.md
|
- docs/server.md
|
||||||
- docs/security.md
|
- docs/security.md
|
||||||
- docs/secrets.md
|
- docs/secrets.md
|
||||||
|
|||||||
+6
-8
@@ -39,10 +39,9 @@ Server-side administration must use `docker exec` or another container attached
|
|||||||
|
|
||||||
## Secrets
|
## Secrets
|
||||||
|
|
||||||
The SA password is stored outside the repository:
|
The SA password is provided by Infisical at runtime:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
|
||||||
MSSQL_SA_PASSWORD
|
MSSQL_SA_PASSWORD
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -52,14 +51,13 @@ Never commit the value to Git or place it directly in the Compose file.
|
|||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Docker Compose must be given the secrets file for interpolation:
|
The stack is deployed with Infisical injection instead of a local secrets file:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /srv/docker/mssql
|
slcompose up mssql
|
||||||
docker compose --env-file /srv/secrets/company.env up -d
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The Compose `env_file:` setting passes variables into the container. It does not make them available while Compose resolves `${MSSQL_SA_PASSWORD}`, which is why `--env-file` is required.
|
Secrets are injected into the environment before Docker Compose evaluates variables such as `${MSSQL_SA_PASSWORD}`.
|
||||||
|
|
||||||
Validate startup:
|
Validate startup:
|
||||||
|
|
||||||
@@ -94,7 +92,7 @@ Do not delete or recreate the directory after databases exist. Removing `/srv/do
|
|||||||
|
|
||||||
### Variable Is Not Set
|
### Variable Is Not Set
|
||||||
|
|
||||||
If Compose reports that `MSSQL_SA_PASSWORD` is unset and defaults to a blank string, use the required `docker compose --env-file /srv/secrets/company.env up -d` command.
|
If Compose reports that `MSSQL_SA_PASSWORD` is unset and defaults to a blank string, run the stack through `slcompose` so Infisical injects the value before Docker Compose evaluates the environment.
|
||||||
|
|
||||||
### System Directory Permission Denied
|
### System Directory Permission Denied
|
||||||
|
|
||||||
@@ -102,7 +100,7 @@ If `[/.system]` cannot be created, verify that `/srv/docker/mssql/data` is owned
|
|||||||
|
|
||||||
### Password Validation Failed
|
### Password Validation Failed
|
||||||
|
|
||||||
Confirm that the password meets SQL Server complexity requirements and that Compose resolved `MSSQL_SA_PASSWORD` from the secrets file.
|
Confirm that the password meets SQL Server complexity requirements and that Compose resolved `MSSQL_SA_PASSWORD` from Infisical.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ services:
|
|||||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||||
container_name: mssql
|
container_name: mssql
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
# Secrets are injected by Infisical at runtime.
|
||||||
- /srv/secrets/company.env
|
|
||||||
environment:
|
environment:
|
||||||
ACCEPT_EULA: Y
|
ACCEPT_EULA: Y
|
||||||
MSSQL_PID: Express
|
MSSQL_PID: Express
|
||||||
MSSQL_SA_PASSWORD: ${MSSQL_SA_PASSWORD}
|
MSSQL_SA_PASSWORD: ''
|
||||||
volumes:
|
volumes:
|
||||||
- /srv/docker/mssql/data:/var/opt/mssql
|
- /srv/docker/mssql/data:/var/opt/mssql
|
||||||
networks:
|
networks:
|
||||||
|
|||||||
+4
-14
@@ -99,11 +99,7 @@ Purpose:
|
|||||||
* Mention notifications
|
* Mention notifications
|
||||||
* Project updates
|
* Project updates
|
||||||
|
|
||||||
SMTP credentials are stored in:
|
SMTP credentials are provided by Infisical at runtime.
|
||||||
|
|
||||||
```text
|
|
||||||
/srv/secrets/company.env
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -128,13 +124,7 @@ This directory must be included in backups.
|
|||||||
|
|
||||||
## Secrets
|
## Secrets
|
||||||
|
|
||||||
The following values are stored in:
|
The following values are provided by Infisical at runtime when the stack is deployed:
|
||||||
|
|
||||||
```text
|
|
||||||
/srv/secrets/company.env
|
|
||||||
```
|
|
||||||
|
|
||||||
Variables:
|
|
||||||
|
|
||||||
```text
|
```text
|
||||||
POSTGRES_OPENPROJECT_PASSWORD
|
POSTGRES_OPENPROJECT_PASSWORD
|
||||||
@@ -231,7 +221,7 @@ openproject
|
|||||||
### Secrets
|
### Secrets
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical service path for OpenProject
|
||||||
```
|
```
|
||||||
|
|
||||||
Without these items, a complete restoration is not possible.
|
Without these items, a complete restoration is not possible.
|
||||||
@@ -244,7 +234,7 @@ To restore OpenProject:
|
|||||||
|
|
||||||
1. Restore PostgreSQL database.
|
1. Restore PostgreSQL database.
|
||||||
2. Restore OpenProject assets directory.
|
2. Restore OpenProject assets directory.
|
||||||
3. Restore company.env secrets.
|
3. Restore or reauthorize Infisical access and the OpenProject secret path.
|
||||||
4. Deploy Docker Compose stack.
|
4. Deploy Docker Compose stack.
|
||||||
5. Verify SMTP configuration.
|
5. Verify SMTP configuration.
|
||||||
6. Verify access through Nginx Proxy Manager.
|
6. Verify access through Nginx Proxy Manager.
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ services:
|
|||||||
container_name: openproject
|
container_name: openproject
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
env_file:
|
# Secrets are injected by Infisical at runtime.
|
||||||
- /srv/secrets/company.env
|
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
SECRET_KEY_BASE: ${OPENPROJECT_SECRET_KEY_BASE}
|
SECRET_KEY_BASE: ${OPENPROJECT_SECRET_KEY_BASE}
|
||||||
OPENPROJECT_HOST__NAME: team.silveressence.net
|
OPENPROJECT_HOST__NAME: team.silveressence.net
|
||||||
|
|||||||
+4
-4
@@ -112,7 +112,7 @@ Each application should use its own dedicated database user whenever possible.
|
|||||||
Credentials are stored in:
|
Credentials are stored in:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/srv/secrets/company.env
|
Infisical
|
||||||
```
|
```
|
||||||
|
|
||||||
Current variables:
|
Current variables:
|
||||||
@@ -229,7 +229,7 @@ docker exec -i postgres psql -U postgres < postgres-full-backup.sql
|
|||||||
|
|
||||||
* PostgreSQL is not exposed publicly.
|
* PostgreSQL is not exposed publicly.
|
||||||
* Database traffic is restricted to Docker internal networks.
|
* Database traffic is restricted to Docker internal networks.
|
||||||
* Credentials are stored in `/srv/secrets/company.env`.
|
* Credentials are stored in Infisical and injected at runtime by `slcompose`.
|
||||||
* Administrative access should use the `postgres` role only when necessary.
|
* Administrative access should use the `postgres` role only when necessary.
|
||||||
* Applications should use dedicated database users.
|
* Applications should use dedicated database users.
|
||||||
|
|
||||||
@@ -267,10 +267,10 @@ Minimum requirements for recovery:
|
|||||||
|
|
||||||
* PostgreSQL container configuration
|
* PostgreSQL container configuration
|
||||||
* Database backups
|
* Database backups
|
||||||
* `/srv/secrets/company.env`
|
* Infisical access and PostgreSQL service secrets
|
||||||
* Docker network configuration
|
* Docker network configuration
|
||||||
|
|
||||||
Without the secrets file, applications may not be able to reconnect to their databases after restoration.
|
Without Infisical recovery, applications may not be able to reconnect to their databases after restoration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user