Compare commits
13 Commits
3835b7b22b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| ea638c0eae | |||
| 3f94ced9ea | |||
| a81aa80161 | |||
| a9a758d332 | |||
| a74909be25 | |||
| 4cf06da0a8 | |||
| db42baa33e | |||
| 4c2da84795 | |||
| ab461a5c08 | |||
| a8e23d3036 | |||
| b43f2b790e | |||
| efbdfb241c | |||
| 02a7ac7971 |
@@ -1,16 +1,197 @@
|
||||
# SilverLinux
|
||||
# SilverLinux Infrastructure
|
||||
|
||||
Production infrastructure for Silver Solutions.
|
||||
This repository contains the infrastructure configuration, deployment files and operational documentation for the SilverLinux server.
|
||||
|
||||
## Services
|
||||
SilverLinux is the primary self-hosted platform for Silver Solutions and hosts source control, project management, collaboration, communication and CI/CD services.
|
||||
|
||||
- Nginx Proxy Manager
|
||||
- Portainer
|
||||
- PostgreSQL
|
||||
- Gitea
|
||||
---
|
||||
|
||||
## Server
|
||||
## Server Information
|
||||
|
||||
- Ubuntu 24.04
|
||||
- Docker 29
|
||||
- RAID1
|
||||
| Property | Value |
|
||||
| ---------------- | ----------------------- |
|
||||
| Hostname | silverlinux |
|
||||
| Provider | OVH |
|
||||
| Operating System | Ubuntu Server 24.04 LTS |
|
||||
| Public IP | 51.255.83.140 |
|
||||
| CPU | Intel Xeon-D 1520 |
|
||||
| Memory | 32 GB RAM |
|
||||
| Storage | 2 × 480 GB SSD RAID1 |
|
||||
|
||||
---
|
||||
|
||||
## Core Services
|
||||
|
||||
### Running
|
||||
|
||||
* PostgreSQL
|
||||
* Microsoft SQL Server 2022 Express
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Jitsi Meet
|
||||
* Portainer
|
||||
* Nginx Proxy Manager
|
||||
* BaGet
|
||||
* Gitea Actions Runner
|
||||
* DbGate
|
||||
* Xray
|
||||
* Sentry
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
* Nextcloud
|
||||
|
||||
### Planned
|
||||
|
||||
* Loki
|
||||
* Redis
|
||||
* Authelia
|
||||
* CrowdSec
|
||||
* Restic
|
||||
* Harbor
|
||||
* SonarQube
|
||||
* Backstage
|
||||
|
||||
See [docs/roadmap.md](docs/roadmap.md) for the phased infrastructure roadmap.
|
||||
|
||||
### Removed
|
||||
|
||||
* Plane.so (replaced by OpenProject)
|
||||
|
||||
---
|
||||
|
||||
## 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
|
||||
|
||||
The following components are shared across multiple services:
|
||||
|
||||
* Docker
|
||||
* Docker Compose
|
||||
* Internal Docker Network
|
||||
* Proxy Docker Network
|
||||
* Isolated Docker Networks
|
||||
* Monitoring Docker Stack
|
||||
* Automated Backup System
|
||||
* Shared Secrets Management (Infisical + slcompose)
|
||||
|
||||
Secrets are managed centrally through Infisical and injected at runtime by the slcompose wrapper.
|
||||
|
||||
---
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```text
|
||||
baget/
|
||||
dbgate/
|
||||
docs/
|
||||
docs/nextcloud.md
|
||||
gitea/
|
||||
jitsi/
|
||||
mssql/
|
||||
nginx-proxy-manager/
|
||||
openproject/
|
||||
portainer/
|
||||
postgres/
|
||||
scripts/
|
||||
```
|
||||
|
||||
Each service folder contains:
|
||||
|
||||
* docker-compose.yml
|
||||
* README.md
|
||||
* .env.example
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
This repository serves as the single source of truth for rebuilding and maintaining the SilverLinux environment.
|
||||
|
||||
Infrastructure documentation, Docker Compose files, backup procedures, deployment notes and operational decisions are stored here.
|
||||
|
||||
The goal is that the entire environment can be rebuilt from this repository and the documented backup files.
|
||||
|
||||
---
|
||||
|
||||
## CI/CD
|
||||
|
||||
Gitea Actions is enabled globally and uses the self-hosted `silverlinux-runner` on SilverLinux. The operational Silver 2.0 package workflow builds and publishes NuGet packages to the internal BaGet feed.
|
||||
|
||||
See [docs/cicd.md](docs/cicd.md) for the runner, workflow triggers, pipeline stages and secret locations.
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
Never commit:
|
||||
|
||||
* Passwords
|
||||
* API Keys
|
||||
* SMTP Credentials
|
||||
* OAuth Secrets
|
||||
* SSL Private Keys
|
||||
* Database Credentials
|
||||
* Real `.env` files
|
||||
* Infisical tokens
|
||||
* Sentry upstream installer secrets
|
||||
|
||||
Use example files whenever possible.
|
||||
|
||||
---
|
||||
|
||||
## Disaster Recovery
|
||||
|
||||
This repository should contain enough information to rebuild the entire SilverLinux environment from scratch.
|
||||
|
||||
See:
|
||||
|
||||
* docs/server.md
|
||||
* docs/network.md
|
||||
* docs/roadmap.md
|
||||
* docs/backups.md
|
||||
* docs/security.md
|
||||
* docs/secrets.md
|
||||
|
||||
+471
@@ -0,0 +1,471 @@
|
||||
# SilverLinux Infrastructure Summary
|
||||
|
||||
Last Updated: 2026-07-08
|
||||
|
||||
## Overview
|
||||
|
||||
SilverLinux is the primary infrastructure server for Silver Solutions.
|
||||
|
||||
The platform hosts source control, project management, video conferencing, container management and supporting infrastructure services.
|
||||
|
||||
Monitoring, alerting, automated backups and restore validation are now production-ready.
|
||||
|
||||
---
|
||||
|
||||
## Public Services
|
||||
|
||||
| Service | URL |
|
||||
| ----------- | ----------------------------------- |
|
||||
| Gitea | https://git.silveressence.net |
|
||||
| OpenProject | https://team.silveressence.net |
|
||||
| Portainer | https://portainer.silveressence.net |
|
||||
| Jitsi Meet | https://meet.silveressence.net |
|
||||
| BaGet | https://nuget.silveressence.net |
|
||||
| DbGate | https://dbgate.silveressence.net |
|
||||
| Sentry | https://sentry.silveressence.net |
|
||||
| Nextcloud | https://cloud.silveressence.net |
|
||||
| Xray | Public tunneling endpoint |
|
||||
|
||||
---
|
||||
|
||||
## Running Services
|
||||
|
||||
### Gitea
|
||||
|
||||
Purpose:
|
||||
|
||||
* Git repositories
|
||||
* Pull requests
|
||||
* Issue tracking
|
||||
* Gitea Actions enabled globally
|
||||
* Self-hosted Actions runner operational
|
||||
* NuGet package publishing to BaGet
|
||||
|
||||
Authentication:
|
||||
|
||||
* Local accounts
|
||||
* Planned Google OAuth2
|
||||
* Planned GitHub OAuth2
|
||||
|
||||
Email:
|
||||
|
||||
* SMTP configured
|
||||
* Password reset supported
|
||||
|
||||
---
|
||||
|
||||
### OpenProject
|
||||
|
||||
Purpose:
|
||||
|
||||
* Project management
|
||||
* Sprint planning
|
||||
* Time tracking
|
||||
* Roadmaps
|
||||
* Team collaboration
|
||||
|
||||
Email:
|
||||
|
||||
* SMTP configured
|
||||
* Notifications enabled
|
||||
|
||||
---
|
||||
|
||||
### Jitsi Meet
|
||||
|
||||
Purpose:
|
||||
|
||||
* Video conferencing
|
||||
* Screen sharing
|
||||
* Team meetings
|
||||
|
||||
Authentication:
|
||||
|
||||
* Internal authentication
|
||||
* Guest access enabled
|
||||
|
||||
---
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
Purpose:
|
||||
|
||||
* Shared database platform
|
||||
* OpenProject database
|
||||
* Gitea database
|
||||
* Future application databases
|
||||
|
||||
---
|
||||
|
||||
### Microsoft SQL Server Express
|
||||
|
||||
Purpose:
|
||||
|
||||
* Support projects requiring Microsoft SQL Server
|
||||
* Provide a private SQL Server 2022 Express platform
|
||||
|
||||
Access:
|
||||
|
||||
* Docker `internal` network only
|
||||
* Port 1433 is not publicly exposed
|
||||
|
||||
Status:
|
||||
|
||||
* Operational
|
||||
|
||||
---
|
||||
|
||||
### Portainer
|
||||
|
||||
Purpose:
|
||||
|
||||
* Docker administration
|
||||
* Stack deployment
|
||||
* Container monitoring
|
||||
|
||||
---
|
||||
|
||||
### Nginx Proxy Manager
|
||||
|
||||
Purpose:
|
||||
|
||||
* Reverse proxy
|
||||
* SSL certificate management
|
||||
* Domain routing
|
||||
|
||||
---
|
||||
|
||||
### Monitoring Stack
|
||||
|
||||
Purpose:
|
||||
|
||||
* Metrics collection
|
||||
* Monitoring dashboards
|
||||
* Host and Docker visibility
|
||||
* Backup metrics visibility
|
||||
|
||||
Components:
|
||||
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
|
||||
Validated:
|
||||
|
||||
* Prometheus UI
|
||||
* Prometheus targets
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Backup metrics
|
||||
* Grafana datasource
|
||||
* Alertmanager email routing
|
||||
|
||||
Dashboards:
|
||||
|
||||
* Custom backup dashboard
|
||||
* Custom system dashboard
|
||||
* Docker monitoring dashboard
|
||||
|
||||
Alerting:
|
||||
|
||||
* Incident grouping
|
||||
* Severity-based routing
|
||||
* Alert deduplication
|
||||
* Multi-recipient email notifications
|
||||
|
||||
Status:
|
||||
|
||||
* Production ready
|
||||
|
||||
---
|
||||
|
||||
### Automated Backup System
|
||||
|
||||
Purpose:
|
||||
|
||||
* Daily backup execution
|
||||
* Archive generation
|
||||
* HTML reporting
|
||||
* Email notification
|
||||
* Restore validation
|
||||
* Prometheus backup metrics
|
||||
|
||||
Current version:
|
||||
|
||||
* Backup v5.3
|
||||
|
||||
Validated:
|
||||
|
||||
* Backup execution
|
||||
* Restore archive extraction
|
||||
* MSSQL backup integrity
|
||||
* PostgreSQL backup
|
||||
* Email notifications
|
||||
* Cron automation
|
||||
* Backup metrics export
|
||||
* Lock file protection
|
||||
* Disk space validation
|
||||
* Structured failure handling
|
||||
|
||||
Status:
|
||||
|
||||
* Production ready
|
||||
|
||||
---
|
||||
|
||||
### BaGet
|
||||
|
||||
Purpose:
|
||||
|
||||
* Private NuGet package hosting
|
||||
* Internal Silver.* package distribution
|
||||
|
||||
Access:
|
||||
|
||||
* Routed through Nginx Proxy Manager
|
||||
* https://nuget.silveressence.net
|
||||
|
||||
---
|
||||
|
||||
### Gitea Actions Runner
|
||||
|
||||
Purpose:
|
||||
|
||||
* Execute Gitea Actions workflows
|
||||
* Build and package Silver 2.0 libraries
|
||||
* Publish NuGet packages to BaGet
|
||||
|
||||
Status:
|
||||
|
||||
* Global runner operational as `silverlinux-runner`
|
||||
|
||||
---
|
||||
|
||||
### DbGate
|
||||
|
||||
Purpose:
|
||||
|
||||
* Browser-based MSSQL and PostgreSQL administration
|
||||
|
||||
Access:
|
||||
|
||||
* https://dbgate.silveressence.net
|
||||
* HTTPS through Nginx Proxy Manager
|
||||
* Username and password required
|
||||
|
||||
Status:
|
||||
|
||||
* Operational
|
||||
|
||||
---
|
||||
|
||||
### 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
|
||||
|
||||
Purpose:
|
||||
|
||||
* Connectivity and tunneling layer
|
||||
* Improve stable access paths to SilverLinux
|
||||
|
||||
Access:
|
||||
|
||||
* Attached to `proxy`
|
||||
* Publishes `32443 -> 8080/tcp`
|
||||
* `xray_default` exists, but no running Xray container was attached to it in the 2026-06-24 runtime snapshot
|
||||
|
||||
Status:
|
||||
|
||||
* Operational
|
||||
|
||||
---
|
||||
|
||||
## Shared Infrastructure
|
||||
|
||||
### Docker
|
||||
|
||||
Purpose:
|
||||
|
||||
* Container hosting
|
||||
* Service isolation
|
||||
|
||||
### Internal Network
|
||||
|
||||
Purpose:
|
||||
|
||||
* Private communication between services
|
||||
|
||||
### Proxy Network
|
||||
|
||||
Purpose:
|
||||
|
||||
* Public HTTP and HTTPS services through Nginx Proxy Manager
|
||||
|
||||
### Isolated Networks
|
||||
|
||||
Purpose:
|
||||
|
||||
* Separate specialized stacks such as Jitsi, Xray and CI/CD runners where active runtime attachments support it
|
||||
|
||||
### Shared Secrets
|
||||
|
||||
Primary source:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* SMTP credentials
|
||||
* PostgreSQL passwords
|
||||
* MSSQL SA password
|
||||
* OpenProject secrets
|
||||
* DbGate password
|
||||
* Nextcloud secrets
|
||||
* Future OAuth secrets
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## Architecture Decisions
|
||||
|
||||
### OpenProject Selected
|
||||
|
||||
OpenProject is the primary project management platform.
|
||||
|
||||
### Plane.so Removed
|
||||
|
||||
Plane.so was removed to reduce maintenance complexity and duplicate functionality. It is not used and will not be used. Its containers, Nginx Proxy Manager route and unused SSL certificate were removed.
|
||||
|
||||
### Centralized Secrets
|
||||
|
||||
All standard service credentials are stored in:
|
||||
|
||||
```text
|
||||
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 is classified as a tunneling and connectivity layer rather than an application backend.
|
||||
|
||||
### Multi-Network Segmentation
|
||||
|
||||
SilverLinux uses `internal`, `proxy` and isolated infrastructure networks to separate database, public and specialized stack traffic.
|
||||
|
||||
---
|
||||
|
||||
## Future Roadmap
|
||||
|
||||
See:
|
||||
|
||||
```text
|
||||
docs/roadmap.md
|
||||
```
|
||||
|
||||
### Phase 1 - Immediate Impact
|
||||
|
||||
* Loki logging
|
||||
* Redis
|
||||
* Authelia SSO
|
||||
|
||||
Completed:
|
||||
|
||||
* Grafana + Prometheus
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
* Backup metrics integration
|
||||
* Incident intelligence
|
||||
|
||||
### Phase 2 - Security And Stability
|
||||
|
||||
* CrowdSec
|
||||
* Fail2Ban upgrade
|
||||
* Cloudflare rate limiting and WAF
|
||||
|
||||
Completed:
|
||||
|
||||
* Backup v5.3 automation
|
||||
* Restore validation
|
||||
* Sentry
|
||||
|
||||
### Phase 3 - Scale And Enterprise Services
|
||||
|
||||
* SonarQube
|
||||
* Harbor Docker registry
|
||||
* Backstage portal
|
||||
|
||||
---
|
||||
|
||||
## Mission
|
||||
|
||||
Provide a secure, reliable and self-hosted platform for software development and business operations within Silver Solutions.
|
||||
@@ -0,0 +1,83 @@
|
||||
# BaGet
|
||||
|
||||
## Overview
|
||||
|
||||
BaGet is the private NuGet package server for Silver Solutions.
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://nuget.silveressence.net
|
||||
```
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
Public HTTPS access is routed through Nginx Proxy Manager. The BaGet container is connected to the external `proxy` Docker network.
|
||||
|
||||
NuGet v3 feed:
|
||||
|
||||
```text
|
||||
https://nuget.silveressence.net/v3/index.json
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Current configuration is stored directly in the Docker Compose file.
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/baget/docker-compose.yml
|
||||
```
|
||||
|
||||
Current configuration includes:
|
||||
|
||||
* ApiKey
|
||||
* Storage configuration
|
||||
* Database configuration
|
||||
* Search configuration
|
||||
|
||||
## Data Storage
|
||||
|
||||
```text
|
||||
/srv/docker/baget/data
|
||||
```
|
||||
|
||||
This directory contains the SQLite database and hosted NuGet packages and should be included in backups.
|
||||
|
||||
## Reverse Proxy
|
||||
|
||||
| Setting | Value |
|
||||
| ---------------- | ----------------------------------- |
|
||||
| Public URL | `https://nuget.silveressence.net` |
|
||||
| Target container | `baget` |
|
||||
| Target port | `80` |
|
||||
| Docker network | `proxy` |
|
||||
|
||||
## Gitea Actions Integration
|
||||
|
||||
The Silver 2.0 workflow at `.gitea/workflows/package.yml` publishes packages to this feed through the global `silverlinux-runner`.
|
||||
|
||||
Publishing requires the repository Actions secret:
|
||||
|
||||
```text
|
||||
BAGET_API_KEY
|
||||
```
|
||||
|
||||
It is stored under **Repository Settings -> Actions -> Secrets** and must never be committed to a repository.
|
||||
|
||||
The end-to-end Gitea Actions to BaGet publishing pipeline is operational.
|
||||
|
||||
### Secret Management
|
||||
|
||||
BaGet runtime secrets should be managed through:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
This keeps BaGet aligned with the standard SilverLinux `slcompose` deployment pattern. The repository must not contain the real BaGet API key.
|
||||
@@ -0,0 +1,26 @@
|
||||
services:
|
||||
baget:
|
||||
image: loicsharma/baget:latest
|
||||
container_name: baget
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
- "5555:80"
|
||||
|
||||
environment:
|
||||
ApiKey: "your api key"
|
||||
Storage__Type: FileSystem
|
||||
Storage__Path: /var/baget/packages
|
||||
Database__Type: Sqlite
|
||||
Database__ConnectionString: Data Source=/var/baget/baget.db
|
||||
Search__Type: Database
|
||||
|
||||
volumes:
|
||||
- /srv/docker/baget/data:/var/baget
|
||||
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
@@ -0,0 +1,135 @@
|
||||
# DbGate
|
||||
|
||||
## Overview
|
||||
|
||||
DbGate is the HTTPS-accessible database administration portal for SilverLinux.
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://dbgate.silveressence.net
|
||||
```
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
It administers private Microsoft SQL Server and PostgreSQL instances without exposing either database server directly to the internet.
|
||||
|
||||
---
|
||||
|
||||
## Service Information
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Container | `dbgate` |
|
||||
| Image | `dbgate/dbgate:latest` |
|
||||
| Application port | `3000` |
|
||||
| Networks | `internal`, `proxy` |
|
||||
| Compose location | `/srv/docker/dbgate/docker-compose.yml` |
|
||||
| Data location | `/srv/docker/dbgate/data` |
|
||||
|
||||
The `internal` network provides database access. The `proxy` network connects DbGate to Nginx Proxy Manager.
|
||||
|
||||
---
|
||||
|
||||
## Reverse Proxy
|
||||
|
||||
| Setting | Value |
|
||||
| --- | --- |
|
||||
| Domain | `dbgate.silveressence.net` |
|
||||
| Scheme | `http` |
|
||||
| Forward host | `dbgate` |
|
||||
| Forward port | `3000` |
|
||||
| SSL | Let's Encrypt |
|
||||
| Force SSL | Enabled |
|
||||
| HTTP/2 | Enabled |
|
||||
|
||||
Only DbGate is publicly accessible. MSSQL port `1433` and PostgreSQL port `5432` remain private.
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
DbGate requires a username and password before granting access. The initial unauthenticated deployment was corrected by configuring `LOGIN` and `PASSWORD`.
|
||||
|
||||
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.
|
||||
|
||||
Operational requirement:
|
||||
|
||||
* Keep `DBGATE_PASSWORD` in the DbGate Infisical path.
|
||||
* Deploy through `slcompose` so the value is injected before Docker Compose evaluates the environment.
|
||||
* Remove any legacy plaintext credential from the server-side Compose file if it still exists.
|
||||
|
||||
---
|
||||
|
||||
## Database Connections
|
||||
|
||||
### SilverLinux MSSQL
|
||||
|
||||
| Setting | Value |
|
||||
| --- | --- |
|
||||
| Engine | SQL Server |
|
||||
| Server | `mssql` |
|
||||
| Port | `1433` |
|
||||
| Default database | `master` |
|
||||
| User | `sa` |
|
||||
| Encrypt | Yes |
|
||||
| Trust server certificate | Yes |
|
||||
|
||||
The connection was validated against `master`, `model`, `msdb` and `tempdb`.
|
||||
|
||||
PostgreSQL is also reachable through the shared `internal` network using hostname `postgres` and port `5432`.
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
docker logs dbgate
|
||||
```
|
||||
|
||||
Expected log message:
|
||||
|
||||
```text
|
||||
DbGate API listening on port 3000
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
```text
|
||||
Internet
|
||||
-> Nginx Proxy Manager
|
||||
-> DbGate
|
||||
-> MSSQL 2022 Express
|
||||
-> PostgreSQL 17
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Requirements
|
||||
|
||||
Back up:
|
||||
|
||||
```text
|
||||
/srv/docker/dbgate/data
|
||||
```
|
||||
|
||||
Also retain the Compose definition, Nginx Proxy Manager configuration and DbGate credential through Infisical recovery.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* mssql/README.md
|
||||
* postgres/README.md
|
||||
* nginx-proxy-manager/README.md
|
||||
* docs/domains.md
|
||||
* docs/security.md
|
||||
* docs/secrets.md
|
||||
* docs/backups.md
|
||||
@@ -0,0 +1,19 @@
|
||||
services:
|
||||
dbgate:
|
||||
image: dbgate/dbgate:latest
|
||||
container_name: dbgate
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
LOGIN: admin
|
||||
PASSWORD: ${DBGATE_PASSWORD}
|
||||
volumes:
|
||||
- /srv/docker/dbgate/data:/root/.dbgate
|
||||
networks:
|
||||
- internal
|
||||
- proxy
|
||||
|
||||
networks:
|
||||
internal:
|
||||
external: true
|
||||
proxy:
|
||||
external: true
|
||||
@@ -0,0 +1,246 @@
|
||||
# SilverLinux AI Context
|
||||
|
||||
## Purpose
|
||||
|
||||
SilverLinux is the primary self-hosted infrastructure server for Silver Solutions.
|
||||
|
||||
The goal is to host all development, collaboration, deployment and internal tooling.
|
||||
|
||||
## Server
|
||||
|
||||
Hostname: silverlinux
|
||||
|
||||
OS: Ubuntu Server 24.04 LTS
|
||||
|
||||
Provider: OVH
|
||||
|
||||
Public IP: 51.255.83.140
|
||||
|
||||
## Core Services
|
||||
|
||||
* PostgreSQL
|
||||
* Microsoft SQL Server 2022 Express
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Jitsi Meet
|
||||
* Portainer
|
||||
* Nginx Proxy Manager
|
||||
* BaGet
|
||||
* Gitea Actions Runner (`silverlinux-runner`)
|
||||
* DbGate
|
||||
* Xray
|
||||
* Sentry (Error Tracking & Observability)
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
* Nextcloud
|
||||
|
||||
## Domains
|
||||
|
||||
git.silveressence.net -> Gitea
|
||||
|
||||
team.silveressence.net -> OpenProject
|
||||
|
||||
meet.silveressence.net -> Jitsi
|
||||
|
||||
portainer.silveressence.net -> Portainer
|
||||
|
||||
nuget.silveressence.net -> BaGet (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
|
||||
|
||||
## Secrets
|
||||
|
||||
Secrets are stored in Infisical and injected at runtime via the **slcompose orchestrator**.
|
||||
|
||||
Never hardcode credentials. Standard SilverLinux services receive environment variables through Infisical's secret injection at container startup.
|
||||
|
||||
Sentry is the exception because it is a much larger upstream self-hosted application and follows the default Sentry installation pattern.
|
||||
|
||||
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
|
||||
|
||||
proxy
|
||||
internal
|
||||
jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
||||
xray_default
|
||||
gitea-runner_default
|
||||
|
||||
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.
|
||||
|
||||
## Authentication
|
||||
|
||||
Gitea:
|
||||
|
||||
* Local accounts
|
||||
* OpenID disabled
|
||||
* Google OAuth planned
|
||||
* GitHub OAuth planned
|
||||
|
||||
OpenProject:
|
||||
|
||||
* Local accounts
|
||||
|
||||
## CI/CD
|
||||
|
||||
Gitea Actions is enabled globally.
|
||||
|
||||
The global self-hosted runner is operational at `/srv/docker/gitea-runner` with the name `silverlinux-runner`.
|
||||
|
||||
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 Infisical. The BaGet publishing key is stored as the repository Actions secret `BAGET_API_KEY`.
|
||||
|
||||
## Databases
|
||||
|
||||
PostgreSQL 17 and Microsoft SQL Server 2022 Express are operational.
|
||||
|
||||
MSSQL uses hostname `mssql` on the `internal` Docker network. Port 1433 is not published.
|
||||
|
||||
DbGate provides authenticated HTTPS administration for MSSQL and PostgreSQL at `https://dbgate.silveressence.net`.
|
||||
|
||||
Xray is a connectivity layer, not an application backend. It runs from `ghcr.io/xtls/xray-core:latest` and publishes `0.0.0.0:32443 -> 8080/tcp`. Its endpoint exposure and access policy should be reviewed during security checks.
|
||||
|
||||
## Monitoring
|
||||
|
||||
The monitoring stack is operational.
|
||||
|
||||
Components:
|
||||
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
|
||||
Validated:
|
||||
|
||||
* Prometheus UI
|
||||
* Prometheus targets
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Backup metrics
|
||||
* Grafana datasource
|
||||
* Alertmanager email routing
|
||||
|
||||
Grafana has custom backup, system and Docker monitoring dashboards.
|
||||
|
||||
Alertmanager implements incident intelligence with incident groups:
|
||||
|
||||
* `backup_failure`
|
||||
* `system_pressure`
|
||||
* `storage_pressure`
|
||||
* `database_outage`
|
||||
* `monitoring_failure`
|
||||
* `container_health`
|
||||
|
||||
## Backup
|
||||
|
||||
Backup v5.3 is production.
|
||||
|
||||
Implemented:
|
||||
|
||||
* Daily cron backup
|
||||
* HTML reports
|
||||
* Email reports through Postfix and Gmail SMTP
|
||||
* Automatic archive generation
|
||||
* Automatic cleanup
|
||||
* Prometheus metrics export
|
||||
* Restore validation
|
||||
* Lock file protection
|
||||
* Disk space validation
|
||||
* Central logging
|
||||
* Structured failure handling
|
||||
|
||||
Verified:
|
||||
|
||||
* PostgreSQL
|
||||
* MSSQL
|
||||
* Gitea
|
||||
* BaGet
|
||||
* OpenProject assets
|
||||
* Docker configuration
|
||||
|
||||
## Documentation
|
||||
|
||||
Read all files in:
|
||||
|
||||
docs/
|
||||
|
||||
and the README.md of each service folder before making infrastructure recommendations.
|
||||
|
||||
Roadmap:
|
||||
|
||||
* Phase 1 completed: Grafana, Prometheus, Node Exporter, cAdvisor, Alertmanager, backup metrics integration, incident intelligence
|
||||
* Phase 1 remaining: Loki, Redis, Authelia
|
||||
* Phase 2 completed: Backup v5.3 automation, restore validation
|
||||
* Phase 2 completed: Sentry
|
||||
* Phase 2 remaining: CrowdSec, Fail2Ban upgrade, Cloudflare rate limiting and WAF
|
||||
* Phase 3 completed: Nextcloud
|
||||
* Phase 3 remaining: SonarQube, Harbor, Backstage
|
||||
|
||||
See:
|
||||
|
||||
```text
|
||||
docs/roadmap.md
|
||||
```
|
||||
|
||||
## Important Decisions
|
||||
|
||||
* Plane.so removed
|
||||
* OpenProject selected
|
||||
* Centralized secrets implemented
|
||||
* Nginx Proxy Manager selected
|
||||
* PostgreSQL selected as shared database platform
|
||||
* BaGet deployed at nuget.silveressence.net through Nginx Proxy Manager
|
||||
* Gitea Actions and a global self-hosted runner selected for package publishing
|
||||
* MSSQL Express deployed alongside PostgreSQL
|
||||
* DbGate selected as the database administration portal
|
||||
* Xray introduced as a tunneling and connectivity layer
|
||||
* 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
|
||||
+736
@@ -0,0 +1,736 @@
|
||||
# Backups
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the backup strategy for SilverLinux.
|
||||
|
||||
The goal is to ensure that all critical services can be restored after hardware failure, accidental deletion, corruption, or disaster recovery scenarios.
|
||||
|
||||
Current state:
|
||||
|
||||
```text
|
||||
Backup v5.3 production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup System Status
|
||||
|
||||
### Backup v1.4
|
||||
|
||||
Implemented:
|
||||
|
||||
* HTML backup reports
|
||||
* Email notification after backup
|
||||
* Automatic archive creation
|
||||
* Backup logging
|
||||
* Restore validation
|
||||
|
||||
---
|
||||
|
||||
### Backup v1.5
|
||||
|
||||
Implemented:
|
||||
|
||||
* MSSQL backup fix
|
||||
* Runtime MSSQL data included correctly
|
||||
* Restore tests verified MSSQL data is present in backups
|
||||
* Improved backup structure
|
||||
|
||||
---
|
||||
|
||||
### Backup v2
|
||||
|
||||
Implemented:
|
||||
|
||||
* Backup metrics generation
|
||||
* Prometheus metrics export
|
||||
* Backup duration metric
|
||||
* Backup size metric
|
||||
* Backup success metric
|
||||
* Automatic low disk space handling
|
||||
* Automatic deletion of oldest backups when required
|
||||
* Improved logging
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Backup v5.3
|
||||
|
||||
Implemented:
|
||||
|
||||
* PostgreSQL backup using `pg_dumpall`
|
||||
* MSSQL backup using `sqlcmd` and `docker cp`
|
||||
* Gitea backup
|
||||
* BaGet backup
|
||||
* OpenProject backup
|
||||
* Docker configuration backup
|
||||
* Final compressed archive
|
||||
* Lock file protection
|
||||
* Disk space validation
|
||||
* Central backup logging
|
||||
* Structured failure handling
|
||||
* Prometheus Textfile Collector metrics output
|
||||
* Backup success and failure tracking
|
||||
* Duration and size monitoring
|
||||
* Historical logging
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Production
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Priorities
|
||||
|
||||
### Critical
|
||||
|
||||
These items must always be backed up.
|
||||
|
||||
#### PostgreSQL
|
||||
|
||||
Contains:
|
||||
|
||||
* OpenProject database
|
||||
* Gitea database
|
||||
* Future application databases
|
||||
|
||||
Importance:
|
||||
|
||||
Critical
|
||||
|
||||
---
|
||||
|
||||
#### Microsoft SQL Server
|
||||
|
||||
Data location:
|
||||
|
||||
```text
|
||||
/srv/docker/mssql/data
|
||||
```
|
||||
|
||||
Required:
|
||||
|
||||
* Native SQL Server database backups
|
||||
* MSSQL Compose configuration
|
||||
* `MSSQL_SA_PASSWORD` from Infisical recovery data
|
||||
* Runtime MSSQL data included by the v1.5+ backup structure
|
||||
|
||||
Importance:
|
||||
|
||||
Critical
|
||||
|
||||
Restore validation has verified that MSSQL data is present in current backup archives.
|
||||
|
||||
---
|
||||
|
||||
#### Gitea Data
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/gitea/data
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Git repositories
|
||||
* Attachments
|
||||
* Configuration
|
||||
* User data
|
||||
|
||||
Importance:
|
||||
|
||||
Critical
|
||||
|
||||
---
|
||||
|
||||
#### OpenProject Assets
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/openproject/assets
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Attachments
|
||||
* Uploaded files
|
||||
* User generated content
|
||||
|
||||
Importance:
|
||||
|
||||
Critical
|
||||
|
||||
---
|
||||
|
||||
#### Shared Secrets
|
||||
|
||||
Source:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* SMTP credentials
|
||||
* PostgreSQL passwords
|
||||
* MSSQL SA password
|
||||
* OpenProject secrets
|
||||
* DbGate password
|
||||
* Future OAuth secrets
|
||||
|
||||
Importance:
|
||||
|
||||
Critical
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Nginx Proxy Manager
|
||||
|
||||
Locations:
|
||||
|
||||
```text
|
||||
/srv/docker/nginx-proxy-manager/data
|
||||
/srv/docker/nginx-proxy-manager/letsencrypt
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Proxy configuration
|
||||
* SSL certificates
|
||||
* Domain routing
|
||||
|
||||
Importance:
|
||||
|
||||
Critical
|
||||
|
||||
---
|
||||
|
||||
### Medium Priority
|
||||
|
||||
#### Portainer
|
||||
|
||||
Volume:
|
||||
|
||||
```text
|
||||
portainer_portainer_data
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Portainer users
|
||||
* Portainer configuration
|
||||
* Stack definitions
|
||||
|
||||
Importance:
|
||||
|
||||
Medium
|
||||
|
||||
Can be recreated if necessary.
|
||||
|
||||
---
|
||||
|
||||
#### Jitsi Configuration
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/jitsi
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Jitsi configuration
|
||||
* Internal authentication configuration
|
||||
|
||||
Importance:
|
||||
|
||||
Medium
|
||||
|
||||
---
|
||||
|
||||
#### BaGet Data
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/baget/data
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Hosted NuGet packages
|
||||
* SQLite database
|
||||
|
||||
Importance:
|
||||
|
||||
Medium
|
||||
|
||||
---
|
||||
|
||||
#### Gitea Actions Runner Configuration
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/gitea-runner
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Runner deployment configuration
|
||||
* Runner state
|
||||
|
||||
The registration token is stored in Infisical.
|
||||
|
||||
Importance:
|
||||
|
||||
Medium
|
||||
|
||||
---
|
||||
|
||||
#### DbGate Data
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/dbgate/data
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Saved connections
|
||||
* DbGate application state
|
||||
|
||||
Also retain the Nginx Proxy Manager route and DbGate authentication credential.
|
||||
|
||||
Importance:
|
||||
|
||||
Medium
|
||||
|
||||
---
|
||||
|
||||
#### Xray Configuration
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/xray
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Xray Docker Compose configuration
|
||||
* Xray runtime configuration
|
||||
* Endpoint credentials, UUIDs or keys if stored with the service
|
||||
|
||||
Importance:
|
||||
|
||||
Medium
|
||||
|
||||
Xray credentials and keys must be backed up securely and must never be committed to Git.
|
||||
|
||||
---
|
||||
|
||||
## Backup Storage
|
||||
|
||||
Current backup capabilities:
|
||||
|
||||
* Automatic archive generation
|
||||
* HTML backup report generation
|
||||
* Backup log generation
|
||||
* Email report delivery
|
||||
* Prometheus metrics export
|
||||
* Automatic cleanup when disk space is low
|
||||
* Automatic deletion of oldest backups when required
|
||||
|
||||
---
|
||||
|
||||
Current Location:
|
||||
|
||||
```text
|
||||
/srv/backups
|
||||
```
|
||||
|
||||
Suggested Structure:
|
||||
|
||||
```text
|
||||
/srv/backups/
|
||||
├── daily
|
||||
├── weekly
|
||||
└── monthly
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Retention Policy
|
||||
|
||||
Current cleanup behavior:
|
||||
|
||||
* Backup v5.3 monitors available disk space.
|
||||
* If disk space is low, the oldest backups are deleted automatically.
|
||||
* Cleanup is logged.
|
||||
|
||||
---
|
||||
|
||||
### Daily
|
||||
|
||||
Keep:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
Keep:
|
||||
|
||||
```text
|
||||
4 weeks
|
||||
```
|
||||
|
||||
### Monthly
|
||||
|
||||
Keep:
|
||||
|
||||
```text
|
||||
12 months
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Restore Priorities
|
||||
|
||||
Restore order:
|
||||
|
||||
1. Shared secrets
|
||||
2. PostgreSQL
|
||||
3. Microsoft SQL Server
|
||||
4. Nginx Proxy Manager
|
||||
5. Gitea
|
||||
6. OpenProject
|
||||
7. Portainer
|
||||
8. Jitsi
|
||||
9. BaGet
|
||||
10. Gitea Actions Runner
|
||||
11. DbGate
|
||||
12. Xray
|
||||
13. Nextcloud
|
||||
14. Sentry
|
||||
|
||||
---
|
||||
|
||||
## Restore Validation
|
||||
|
||||
Restore procedure has been validated.
|
||||
|
||||
Completed:
|
||||
|
||||
* Dry-run restore
|
||||
* Full archive validation
|
||||
* Archive extraction
|
||||
|
||||
Verified:
|
||||
|
||||
* PostgreSQL
|
||||
* Microsoft SQL Server
|
||||
* Gitea
|
||||
* BaGet
|
||||
* OpenProject assets
|
||||
* 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:
|
||||
|
||||
* MSSQL backup integrity verified
|
||||
* PostgreSQL backup verified
|
||||
* Restore archive extraction verified
|
||||
|
||||
---
|
||||
|
||||
## Monitoring Integration
|
||||
|
||||
Backup v5.3 exports metrics for Prometheus.
|
||||
|
||||
Current metrics:
|
||||
|
||||
* Backup success
|
||||
* Backup duration
|
||||
* Backup size
|
||||
* Backup timestamp
|
||||
|
||||
Metric names:
|
||||
|
||||
* `silverlinux_backup_success`
|
||||
* `silverlinux_backup_duration_seconds`
|
||||
* `silverlinux_backup_size_bytes`
|
||||
* `silverlinux_backup_timestamp_seconds`
|
||||
|
||||
Export path:
|
||||
|
||||
```text
|
||||
Node Exporter Textfile Collector
|
||||
```
|
||||
|
||||
Prometheus target status:
|
||||
|
||||
```text
|
||||
Validated
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Automation
|
||||
|
||||
Current automation:
|
||||
|
||||
* Daily backup execution
|
||||
* Root cron configuration
|
||||
* Backup wrapper command
|
||||
* Email report
|
||||
* HTML report
|
||||
* Automatic cleanup
|
||||
* Automatic archive generation
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Email Notifications
|
||||
|
||||
Postfix is configured to relay through Gmail SMTP.
|
||||
|
||||
Implemented:
|
||||
|
||||
* Gmail relay
|
||||
* App Password authentication
|
||||
* TLS encryption
|
||||
* Successful email delivery
|
||||
* Backup success emails
|
||||
* Backup report emails
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Disaster Recovery Checklist
|
||||
|
||||
### Step 1
|
||||
|
||||
Install:
|
||||
|
||||
* Ubuntu Server
|
||||
* Docker
|
||||
* Docker Compose
|
||||
|
||||
### Step 2
|
||||
|
||||
Restore or reauthorize:
|
||||
|
||||
```text
|
||||
Infisical access and service secret paths
|
||||
```
|
||||
|
||||
### Step 3
|
||||
|
||||
Restore:
|
||||
|
||||
```text
|
||||
/srv/docker
|
||||
```
|
||||
|
||||
data directories.
|
||||
|
||||
### Step 4
|
||||
|
||||
Restore PostgreSQL and Microsoft SQL Server databases.
|
||||
|
||||
### Step 5
|
||||
|
||||
Deploy Docker stacks.
|
||||
|
||||
### Step 6
|
||||
|
||||
Verify:
|
||||
|
||||
* DNS
|
||||
* SSL certificates
|
||||
* Email delivery
|
||||
* Application access
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/security.md
|
||||
* docs/secrets.md
|
||||
* docs/monitoring.md
|
||||
* postgres/README.md
|
||||
* gitea/README.md
|
||||
* openproject/README.md
|
||||
* mssql/README.md
|
||||
* dbgate/README.md
|
||||
* docs/roadmap.md
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
# CI/CD
|
||||
|
||||
## Overview
|
||||
|
||||
SilverLinux provides CI/CD through globally enabled Gitea Actions and a self-hosted runner. Package publishing is operational; application deployment to Windows IIS and Linux targets remains future work.
|
||||
|
||||
---
|
||||
|
||||
## Gitea Actions
|
||||
|
||||
Gitea Actions is enabled in Gitea's `app.ini` and is available globally.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Self-Hosted Runner
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Location | `/srv/docker/gitea-runner` |
|
||||
| Image | `gitea/act_runner:latest` |
|
||||
| Runner name | `silverlinux-runner` |
|
||||
| Runner type | Global Runner |
|
||||
| Status | Operational |
|
||||
|
||||
Runner labels:
|
||||
|
||||
* `ubuntu-latest`
|
||||
* `ubuntu-24.04`
|
||||
* `ubuntu-22.04`
|
||||
|
||||
The global runner can execute Actions workflows for repositories hosted by the SilverLinux Gitea instance.
|
||||
|
||||
---
|
||||
|
||||
## Silver 2.0 Package Publishing
|
||||
|
||||
Workflow:
|
||||
|
||||
```text
|
||||
.gitea/workflows/package.yml
|
||||
```
|
||||
|
||||
The workflow runs when both conditions are satisfied:
|
||||
|
||||
1. Code is pushed to the `net-8-version` branch.
|
||||
2. The commit message contains `[Package]`.
|
||||
|
||||
Example commit message:
|
||||
|
||||
```text
|
||||
Package Silver 2.0 libraries [Package]
|
||||
```
|
||||
|
||||
Pipeline steps:
|
||||
|
||||
1. Check out the repository.
|
||||
2. Install the .NET 8 SDK.
|
||||
3. Restore the solution.
|
||||
4. Build the solution using the `Deploy` configuration.
|
||||
5. Pack the NuGet packages.
|
||||
6. Push the packages to BaGet.
|
||||
|
||||
NuGet feed:
|
||||
|
||||
```text
|
||||
https://nuget.silveressence.net/v3/index.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Operational Flow
|
||||
|
||||
```text
|
||||
Git push
|
||||
-> Gitea Actions
|
||||
-> silverlinux-runner
|
||||
-> dotnet restore
|
||||
-> dotnet build
|
||||
-> dotnet pack
|
||||
-> BaGet package publish
|
||||
```
|
||||
|
||||
The complete workflow has been tested successfully and is operational.
|
||||
|
||||
---
|
||||
|
||||
## Secrets
|
||||
|
||||
Runner registration token:
|
||||
|
||||
```text
|
||||
GITEA_RUNNER_REGISTRATION_TOKEN
|
||||
```
|
||||
|
||||
Source:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
BaGet publishing credential:
|
||||
|
||||
```text
|
||||
Repository Settings -> Actions -> Secrets
|
||||
BAGET_API_KEY
|
||||
```
|
||||
|
||||
No credentials are stored in repositories. Infrastructure-level secrets belong in Infisical; repository workflow secrets belong in Gitea Actions Secrets.
|
||||
|
||||
---
|
||||
|
||||
## Future Deployment Targets
|
||||
|
||||
### Windows IIS
|
||||
|
||||
Planned targets include ASP.NET Core, Blazor Server and Blazor Web App deployments.
|
||||
|
||||
```text
|
||||
Publish -> Copy files -> Restart IIS site
|
||||
```
|
||||
|
||||
Status: Planned
|
||||
|
||||
### Linux Containers
|
||||
|
||||
```text
|
||||
Build image -> Push image -> Deploy stack
|
||||
```
|
||||
|
||||
Status: Future
|
||||
|
||||
---
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
* Automated tests
|
||||
* Automated Windows IIS deployment
|
||||
* Linux container deployment
|
||||
* Release pipelines
|
||||
* Multi-environment deployments
|
||||
* Package publishing for additional repositories
|
||||
|
||||
---
|
||||
|
||||
## Related Services
|
||||
|
||||
* Gitea
|
||||
* Gitea Actions Runner
|
||||
* BaGet
|
||||
* Portainer
|
||||
* Nginx Proxy Manager
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* gitea/README.md
|
||||
* baget/README.md
|
||||
* docs/server.md
|
||||
* docs/security.md
|
||||
* docs/secrets.md
|
||||
@@ -0,0 +1,668 @@
|
||||
# Architecture Decisions
|
||||
|
||||
## Purpose
|
||||
|
||||
This document records important architectural and operational decisions made for SilverLinux.
|
||||
|
||||
The goal is to document not only what was implemented, but also why the decision was made.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-17
|
||||
|
||||
### Ubuntu 24.04 LTS Selected
|
||||
|
||||
Decision:
|
||||
|
||||
Use Ubuntu Server 24.04 LTS as the operating system.
|
||||
|
||||
Reason:
|
||||
|
||||
* Long-term support
|
||||
* Large community
|
||||
* Excellent Docker support
|
||||
* Familiar administration tools
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-17
|
||||
|
||||
### Docker Standardization
|
||||
|
||||
Decision:
|
||||
|
||||
All services should run in Docker containers whenever possible.
|
||||
|
||||
Reason:
|
||||
|
||||
* Consistent deployment
|
||||
* Easier backups
|
||||
* Easier migrations
|
||||
* Better isolation
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-17
|
||||
|
||||
### Nginx Proxy Manager Selected
|
||||
|
||||
Decision:
|
||||
|
||||
Use Nginx Proxy Manager as the reverse proxy solution.
|
||||
|
||||
Reason:
|
||||
|
||||
* Easy SSL management
|
||||
* Simple administration
|
||||
* User-friendly interface
|
||||
* Fast deployment
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-17
|
||||
|
||||
### Gitea Selected
|
||||
|
||||
Decision:
|
||||
|
||||
Use Gitea for source control.
|
||||
|
||||
Reason:
|
||||
|
||||
* Self-hosted
|
||||
* Lightweight
|
||||
* GitHub-like experience
|
||||
* Excellent Docker support
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-17
|
||||
|
||||
### PostgreSQL Selected
|
||||
|
||||
Decision:
|
||||
|
||||
Use PostgreSQL as the central database platform.
|
||||
|
||||
Reason:
|
||||
|
||||
* Reliability
|
||||
* Mature ecosystem
|
||||
* Supports multiple applications
|
||||
* Strong backup tooling
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-17
|
||||
|
||||
### OpenProject Selected
|
||||
|
||||
Decision:
|
||||
|
||||
Use OpenProject for project management.
|
||||
|
||||
Reason:
|
||||
|
||||
* Mature platform
|
||||
* Open source
|
||||
* Strong planning features
|
||||
* Work package management
|
||||
* Time tracking
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-21
|
||||
|
||||
### Plane.so Removed
|
||||
|
||||
Decision:
|
||||
|
||||
Do not deploy Plane.so.
|
||||
|
||||
Reason:
|
||||
|
||||
* OpenProject fully satisfies requirements
|
||||
* Reduces maintenance burden
|
||||
* Avoids duplicate functionality
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-21
|
||||
|
||||
### Centralized Secrets Management
|
||||
|
||||
Decision:
|
||||
|
||||
Originally store shared credentials in a single secrets file.
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
Legacy local secrets file
|
||||
```
|
||||
|
||||
Reason:
|
||||
|
||||
* Avoid secrets in Docker Compose files
|
||||
* Easier credential rotation
|
||||
* Easier disaster recovery
|
||||
* Reduced risk of accidental exposure
|
||||
|
||||
Status:
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-21
|
||||
|
||||
### OpenID Disabled in Gitea
|
||||
|
||||
Decision:
|
||||
|
||||
Disable OpenID authentication.
|
||||
|
||||
Reason:
|
||||
|
||||
* Not required
|
||||
* Reduces attack surface
|
||||
* Simplifies authentication model
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-21
|
||||
|
||||
### Gmail SMTP Selected
|
||||
|
||||
Decision:
|
||||
|
||||
Use Gmail SMTP for outbound email.
|
||||
|
||||
Sender:
|
||||
|
||||
```text
|
||||
noreply@silveressence.net
|
||||
```
|
||||
|
||||
Reason:
|
||||
|
||||
* Reliable delivery
|
||||
* Easy setup
|
||||
* Supports application notifications
|
||||
|
||||
Status:
|
||||
|
||||
Implemented
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-21 - Adopt Gitea Actions + Self-Hosted Runner for Package Publishing
|
||||
|
||||
Decision:
|
||||
|
||||
* Replace GitHub Actions with self-hosted Gitea Actions.
|
||||
* Execute package publishing on SilverLinux using the global `silverlinux-runner`.
|
||||
* Publish internal NuGet packages to BaGet.
|
||||
* 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.
|
||||
|
||||
Reason:
|
||||
|
||||
* Keep source control, build execution and package hosting inside SilverLinux.
|
||||
* Avoid storing credentials in repositories.
|
||||
* Provide a simple, explicit package-release convention.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Accepted
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-21 - BaGet Secret Storage
|
||||
|
||||
Decision:
|
||||
|
||||
The BaGet API key is currently stored directly in the BaGet Docker Compose configuration.
|
||||
|
||||
Reason:
|
||||
|
||||
* Simplicity during initial deployment.
|
||||
|
||||
Current Plan:
|
||||
|
||||
Move the API key into the centralized SilverLinux secrets management system:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
when the BaGet deployment is fully aligned with the standard `slcompose` pattern.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-22 - Deploy Microsoft SQL Server Express Alongside PostgreSQL
|
||||
|
||||
Decision:
|
||||
|
||||
* Run Microsoft SQL Server 2022 Express alongside PostgreSQL.
|
||||
* Attach MSSQL only to the `internal` Docker network.
|
||||
* Do not publish port `1433` or route MSSQL through the reverse proxy.
|
||||
* Store `MSSQL_SA_PASSWORD` in Infisical.
|
||||
|
||||
Reason:
|
||||
|
||||
* Support Silver projects that require Microsoft SQL Server compatibility.
|
||||
* Allow both database platforms to coexist without exposing database ports.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Implemented
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-22 - Select DbGate for Database Administration
|
||||
|
||||
Decision:
|
||||
|
||||
* Use DbGate to administer Microsoft SQL Server and PostgreSQL.
|
||||
* Connect DbGate to both the `internal` and `proxy` Docker networks.
|
||||
* Publish only the DbGate web interface through Nginx Proxy Manager.
|
||||
* Require DbGate authentication and HTTPS.
|
||||
|
||||
Reason:
|
||||
|
||||
* Provides one lightweight, modern browser interface for both database platforms.
|
||||
* Keeps PostgreSQL and MSSQL private.
|
||||
|
||||
Follow-up:
|
||||
|
||||
Move the DbGate password from any legacy server-side Compose configuration to Infisical.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Implemented
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-24 - Formalize Multi-Network Segmentation
|
||||
|
||||
Decision:
|
||||
|
||||
* Treat SilverLinux as a three-layer Docker network architecture.
|
||||
* Use `internal` for private databases and backend service traffic.
|
||||
* Use `proxy` for public HTTP and HTTPS services routed through Nginx Proxy Manager.
|
||||
* Use isolated stack networks for Jitsi, Xray and CI/CD runner traffic where the active runtime attachments support it.
|
||||
|
||||
Reason:
|
||||
|
||||
* Keep databases private while allowing selected web interfaces to be public.
|
||||
* Reduce unnecessary cross-service connectivity.
|
||||
* Make specialized infrastructure stacks easier to reason about and audit.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Accepted
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-24 - Confirm Nginx Proxy Manager as the Single Reverse Proxy
|
||||
|
||||
Decision:
|
||||
|
||||
Use Nginx Proxy Manager as the sole reverse proxy and SSL termination layer for SilverLinux HTTP and HTTPS services.
|
||||
|
||||
Reason:
|
||||
|
||||
* The active platform uses Nginx Proxy Manager for domain routing.
|
||||
* No Traefik or alternate reverse proxy is active.
|
||||
* A single proxy layer keeps exposure and certificate management centralized.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Confirmed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-24 - Add Xray Connectivity Layer
|
||||
|
||||
Decision:
|
||||
|
||||
* Classify Xray as a network tunneling and connectivity layer.
|
||||
* Attach Xray to the `proxy` network for public endpoint access.
|
||||
* Keep `xray_default` documented as the Compose-created Xray stack network.
|
||||
* Monitor the service as an exposed connectivity endpoint rather than as an application backend.
|
||||
|
||||
Reason:
|
||||
|
||||
* Improve connectivity stability to SilverLinux.
|
||||
* Support secure long-distance connection paths.
|
||||
* Keep tunneling concerns separate from application and database services.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Accepted
|
||||
```
|
||||
|
||||
Runtime Note:
|
||||
|
||||
The 2026-06-24 Docker snapshot showed the running `xray` container attached to `proxy` only. The `xray_default` network existed but had no running containers attached.
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-24 - Confirm Jitsi Meet Is Fully Deployed
|
||||
|
||||
Decision:
|
||||
|
||||
Treat the Jitsi Meet stack as an operational isolated collaboration stack.
|
||||
|
||||
Components:
|
||||
|
||||
* jitsi-web
|
||||
* jitsi-jvb
|
||||
* jitsi-jicofo
|
||||
* jitsi-prosody
|
||||
|
||||
Networks:
|
||||
|
||||
* `proxy`
|
||||
* `jitsi-docker-jitsi-meet-aa76415_meet.jitsi`
|
||||
|
||||
Reason:
|
||||
|
||||
* Jitsi Web is expected to be public.
|
||||
* Internal Jitsi components should remain isolated inside the Jitsi stack network.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Confirmed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-24 - Adopt Phased Infrastructure Roadmap
|
||||
|
||||
Decision:
|
||||
|
||||
Use a phased roadmap for planned SilverLinux platform improvements.
|
||||
|
||||
Phases:
|
||||
|
||||
* Phase 1: Grafana, Prometheus, Loki, Redis and Authelia.
|
||||
* Phase 2: CrowdSec, Sentry, Restic, Fail2Ban upgrade and Cloudflare rate limiting/WAF.
|
||||
* Phase 3: SonarQube, Harbor, Backstage and Nextcloud.
|
||||
|
||||
Reason:
|
||||
|
||||
* Prioritize observability, access control and shared runtime foundations first.
|
||||
* Add security and backup maturity before larger platform expansion.
|
||||
* Keep enterprise developer-platform tools grouped together.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
Decision:
|
||||
|
||||
Deploy a dedicated monitoring Docker stack using:
|
||||
|
||||
* Prometheus for metrics collection
|
||||
* Grafana for visualization
|
||||
* Node Exporter for host metrics
|
||||
* cAdvisor for Docker metrics
|
||||
* Alertmanager for alert routing and incident notifications
|
||||
|
||||
Reason:
|
||||
|
||||
* Prometheus provides a standard pull-based metrics system.
|
||||
* Grafana provides flexible dashboards and datasource integration.
|
||||
* Node Exporter provides host CPU, memory and disk visibility.
|
||||
* cAdvisor provides Docker container visibility.
|
||||
* Alertmanager provides grouping, deduplication and multi-recipient email routing.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Implemented
|
||||
```
|
||||
|
||||
Validation:
|
||||
|
||||
* Prometheus UI validated
|
||||
* Prometheus targets validated
|
||||
* Grafana datasource connected to Prometheus
|
||||
* Initial monitoring dashboards created and validated
|
||||
* Alertmanager email routing validated
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-25 - Export Backup Metrics Through Node Exporter
|
||||
|
||||
Decision:
|
||||
|
||||
Export SilverLinux backup metrics through the Node Exporter Textfile Collector.
|
||||
|
||||
Metrics:
|
||||
|
||||
* `silverlinux_backup_success`
|
||||
* `silverlinux_backup_duration_seconds`
|
||||
* `silverlinux_backup_size_bytes`
|
||||
* `silverlinux_backup_timestamp_seconds`
|
||||
|
||||
Reason:
|
||||
|
||||
* Keep backup status visible in the same monitoring stack as host and container metrics.
|
||||
* Avoid a separate metrics service for backup scripts.
|
||||
* Allow Grafana dashboards to show backup health.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Implemented
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-25 - Validate Backup v5.3 And Restore Workflow
|
||||
|
||||
Decision:
|
||||
|
||||
Treat Backup v5.3 as the operational SilverLinux backup system.
|
||||
|
||||
Implemented:
|
||||
|
||||
* HTML backup reports
|
||||
* Email notifications
|
||||
* Automatic archive creation
|
||||
* Backup logging
|
||||
* Restore validation
|
||||
* MSSQL data inclusion fix
|
||||
* Backup metrics
|
||||
* Automatic low disk space cleanup
|
||||
* Daily cron execution
|
||||
* Lock file protection
|
||||
* Disk space validation
|
||||
* Central logging
|
||||
* Structured failure handling
|
||||
|
||||
Validation:
|
||||
|
||||
* Dry-run restore completed
|
||||
* Full archive validation completed
|
||||
* PostgreSQL restore coverage verified
|
||||
* MSSQL backup integrity verified
|
||||
* Gitea backup verified
|
||||
* BaGet backup verified
|
||||
* OpenProject assets verified
|
||||
* Docker configuration verified
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Implemented
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2026-06-25 - Implement Incident Intelligence Alerting
|
||||
|
||||
Decision:
|
||||
|
||||
Use Alertmanager with incident grouping, severity-based routing and alert deduplication for SilverLinux monitoring.
|
||||
|
||||
Incident groups:
|
||||
|
||||
* `backup_failure`
|
||||
* `system_pressure`
|
||||
* `storage_pressure`
|
||||
* `database_outage`
|
||||
* `monitoring_failure`
|
||||
* `container_health`
|
||||
|
||||
Reason:
|
||||
|
||||
* Merge related alerts into single incidents.
|
||||
* Reduce notification noise.
|
||||
* Route alerts by severity.
|
||||
* Make alerts root-cause oriented.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
Document future decisions using the following template:
|
||||
|
||||
Date:
|
||||
|
||||
Decision:
|
||||
|
||||
Reason:
|
||||
|
||||
Alternatives Considered:
|
||||
|
||||
Status:
|
||||
+467
@@ -0,0 +1,467 @@
|
||||
# Domains
|
||||
|
||||
## Overview
|
||||
|
||||
This document contains the public domains used by SilverLinux and the services they expose.
|
||||
|
||||
All public services are routed through Nginx Proxy Manager.
|
||||
|
||||
Verified proxy-host snapshot:
|
||||
|
||||
```text
|
||||
2026-06-24, with Nextcloud and Sentry evidence added from 2026-07-08 server output
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Primary Domain
|
||||
|
||||
```text
|
||||
silveressence.net
|
||||
```
|
||||
|
||||
Used for:
|
||||
|
||||
* Public services
|
||||
* Subdomains
|
||||
* SSL certificates
|
||||
|
||||
---
|
||||
|
||||
## Nginx Proxy Manager Hosts
|
||||
|
||||
| ID | Domain | Forward target | SSL Force | HTTP/2 | HSTS | WebSocket | Access List | Status |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| 1 | `portainer.silveressence.net` | `http://portainer:9000` | enabled | enabled | enabled | enabled | none | enabled |
|
||||
| 2 | `git.silveressence.net` | `http://gitea:3000` | disabled | disabled | disabled | enabled | none | enabled |
|
||||
| 3 | `meet.silveressence.net` | `http://jitsi-docker-jitsi-meet-aa76415-web-1:80` | disabled | disabled | 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 |
|
||||
| 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.
|
||||
|
||||
---
|
||||
|
||||
## Additional Active Proxy Hosts
|
||||
|
||||
These proxy hosts were present and enabled in Nginx Proxy Manager during the 2026-06-24 snapshot, but are not part of the current core infrastructure service inventory.
|
||||
|
||||
| ID | Domain | Forward target | Reason |
|
||||
| --- | --- | --- | --- |
|
||||
| 7 | `cicd.silveressence.net` | `http://bobsAutowas:8080` | Active prototype deployment and test endpoint; may change frequently |
|
||||
| 9 | `exactsyncer.silveressence.net` | `http://exact-syncer:8080` | Active client-facing demo for the Exact Online syncer application |
|
||||
|
||||
Action:
|
||||
|
||||
* Keep `cicd.silveressence.net` documented as a fast-changing prototype endpoint.
|
||||
* Keep `exactsyncer.silveressence.net` documented as an intentional client-facing demo endpoint.
|
||||
* Document owner, authentication model and exposure policy for active non-core endpoints.
|
||||
|
||||
Plane.so cleanup:
|
||||
|
||||
* Plane.so containers were removed.
|
||||
* `plane.silveressence.net` was removed from Nginx Proxy Manager.
|
||||
* The unused Plane.so SSL certificate was removed from the server.
|
||||
|
||||
---
|
||||
|
||||
## Proxy Hardening Review
|
||||
|
||||
Nginx Proxy Manager findings from the 2026-06-24 snapshot:
|
||||
|
||||
* `portainer.silveressence.net` has SSL Force, HTTP/2 and HSTS enabled.
|
||||
* `team.silveressence.net` has SSL Force and HTTP/2 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.
|
||||
* 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.
|
||||
|
||||
---
|
||||
|
||||
## Domain Details
|
||||
|
||||
### Gitea
|
||||
|
||||
Domain:
|
||||
|
||||
```text
|
||||
git.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Source control
|
||||
* Git repositories
|
||||
* Pull requests
|
||||
* Issue tracking
|
||||
|
||||
Container:
|
||||
|
||||
```text
|
||||
gitea
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### OpenProject
|
||||
|
||||
Domain:
|
||||
|
||||
```text
|
||||
team.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Project management
|
||||
* Work packages
|
||||
* Time tracking
|
||||
* Team collaboration
|
||||
|
||||
Container:
|
||||
|
||||
```text
|
||||
openproject
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Jitsi Meet
|
||||
|
||||
Domain:
|
||||
|
||||
```text
|
||||
meet.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Video conferencing
|
||||
* Team meetings
|
||||
* Customer meetings
|
||||
|
||||
Container Stack:
|
||||
|
||||
```text
|
||||
jitsi-docker-jitsi-meet-aa76415-web-1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Portainer
|
||||
|
||||
Domain:
|
||||
|
||||
```text
|
||||
portainer.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Docker management
|
||||
* Infrastructure administration
|
||||
|
||||
Container:
|
||||
|
||||
```text
|
||||
portainer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### BaGet
|
||||
|
||||
Domain:
|
||||
|
||||
```text
|
||||
nuget.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Private NuGet package hosting
|
||||
|
||||
Container:
|
||||
|
||||
```text
|
||||
baget
|
||||
```
|
||||
|
||||
Routing:
|
||||
|
||||
```text
|
||||
Nginx Proxy Manager -> baget:80
|
||||
```
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
Domain:
|
||||
|
||||
```text
|
||||
dbgate.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* HTTPS database administration portal
|
||||
|
||||
Container:
|
||||
|
||||
```text
|
||||
dbgate
|
||||
```
|
||||
|
||||
Routing:
|
||||
|
||||
```text
|
||||
Nginx Proxy Manager -> dbgate:3000
|
||||
```
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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 records should point to:
|
||||
|
||||
```text
|
||||
51.255.83.140
|
||||
```
|
||||
|
||||
Server:
|
||||
|
||||
```text
|
||||
SilverLinux
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SSL Certificates
|
||||
|
||||
SSL certificates are managed through:
|
||||
|
||||
```text
|
||||
Nginx Proxy Manager
|
||||
```
|
||||
|
||||
Certificate data location:
|
||||
|
||||
```text
|
||||
/srv/docker/nginx-proxy-manager/letsencrypt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Routing
|
||||
|
||||
Internet
|
||||
↓
|
||||
Nginx Proxy Manager
|
||||
↓
|
||||
Service Container
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
git.silveressence.net
|
||||
↓
|
||||
gitea
|
||||
|
||||
team.silveressence.net
|
||||
↓
|
||||
openproject
|
||||
|
||||
meet.silveressence.net
|
||||
↓
|
||||
jitsi
|
||||
|
||||
portainer.silveressence.net
|
||||
↓
|
||||
portainer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/security.md
|
||||
* docs/network.md
|
||||
* nginx-proxy-manager/README.md
|
||||
+283
@@ -0,0 +1,283 @@
|
||||
# Email Configuration
|
||||
|
||||
## Overview
|
||||
|
||||
SilverLinux uses a centralized SMTP configuration for application email delivery.
|
||||
|
||||
Email is used for:
|
||||
|
||||
* Password resets
|
||||
* User invitations
|
||||
* Notifications
|
||||
* System alerts
|
||||
* Backup reports
|
||||
* Future CI/CD notifications
|
||||
|
||||
---
|
||||
|
||||
## Sender Address
|
||||
|
||||
```text
|
||||
noreply@silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Automated emails
|
||||
* Application notifications
|
||||
* No inbound processing required
|
||||
|
||||
---
|
||||
|
||||
## SMTP Provider
|
||||
|
||||
Provider:
|
||||
|
||||
```text
|
||||
Gmail SMTP
|
||||
```
|
||||
|
||||
Server:
|
||||
|
||||
```text
|
||||
smtp.gmail.com
|
||||
```
|
||||
|
||||
Port:
|
||||
|
||||
```text
|
||||
587
|
||||
```
|
||||
|
||||
Security:
|
||||
|
||||
```text
|
||||
STARTTLS
|
||||
```
|
||||
|
||||
Authentication:
|
||||
|
||||
```text
|
||||
Login
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secret Storage
|
||||
|
||||
SMTP credentials are stored in:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Variables:
|
||||
|
||||
```text
|
||||
SMTP_HOST
|
||||
SMTP_PORT
|
||||
SMTP_USERNAME
|
||||
SMTP_PASSWORD
|
||||
```
|
||||
|
||||
These values must never be committed to Git repositories.
|
||||
|
||||
---
|
||||
|
||||
## Applications Using Email
|
||||
|
||||
### OpenProject
|
||||
|
||||
Purpose:
|
||||
|
||||
* Password reset emails
|
||||
* Work package notifications
|
||||
* Mention notifications
|
||||
* User invitations
|
||||
|
||||
Sender:
|
||||
|
||||
```text
|
||||
noreply@silveressence.net
|
||||
```
|
||||
|
||||
Status:
|
||||
|
||||
Configured
|
||||
|
||||
---
|
||||
|
||||
### Gitea
|
||||
|
||||
Purpose:
|
||||
|
||||
* Password reset emails
|
||||
* Repository notifications
|
||||
* User invitations
|
||||
|
||||
Sender:
|
||||
|
||||
```text
|
||||
noreply@silveressence.net
|
||||
```
|
||||
|
||||
Status:
|
||||
|
||||
Configured
|
||||
|
||||
---
|
||||
|
||||
### Backup System
|
||||
|
||||
Purpose:
|
||||
|
||||
* Backup success emails
|
||||
* HTML backup report emails
|
||||
* Operational backup notifications
|
||||
|
||||
Delivery:
|
||||
|
||||
* Postfix relay through Gmail SMTP
|
||||
* Gmail App Password authentication
|
||||
* TLS encryption
|
||||
|
||||
Status:
|
||||
|
||||
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
|
||||
|
||||
Purpose:
|
||||
|
||||
* Monitoring alert emails
|
||||
* Incident grouped notifications
|
||||
* Severity-based alert routing
|
||||
|
||||
Recipients:
|
||||
|
||||
* `oclick021@gmail.com`
|
||||
* `martin@silversolutions.nl`
|
||||
|
||||
Status:
|
||||
|
||||
Configured and validated
|
||||
|
||||
---
|
||||
|
||||
## Future Applications
|
||||
|
||||
Future services should use the centralized SMTP configuration whenever possible.
|
||||
|
||||
Examples:
|
||||
|
||||
* BaGet
|
||||
* CI/CD notifications
|
||||
* Alerting systems
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### OpenProject
|
||||
|
||||
Test by:
|
||||
|
||||
1. Creating a user.
|
||||
2. Triggering a password reset.
|
||||
3. Verifying email delivery.
|
||||
|
||||
### Gitea
|
||||
|
||||
Test by:
|
||||
|
||||
1. Opening "Forgot Password".
|
||||
2. Requesting a password reset.
|
||||
3. Verifying email delivery.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### OpenProject
|
||||
|
||||
View logs:
|
||||
|
||||
```bash
|
||||
docker logs openproject
|
||||
```
|
||||
|
||||
### Gitea
|
||||
|
||||
View logs:
|
||||
|
||||
```bash
|
||||
docker logs gitea
|
||||
```
|
||||
|
||||
### Gmail Authentication
|
||||
|
||||
Verify:
|
||||
|
||||
* App password is valid
|
||||
* SMTP credentials match the Infisical values injected by `slcompose`
|
||||
* STARTTLS is enabled
|
||||
* Port 587 is used
|
||||
|
||||
### Backup Reports
|
||||
|
||||
Verify:
|
||||
|
||||
* Postfix relay is active
|
||||
* Gmail App Password authentication succeeds
|
||||
* TLS delivery succeeds
|
||||
* Backup wrapper sends the HTML report after backup completion
|
||||
|
||||
---
|
||||
|
||||
## Security Notes
|
||||
|
||||
* Use Gmail App Passwords.
|
||||
* Never use personal Gmail passwords.
|
||||
* Store SMTP credentials only in Infisical.
|
||||
* Rotate credentials if they become exposed.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/secrets.md
|
||||
* docs/security.md
|
||||
* docs/backups.md
|
||||
* docs/monitoring.md
|
||||
* openproject/README.md
|
||||
* gitea/README.md
|
||||
@@ -0,0 +1,311 @@
|
||||
# Monitoring And Alerting
|
||||
|
||||
## Overview
|
||||
|
||||
SilverLinux runs a self-hosted observability stack for metrics, dashboards, backup visibility and incident alerting.
|
||||
|
||||
Current state:
|
||||
|
||||
```text
|
||||
Production ready
|
||||
```
|
||||
|
||||
The stack has evolved from basic monitoring into an incident intelligence system with alert grouping, severity routing and email notifications.
|
||||
|
||||
---
|
||||
|
||||
## Stack Components
|
||||
|
||||
### Prometheus
|
||||
|
||||
Purpose:
|
||||
|
||||
* Metrics collection
|
||||
* Alert rule evaluation
|
||||
* Monitoring data storage
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Grafana
|
||||
|
||||
Purpose:
|
||||
|
||||
* Monitoring dashboards
|
||||
* Prometheus datasource visualization
|
||||
* Backup, system and Docker visibility
|
||||
|
||||
Dashboards:
|
||||
|
||||
* Custom backup dashboard
|
||||
* Custom system dashboard
|
||||
* Docker monitoring dashboard
|
||||
|
||||
Compatibility note:
|
||||
|
||||
The imported Prometheus 2.0 Overview dashboard is not compatible with Prometheus `3.5.4`. This is a third-party dashboard compatibility issue, not an infrastructure problem.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Node Exporter
|
||||
|
||||
Purpose:
|
||||
|
||||
* Host metrics
|
||||
* CPU, memory and disk metrics
|
||||
* Textfile Collector for custom backup metrics
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### cAdvisor
|
||||
|
||||
Purpose:
|
||||
|
||||
* Docker container metrics
|
||||
* Container CPU and memory visibility
|
||||
* Container health and restart visibility
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Alertmanager
|
||||
|
||||
Purpose:
|
||||
|
||||
* Alert routing
|
||||
* Alert grouping
|
||||
* Alert deduplication
|
||||
* Email notifications
|
||||
* Incident intelligence
|
||||
|
||||
Recipients:
|
||||
|
||||
* `oclick021@gmail.com`
|
||||
* `martin@silversolutions.nl`
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Infrastructure
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/monitoring
|
||||
```
|
||||
|
||||
Architecture:
|
||||
|
||||
* Docker-based stack
|
||||
* Persistent Prometheus volume
|
||||
* Persistent Grafana volume
|
||||
* Dedicated monitoring network
|
||||
|
||||
---
|
||||
|
||||
## Metrics
|
||||
|
||||
### System Metrics
|
||||
|
||||
Examples:
|
||||
|
||||
* `node_load1`
|
||||
* `node_memory_*`
|
||||
* `node_filesystem_*`
|
||||
* Container metrics through cAdvisor
|
||||
|
||||
---
|
||||
|
||||
### Backup Metrics
|
||||
|
||||
Export method:
|
||||
|
||||
```text
|
||||
Node Exporter Textfile Collector
|
||||
```
|
||||
|
||||
Metrics:
|
||||
|
||||
* `silverlinux_backup_success`
|
||||
* `silverlinux_backup_duration_seconds`
|
||||
* `silverlinux_backup_size_bytes`
|
||||
* `silverlinux_backup_timestamp_seconds`
|
||||
|
||||
---
|
||||
|
||||
## Prometheus Scrape Targets
|
||||
|
||||
Prometheus successfully scrapes:
|
||||
|
||||
* Prometheus
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* SilverLinux backup metrics
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Validated
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alerting Evolution
|
||||
|
||||
### Stage v1
|
||||
|
||||
Implemented:
|
||||
|
||||
* Basic Prometheus rules
|
||||
* Simple email alerts
|
||||
|
||||
---
|
||||
|
||||
### Stage v2
|
||||
|
||||
Implemented:
|
||||
|
||||
* Alertmanager
|
||||
* Email routing
|
||||
* Multi-recipient alerts
|
||||
|
||||
---
|
||||
|
||||
### Stage v3-v4
|
||||
|
||||
Implemented:
|
||||
|
||||
* `incident_group` concept
|
||||
* Alert correlation by service
|
||||
* Severity-based routing
|
||||
* Alert deduplication
|
||||
* Reduced notification noise
|
||||
|
||||
---
|
||||
|
||||
## Incident Groups
|
||||
|
||||
Alertmanager groups alerts by incident category.
|
||||
|
||||
Incident groups:
|
||||
|
||||
* `backup_failure`
|
||||
* `system_pressure`
|
||||
* `storage_pressure`
|
||||
* `database_outage`
|
||||
* `monitoring_failure`
|
||||
* `container_health`
|
||||
|
||||
Outcome:
|
||||
|
||||
* Multiple related alerts merge into single incidents.
|
||||
* Alerts are root-cause oriented.
|
||||
* Alert fatigue is reduced.
|
||||
|
||||
---
|
||||
|
||||
## Alert Rules
|
||||
|
||||
### Backup
|
||||
|
||||
* `BackupFailed`
|
||||
* `BackupStale`
|
||||
|
||||
### System
|
||||
|
||||
* `HighCPU`
|
||||
* `HighMemoryUsage`
|
||||
* `DiskAlmostFull`
|
||||
|
||||
### Monitoring
|
||||
|
||||
* `PrometheusDown`
|
||||
* `GrafanaDown`
|
||||
|
||||
### Databases
|
||||
|
||||
* `PostgresDown`
|
||||
* `MSSQLDown`
|
||||
|
||||
### Containers
|
||||
|
||||
* `ContainerDown`
|
||||
* `TooManyRestarts`
|
||||
|
||||
---
|
||||
|
||||
## Implementation Fixes
|
||||
|
||||
Resolved during implementation:
|
||||
|
||||
* Fixed Docker mount errors caused by file versus directory conflicts
|
||||
* Standardized alert rule file naming as `alerts.yml`
|
||||
* Fixed Prometheus rule loading configuration
|
||||
* Eliminated duplicate backup success metric sources
|
||||
* Unified backup metric naming to `silverlinux_backup_*`
|
||||
|
||||
---
|
||||
|
||||
## Data Flow
|
||||
|
||||
```text
|
||||
Servers
|
||||
-> Node Exporter / cAdvisor
|
||||
-> Prometheus
|
||||
-> Alertmanager
|
||||
-> Email notifications
|
||||
-> Grafana dashboards
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validation
|
||||
|
||||
Validated:
|
||||
|
||||
* Prometheus UI
|
||||
* Prometheus targets
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Backup metrics
|
||||
* Grafana datasource
|
||||
* Alertmanager email routing
|
||||
* Backup success and failure visibility
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/services.md
|
||||
* docs/backups.md
|
||||
* docs/security.md
|
||||
* docs/network.md
|
||||
* docs/email.md
|
||||
* docs/decisions.md
|
||||
+400
@@ -0,0 +1,400 @@
|
||||
# Network Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
SilverLinux uses Docker networks to separate public entry points, private service communication and isolated infrastructure stacks.
|
||||
|
||||
Current model:
|
||||
|
||||
* `internal` for private databases and backend service traffic
|
||||
* `proxy` for HTTP and HTTPS services routed by Nginx Proxy Manager
|
||||
* Isolated stack networks for specialized infrastructure such as Jitsi, Xray, monitoring, Sentry and CI/CD runners
|
||||
|
||||
Verified runtime snapshot:
|
||||
|
||||
```text
|
||||
2026-06-24 10:15 CEST, with Nextcloud and Sentry evidence added from 2026-07-08 server output
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Network Layers
|
||||
|
||||
### Internal Layer
|
||||
|
||||
Purpose:
|
||||
|
||||
* Private database access
|
||||
* Backend-to-database communication
|
||||
* Service traffic that should not be reachable from the internet
|
||||
|
||||
Network:
|
||||
|
||||
```text
|
||||
internal
|
||||
```
|
||||
|
||||
Services:
|
||||
|
||||
* PostgreSQL
|
||||
* Microsoft SQL Server Express
|
||||
* Gitea backend connectivity
|
||||
* OpenProject backend connectivity
|
||||
* DbGate database connectivity
|
||||
|
||||
Policy:
|
||||
|
||||
* Database ports must not be published on the host
|
||||
* Database engines must not be routed through Nginx Proxy Manager
|
||||
* Only containers that require private backend access should join this network
|
||||
|
||||
---
|
||||
|
||||
### Proxy Layer
|
||||
|
||||
Purpose:
|
||||
|
||||
* Public HTTP and HTTPS entry point
|
||||
* SSL termination
|
||||
* Domain routing through Nginx Proxy Manager
|
||||
|
||||
Network:
|
||||
|
||||
```text
|
||||
proxy
|
||||
```
|
||||
|
||||
Public services:
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Portainer
|
||||
* DbGate
|
||||
* Xray
|
||||
* Jitsi Web
|
||||
* BaGet
|
||||
* Nextcloud
|
||||
* Sentry
|
||||
|
||||
Internal monitoring services:
|
||||
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
|
||||
Verified subnet:
|
||||
|
||||
```text
|
||||
172.18.0.0/16
|
||||
```
|
||||
|
||||
Policy:
|
||||
|
||||
* Nginx Proxy Manager is the single reverse proxy system
|
||||
* HTTP services should be exposed through Nginx Proxy Manager instead of direct host ports
|
||||
* Public management and administration services require strong authentication
|
||||
|
||||
---
|
||||
|
||||
### Isolated Infrastructure Layers
|
||||
|
||||
Purpose:
|
||||
|
||||
* Keep specialized stacks separate from the shared application and database networks
|
||||
* Limit cross-service traffic to only the attachments each stack requires
|
||||
|
||||
Networks:
|
||||
|
||||
```text
|
||||
jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
||||
xray_default
|
||||
gitea-runner_default
|
||||
monitoring stack network
|
||||
sentry-self-hosted_default
|
||||
```
|
||||
|
||||
#### jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
||||
|
||||
Purpose:
|
||||
|
||||
* Isolated Jitsi communication cluster
|
||||
|
||||
Services:
|
||||
|
||||
* jitsi-web
|
||||
* jitsi-jvb
|
||||
* jitsi-jicofo
|
||||
* jitsi-prosody
|
||||
|
||||
Public attachment:
|
||||
|
||||
* All currently running Jitsi containers also attach to `proxy`.
|
||||
* Public user access is expected through the Jitsi Web component.
|
||||
|
||||
Verified subnet:
|
||||
|
||||
```text
|
||||
172.20.0.0/16
|
||||
```
|
||||
|
||||
#### xray_default
|
||||
|
||||
Purpose:
|
||||
|
||||
* Isolated tunneling and connectivity system
|
||||
* Compose-created network for the Xray stack
|
||||
|
||||
Services:
|
||||
|
||||
* No running containers were attached in the 2026-06-24 runtime snapshot
|
||||
|
||||
Public attachment:
|
||||
|
||||
* The running `xray` container is attached to `proxy`.
|
||||
* The running `xray` container was not attached to `xray_default` in the 2026-06-24 runtime snapshot.
|
||||
|
||||
Verified subnet:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
Purpose:
|
||||
|
||||
* Runner execution and workflow isolation
|
||||
* Keep build traffic separate from public services and private databases unless explicit access is required
|
||||
|
||||
Runtime attachment:
|
||||
|
||||
* `gitea-runner` is attached to both `gitea-runner_default` and `internal`.
|
||||
|
||||
Verified subnet:
|
||||
|
||||
```text
|
||||
172.21.0.0/16
|
||||
```
|
||||
|
||||
#### Monitoring Stack Network
|
||||
|
||||
Purpose:
|
||||
|
||||
* Dedicated monitoring stack communication
|
||||
* Prometheus scraping of monitoring targets
|
||||
* Grafana datasource connectivity to Prometheus
|
||||
|
||||
Services:
|
||||
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
|
||||
Validated:
|
||||
|
||||
* Prometheus scrapes Prometheus
|
||||
* Prometheus scrapes Node Exporter
|
||||
* Prometheus scrapes cAdvisor
|
||||
* Prometheus scrapes SilverLinux backup metrics
|
||||
* Grafana connects to Prometheus
|
||||
* 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
|
||||
|
||||
The current Docker runtime includes these host-published ports.
|
||||
|
||||
| Service | Published port | Container port | UFW state | Notes |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Nginx Proxy Manager | `80`, `81`, `443` | `80`, `81`, `443` | `80` and `443` allowed; `81` not listed | Public proxy and NPM admin interface |
|
||||
| Gitea | `2222` | `22` | Allowed | Git SSH access |
|
||||
| OpenProject | `8082` | `80` | Not listed as allowed | Direct HTTP port also published |
|
||||
| BaGet | `5555` | `80` | Not listed as allowed | Direct HTTP port 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 |
|
||||
| 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:
|
||||
|
||||
* `8080/tcp`
|
||||
* `8085/tcp`
|
||||
* `8444/tcp`
|
||||
|
||||
Database ports:
|
||||
|
||||
* PostgreSQL exposes `5432/tcp` only inside Docker.
|
||||
* MSSQL exposes `1433/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
|
||||
|
||||
```text
|
||||
Internet
|
||||
-> Nginx Proxy Manager
|
||||
-> proxy network
|
||||
-> Gitea
|
||||
-> OpenProject
|
||||
-> Portainer
|
||||
-> DbGate
|
||||
-> Xray
|
||||
-> Jitsi Web
|
||||
-> BaGet
|
||||
-> Nextcloud
|
||||
-> Sentry
|
||||
|
||||
internal network
|
||||
-> PostgreSQL
|
||||
-> Microsoft SQL Server Express
|
||||
-> backend service database access
|
||||
|
||||
isolated networks
|
||||
-> jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
||||
-> xray_default
|
||||
-> gitea-runner_default
|
||||
-> monitoring stack network
|
||||
-> nextcloud_nextcloud_internal
|
||||
-> sentry-self-hosted_default
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Default Docker Networks
|
||||
|
||||
Docker default networks remain present:
|
||||
|
||||
* `bridge`
|
||||
* `host`
|
||||
* `none`
|
||||
|
||||
These are system defaults and are not the preferred routing model for SilverLinux application services.
|
||||
|
||||
---
|
||||
|
||||
## Verification Checklist
|
||||
|
||||
Periodically verify:
|
||||
|
||||
* PostgreSQL and MSSQL are attached only to private networks required by their consumers
|
||||
* Nginx Proxy Manager remains the only reverse proxy for HTTP services
|
||||
* Nginx Proxy Manager routes match the documented proxy-host table in `docs/domains.md`
|
||||
* DbGate authentication is enabled and tested
|
||||
* DbGate and Portainer have an access restriction policy
|
||||
* Xray exposure policy is documented and monitored
|
||||
* Jitsi Web is reachable through `proxy`
|
||||
* 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
|
||||
* 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
|
||||
* Prometheus targets remain 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
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/services.md
|
||||
* docs/security.md
|
||||
* docs/monitoring.md
|
||||
* docs/decisions.md
|
||||
* nginx-proxy-manager/README.md
|
||||
@@ -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
|
||||
+396
@@ -0,0 +1,396 @@
|
||||
# Roadmap
|
||||
|
||||
## Overview
|
||||
|
||||
This document tracks planned SilverLinux infrastructure improvements.
|
||||
|
||||
The roadmap focuses on observability, access control, security hardening, platform services and backup maturity.
|
||||
|
||||
---
|
||||
|
||||
## Planned Capabilities
|
||||
|
||||
### Collaboration And Storage
|
||||
|
||||
#### Nextcloud
|
||||
|
||||
Purpose:
|
||||
|
||||
* Self-hosted file sharing
|
||||
* Team document storage
|
||||
* Optional collaboration layer for internal operations
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
#### Grafana And Prometheus
|
||||
|
||||
Purpose:
|
||||
|
||||
* Metrics collection
|
||||
* Dashboards and visualization
|
||||
* Host and container health monitoring
|
||||
* Alerting foundation
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Completed
|
||||
```
|
||||
|
||||
Completed components:
|
||||
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
|
||||
Validation:
|
||||
|
||||
* Prometheus UI validated
|
||||
* Prometheus targets validated
|
||||
* Grafana datasource connected to Prometheus
|
||||
* Initial dashboards created and validated
|
||||
* Alertmanager email routing validated
|
||||
|
||||
Alerting:
|
||||
|
||||
* Incident grouping implemented
|
||||
* Severity-based routing implemented
|
||||
* Alert deduplication implemented
|
||||
* Multi-recipient email alerts implemented
|
||||
|
||||
---
|
||||
|
||||
#### Loki
|
||||
|
||||
Purpose:
|
||||
|
||||
* Central log aggregation
|
||||
* Log exploration through Grafana
|
||||
* Faster incident investigation
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Sentry
|
||||
|
||||
Purpose:
|
||||
|
||||
* Application error tracking
|
||||
* Release health visibility
|
||||
* Exception diagnostics for deployed apps
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
#### Authelia
|
||||
|
||||
Purpose:
|
||||
|
||||
* Identity and access management for exposed admin areas
|
||||
* SSO gateway for sensitive services
|
||||
* Additional protection for DbGate, Portainer, Gitea admin areas and OpenProject admin areas
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Security Hardening
|
||||
|
||||
#### Fail2Ban Upgrade
|
||||
|
||||
Purpose:
|
||||
|
||||
* Improve brute-force protection
|
||||
* Expand jail coverage beyond SSH where practical
|
||||
* Align detection with exposed administrative services
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### CrowdSec
|
||||
|
||||
Purpose:
|
||||
|
||||
* Collaborative intrusion detection
|
||||
* Behavior-based blocking
|
||||
* Additional protection for public endpoints
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Cloudflare Rate Limiting And WAF
|
||||
|
||||
Purpose:
|
||||
|
||||
* Rate limiting for exposed admin areas
|
||||
* WAF rules for common attack patterns
|
||||
* Brute-force protection before traffic reaches SilverLinux
|
||||
|
||||
Target areas:
|
||||
|
||||
* DbGate
|
||||
* Portainer
|
||||
* Gitea administrator areas
|
||||
* OpenProject administrator areas
|
||||
* Prototype and demo endpoints where appropriate
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Platform Services
|
||||
|
||||
#### Harbor
|
||||
|
||||
Purpose:
|
||||
|
||||
* Docker image registry
|
||||
* Internal image distribution
|
||||
* Container artifact management
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### SonarQube
|
||||
|
||||
Purpose:
|
||||
|
||||
* Code quality scanning
|
||||
* Security scanning
|
||||
* Technical debt tracking
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### Backstage
|
||||
|
||||
Purpose:
|
||||
|
||||
* Internal developer portal
|
||||
* Service catalog
|
||||
* Platform documentation entry point
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Performance
|
||||
|
||||
#### Redis
|
||||
|
||||
Purpose:
|
||||
|
||||
* Caching layer for databases and high-traffic application reads
|
||||
* Session storage where supported by applications
|
||||
* Future scaling support
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Backup And Restore
|
||||
|
||||
#### Restic
|
||||
|
||||
Purpose:
|
||||
|
||||
* Versioned backup jobs
|
||||
* Restore workflows
|
||||
* Encrypted backups
|
||||
* Better backup retention management
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Planned
|
||||
```
|
||||
|
||||
Current backup status:
|
||||
|
||||
```text
|
||||
Backup v5.3 production
|
||||
```
|
||||
|
||||
Completed:
|
||||
|
||||
* Daily cron backup
|
||||
* Email reports
|
||||
* HTML reports
|
||||
* Automatic archive generation
|
||||
* Automatic cleanup
|
||||
* Backup metrics export
|
||||
* Restore validation
|
||||
* Lock file protection
|
||||
* Disk space validation
|
||||
* Central logging
|
||||
* Structured failure handling
|
||||
|
||||
---
|
||||
|
||||
## Priority Phases
|
||||
|
||||
### Phase 1 - Immediate Impact
|
||||
|
||||
Items:
|
||||
|
||||
* Loki
|
||||
* Redis
|
||||
* Authelia
|
||||
|
||||
Completed:
|
||||
|
||||
* Grafana
|
||||
* Prometheus
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Alertmanager
|
||||
* Backup metrics integration
|
||||
* Incident intelligence
|
||||
|
||||
---
|
||||
|
||||
### Phase 2 - Security And Stability
|
||||
|
||||
Items:
|
||||
|
||||
* CrowdSec
|
||||
* Fail2Ban upgrade
|
||||
* Cloudflare rate limiting and WAF
|
||||
|
||||
Completed:
|
||||
|
||||
* Backup v5.3 automation
|
||||
* Restore validation
|
||||
* Sentry
|
||||
|
||||
---
|
||||
|
||||
### Phase 3 - Scale And Enterprise Services
|
||||
|
||||
Items:
|
||||
|
||||
* SonarQube
|
||||
* Harbor Docker registry
|
||||
* Backstage portal
|
||||
|
||||
Completed:
|
||||
|
||||
* Nextcloud
|
||||
|
||||
---
|
||||
|
||||
## Documentation Requirements
|
||||
|
||||
Each roadmap item should receive documentation before deployment:
|
||||
|
||||
* Service purpose
|
||||
* Docker Compose location
|
||||
* Data and backup paths
|
||||
* Network attachments
|
||||
* Public exposure policy
|
||||
* Authentication model
|
||||
* Secrets required
|
||||
* Restore procedure
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/services.md
|
||||
* docs/security.md
|
||||
* docs/network.md
|
||||
* docs/backups.md
|
||||
* docs/monitoring.md
|
||||
* docs/decisions.md
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
# Secrets Management
|
||||
|
||||
## Overview
|
||||
|
||||
SilverLinux uses Infisical for centralized secret management. Secrets are injected into standard Compose stacks at runtime by `slcompose`, which wraps `infisical run`.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
The Infisical deployment flow provides a single source of truth for:
|
||||
|
||||
* SMTP credentials
|
||||
* Database passwords
|
||||
* Application secrets
|
||||
* OAuth client secrets
|
||||
* Future API keys
|
||||
|
||||
Applications should load secrets using Infisical injection at deployment time through `slcompose`.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
slcompose up gitea
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Current Variables
|
||||
|
||||
### Email
|
||||
|
||||
```text
|
||||
SMTP_HOST
|
||||
SMTP_PORT
|
||||
SMTP_USERNAME
|
||||
SMTP_PASSWORD
|
||||
```
|
||||
|
||||
Used by:
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Future services
|
||||
|
||||
---
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
```text
|
||||
POSTGRES_ROOT_PASSWORD
|
||||
POSTGRES_OPENPROJECT_PASSWORD
|
||||
```
|
||||
|
||||
Used by:
|
||||
|
||||
* PostgreSQL
|
||||
* OpenProject
|
||||
* Gitea
|
||||
|
||||
---
|
||||
|
||||
### Microsoft SQL Server
|
||||
|
||||
```text
|
||||
MSSQL_SA_PASSWORD
|
||||
```
|
||||
|
||||
Used by:
|
||||
|
||||
* Microsoft SQL Server 2022 Express
|
||||
* DbGate's MSSQL connection
|
||||
|
||||
---
|
||||
|
||||
### OpenProject
|
||||
|
||||
```text
|
||||
OPENPROJECT_SECRET_KEY_BASE
|
||||
```
|
||||
|
||||
Used by:
|
||||
|
||||
* OpenProject
|
||||
|
||||
---
|
||||
|
||||
### Gitea Actions Runner
|
||||
|
||||
```text
|
||||
GITEA_RUNNER_REGISTRATION_TOKEN
|
||||
```
|
||||
|
||||
Used by:
|
||||
|
||||
* The global `silverlinux-runner`
|
||||
* Runner registration and reconnection
|
||||
|
||||
Repository workflow credentials, including `BAGET_API_KEY`, are stored in Gitea under **Repository Settings -> Actions -> Secrets** and are not stored in repositories.
|
||||
|
||||
---
|
||||
|
||||
### Jitsi
|
||||
|
||||
```text
|
||||
JICOFO_AUTH_PASSWORD
|
||||
JVB_AUTH_PASSWORD
|
||||
JIBRI_XMPP_PASSWORD
|
||||
JIBRI_RECORDER_PASSWORD
|
||||
JIGASI_XMPP_PASSWORD
|
||||
JIGASI_TRANSCRIBER_PASSWORD
|
||||
```
|
||||
|
||||
Used by:
|
||||
|
||||
* Jitsi Meet
|
||||
|
||||
---
|
||||
|
||||
### 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
|
||||
|
||||
```text
|
||||
GOOGLE_CLIENT_ID
|
||||
GOOGLE_CLIENT_SECRET
|
||||
|
||||
GITHUB_CLIENT_ID
|
||||
GITHUB_CLIENT_SECRET
|
||||
|
||||
MICROSOFT_CLIENT_ID
|
||||
MICROSOFT_CLIENT_SECRET
|
||||
```
|
||||
|
||||
Future use:
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Other applications
|
||||
|
||||
---
|
||||
|
||||
### Sentry Exception
|
||||
|
||||
```text
|
||||
Sentry self-hosted installer secrets
|
||||
```
|
||||
|
||||
Used by:
|
||||
|
||||
* Sentry
|
||||
|
||||
Notes:
|
||||
|
||||
* 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).
|
||||
|
||||
---
|
||||
|
||||
## Rules
|
||||
|
||||
* Never commit secrets to Git.
|
||||
* Never store passwords directly in docker-compose files.
|
||||
* Never share Infisical exports, tokens or raw service `.env` files.
|
||||
* Use environment variables whenever possible.
|
||||
* Use `.env.example` files for documentation.
|
||||
* Rotate credentials immediately if exposure is suspected.
|
||||
|
||||
---
|
||||
|
||||
## Backup Requirements
|
||||
|
||||
Backups must preserve the ability to recover Infisical-managed secrets.
|
||||
|
||||
```text
|
||||
Infisical project data and service secret paths
|
||||
```
|
||||
|
||||
Loss of the Infisical secret source may prevent applications from starting correctly.
|
||||
|
||||
---
|
||||
|
||||
## Recovery Procedure
|
||||
|
||||
If the server must be rebuilt:
|
||||
|
||||
1. Restore or reauthorize Infisical access.
|
||||
2. Verify `/etc/infisical/token` and any required Infisical domain configuration.
|
||||
3. Deploy Docker stacks through `slcompose`.
|
||||
4. Verify services can access required variables.
|
||||
5. Verify SMTP functionality.
|
||||
6. Verify database connectivity.
|
||||
|
||||
---
|
||||
|
||||
## Security Notes
|
||||
|
||||
Infisical contains credentials for multiple services.
|
||||
|
||||
Access should be restricted to system administrators only.
|
||||
|
||||
The local Infisical token under `/etc/infisical/token` must be protected with root-only permissions.
|
||||
|
||||
---
|
||||
|
||||
## Related Documents
|
||||
|
||||
* docs/email.md
|
||||
* docs/security.md
|
||||
* docs/server.md
|
||||
* docs/backups.md
|
||||
@@ -0,0 +1,401 @@
|
||||
# Security
|
||||
|
||||
## Overview
|
||||
|
||||
SilverLinux hosts critical infrastructure for Silver Solutions.
|
||||
|
||||
This document describes the security measures implemented on the server and operational security requirements.
|
||||
|
||||
---
|
||||
|
||||
## Access Control
|
||||
|
||||
### SSH Access
|
||||
|
||||
SSH access is limited to authorized administrators.
|
||||
|
||||
Authentication:
|
||||
|
||||
* SSH key authentication
|
||||
* Password login discouraged
|
||||
* Root login disabled
|
||||
|
||||
Primary user:
|
||||
|
||||
```text
|
||||
ubuntu
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Firewall
|
||||
|
||||
### UFW
|
||||
|
||||
UFW is enabled and used as the primary host firewall.
|
||||
|
||||
Verified allowed incoming ports from `sudo ufw status verbose`:
|
||||
|
||||
| Port | Purpose |
|
||||
| ---- | ------- |
|
||||
| 22 | SSH |
|
||||
| 80 | HTTP |
|
||||
| 443 | HTTPS |
|
||||
| 2222 | Gitea Git SSH |
|
||||
| 10000/udp | Jitsi JVB media |
|
||||
| 8085 | Explicitly allowed non-standard TCP port |
|
||||
| 8443 | Explicitly allowed non-standard HTTPS port |
|
||||
| 8444 | Explicitly allowed non-standard TCP port |
|
||||
| 8080 | Explicitly allowed non-standard TCP port |
|
||||
| 32443 | Xray public tunneling endpoint |
|
||||
|
||||
Default policy:
|
||||
|
||||
* deny incoming
|
||||
* allow outgoing
|
||||
* deny routed
|
||||
|
||||
All other ports should remain blocked unless explicitly required.
|
||||
|
||||
Known runtime-published non-standard ports from the 2026-06-24 Docker snapshot:
|
||||
|
||||
| Port | Service | UFW state | Notes |
|
||||
| ---- | ------- | --------- | ----- |
|
||||
| 81 | Nginx Proxy Manager | Not listed as allowed | Admin interface is published by Docker, but not allowed by UFW snapshot |
|
||||
| 2222 | Gitea | Allowed | Git SSH |
|
||||
| 32443 | Xray | Allowed | Public tunneling endpoint |
|
||||
| 5555 | BaGet | Not listed as allowed | Direct HTTP port is published by Docker, but not allowed by UFW snapshot |
|
||||
| 8000 | Jitsi Web | Not listed as allowed | Direct HTTP port is published by Docker, but not allowed by UFW snapshot |
|
||||
| 8443 | Jitsi Web | Allowed | Direct HTTPS port |
|
||||
| 10000/udp | Jitsi JVB | Allowed | Required media bridge traffic |
|
||||
| 8082 | OpenProject | Not listed as allowed | Direct HTTP port is published by Docker, but not allowed by UFW snapshot |
|
||||
|
||||
These ports must either be intentionally allowed and documented in UFW, or blocked at the host firewall if only Nginx Proxy Manager should be public.
|
||||
|
||||
UFW also allows `8080`, `8085` and `8444`, but no matching Docker-published service was identified in the 2026-06-24 Docker snapshot. These rules should be reviewed and removed if they are no longer required.
|
||||
|
||||
---
|
||||
|
||||
## Intrusion Protection
|
||||
|
||||
### Fail2Ban
|
||||
|
||||
Fail2Ban is enabled.
|
||||
|
||||
Purpose:
|
||||
|
||||
* Detect brute-force attacks
|
||||
* Automatically block malicious IP addresses
|
||||
* Protect SSH access
|
||||
|
||||
Planned improvements:
|
||||
|
||||
* Upgrade Fail2Ban coverage
|
||||
* Add CrowdSec for collaborative intrusion detection
|
||||
* Add Cloudflare rate limiting and WAF for exposed administrative endpoints
|
||||
|
||||
---
|
||||
|
||||
## Secrets Management
|
||||
|
||||
Shared secrets are stored in:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
* SMTP credentials
|
||||
* PostgreSQL passwords
|
||||
* MSSQL SA password
|
||||
* OpenProject secrets
|
||||
* Future OAuth secrets
|
||||
|
||||
Rules:
|
||||
|
||||
* Never commit secrets to Git
|
||||
* Never share secrets in documentation
|
||||
* 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:
|
||||
|
||||
```text
|
||||
docs/secrets.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SSL Certificates
|
||||
|
||||
SSL certificates are managed through Nginx Proxy Manager.
|
||||
|
||||
Certificates are automatically renewed.
|
||||
|
||||
All public services should be accessible through HTTPS only.
|
||||
|
||||
---
|
||||
|
||||
## Public Exposure
|
||||
|
||||
Public HTTP and HTTPS services are routed through the `proxy` Docker network and Nginx Proxy Manager.
|
||||
|
||||
Publicly exposed services:
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Portainer
|
||||
* DbGate
|
||||
* Xray
|
||||
* Jitsi Web
|
||||
* BaGet
|
||||
* Nextcloud
|
||||
* Sentry
|
||||
|
||||
High-sensitivity exposure:
|
||||
|
||||
* 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.
|
||||
* 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:
|
||||
|
||||
* No proxy host had an Nginx Proxy Manager access list assigned.
|
||||
* DbGate was enabled without SSL Force, HTTP/2 or HSTS.
|
||||
* Gitea, Jitsi Meet and BaGet were enabled without SSL Force.
|
||||
* 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.
|
||||
* `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:
|
||||
|
||||
1. Enable SSL Force for all HTTPS public service routes unless there is a documented exception.
|
||||
2. Enable SSL Force, HTTP/2 and HSTS for Nextcloud unless there is a documented exception.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
## Email Security
|
||||
|
||||
Outgoing email is provided through Gmail SMTP.
|
||||
|
||||
Credentials are stored in:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Requirements:
|
||||
|
||||
* Use Gmail App Passwords only
|
||||
* Never store personal account passwords
|
||||
* Rotate credentials if exposure is suspected
|
||||
|
||||
Sender address:
|
||||
|
||||
```text
|
||||
noreply@silveressence.net
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
### Current
|
||||
|
||||
* Local user accounts
|
||||
* Strong passwords
|
||||
|
||||
### Planned
|
||||
|
||||
Future OAuth providers:
|
||||
|
||||
* Google OAuth2
|
||||
* GitHub OAuth2
|
||||
* Authelia SSO for exposed admin areas
|
||||
|
||||
Requirements:
|
||||
|
||||
* Store client secrets in Infisical
|
||||
* Use least-privilege scopes
|
||||
* Disable unused authentication providers
|
||||
|
||||
Planned protected areas:
|
||||
|
||||
* DbGate
|
||||
* Portainer
|
||||
* Gitea administrator areas
|
||||
* OpenProject administrator areas
|
||||
|
||||
### Disabled
|
||||
|
||||
* OpenID authentication
|
||||
|
||||
Reason:
|
||||
|
||||
OpenID is not required and increases attack surface.
|
||||
|
||||
---
|
||||
|
||||
## Two-Factor Authentication
|
||||
|
||||
Where supported:
|
||||
|
||||
* Enable 2FA for administrator accounts
|
||||
* Encourage 2FA for all users
|
||||
|
||||
Priority:
|
||||
|
||||
1. Gitea administrators
|
||||
2. OpenProject administrators
|
||||
|
||||
---
|
||||
|
||||
## Database Security
|
||||
|
||||
PostgreSQL and Microsoft SQL Server are not exposed publicly.
|
||||
|
||||
Database access is restricted to Docker internal networks.
|
||||
|
||||
Applications and DbGate communicate with the database containers through the `internal` Docker network.
|
||||
|
||||
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
|
||||
|
||||
Xray is classified as a network tunneling and connectivity layer, not as an application service.
|
||||
|
||||
Requirements:
|
||||
|
||||
* Keep the Xray service isolated from private database networks unless a documented need exists.
|
||||
* Monitor logs and traffic patterns for abuse.
|
||||
* Review access policy after configuration changes.
|
||||
* Keep secrets, UUIDs, keys and endpoint credentials outside the repository.
|
||||
|
||||
---
|
||||
|
||||
## Docker Security
|
||||
|
||||
Services are isolated through Docker containers.
|
||||
|
||||
Principles:
|
||||
|
||||
* Public services should be exposed only through Nginx Proxy Manager
|
||||
* Internal services should not expose ports publicly
|
||||
* Services should communicate through Docker networks
|
||||
* Containers should run with the minimum required privileges
|
||||
|
||||
Networks:
|
||||
|
||||
* proxy
|
||||
* internal
|
||||
* jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
||||
* xray_default
|
||||
* gitea-runner_default
|
||||
* nextcloud_nextcloud_internal
|
||||
|
||||
Network model:
|
||||
|
||||
* `internal` is for private database and backend traffic.
|
||||
* `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.
|
||||
* `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.
|
||||
|
||||
---
|
||||
|
||||
## System Updates
|
||||
|
||||
The operating system and containers should be updated regularly.
|
||||
|
||||
Recommendations:
|
||||
|
||||
* Apply Ubuntu security updates
|
||||
* Update Docker images periodically
|
||||
* Remove unused containers and images
|
||||
* Review security advisories for critical services
|
||||
|
||||
---
|
||||
|
||||
## Backup Security
|
||||
|
||||
Backups must include:
|
||||
|
||||
* Configuration files
|
||||
* Docker Compose files
|
||||
* Application data
|
||||
* PostgreSQL databases
|
||||
* Shared secrets
|
||||
|
||||
Backups must never be stored inside public repositories.
|
||||
|
||||
---
|
||||
|
||||
## Security Review Checklist
|
||||
|
||||
Periodically verify:
|
||||
|
||||
* SSH keys are current
|
||||
* Unused accounts are removed
|
||||
* Fail2Ban is active
|
||||
* Planned CrowdSec and Cloudflare WAF status is reviewed
|
||||
* UFW is active
|
||||
* SSL certificates are valid
|
||||
* Secrets are not stored in repositories
|
||||
* Backups are functioning
|
||||
* Administrator accounts have 2FA enabled
|
||||
* DbGate login is enforced
|
||||
* DbGate proxy route has SSL Force and an access restriction policy
|
||||
* 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
|
||||
* Removed proxy hosts and unused certificates stay removed unless explicitly approved
|
||||
* Prototype and demo proxy hosts have documented owners and exposure expectations
|
||||
* Direct host-published ports are intentional or blocked by UFW
|
||||
* UFW rules `8080`, `8085` and `8444` still have a documented owner
|
||||
* Review application logs
|
||||
* Review Docker logs
|
||||
* Review authentication failures
|
||||
* Review Fail2Ban bans
|
||||
|
||||
---
|
||||
|
||||
## Incident Response
|
||||
|
||||
If a credential is exposed:
|
||||
|
||||
1. Rotate the credential immediately.
|
||||
2. Rotate or update the value in Infisical.
|
||||
3. Restart affected services.
|
||||
4. Review logs for unauthorized access.
|
||||
5. Update documentation if required.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/secrets.md
|
||||
* docs/backups.md
|
||||
* docs/email.md
|
||||
* docs/network.md
|
||||
* docs/roadmap.md
|
||||
* nginx-proxy-manager/README.md
|
||||
+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)
|
||||
+517
@@ -0,0 +1,517 @@
|
||||
# Server Information
|
||||
|
||||
## Overview
|
||||
|
||||
SilverLinux is the primary self-hosted infrastructure server for Silver Solutions.
|
||||
|
||||
The server hosts source control, project management, collaboration, communication and supporting infrastructure services.
|
||||
|
||||
---
|
||||
|
||||
## Host Information
|
||||
|
||||
| Property | Value |
|
||||
| ---------------- | ----------------------- |
|
||||
| Hostname | silverlinux |
|
||||
| Provider | OVH |
|
||||
| Operating System | Ubuntu Server 24.04 LTS |
|
||||
| Public IP | 51.255.83.140 |
|
||||
|
||||
---
|
||||
|
||||
## Hardware
|
||||
|
||||
| Resource | Value |
|
||||
| -------- | -------------------- |
|
||||
| CPU | Intel Xeon-D 1520 |
|
||||
| Memory | 32 GB RAM |
|
||||
| Storage | 2 × 480 GB SSD RAID1 |
|
||||
|
||||
---
|
||||
|
||||
## Installed Software
|
||||
|
||||
### Docker
|
||||
|
||||
Purpose:
|
||||
|
||||
* Container hosting
|
||||
* Service isolation
|
||||
* Deployment management
|
||||
|
||||
### Docker Compose
|
||||
|
||||
Purpose:
|
||||
|
||||
* Multi-container application deployment
|
||||
* Service management
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
Purpose:
|
||||
|
||||
* Primary PostgreSQL database platform
|
||||
|
||||
### Microsoft SQL Server Express
|
||||
|
||||
Purpose:
|
||||
|
||||
* Private SQL Server platform for compatible applications
|
||||
|
||||
### Fail2Ban
|
||||
|
||||
Purpose:
|
||||
|
||||
* SSH brute-force protection
|
||||
|
||||
### UFW
|
||||
|
||||
Purpose:
|
||||
|
||||
* Firewall management
|
||||
|
||||
### Monitoring Stack
|
||||
|
||||
Purpose:
|
||||
|
||||
* Metrics collection
|
||||
* Monitoring dashboards
|
||||
* Host metrics
|
||||
* Docker container metrics
|
||||
|
||||
---
|
||||
|
||||
## Docker Networks
|
||||
|
||||
### internal
|
||||
|
||||
Purpose:
|
||||
|
||||
Private communication between services.
|
||||
|
||||
Examples:
|
||||
|
||||
* Gitea → PostgreSQL
|
||||
* OpenProject → PostgreSQL
|
||||
|
||||
---
|
||||
|
||||
### proxy
|
||||
|
||||
Purpose:
|
||||
|
||||
Public-facing services behind Nginx Proxy Manager.
|
||||
|
||||
Examples:
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Jitsi Meet
|
||||
* Portainer
|
||||
* DbGate
|
||||
|
||||
---
|
||||
|
||||
### jitsi-docker-jitsi-meet-aa76415_meet.jitsi
|
||||
|
||||
Purpose:
|
||||
|
||||
Isolated Jitsi communication cluster.
|
||||
|
||||
Examples:
|
||||
|
||||
* jitsi-web
|
||||
* jitsi-jvb
|
||||
* jitsi-jicofo
|
||||
* jitsi-prosody
|
||||
|
||||
---
|
||||
|
||||
### xray_default
|
||||
|
||||
Purpose:
|
||||
|
||||
Compose-created tunneling and connectivity network for Xray.
|
||||
|
||||
Examples:
|
||||
|
||||
* No running containers were attached in the 2026-06-24 runtime snapshot
|
||||
|
||||
---
|
||||
|
||||
### gitea-runner_default
|
||||
|
||||
Purpose:
|
||||
|
||||
Default Compose network for the Gitea Actions runner stack.
|
||||
|
||||
Examples:
|
||||
|
||||
* gitea-runner
|
||||
|
||||
---
|
||||
|
||||
## Running Services
|
||||
|
||||
* PostgreSQL
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Jitsi Meet
|
||||
* Portainer
|
||||
* Nginx Proxy Manager
|
||||
* BaGet
|
||||
* Gitea Actions Runner
|
||||
* Microsoft SQL Server 2022 Express
|
||||
* DbGate
|
||||
* Xray
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* Sentry
|
||||
* Nextcloud
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
### Docker Services
|
||||
|
||||
```text
|
||||
/srv/docker
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
```text
|
||||
/srv/docker/gitea
|
||||
/srv/docker/openproject
|
||||
/srv/docker/postgres
|
||||
/srv/docker/jitsi
|
||||
/srv/docker/portainer
|
||||
/srv/docker/nginx-proxy-manager
|
||||
/srv/docker/baget
|
||||
/srv/docker/gitea-runner
|
||||
/srv/docker/mssql
|
||||
/srv/docker/dbgate
|
||||
/srv/docker/xray
|
||||
/srv/docker/monitoring
|
||||
/srv/docker/nextcloud
|
||||
/srv/docker/sentry
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Shared Secrets
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* SMTP credentials
|
||||
* Database passwords
|
||||
* Application secrets
|
||||
* MSSQL SA password
|
||||
* DbGate password
|
||||
* 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
|
||||
|
||||
```text
|
||||
/srv/backups
|
||||
```
|
||||
|
||||
Suggested structure:
|
||||
|
||||
```text
|
||||
/srv/backups/daily
|
||||
/srv/backups/weekly
|
||||
/srv/backups/monthly
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service Data Locations
|
||||
|
||||
### Gitea
|
||||
|
||||
```text
|
||||
/srv/docker/gitea/data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### OpenProject
|
||||
|
||||
```text
|
||||
/srv/docker/openproject/assets
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
```text
|
||||
/srv/docker/postgres/data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Microsoft SQL Server Express
|
||||
|
||||
```text
|
||||
/srv/docker/mssql/data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### DbGate
|
||||
|
||||
```text
|
||||
/srv/docker/dbgate/data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Nginx Proxy Manager
|
||||
|
||||
```text
|
||||
/srv/docker/nginx-proxy-manager/data
|
||||
/srv/docker/nginx-proxy-manager/letsencrypt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Jitsi
|
||||
|
||||
```text
|
||||
/srv/docker/jitsi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### BaGet
|
||||
|
||||
```text
|
||||
/srv/docker/baget/data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Gitea Actions Runner
|
||||
|
||||
```text
|
||||
/srv/docker/gitea-runner
|
||||
```
|
||||
|
||||
Runner:
|
||||
|
||||
```text
|
||||
silverlinux-runner
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Xray
|
||||
|
||||
```text
|
||||
/srv/docker/xray
|
||||
```
|
||||
|
||||
Network:
|
||||
|
||||
```text
|
||||
proxy
|
||||
```
|
||||
|
||||
Published port:
|
||||
|
||||
```text
|
||||
0.0.0.0:32443 -> 8080/tcp
|
||||
```
|
||||
|
||||
Image:
|
||||
|
||||
```text
|
||||
ghcr.io/xtls/xray-core:latest
|
||||
```
|
||||
|
||||
Runtime note:
|
||||
|
||||
The `xray_default` network exists, but the running `xray` container was attached only to `proxy` in the 2026-06-24 runtime snapshot.
|
||||
|
||||
---
|
||||
|
||||
### 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
|
||||
|
||||
```text
|
||||
/srv/docker/monitoring
|
||||
```
|
||||
|
||||
Components:
|
||||
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
|
||||
Validated:
|
||||
|
||||
* Prometheus targets
|
||||
* Grafana Prometheus datasource
|
||||
* Backup metrics
|
||||
* Host metrics
|
||||
* Docker metrics
|
||||
|
||||
---
|
||||
|
||||
## SSH Access
|
||||
|
||||
Primary user:
|
||||
|
||||
```text
|
||||
ubuntu
|
||||
```
|
||||
|
||||
Authentication:
|
||||
|
||||
* SSH key authentication
|
||||
* Root login disabled
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
Implemented:
|
||||
|
||||
* UFW enabled
|
||||
* Fail2Ban enabled
|
||||
* Shared secrets stored outside Git repositories
|
||||
* SSL certificates managed through Nginx Proxy Manager
|
||||
* PostgreSQL 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
|
||||
* Xray is not attached to the private database network and is monitored as a tunneling endpoint
|
||||
* OpenID disabled in Gitea
|
||||
|
||||
---
|
||||
|
||||
## Email
|
||||
|
||||
Sender address:
|
||||
|
||||
```text
|
||||
noreply@silveressence.net
|
||||
```
|
||||
|
||||
SMTP credentials are stored in:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Used by:
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Nextcloud
|
||||
|
||||
---
|
||||
|
||||
## Disaster Recovery
|
||||
|
||||
This repository should contain enough information to rebuild the SilverLinux environment from scratch.
|
||||
|
||||
Recovery priorities:
|
||||
|
||||
1. Restore secrets
|
||||
2. Restore PostgreSQL
|
||||
3. Restore Nginx Proxy Manager
|
||||
4. Restore Gitea
|
||||
5. Restore OpenProject
|
||||
6. Restore remaining services
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/secrets.md
|
||||
* docs/security.md
|
||||
* docs/backups.md
|
||||
* docs/services.md
|
||||
* docs/network.md
|
||||
* docs/domains.md
|
||||
@@ -0,0 +1,855 @@
|
||||
# Services
|
||||
|
||||
## Overview
|
||||
|
||||
This document lists all services running on SilverLinux and their purpose.
|
||||
|
||||
Generated state reference:
|
||||
|
||||
```text
|
||||
2026-06-25 infrastructure review
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running Services
|
||||
|
||||
### PostgreSQL
|
||||
|
||||
Purpose:
|
||||
|
||||
* Primary shared database platform
|
||||
* Application data storage
|
||||
|
||||
Used by:
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Microsoft SQL Server Express
|
||||
|
||||
Purpose:
|
||||
|
||||
* Secondary database platform for SQL Server compatibility
|
||||
* Support future applications requiring Microsoft SQL Server
|
||||
* Extend the platform beyond PostgreSQL-only workloads
|
||||
|
||||
Image:
|
||||
|
||||
```text
|
||||
mcr.microsoft.com/mssql/server:2022-latest
|
||||
```
|
||||
|
||||
Network:
|
||||
|
||||
```text
|
||||
internal
|
||||
```
|
||||
|
||||
Exposure:
|
||||
|
||||
* Port 1433 is not published
|
||||
* Not routed through Nginx Proxy Manager
|
||||
* Private database access only
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Gitea
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://git.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Source control
|
||||
* Git repositories
|
||||
* Pull requests
|
||||
* Issue tracking
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### OpenProject
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://team.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Project management
|
||||
* Work packages
|
||||
* Time tracking
|
||||
* Team collaboration
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Jitsi Meet
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://meet.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Video conferencing
|
||||
* Team meetings
|
||||
* Customer meetings
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Portainer
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://portainer.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Docker administration
|
||||
* Stack deployment
|
||||
* Container monitoring
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Nginx Proxy Manager
|
||||
|
||||
Purpose:
|
||||
|
||||
* Reverse proxy
|
||||
* SSL termination
|
||||
* Domain routing
|
||||
* Certificate management
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Prometheus
|
||||
|
||||
Purpose:
|
||||
|
||||
* Metrics collection
|
||||
* Alert rule engine
|
||||
* Monitoring data storage
|
||||
* Scrape targets for system, Docker and backup metrics
|
||||
|
||||
Scrapes:
|
||||
|
||||
* Prometheus
|
||||
* Node Exporter
|
||||
* cAdvisor
|
||||
* SilverLinux backup metrics
|
||||
|
||||
Alert categories:
|
||||
|
||||
* Backup
|
||||
* System pressure
|
||||
* Monitoring health
|
||||
* Database availability
|
||||
* Container health
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Grafana
|
||||
|
||||
Purpose:
|
||||
|
||||
* Monitoring dashboards
|
||||
* Metrics visualization
|
||||
* Prometheus datasource frontend
|
||||
|
||||
Dashboards:
|
||||
|
||||
* Custom backup dashboard
|
||||
* Custom system dashboard
|
||||
* Docker monitoring dashboard
|
||||
|
||||
Note:
|
||||
|
||||
The imported Prometheus 2.0 Overview dashboard is not compatible with the installed Prometheus version `3.5.4`. This is a third-party dashboard compatibility issue, not an infrastructure problem.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Alertmanager
|
||||
|
||||
Purpose:
|
||||
|
||||
* Alert routing
|
||||
* Email notifications
|
||||
* Incident grouping
|
||||
* Alert deduplication
|
||||
* Severity-based routing
|
||||
|
||||
Recipients:
|
||||
|
||||
* `oclick021@gmail.com`
|
||||
* `martin@silversolutions.nl`
|
||||
|
||||
Incident groups:
|
||||
|
||||
* `backup_failure`
|
||||
* `system_pressure`
|
||||
* `storage_pressure`
|
||||
* `database_outage`
|
||||
* `monitoring_failure`
|
||||
* `container_health`
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Node Exporter
|
||||
|
||||
Purpose:
|
||||
|
||||
* Host metrics collection
|
||||
* CPU, memory and disk metrics
|
||||
* Textfile Collector endpoint for SilverLinux backup metrics
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### cAdvisor
|
||||
|
||||
Purpose:
|
||||
|
||||
* Docker container metrics
|
||||
* Container CPU, memory and runtime visibility
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### BaGet
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://nuget.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Private NuGet repository
|
||||
* Internal Silver.* package distribution
|
||||
* Package source for CI/CD
|
||||
* Package source for team development
|
||||
|
||||
Access:
|
||||
|
||||
* Routed through Nginx Proxy Manager
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Gitea Actions Runner
|
||||
|
||||
Location:
|
||||
|
||||
```text
|
||||
/srv/docker/gitea-runner
|
||||
```
|
||||
|
||||
Image:
|
||||
|
||||
```text
|
||||
gitea/act_runner:latest
|
||||
```
|
||||
|
||||
Runner Name:
|
||||
|
||||
```text
|
||||
silverlinux-runner
|
||||
```
|
||||
|
||||
Type:
|
||||
|
||||
```text
|
||||
Global Runner
|
||||
```
|
||||
|
||||
Labels:
|
||||
|
||||
* `ubuntu-latest`
|
||||
* `ubuntu-24.04`
|
||||
* `ubuntu-22.04`
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://dbgate.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Browser-based PostgreSQL administration
|
||||
* Browser-based MSSQL administration
|
||||
* Database explorer and debugging interface
|
||||
|
||||
Networks:
|
||||
|
||||
* `internal` for private database connectivity
|
||||
* `proxy` for Nginx Proxy Manager
|
||||
|
||||
Security:
|
||||
|
||||
* Publicly reachable through the proxy layer
|
||||
* HTTPS enforced
|
||||
* DbGate username and password required
|
||||
* Authentication must remain hardened and periodically verified
|
||||
* Database ports remain private
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Nextcloud
|
||||
|
||||
URL:
|
||||
|
||||
```text
|
||||
https://cloud.silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Private cloud storage
|
||||
* File sharing
|
||||
* 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:
|
||||
|
||||
```text
|
||||
Primary production connectivity layer
|
||||
```
|
||||
|
||||
Networks:
|
||||
|
||||
* `proxy`
|
||||
|
||||
Runtime ports:
|
||||
|
||||
```text
|
||||
0.0.0.0:32443 -> 8080/tcp
|
||||
```
|
||||
|
||||
Image:
|
||||
|
||||
```text
|
||||
ghcr.io/xtls/xray-core:latest
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
Security:
|
||||
|
||||
* Public tunneling endpoint exposure must be monitored
|
||||
* Access policy and abuse monitoring must be reviewed regularly
|
||||
* Not classified as an application backend service
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
### Docker
|
||||
|
||||
Purpose:
|
||||
|
||||
* Container hosting
|
||||
* Service isolation
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Internal Docker Network
|
||||
|
||||
Purpose:
|
||||
|
||||
* Private communication between services
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Proxy Docker Network
|
||||
|
||||
Purpose:
|
||||
|
||||
* HTTP and HTTPS service exposure through Nginx Proxy Manager
|
||||
* Shared public routing layer for web-facing services
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Isolated Docker Networks
|
||||
|
||||
Purpose:
|
||||
|
||||
* Keep specialized infrastructure stacks isolated from application backends
|
||||
* Separate Jitsi, Xray and CI/CD runner traffic from shared database traffic
|
||||
|
||||
Networks:
|
||||
|
||||
* `jitsi-docker-jitsi-meet-aa76415_meet.jitsi`
|
||||
* `xray_default`
|
||||
* `gitea-runner_default`
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Running
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Shared Secrets
|
||||
|
||||
Source:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* SMTP credentials
|
||||
* Database passwords
|
||||
* Application secrets
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
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
|
||||
|
||||
## Planned Services
|
||||
|
||||
See:
|
||||
|
||||
```text
|
||||
docs/roadmap.md
|
||||
```
|
||||
|
||||
Phase 1:
|
||||
|
||||
* Loki
|
||||
* Redis
|
||||
* Authelia
|
||||
|
||||
Phase 2:
|
||||
|
||||
* CrowdSec
|
||||
* Restic
|
||||
* Fail2Ban upgrade
|
||||
* Cloudflare rate limiting and WAF
|
||||
|
||||
Phase 3:
|
||||
|
||||
* SonarQube
|
||||
* Harbor
|
||||
* Backstage
|
||||
|
||||
---
|
||||
|
||||
### Plane.so
|
||||
|
||||
Reason:
|
||||
|
||||
OpenProject was selected as the primary project management platform. Plane.so is not used and will not be used.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Removed
|
||||
```
|
||||
|
||||
Cleanup:
|
||||
|
||||
* Containers removed
|
||||
* Nginx Proxy Manager route removed
|
||||
* Unused SSL certificate removed from the server
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/network.md
|
||||
* docs/roadmap.md
|
||||
* docs/monitoring.md
|
||||
* docs/domains.md
|
||||
* docs/security.md
|
||||
* docs/backups.md
|
||||
@@ -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
|
||||
@@ -0,0 +1,30 @@
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
USER_UID: 1000
|
||||
USER_GID: 1000
|
||||
GITEA__database__DB_TYPE: postgres
|
||||
GITEA__database__HOST: postgres:5432
|
||||
GITEA__database__NAME: gitea
|
||||
GITEA__database__USER: postgres
|
||||
GITEA__database__PASSWD: Saeed123!
|
||||
GITEA__server__DOMAIN: git.silveressence.net
|
||||
GITEA__server__ROOT_URL: https://git.silveressence.net/
|
||||
GITEA__server__SSH_DOMAIN: git.silveressence.net
|
||||
GITEA__server__SSH_PORT: 2222
|
||||
volumes:
|
||||
- /srv/docker/gitea/data:/data
|
||||
ports:
|
||||
- "2222:22"
|
||||
networks:
|
||||
- proxy
|
||||
- internal
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
internal:
|
||||
external: true
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
# Gitea
|
||||
|
||||
## Overview
|
||||
|
||||
Gitea is the self-hosted Git platform used by Silver Solutions.
|
||||
|
||||
It provides:
|
||||
|
||||
* Git repository hosting
|
||||
* Pull requests
|
||||
* Issue tracking
|
||||
* Wiki support
|
||||
* Releases
|
||||
* CI/CD integration
|
||||
* Package registry support
|
||||
|
||||
Gitea serves as the central source control platform for SilverLinux infrastructure and application development.
|
||||
|
||||
---
|
||||
|
||||
## Service Information
|
||||
|
||||
### URL
|
||||
|
||||
```text
|
||||
https://git.silveressence.net
|
||||
```
|
||||
|
||||
### Container Name
|
||||
|
||||
```text
|
||||
gitea
|
||||
```
|
||||
|
||||
### Image
|
||||
|
||||
```text
|
||||
gitea/gitea:latest
|
||||
```
|
||||
|
||||
### Docker Networks
|
||||
|
||||
```text
|
||||
proxy
|
||||
internal
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Gitea is used for:
|
||||
|
||||
* Source control
|
||||
* Infrastructure repositories
|
||||
* Application repositories
|
||||
* Pull requests
|
||||
* Issue management
|
||||
* Release management
|
||||
* Gitea Actions CI/CD pipelines
|
||||
|
||||
---
|
||||
|
||||
## Database
|
||||
|
||||
Database:
|
||||
|
||||
```text
|
||||
gitea
|
||||
```
|
||||
|
||||
Database Host:
|
||||
|
||||
```text
|
||||
postgres
|
||||
```
|
||||
|
||||
Database User:
|
||||
|
||||
```text
|
||||
postgres
|
||||
```
|
||||
|
||||
Current password source:
|
||||
|
||||
```text
|
||||
POSTGRES_ROOT_PASSWORD
|
||||
```
|
||||
|
||||
Stored in:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Future improvement:
|
||||
|
||||
Create a dedicated Gitea database user and password.
|
||||
|
||||
---
|
||||
|
||||
## Email Configuration
|
||||
|
||||
Sender Address:
|
||||
|
||||
```text
|
||||
noreply@silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Password reset emails
|
||||
* Account notifications
|
||||
* Repository notifications
|
||||
* User invitations
|
||||
|
||||
SMTP secrets are provided by Infisical at runtime.
|
||||
|
||||
These values are resolved during deployment by `infisical run`.
|
||||
|
||||
Variables:
|
||||
|
||||
```text
|
||||
SMTP_HOST
|
||||
SMTP_PORT
|
||||
SMTP_USERNAME
|
||||
SMTP_PASSWORD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
### Current
|
||||
|
||||
* Local user accounts
|
||||
* Email login
|
||||
* Password login
|
||||
|
||||
### Disabled
|
||||
|
||||
OpenID authentication is disabled.
|
||||
|
||||
Reason:
|
||||
|
||||
OpenID is not required and increases the attack surface.
|
||||
|
||||
### Planned
|
||||
|
||||
Future authentication providers:
|
||||
|
||||
* Google OAuth2
|
||||
* GitHub OAuth2
|
||||
|
||||
Purpose:
|
||||
|
||||
* Easier onboarding of freelancers
|
||||
* Easier onboarding of external collaborators
|
||||
* Reduced password management
|
||||
|
||||
---
|
||||
|
||||
## SSH Access
|
||||
|
||||
SSH Domain:
|
||||
|
||||
```text
|
||||
git.silveressence.net
|
||||
```
|
||||
|
||||
SSH Port:
|
||||
|
||||
```text
|
||||
2222
|
||||
```
|
||||
|
||||
Clone example:
|
||||
|
||||
```bash
|
||||
git clone ssh://git@git.silveressence.net:2222/username/repository.git
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Storage
|
||||
|
||||
Application Data:
|
||||
|
||||
```text
|
||||
/srv/docker/gitea/data
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Repositories
|
||||
* Attachments
|
||||
* Configuration
|
||||
* Actions data
|
||||
* Package registry data
|
||||
* User information
|
||||
|
||||
This directory is critical and must be included in backups.
|
||||
|
||||
---
|
||||
|
||||
## Gitea Actions
|
||||
|
||||
Gitea Actions is enabled in `app.ini` and available globally.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
### Global Runner
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Location | `/srv/docker/gitea-runner` |
|
||||
| Image | `gitea/act_runner:latest` |
|
||||
| Name | `silverlinux-runner` |
|
||||
| Type | Global Runner |
|
||||
| Status | Operational |
|
||||
|
||||
Labels:
|
||||
|
||||
* `ubuntu-latest`
|
||||
* `ubuntu-24.04`
|
||||
* `ubuntu-22.04`
|
||||
|
||||
The runner registration token is loaded from `GITEA_RUNNER_REGISTRATION_TOKEN` in Infisical through `slcompose`.
|
||||
|
||||
### Package Publishing
|
||||
|
||||
Silver 2.0 uses `.gitea/workflows/package.yml` to build and publish NuGet packages to BaGet. A push to `net-8-version` triggers packaging when the commit message contains `[Package]`.
|
||||
|
||||
The publishing credential is stored as the repository Actions secret `BAGET_API_KEY`.
|
||||
|
||||
---
|
||||
|
||||
## Secrets
|
||||
|
||||
Gitea and its Actions runner use infrastructure secrets stored in:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Variables:
|
||||
|
||||
```text
|
||||
POSTGRES_ROOT_PASSWORD
|
||||
|
||||
SMTP_HOST
|
||||
SMTP_PORT
|
||||
SMTP_USERNAME
|
||||
SMTP_PASSWORD
|
||||
|
||||
GITEA_RUNNER_REGISTRATION_TOKEN
|
||||
```
|
||||
|
||||
The Gitea container uses the database and SMTP variables. The Actions runner uses `GITEA_RUNNER_REGISTRATION_TOKEN`.
|
||||
|
||||
Future variables:
|
||||
|
||||
```text
|
||||
GOOGLE_CLIENT_ID
|
||||
GOOGLE_CLIENT_SECRET
|
||||
|
||||
GITHUB_CLIENT_ID
|
||||
GITHUB_CLIENT_SECRET
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Docker Configuration
|
||||
|
||||
Volume Mapping:
|
||||
|
||||
```text
|
||||
/srv/docker/gitea/data:/data
|
||||
```
|
||||
|
||||
Port Mapping:
|
||||
|
||||
```text
|
||||
2222:22
|
||||
```
|
||||
|
||||
Networks:
|
||||
|
||||
```text
|
||||
proxy
|
||||
internal
|
||||
```
|
||||
|
||||
HTTP traffic is routed through Nginx Proxy Manager.
|
||||
|
||||
---
|
||||
|
||||
## Administration
|
||||
|
||||
View Logs:
|
||||
|
||||
```bash
|
||||
docker logs gitea
|
||||
```
|
||||
|
||||
Restart Service:
|
||||
|
||||
```bash
|
||||
docker restart gitea
|
||||
```
|
||||
|
||||
Open Shell:
|
||||
|
||||
```bash
|
||||
docker exec -it gitea bash
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Requirements
|
||||
|
||||
The following items must be backed up:
|
||||
|
||||
### Database
|
||||
|
||||
```text
|
||||
gitea
|
||||
```
|
||||
|
||||
### Application Data
|
||||
|
||||
```text
|
||||
/srv/docker/gitea/data
|
||||
```
|
||||
|
||||
### Secrets
|
||||
|
||||
```text
|
||||
Infisical service paths for Gitea and the Gitea runner
|
||||
```
|
||||
|
||||
Without these items, a complete restoration is not possible.
|
||||
|
||||
---
|
||||
|
||||
## Recovery Checklist
|
||||
|
||||
To restore Gitea:
|
||||
|
||||
1. Restore PostgreSQL database.
|
||||
2. Restore Gitea data directory.
|
||||
3. Restore or reauthorize Infisical access and service secret paths.
|
||||
4. Deploy Docker Compose stack.
|
||||
5. Verify SMTP configuration.
|
||||
6. Verify SSH access.
|
||||
7. Verify access through Nginx Proxy Manager.
|
||||
|
||||
---
|
||||
|
||||
## Future Roadmap
|
||||
|
||||
### Short Term
|
||||
|
||||
* Enable 2FA for administrator accounts
|
||||
* Configure backup automation
|
||||
* Configure Google OAuth2
|
||||
* Configure GitHub OAuth2
|
||||
|
||||
### Long Term
|
||||
|
||||
* Deploy applications directly from Gitea
|
||||
* Expand package publishing to additional repositories
|
||||
|
||||
---
|
||||
|
||||
## Related Services
|
||||
|
||||
* PostgreSQL
|
||||
* Nginx Proxy Manager
|
||||
* OpenProject
|
||||
* Portainer
|
||||
* BaGet
|
||||
* Gitea Actions Runner
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/security.md
|
||||
* docs/secrets.md
|
||||
* docs/backups.md
|
||||
* postgres/README.md
|
||||
* docs/cicd.md
|
||||
@@ -0,0 +1,30 @@
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
USER_UID: 1000
|
||||
USER_GID: 1000
|
||||
GITEA__database__DB_TYPE: postgres
|
||||
GITEA__database__HOST: postgres:5432
|
||||
GITEA__database__NAME: gitea
|
||||
GITEA__database__USER: postgres
|
||||
GITEA__database__PASSWD: Saeed123!
|
||||
GITEA__server__DOMAIN: git.silveressence.net
|
||||
GITEA__server__ROOT_URL: https://git.silveressence.net/
|
||||
GITEA__server__SSH_DOMAIN: git.silveressence.net
|
||||
GITEA__server__SSH_PORT: 2222
|
||||
volumes:
|
||||
- /srv/docker/gitea/data:/data
|
||||
ports:
|
||||
- "2222:22"
|
||||
networks:
|
||||
- proxy
|
||||
- internal
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
internal:
|
||||
external: true
|
||||
@@ -0,0 +1,19 @@
|
||||
PUBLIC_URL=https://meet.silveressence.net
|
||||
|
||||
HTTP_PORT=8000
|
||||
HTTPS_PORT=8443
|
||||
|
||||
TZ=Europe/Amsterdam
|
||||
|
||||
ENABLE_AUTH=1
|
||||
ENABLE_GUESTS=1
|
||||
AUTH_TYPE=internal
|
||||
|
||||
JVB_ADVERTISE_IPS=51.255.83.140
|
||||
|
||||
JICOFO_AUTH_PASSWORD=
|
||||
JVB_AUTH_PASSWORD=
|
||||
JIBRI_XMPP_PASSWORD=
|
||||
JIBRI_RECORDER_PASSWORD=
|
||||
JIGASI_XMPP_PASSWORD=
|
||||
JIGASI_TRANSCRIBER_PASSWORD=
|
||||
@@ -0,0 +1,74 @@
|
||||
# Jitsi Meet
|
||||
|
||||
## Overview
|
||||
|
||||
Jitsi Meet provides video conferencing capabilities for Silver Solutions.
|
||||
|
||||
URL:
|
||||
|
||||
https://meet.silveressence.net
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
- Team meetings
|
||||
- Customer meetings
|
||||
- Screen sharing
|
||||
- Browser-based conferencing
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
Current configuration:
|
||||
|
||||
- Internal authentication enabled
|
||||
- Guest access enabled
|
||||
|
||||
Configuration stored in:
|
||||
|
||||
/srv/docker/jitsi/jitsi-docker-jitsi-meet-aa76415/.env
|
||||
|
||||
---
|
||||
|
||||
## Important Secrets
|
||||
|
||||
Stored in:
|
||||
|
||||
Infisical
|
||||
|
||||
Variables:
|
||||
|
||||
- JICOFO_AUTH_PASSWORD
|
||||
- JVB_AUTH_PASSWORD
|
||||
- JIBRI_XMPP_PASSWORD
|
||||
- JIBRI_RECORDER_PASSWORD
|
||||
- JIGASI_XMPP_PASSWORD
|
||||
- JIGASI_TRANSCRIBER_PASSWORD
|
||||
|
||||
---
|
||||
|
||||
## Ports
|
||||
|
||||
| Port | Purpose |
|
||||
|--------|---------|
|
||||
| 80 | HTTP |
|
||||
| 443 | HTTPS |
|
||||
| 10000/UDP | Media Traffic |
|
||||
|
||||
---
|
||||
|
||||
## Data Location
|
||||
|
||||
Configuration:
|
||||
|
||||
/srv/docker/jitsi
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- docs/server.md
|
||||
- docs/security.md
|
||||
- docs/secrets.md
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
# Microsoft SQL Server Express
|
||||
|
||||
## Overview
|
||||
|
||||
Microsoft SQL Server 2022 Express runs alongside PostgreSQL for Silver projects that require Microsoft SQL Server compatibility.
|
||||
|
||||
Status:
|
||||
|
||||
```text
|
||||
Operational
|
||||
```
|
||||
|
||||
Verified version:
|
||||
|
||||
```text
|
||||
Microsoft SQL Server 2022 Express Edition (64-bit)
|
||||
Linux
|
||||
Version 16.0.4255.1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Service Information
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Container | `mssql` |
|
||||
| Image | `mcr.microsoft.com/mssql/server:2022-latest` |
|
||||
| Edition | Express |
|
||||
| Docker network | `internal` |
|
||||
| Compose location | `/srv/docker/mssql/docker-compose.yml` |
|
||||
| Data location | `/srv/docker/mssql/data` |
|
||||
|
||||
Port `1433` is not published by Docker or exposed through Nginx Proxy Manager. Applications connect privately over the `internal` Docker network using hostname `mssql`.
|
||||
|
||||
Server-side administration must use `docker exec` or another container attached to `internal`; there is no host-bound SQL port in the current configuration.
|
||||
|
||||
---
|
||||
|
||||
## Secrets
|
||||
|
||||
The SA password is provided by Infisical at runtime:
|
||||
|
||||
```text
|
||||
MSSQL_SA_PASSWORD
|
||||
```
|
||||
|
||||
Never commit the value to Git or place it directly in the Compose file.
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
The stack is deployed with Infisical injection instead of a local secrets file:
|
||||
|
||||
```bash
|
||||
slcompose up mssql
|
||||
```
|
||||
|
||||
Secrets are injected into the environment before Docker Compose evaluates variables such as `${MSSQL_SA_PASSWORD}`.
|
||||
|
||||
Validate startup:
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
docker logs mssql
|
||||
```
|
||||
|
||||
Expected log message:
|
||||
|
||||
```text
|
||||
SQL Server is now ready for client connections.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Data Directory Permissions
|
||||
|
||||
The SQL Server container runs as UID and GID `10001`. For a new, empty deployment, initialize the bind-mounted directory with:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /srv/docker/mssql/data
|
||||
sudo chown -R 10001:10001 /srv/docker/mssql/data
|
||||
sudo chmod -R 700 /srv/docker/mssql/data
|
||||
```
|
||||
|
||||
Do not delete or recreate the directory after databases exist. Removing `/srv/docker/mssql/data` destroys the persisted SQL Server data.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Variable Is Not Set
|
||||
|
||||
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
|
||||
|
||||
If `[/.system]` cannot be created, verify that `/srv/docker/mssql/data` is owned by `10001:10001` with mode `700`.
|
||||
|
||||
### Password Validation Failed
|
||||
|
||||
Confirm that the password meets SQL Server complexity requirements and that Compose resolved `MSSQL_SA_PASSWORD` from Infisical.
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/services.md
|
||||
* docs/security.md
|
||||
* docs/secrets.md
|
||||
* docs/backups.md
|
||||
* dbgate/README.md
|
||||
* postgres/README.md
|
||||
@@ -0,0 +1,18 @@
|
||||
services:
|
||||
mssql:
|
||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||
container_name: mssql
|
||||
restart: unless-stopped
|
||||
# Secrets are injected by Infisical at runtime.
|
||||
environment:
|
||||
ACCEPT_EULA: Y
|
||||
MSSQL_PID: Express
|
||||
MSSQL_SA_PASSWORD: ''
|
||||
volumes:
|
||||
- /srv/docker/mssql/data:/var/opt/mssql
|
||||
networks:
|
||||
- internal
|
||||
|
||||
networks:
|
||||
internal:
|
||||
external: true
|
||||
@@ -0,0 +1,208 @@
|
||||
# Nginx Proxy Manager
|
||||
|
||||
## Overview
|
||||
|
||||
Nginx Proxy Manager (NPM) is the public entry point for all internet-facing services hosted on SilverLinux.
|
||||
|
||||
It provides:
|
||||
|
||||
* Reverse proxy routing
|
||||
* SSL certificate management
|
||||
* HTTPS termination
|
||||
* Domain forwarding
|
||||
* Centralized access to services
|
||||
|
||||
All public services should be exposed through Nginx Proxy Manager instead of directly exposing application ports.
|
||||
|
||||
---
|
||||
|
||||
## Service Information
|
||||
|
||||
Container Name:
|
||||
|
||||
```text
|
||||
nginx-proxy-manager
|
||||
```
|
||||
|
||||
Image:
|
||||
|
||||
```text
|
||||
jc21/nginx-proxy-manager:latest
|
||||
```
|
||||
|
||||
Docker Network:
|
||||
|
||||
```text
|
||||
proxy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Ports
|
||||
|
||||
| Port | Purpose |
|
||||
| ---- | ---------------------------------- |
|
||||
| 80 | HTTP |
|
||||
| 81 | Nginx Proxy Manager Administration |
|
||||
| 443 | HTTPS |
|
||||
|
||||
---
|
||||
|
||||
## Data Storage
|
||||
|
||||
### Application Data
|
||||
|
||||
```text
|
||||
/srv/docker/nginx-proxy-manager/data
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Proxy host configuration
|
||||
* Access lists
|
||||
* Users
|
||||
* Application settings
|
||||
* SSL metadata
|
||||
|
||||
---
|
||||
|
||||
### SSL Certificates
|
||||
|
||||
```text
|
||||
/srv/docker/nginx-proxy-manager/letsencrypt
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Let's Encrypt certificates
|
||||
* Private keys
|
||||
* Renewal information
|
||||
|
||||
This folder is critical for disaster recovery.
|
||||
|
||||
---
|
||||
|
||||
## Responsibilities
|
||||
|
||||
Nginx Proxy Manager is responsible for:
|
||||
|
||||
### Reverse Proxy
|
||||
|
||||
Routing incoming requests to Docker containers.
|
||||
|
||||
Examples:
|
||||
|
||||
| Domain | Target Service |
|
||||
| --------------------------- | -------------- |
|
||||
| git.silveressence.net | Gitea |
|
||||
| team.silveressence.net | OpenProject |
|
||||
| meet.silveressence.net | Jitsi |
|
||||
| portainer.silveressence.net | Portainer |
|
||||
| nuget.silveressence.net | BaGet |
|
||||
| dbgate.silveressence.net | DbGate |
|
||||
|
||||
---
|
||||
|
||||
### SSL Certificates
|
||||
|
||||
Provides:
|
||||
|
||||
* HTTPS encryption
|
||||
* Certificate renewal
|
||||
* Certificate management
|
||||
|
||||
All public services should use HTTPS.
|
||||
|
||||
---
|
||||
|
||||
### Domain Management
|
||||
|
||||
Centralized management for:
|
||||
|
||||
* Domains
|
||||
* Subdomains
|
||||
* SSL certificates
|
||||
* Proxy routing
|
||||
|
||||
---
|
||||
|
||||
## Docker Configuration
|
||||
|
||||
Volumes:
|
||||
|
||||
```text
|
||||
/srv/docker/nginx-proxy-manager/data:/data
|
||||
/srv/docker/nginx-proxy-manager/letsencrypt:/etc/letsencrypt
|
||||
```
|
||||
|
||||
Network:
|
||||
|
||||
```text
|
||||
proxy
|
||||
```
|
||||
|
||||
Applications exposed through NPM must be connected to the proxy network.
|
||||
|
||||
---
|
||||
|
||||
## Administration
|
||||
|
||||
Web Interface:
|
||||
|
||||
```text
|
||||
https://portainer.silveressence.net
|
||||
```
|
||||
|
||||
Nginx Proxy Manager Admin:
|
||||
|
||||
```text
|
||||
http://SERVER-IP:81
|
||||
```
|
||||
|
||||
or through the configured domain if one exists.
|
||||
|
||||
---
|
||||
|
||||
## Backup Requirements
|
||||
|
||||
The following directories must be backed up:
|
||||
|
||||
```text
|
||||
/srv/docker/nginx-proxy-manager/data
|
||||
/srv/docker/nginx-proxy-manager/letsencrypt
|
||||
```
|
||||
|
||||
Without these directories:
|
||||
|
||||
* SSL certificates are lost
|
||||
* Proxy configurations are lost
|
||||
* Domain mappings must be recreated
|
||||
|
||||
---
|
||||
|
||||
## Security Notes
|
||||
|
||||
* Only ports 80 and 443 should be exposed publicly.
|
||||
* Administrative access should be restricted.
|
||||
* SSL certificates should be renewed automatically.
|
||||
* Services should never be exposed directly to the internet when NPM can proxy them.
|
||||
|
||||
---
|
||||
|
||||
## Related Services
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Jitsi Meet
|
||||
* Portainer
|
||||
* BaGet
|
||||
* DbGate
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/security.md
|
||||
* docs/domains.md
|
||||
* docs/backups.md
|
||||
@@ -0,0 +1,21 @@
|
||||
services:
|
||||
nginx-proxy-manager:
|
||||
image: jc21/nginx-proxy-manager:latest
|
||||
container_name: nginx-proxy-manager
|
||||
restart: unless-stopped
|
||||
|
||||
ports:
|
||||
- "80:80"
|
||||
- "81:81"
|
||||
- "443:443"
|
||||
|
||||
volumes:
|
||||
- /srv/docker/nginx-proxy-manager/data:/data
|
||||
- /srv/docker/nginx-proxy-manager/letsencrypt:/etc/letsencrypt
|
||||
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
@@ -0,0 +1,37 @@
|
||||
services:
|
||||
openproject:
|
||||
image: openproject/openproject:17
|
||||
container_name: openproject
|
||||
restart: unless-stopped
|
||||
|
||||
env_file:
|
||||
- /srv/secrets/company.env
|
||||
|
||||
environment:
|
||||
SECRET_KEY_BASE: ${OPENPROJECT_SECRET_KEY_BASE}
|
||||
OPENPROJECT_HOST__NAME: team.silveressence.net
|
||||
OPENPROJECT_HTTPS: "true"
|
||||
|
||||
DATABASE_URL: postgres://openproject:${POSTGRES_OPENPROJECT_PASSWORD}@postgres:5432/openproject
|
||||
|
||||
OPENPROJECT_EMAIL__DELIVERY__METHOD: smtp
|
||||
OPENPROJECT_SMTP__ADDRESS: ${SMTP_HOST}
|
||||
OPENPROJECT_SMTP__PORT: "${SMTP_PORT}"
|
||||
OPENPROJECT_SMTP__DOMAIN: silveressence.net
|
||||
OPENPROJECT_SMTP__AUTHENTICATION: login
|
||||
OPENPROJECT_SMTP__ENABLE__STARTTLS__AUTO: "true"
|
||||
OPENPROJECT_SMTP__USER__NAME: ${SMTP_USERNAME}
|
||||
OPENPROJECT_SMTP__PASSWORD: ${SMTP_PASSWORD}
|
||||
|
||||
volumes:
|
||||
- /srv/docker/openproject/assets:/var/openproject/assets
|
||||
|
||||
ports:
|
||||
- "8082:80"
|
||||
|
||||
networks:
|
||||
- internal
|
||||
|
||||
networks:
|
||||
internal:
|
||||
external: true
|
||||
@@ -0,0 +1,259 @@
|
||||
# OpenProject
|
||||
|
||||
## Overview
|
||||
|
||||
OpenProject is the project management and collaboration platform used by Silver Solutions.
|
||||
|
||||
It provides:
|
||||
|
||||
* Project management
|
||||
* Task tracking
|
||||
* Work packages
|
||||
* Time tracking
|
||||
* Roadmaps
|
||||
* Team collaboration
|
||||
* Document management
|
||||
|
||||
OpenProject replaces the previously planned Plane.so deployment.
|
||||
|
||||
---
|
||||
|
||||
## Service Information
|
||||
|
||||
### URL
|
||||
|
||||
```text
|
||||
https://team.silveressence.net
|
||||
```
|
||||
|
||||
### Container Name
|
||||
|
||||
```text
|
||||
openproject
|
||||
```
|
||||
|
||||
### Image
|
||||
|
||||
```text
|
||||
openproject/openproject:17
|
||||
```
|
||||
|
||||
### Docker Network
|
||||
|
||||
```text
|
||||
internal
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
OpenProject is used for:
|
||||
|
||||
* Project planning
|
||||
* Task management
|
||||
* Development tracking
|
||||
* Internal collaboration
|
||||
* Customer project management
|
||||
* Team planning
|
||||
|
||||
---
|
||||
|
||||
## Database
|
||||
|
||||
Database:
|
||||
|
||||
```text
|
||||
openproject
|
||||
```
|
||||
|
||||
Database User:
|
||||
|
||||
```text
|
||||
openproject
|
||||
```
|
||||
|
||||
Database Host:
|
||||
|
||||
```text
|
||||
postgres
|
||||
```
|
||||
|
||||
Database access is provided through the internal Docker network.
|
||||
|
||||
---
|
||||
|
||||
## Email Configuration
|
||||
|
||||
Sender Address:
|
||||
|
||||
```text
|
||||
noreply@silveressence.net
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Password reset emails
|
||||
* User notifications
|
||||
* Work package notifications
|
||||
* Mention notifications
|
||||
* Project updates
|
||||
|
||||
SMTP credentials are provided by Infisical at runtime.
|
||||
|
||||
---
|
||||
|
||||
## Data Storage
|
||||
|
||||
Assets Location:
|
||||
|
||||
```text
|
||||
/srv/docker/openproject/assets
|
||||
```
|
||||
|
||||
Contains:
|
||||
|
||||
* Attachments
|
||||
* Uploaded files
|
||||
* Application assets
|
||||
* User generated content
|
||||
|
||||
This directory must be included in backups.
|
||||
|
||||
---
|
||||
|
||||
## Secrets
|
||||
|
||||
The following values are provided by Infisical at runtime when the stack is deployed:
|
||||
|
||||
```text
|
||||
POSTGRES_OPENPROJECT_PASSWORD
|
||||
OPENPROJECT_SECRET_KEY_BASE
|
||||
|
||||
SMTP_HOST
|
||||
SMTP_PORT
|
||||
SMTP_USERNAME
|
||||
SMTP_PASSWORD
|
||||
```
|
||||
|
||||
Secrets must never be committed to Git.
|
||||
|
||||
---
|
||||
|
||||
## Authentication
|
||||
|
||||
Current Authentication:
|
||||
|
||||
* Local accounts
|
||||
|
||||
Future Considerations:
|
||||
|
||||
* Google OAuth2
|
||||
* GitHub OAuth2
|
||||
* Microsoft Entra ID
|
||||
|
||||
---
|
||||
|
||||
## Docker Configuration
|
||||
|
||||
Volume Mapping:
|
||||
|
||||
```text
|
||||
/srv/docker/openproject/assets:/var/openproject/assets
|
||||
```
|
||||
|
||||
Port Mapping:
|
||||
|
||||
```text
|
||||
8082:80
|
||||
```
|
||||
|
||||
Network:
|
||||
|
||||
```text
|
||||
internal
|
||||
```
|
||||
|
||||
OpenProject should not be exposed directly to the internet.
|
||||
|
||||
Access should be routed through Nginx Proxy Manager.
|
||||
|
||||
---
|
||||
|
||||
## Administration
|
||||
|
||||
View Logs:
|
||||
|
||||
```bash
|
||||
docker logs openproject
|
||||
```
|
||||
|
||||
Restart Service:
|
||||
|
||||
```bash
|
||||
docker restart openproject
|
||||
```
|
||||
|
||||
Open Shell:
|
||||
|
||||
```bash
|
||||
docker exec -it openproject bash
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup Requirements
|
||||
|
||||
The following items must be backed up:
|
||||
|
||||
### Database
|
||||
|
||||
```text
|
||||
openproject
|
||||
```
|
||||
|
||||
### Assets
|
||||
|
||||
```text
|
||||
/srv/docker/openproject/assets
|
||||
```
|
||||
|
||||
### Secrets
|
||||
|
||||
```text
|
||||
Infisical service path for OpenProject
|
||||
```
|
||||
|
||||
Without these items, a complete restoration is not possible.
|
||||
|
||||
---
|
||||
|
||||
## Recovery Checklist
|
||||
|
||||
To restore OpenProject:
|
||||
|
||||
1. Restore PostgreSQL database.
|
||||
2. Restore OpenProject assets directory.
|
||||
3. Restore or reauthorize Infisical access and the OpenProject secret path.
|
||||
4. Deploy Docker Compose stack.
|
||||
5. Verify SMTP configuration.
|
||||
6. Verify access through Nginx Proxy Manager.
|
||||
|
||||
---
|
||||
|
||||
## Related Services
|
||||
|
||||
* PostgreSQL
|
||||
* Nginx Proxy Manager
|
||||
* Gitea
|
||||
* Portainer
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/security.md
|
||||
* docs/secrets.md
|
||||
* docs/backups.md
|
||||
* postgres/README.md
|
||||
@@ -0,0 +1,35 @@
|
||||
services:
|
||||
openproject:
|
||||
image: openproject/openproject:17
|
||||
container_name: openproject
|
||||
restart: unless-stopped
|
||||
|
||||
# Secrets are injected by Infisical at runtime.
|
||||
environment:
|
||||
SECRET_KEY_BASE: ${OPENPROJECT_SECRET_KEY_BASE}
|
||||
OPENPROJECT_HOST__NAME: team.silveressence.net
|
||||
OPENPROJECT_HTTPS: "true"
|
||||
|
||||
DATABASE_URL: postgres://openproject:${POSTGRES_OPENPROJECT_PASSWORD}@postgres:5432/openproject
|
||||
|
||||
OPENPROJECT_EMAIL__DELIVERY__METHOD: smtp
|
||||
OPENPROJECT_SMTP__ADDRESS: ${SMTP_HOST}
|
||||
OPENPROJECT_SMTP__PORT: "${SMTP_PORT}"
|
||||
OPENPROJECT_SMTP__DOMAIN: silveressence.net
|
||||
OPENPROJECT_SMTP__AUTHENTICATION: login
|
||||
OPENPROJECT_SMTP__ENABLE__STARTTLS__AUTO: "true"
|
||||
OPENPROJECT_SMTP__USER__NAME: ${SMTP_USERNAME}
|
||||
OPENPROJECT_SMTP__PASSWORD: ${SMTP_PASSWORD}
|
||||
|
||||
volumes:
|
||||
- /srv/docker/openproject/assets:/var/openproject/assets
|
||||
|
||||
ports:
|
||||
- "8082:80"
|
||||
|
||||
networks:
|
||||
- internal
|
||||
|
||||
networks:
|
||||
internal:
|
||||
external: true
|
||||
@@ -0,0 +1,153 @@
|
||||
# Portainer
|
||||
|
||||
## Overview
|
||||
|
||||
Portainer provides a web-based management interface for Docker on SilverLinux.
|
||||
|
||||
It is used to manage containers, networks, volumes, images and Docker stacks through a graphical interface instead of using the command line.
|
||||
|
||||
---
|
||||
|
||||
## Service Information
|
||||
|
||||
### URL
|
||||
|
||||
```text
|
||||
https://portainer.silveressence.net
|
||||
```
|
||||
|
||||
### Container Name
|
||||
|
||||
```text
|
||||
portainer
|
||||
```
|
||||
|
||||
### Image
|
||||
|
||||
```text
|
||||
portainer/portainer-ce:latest
|
||||
```
|
||||
|
||||
### Docker Network
|
||||
|
||||
```text
|
||||
proxy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
Portainer is used for:
|
||||
|
||||
* Managing Docker containers
|
||||
* Managing Docker networks
|
||||
* Managing Docker volumes
|
||||
* Viewing logs
|
||||
* Deploying Docker stacks
|
||||
* Monitoring running services
|
||||
* Performing container maintenance
|
||||
|
||||
---
|
||||
|
||||
## Data Storage
|
||||
|
||||
### Docker Socket
|
||||
|
||||
```text
|
||||
/var/run/docker.sock
|
||||
```
|
||||
|
||||
This allows Portainer to communicate with the Docker engine.
|
||||
|
||||
### Portainer Data
|
||||
|
||||
Docker Volume:
|
||||
|
||||
```text
|
||||
portainer_portainer_data
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* User accounts
|
||||
* Configuration
|
||||
* Stack definitions
|
||||
* Environment settings
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
Portainer has administrative access to Docker.
|
||||
|
||||
Because Portainer uses the Docker socket, users with Portainer administrator access effectively have administrative access to the server.
|
||||
|
||||
Only trusted administrators should have access.
|
||||
|
||||
---
|
||||
|
||||
## Backup Requirements
|
||||
|
||||
The following volume should be included in backups:
|
||||
|
||||
```text
|
||||
portainer_portainer_data
|
||||
```
|
||||
|
||||
Loss of this volume will result in:
|
||||
|
||||
* Loss of Portainer users
|
||||
* Loss of stack definitions
|
||||
* Loss of Portainer configuration
|
||||
|
||||
Docker containers and application data remain unaffected.
|
||||
|
||||
---
|
||||
|
||||
## Network Configuration
|
||||
|
||||
Portainer is connected to the Docker proxy network.
|
||||
|
||||
Applications exposed through Nginx Proxy Manager can communicate with Portainer through this network.
|
||||
|
||||
---
|
||||
|
||||
## Maintenance
|
||||
|
||||
View logs:
|
||||
|
||||
```bash
|
||||
docker logs portainer
|
||||
```
|
||||
|
||||
Restart:
|
||||
|
||||
```bash
|
||||
docker restart portainer
|
||||
```
|
||||
|
||||
Open shell:
|
||||
|
||||
```bash
|
||||
docker exec -it portainer /bin/sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Related Services
|
||||
|
||||
* Nginx Proxy Manager
|
||||
* Docker
|
||||
* PostgreSQL
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* Jitsi Meet
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/security.md
|
||||
* docs/backups.md
|
||||
@@ -0,0 +1,20 @@
|
||||
services:
|
||||
portainer:
|
||||
image: portainer/portainer-ce:latest
|
||||
container_name: portainer
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- portainer_data:/data
|
||||
|
||||
networks:
|
||||
- proxy
|
||||
|
||||
volumes:
|
||||
portainer_data:
|
||||
name: portainer_portainer_data
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
@@ -0,0 +1,50 @@
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
|
||||
env_file:
|
||||
- /srv/secrets/company.env
|
||||
|
||||
environment:
|
||||
USER_UID: "1000"
|
||||
USER_GID: "1000"
|
||||
|
||||
GITEA__database__DB_TYPE: postgres
|
||||
GITEA__database__HOST: postgres:5432
|
||||
GITEA__database__NAME: gitea
|
||||
GITEA__database__USER: postgres
|
||||
GITEA__database__PASSWD: ${POSTGRES_ROOT_PASSWORD}
|
||||
|
||||
GITEA__server__DOMAIN: git.silveressence.net
|
||||
GITEA__server__ROOT_URL: https://git.silveressence.net/
|
||||
GITEA__server__SSH_DOMAIN: git.silveressence.net
|
||||
GITEA__server__SSH_PORT: "2222"
|
||||
|
||||
GITEA__mailer__ENABLED: "true"
|
||||
GITEA__mailer__FROM: noreply@silveressence.net
|
||||
GITEA__mailer__PROTOCOL: smtp+starttls
|
||||
GITEA__mailer__SMTP_ADDR: ${SMTP_HOST}
|
||||
GITEA__mailer__SMTP_PORT: "${SMTP_PORT}"
|
||||
GITEA__mailer__USER: ${SMTP_USERNAME}
|
||||
GITEA__mailer__PASSWD: ${SMTP_PASSWORD}
|
||||
|
||||
GITEA__openid__ENABLE_OPENID_SIGNIN: "false"
|
||||
GITEA__openid__ENABLE_OPENID_SIGNUP: "false"
|
||||
|
||||
volumes:
|
||||
- /srv/docker/gitea/data:/data
|
||||
|
||||
ports:
|
||||
- "2222:22"
|
||||
|
||||
networks:
|
||||
- proxy
|
||||
- internal
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
internal:
|
||||
external: true
|
||||
@@ -0,0 +1,289 @@
|
||||
# PostgreSQL
|
||||
|
||||
## Overview
|
||||
|
||||
PostgreSQL is the primary open-source database platform for SilverLinux and coexists with Microsoft SQL Server 2022 Express.
|
||||
|
||||
Multiple applications use the same PostgreSQL instance while maintaining separate databases and database users.
|
||||
|
||||
This approach simplifies:
|
||||
|
||||
* Backup management
|
||||
* Monitoring
|
||||
* Security
|
||||
* Resource utilization
|
||||
|
||||
---
|
||||
|
||||
## Service Information
|
||||
|
||||
Container Name:
|
||||
|
||||
```text
|
||||
postgres
|
||||
```
|
||||
|
||||
Network:
|
||||
|
||||
```text
|
||||
internal
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
* Application databases
|
||||
* Centralized data storage
|
||||
* Shared database platform
|
||||
|
||||
---
|
||||
|
||||
## Current Databases
|
||||
|
||||
### gitea
|
||||
|
||||
Owner:
|
||||
|
||||
```text
|
||||
gitea
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
Source control and repository management.
|
||||
|
||||
Used by:
|
||||
|
||||
```text
|
||||
gitea
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### openproject
|
||||
|
||||
Owner:
|
||||
|
||||
```text
|
||||
openproject
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
Project management and collaboration.
|
||||
|
||||
Used by:
|
||||
|
||||
```text
|
||||
openproject
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### postgres
|
||||
|
||||
Owner:
|
||||
|
||||
```text
|
||||
postgres
|
||||
```
|
||||
|
||||
Purpose:
|
||||
|
||||
Administrative database.
|
||||
|
||||
Used for PostgreSQL administration and maintenance.
|
||||
|
||||
---
|
||||
|
||||
## Database Ownership
|
||||
|
||||
| Database | Owner |
|
||||
| ----------- | ----------- |
|
||||
| gitea | gitea |
|
||||
| openproject | openproject |
|
||||
| postgres | postgres |
|
||||
|
||||
Each application should use its own dedicated database user whenever possible.
|
||||
|
||||
---
|
||||
|
||||
## Credentials
|
||||
|
||||
Credentials are stored in:
|
||||
|
||||
```text
|
||||
Infisical
|
||||
```
|
||||
|
||||
Current variables:
|
||||
|
||||
```text
|
||||
POSTGRES_ROOT_PASSWORD
|
||||
POSTGRES_OPENPROJECT_PASSWORD
|
||||
```
|
||||
|
||||
Future variables:
|
||||
|
||||
```text
|
||||
POSTGRES_GITEA_PASSWORD
|
||||
POSTGRES_BAGET_PASSWORD
|
||||
```
|
||||
|
||||
Passwords must never be committed to Git repositories.
|
||||
|
||||
---
|
||||
|
||||
## Administration
|
||||
|
||||
Open PostgreSQL shell:
|
||||
|
||||
```bash
|
||||
docker exec -it postgres psql -U postgres
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### List Databases
|
||||
|
||||
```sql
|
||||
\l
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### List Roles
|
||||
|
||||
```sql
|
||||
\du
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### List Connections
|
||||
|
||||
```sql
|
||||
SELECT * FROM pg_stat_activity;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Create Database
|
||||
|
||||
Example:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE myapp;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Create User
|
||||
|
||||
Example:
|
||||
|
||||
```sql
|
||||
CREATE USER myapp WITH PASSWORD 'StrongPassword';
|
||||
```
|
||||
|
||||
Grant permissions:
|
||||
|
||||
```sql
|
||||
GRANT ALL PRIVILEGES ON DATABASE myapp TO myapp;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backup
|
||||
|
||||
Create database backup:
|
||||
|
||||
```bash
|
||||
docker exec postgres pg_dump -U postgres openproject > openproject.sql
|
||||
```
|
||||
|
||||
Create full cluster backup:
|
||||
|
||||
```bash
|
||||
docker exec postgres pg_dumpall -U postgres > postgres-full-backup.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Restore
|
||||
|
||||
Restore database:
|
||||
|
||||
```bash
|
||||
docker exec -i postgres psql -U postgres openproject < openproject.sql
|
||||
```
|
||||
|
||||
Restore complete cluster:
|
||||
|
||||
```bash
|
||||
docker exec -i postgres psql -U postgres < postgres-full-backup.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
* PostgreSQL is not exposed publicly.
|
||||
* Database traffic is restricted to Docker internal networks.
|
||||
* Credentials are stored in Infisical and injected at runtime by `slcompose`.
|
||||
* Administrative access should use the `postgres` role only when necessary.
|
||||
* Applications should use dedicated database users.
|
||||
|
||||
---
|
||||
|
||||
## Monitoring
|
||||
|
||||
Useful commands:
|
||||
|
||||
Database size:
|
||||
|
||||
```sql
|
||||
SELECT pg_database.datname,
|
||||
pg_size_pretty(pg_database_size(pg_database.datname))
|
||||
FROM pg_database;
|
||||
```
|
||||
|
||||
Current connections:
|
||||
|
||||
```sql
|
||||
SELECT count(*) FROM pg_stat_activity;
|
||||
```
|
||||
|
||||
PostgreSQL version:
|
||||
|
||||
```sql
|
||||
SELECT version();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Disaster Recovery
|
||||
|
||||
Minimum requirements for recovery:
|
||||
|
||||
* PostgreSQL container configuration
|
||||
* Database backups
|
||||
* Infisical access and PostgreSQL service secrets
|
||||
* Docker network configuration
|
||||
|
||||
Without Infisical recovery, applications may not be able to reconnect to their databases after restoration.
|
||||
|
||||
---
|
||||
|
||||
## Related Services
|
||||
|
||||
* Gitea
|
||||
* OpenProject
|
||||
* DbGate
|
||||
* Microsoft SQL Server Express
|
||||
|
||||
## Related Documentation
|
||||
|
||||
* docs/server.md
|
||||
* docs/security.md
|
||||
* docs/secrets.md
|
||||
* docs/backups.md
|
||||
@@ -0,0 +1,50 @@
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
restart: unless-stopped
|
||||
|
||||
env_file:
|
||||
- /srv/secrets/company.env
|
||||
|
||||
environment:
|
||||
USER_UID: "1000"
|
||||
USER_GID: "1000"
|
||||
|
||||
GITEA__database__DB_TYPE: postgres
|
||||
GITEA__database__HOST: postgres:5432
|
||||
GITEA__database__NAME: gitea
|
||||
GITEA__database__USER: postgres
|
||||
GITEA__database__PASSWD: ${POSTGRES_ROOT_PASSWORD}
|
||||
|
||||
GITEA__server__DOMAIN: git.silveressence.net
|
||||
GITEA__server__ROOT_URL: https://git.silveressence.net/
|
||||
GITEA__server__SSH_DOMAIN: git.silveressence.net
|
||||
GITEA__server__SSH_PORT: "2222"
|
||||
|
||||
GITEA__mailer__ENABLED: "true"
|
||||
GITEA__mailer__FROM: noreply@silveressence.net
|
||||
GITEA__mailer__PROTOCOL: smtp+starttls
|
||||
GITEA__mailer__SMTP_ADDR: ${SMTP_HOST}
|
||||
GITEA__mailer__SMTP_PORT: "${SMTP_PORT}"
|
||||
GITEA__mailer__USER: ${SMTP_USERNAME}
|
||||
GITEA__mailer__PASSWD: ${SMTP_PASSWORD}
|
||||
|
||||
GITEA__openid__ENABLE_OPENID_SIGNIN: "false"
|
||||
GITEA__openid__ENABLE_OPENID_SIGNUP: "false"
|
||||
|
||||
volumes:
|
||||
- /srv/docker/gitea/data:/data
|
||||
|
||||
ports:
|
||||
- "2222:22"
|
||||
|
||||
networks:
|
||||
- proxy
|
||||
- internal
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
external: true
|
||||
internal:
|
||||
external: true
|
||||
Reference in New Issue
Block a user