OpsGuard Cloud is a lightweight, containerized platform for technical incident management, access auditing, security event tracking and service monitoring.
The project is designed as a realistic portfolio project for profiles focused on system administration, cloud infrastructure, backend development and DevOps fundamentals.
It combines a modern Python API with PostgreSQL, authentication, role-based access control, audit logging, security events, Prometheus metrics, Grafana dashboards and a reverse proxy architecture using Nginx.
In many small technical environments, incidents, access attempts, suspicious events and service errors are managed in a fragmented way:
- isolated messages,
- manual log reviews,
- spreadsheets,
- informal notes,
- no centralized traceability,
- no clear monitoring dashboard.
This makes it difficult to answer basic operational questions:
- When did an incident happen?
- What severity did it have?
- Was it resolved?
- Who changed its status?
- Were there failed or unauthorized access attempts?
- Are services healthy?
- What historical evidence exists?
OpsGuard Cloud provides a small but realistic platform to centralize:
- technical incidents,
- audit logs,
- security events,
- user authentication,
- role-based access control,
- Prometheus metrics,
- Grafana visualization.
The project is not intended to replace enterprise tools. Its goal is to demonstrate how a modern operations platform can be designed, containerized, monitored and prepared for cloud deployment.
User
→ Nginx :8080
→ FastAPI :8000
→ PostgreSQL
Prometheus
→ FastAPI /metrics
Grafana
→ Prometheus
Local services:
opsguard-nginx
opsguard-api
opsguard-db
opsguard-prometheus
opsguard-grafana
- Python
- FastAPI
- PostgreSQL
- SQLAlchemy
- Docker
- Docker Compose
- Nginx
- Prometheus
- Grafana
- JWT authentication
- Role-based access control
- AWS EC2 demo deployment planned
- AWS professional architecture documented as future improvement
The platform allows users to:
- create technical incidents,
- list all incidents,
- view incident details,
- update incident status,
- automatically set
resolved_atwhen an incident is resolved, - delete incidents,
- generate audit records for relevant incident actions.
Incident fields include:
id
title
description
severity
status
created_at
updated_at
resolved_at
Supported severities:
low
medium
high
critical
Supported statuses:
open
in_progress
resolved
The system records important events such as:
- incident creation,
- incident status changes,
- incident deletion,
- successful login,
- failed login,
- access denied,
- security event creation.
Audit logs include:
id
event_type
description
source_ip
user_agent
created_at
The platform can register security-related events such as:
- failed login attempts,
- unauthorized access,
- suspicious payloads,
- simulated SQL injection attempts,
- requests to non-existing routes.
Security events include:
id
event_type
severity
description
source_ip
payload
created_at
Supported security event types:
failed_login_attempt
unauthorized_access
suspicious_payload
sql_injection_attempt
not_found_route
OpsGuard Cloud includes JWT authentication and three user roles:
admin → full access
technician → incident management and security event access
viewer → read-only incident access
Role-based access control is implemented to protect sensitive endpoints.
The API exposes Prometheus-compatible metrics through:
GET /metrics
Main metrics:
opsguard_api_status
opsguard_incidents_total
opsguard_incidents_open
opsguard_incidents_critical
opsguard_security_events_total
opsguard_http_requests_total
opsguard_http_errors_total
Grafana is used to visualize these metrics in a dashboard.
OpsGuard-Cloud/
├── app/
│ ├── core/
│ ├── database/
│ ├── models/
│ ├── routers/
│ ├── schemas/
│ ├── scripts/
│ ├── services/
│ └── main.py
├── docs/
│ ├── arquitectura-local.md
│ ├── arquitectura-aws.md
│ ├── seguridad.md
│ ├── monitorizacion.md
│ ├── pruebas.md
│ ├── costes.md
│ └── mejoras-futuras.md
├── grafana/
├── nginx/
│ └── default.conf
├── prometheus/
│ └── prometheus.yml
├── docker-compose.yml
├── Dockerfile
├── requirements.txt
├── .env.example
├── .gitignore
├── .dockerignore
└── README.md
git clone <repository-url>
cd OpsGuard-CloudOn Linux or macOS:
cp .env.example .envOn Windows PowerShell:
Copy-Item .env.example .envdocker compose up -d --builddocker psExpected containers:
opsguard-nginx
opsguard-api
opsguard-db
opsguard-prometheus
opsguard-grafana
| Service | URL |
|---|---|
| Nginx entrypoint | http://localhost:8080 |
| API docs through Nginx | http://localhost:8080/docs |
| FastAPI direct access | http://localhost:8000/docs |
| Prometheus | http://localhost:9090 |
| Grafana | http://localhost:3000 |
Grafana default local credentials:
username: admin
password: admin
Create the default admin user:
docker exec -it opsguard-api python -m app.scripts.create_adminDefault local admin credentials:
username: admin
password: admin123
Create test users:
docker exec -it opsguard-api python -m app.scripts.create_test_usersTest users:
username: technician
password: tech123
role: technician
username: viewer
password: viewer123
role: viewer
These credentials are only for local development.
| Method | Endpoint | Description |
|---|---|---|
| GET | / |
Root API information |
| GET | /health |
API health check |
| GET | /db-health |
Database connection check |
| GET | /metrics |
Prometheus metrics |
| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/login |
Login and receive JWT token |
| GET | /auth/me |
Get current authenticated user |
| Method | Endpoint | Description |
|---|---|---|
| GET | /incidents |
List incidents |
| GET | /incidents/{id} |
Get incident by ID |
| POST | /incidents |
Create incident |
| PATCH | /incidents/{id}/status |
Update incident status |
| DELETE | /incidents/{id} |
Delete incident |
| Method | Endpoint | Description |
|---|---|---|
| GET | /audit |
List audit logs |
| GET | /audit/{id} |
Get audit log by ID |
| Method | Endpoint | Description |
|---|---|---|
| GET | /security-events |
List security events |
| GET | /security-events/{id} |
Get security event by ID |
| POST | /security-events |
Create security event |
| Endpoint group | Admin | Technician | Viewer |
|---|---|---|---|
| View incidents | Yes | Yes | Yes |
| Create incidents | Yes | Yes | No |
| Update incidents | Yes | Yes | No |
| Delete incidents | Yes | Yes | No |
| View audit logs | Yes | No | No |
| View security events | Yes | Yes | No |
| Create security events | Yes | Yes | No |
- The user sends credentials to:
POST /auth/login
-
The API validates the username and password.
-
If credentials are valid, the API returns a JWT token.
-
The user sends the token in protected requests:
Authorization: Bearer <token>
- The API validates the token and checks the user's role.
Using PowerShell:
$response = Invoke-RestMethod `
-Uri "http://localhost:8080/auth/login" `
-Method Post `
-ContentType "application/x-www-form-urlencoded" `
-Body "username=admin&password=admin123"
$token = $response.access_tokenGet current user:
Invoke-RestMethod `
-Uri "http://localhost:8080/auth/me" `
-Method Get `
-Headers @{ Authorization = "Bearer $token" }Invoke-RestMethod `
-Uri "http://localhost:8080/audit" `
-Method Get `
-Headers @{ Authorization = "Bearer $token" }Without a token, protected endpoints return:
401 Not authenticated
With a valid token but insufficient role permissions, the API returns:
403 Forbidden
Grafana can be configured with Prometheus as datasource.
Prometheus datasource URL inside Docker:
http://prometheus:9090
Recommended Grafana panels:
- API Status
- Total Incidents
- Open Incidents
- Critical Incidents
- Security Events
- HTTP Requests by Endpoint
- HTTP Errors by Endpoint
Example PromQL queries:
opsguard_api_status
opsguard_incidents_total
opsguard_incidents_open
opsguard_incidents_critical
opsguard_security_events_total
sum by (endpoint, status_code) (increase(opsguard_http_errors_total[5m]))
sum by (endpoint, status_code) (opsguard_http_requests_total)
Prometheus is configured in:
prometheus/prometheus.yml
Example configuration:
global:
scrape_interval: 10s
scrape_configs:
- job_name: "opsguard-api"
metrics_path: "/metrics"
static_configs:
- targets: ["api:8000"]Important:
api:8000
is used because Prometheus runs inside Docker Compose and communicates with the FastAPI container through the Docker internal network.
Nginx is used as the public local entrypoint.
Local access:
http://localhost:8080
The local architecture is:
User
→ Nginx :8080
→ FastAPI :8000
Nginx forwards requests to the internal API service:
http://api:8000
This makes the local setup closer to a real deployment architecture and prepares the project for a future AWS EC2 deployment.
The low-cost demo version is designed to run everything on a single temporary EC2 instance:
EC2 Ubuntu
→ Docker
→ Docker Compose
→ Nginx
→ FastAPI
→ PostgreSQL
→ Prometheus
→ Grafana
Suggested Security Group concept:
| Port | Access | Purpose |
|---|---|---|
| 22 | My IP only | SSH |
| 80 | Public | HTTP via Nginx |
| 443 | Public optional | HTTPS |
| 3000 | Restricted | Grafana, only if exposed |
| 5432 | Closed | PostgreSQL must not be public |
PostgreSQL should not be exposed publicly.
This version is suitable for:
- a short demo,
- portfolio screenshots,
- LinkedIn presentation,
- low-cost temporary deployment.
A scalable production-oriented version could evolve into:
Route 53
→ Application Load Balancer
→ ECS Fargate
→ FastAPI containers
→ RDS PostgreSQL Multi-AZ
→ CloudWatch Logs
→ CloudWatch Alarms
→ SNS
→ Secrets Manager
Difference between both versions:
| Area | Low-cost demo | Professional AWS version |
|---|---|---|
| Compute | Single EC2 | ECS Fargate |
| Database | PostgreSQL container | RDS PostgreSQL Multi-AZ |
| Logs | Local container logs | CloudWatch Logs |
| Alerts | Manual/local | CloudWatch Alarms + SNS |
| Secrets | .env |
AWS Secrets Manager |
| Scaling | Manual | Horizontal service scaling |
| Availability | Single instance | Multi-AZ managed services |
| Cost | Low | Higher but production-ready |
The professional architecture is more robust, scalable and production-oriented, but it is not necessary for the first demo because it can generate higher recurring costs.
Estimated cost: 0 EUR
The project runs locally with Docker Desktop.
The demo version can be deployed temporarily on a small EC2 instance.
Possible cost factors:
- EC2 instance hours,
- EBS storage,
- outbound data transfer,
- optional Elastic IP,
- optional domain,
- optional HTTPS setup.
Recommended cost-control actions:
- use a small instance,
- stop or terminate the instance after the demo,
- avoid exposing Grafana publicly,
- keep PostgreSQL private,
- create an AWS Budget alert,
- review AWS pricing before deploying.
The professional version would involve additional services such as:
- Application Load Balancer,
- ECS Fargate,
- RDS PostgreSQL,
- CloudWatch,
- SNS,
- Secrets Manager,
- Route 53.
This version is more realistic for production but has higher cost.
Recommended screenshots for GitHub and LinkedIn:
- Docker Desktop with all containers running.
- FastAPI Swagger documentation.
- Successful
/auth/meresponse. - Protected
/auditreturning401without token. - Audit logs showing login and incident events.
- Security events list.
- Prometheus target
opsguard-apiasUP. - Prometheus query
opsguard_api_status. - Grafana dashboard overview.
- Nginx access through
http://localhost:8080/health.
Suggested folder:
docs/screenshots/
Suggested file names:
01-docker-containers.png
02-fastapi-docs.png
03-auth-me.png
04-audit-protected-401.png
05-audit-logs.png
06-security-events.png
07-prometheus-target-up.png
08-prometheus-api-status.png
09-grafana-dashboard.png
10-nginx-health.png
Additional documentation is available in:
docs/arquitectura-local.md
docs/arquitectura-aws.md
docs/seguridad.md
docs/monitorizacion.md
docs/pruebas.md
docs/costes.md
docs/mejoras-futuras.md
Implemented:
- FastAPI API
- PostgreSQL persistence
- Docker Compose stack
- Incident management
- Audit logs
- Security events
- JWT authentication
- Role-based access control
- Unauthorized access tracking
- Prometheus metrics
- Grafana dashboard
- Nginx reverse proxy
Planned:
- AWS EC2 demo deployment
- HTTPS with Nginx
- CI/CD pipeline
- Alembic migrations
- Automated tests
- Professional AWS architecture documentation
- GitHub Actions
- Deployment guide
- Add Alembic migrations.
- Add automated tests with Pytest.
- Add pagination.
- Add filters by status, severity and date.
- Add structured logging.
- Add better exception handling.
- Add OpenAPI examples.
- Add HTTPS with Nginx.
- Add rate limiting.
- Add brute-force detection.
- Add refresh tokens.
- Add password reset.
- Add account lockout.
- Move secrets to AWS Secrets Manager.
- Add response time histograms.
- Add metrics by security event type.
- Add Grafana provisioning.
- Add predefined dashboard JSON.
- Add Prometheus alerting rules.
- Add alert notifications.
- Deploy demo to EC2.
- Add HTTPS with domain.
- Move database to RDS PostgreSQL.
- Move containers to ECS Fargate.
- Use Application Load Balancer.
- Use CloudWatch Logs.
- Use CloudWatch Alarms.
- Use SNS notifications.
- Use Secrets Manager.
- Add GitHub Actions.
- Add Docker image build pipeline.
- Add linting and formatting.
- Add deployment script.
- Add infrastructure-as-code with Terraform.
OpsGuard Cloud demonstrates the design and implementation of a small operations platform combining:
backend development
system administration
security awareness
monitoring
containerization
cloud readiness
It is a practical evolution from traditional infrastructure projects toward a more modern cloud-oriented and DevOps-ready architecture.