Files
rick-infra/roles/postgresql/README.md
Joakim 4f8da38ca6 Add Nextcloud cloud storage role with split Redis caching strategy
## New Features

- **Nextcloud Role**: Complete cloud storage deployment using Podman Quadlet
  - FPM variant with Caddy reverse proxy and FastCGI
  - PostgreSQL database via Unix socket
  - Valkey/Redis for app-level caching and file locking
  - Automatic HTTPS with Let's Encrypt via Caddy
  - Dual-root pattern: Caddy serves static assets, FPM handles PHP

- **Split Caching Strategy**: Redis caching WITHOUT Redis sessions
  - Custom redis.config.php template for app-level caching only
  - File-based PHP sessions for stability (avoids session lock issues)
  - Prevents cascading failures from session lock contention
  - Documented in role README with detailed rationale

## Infrastructure Updates

- **Socket Permissions**: Update PostgreSQL and Valkey to mode 777
  - Required for containers that switch users (root → www-data)
  - Nextcloud container loses supplementary groups on user switch
  - Security maintained via password authentication (scram-sha-256, requirepass)
  - Documented socket permission architecture in docs/

- **PostgreSQL**: Export client group GID as fact for dependent roles
- **Valkey**: Export client group GID as fact, update socket fix service

## Documentation

- New: docs/socket-permissions-architecture.md
  - Explains 777 vs 770 socket permission trade-offs
  - Documents why group-based access doesn't work for user-switching containers
  - Provides TCP alternative for stricter security requirements

- Updated: All role READMEs with socket permission notes
- New: Nextcloud README with comprehensive deployment, troubleshooting, and Redis architecture documentation

## Configuration

- host_vars: Add Nextcloud vault variables and configuration
- site.yml: Include Nextcloud role in main playbook

## Technical Details

**Why disable Redis sessions?**

The official Nextcloud container enables Redis session handling via REDIS_HOST env var,
which causes severe performance issues:

1. Session lock contention under high concurrency (browser parallel asset requests)
2. Infinite lock retries (default lock_retries=-1) blocking FPM workers
3. Timeout orphaning: reverse proxy kills connection, worker keeps lock
4. Worker pool exhaustion: all 5 default workers blocked on same session lock
5. Cascading failure: new requests queue, more timeouts, more orphaned locks

Solution: Use file-based sessions (reliable, fast for single-server) while keeping
Redis for distributed cache and transactional file locking via custom config file.

This provides optimal performance without the complexity of Redis session debugging.

Tested: Fresh deployment on arch-vps (69.62.119.31)
Domain: https://cloud.jnss.me/
2025-12-14 22:07:08 +01:00

283 lines
7.4 KiB
Markdown

# PostgreSQL Infrastructure Role
This role provides PostgreSQL as shared database infrastructure for rick-infra applications. It follows the self-contained service architecture where this role provides the database server, and applications manage their own databases and users.
## Architecture
PostgreSQL serves as database infrastructure (similar to how Caddy provides web infrastructure):
- **PostgreSQL Role**: Installs and configures PostgreSQL server
- **Application Roles**: Create their own databases/users via dependency
## Features
- ✅ Native Arch Linux installation via pacman
- ✅ Secure configuration with scram-sha-256 authentication
- ✅ SystemD security hardening
- ✅ Data integrity with checksums enabled by default
- ✅ Performance-tuned defaults
- ✅ Comprehensive logging configuration
- ✅ UTF-8 encoding with C.UTF-8 locale
## Usage
### In Application Roles
Add PostgreSQL as a dependency in your application's `meta/main.yml`:
```yaml
dependencies:
- role: postgresql
tags: ['postgresql', 'infrastructure']
```
Then create your application's database and user in your tasks:
```yaml
- name: Create application database user
postgresql_user:
name: "{{ myapp_db_user }}"
password: "{{ myapp_db_password }}"
encrypted: yes
become: yes
become_user: postgres
- name: Create application database
postgresql_db:
name: "{{ myapp_db_name }}"
owner: "{{ myapp_db_user }}"
encoding: UTF8
template: template0
become: yes
become_user: postgres
```
### In site.yml
```yaml
- name: Deploy Infrastructure
hosts: arch-vps
become: yes
roles:
- role: postgresql
tags: ['postgresql', 'infrastructure', 'database']
- role: myapp # Will use PostgreSQL infrastructure
tags: ['myapp']
```
## Configuration Variables
### Basic Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `postgresql_service_enabled` | `true` | Enable PostgreSQL service |
| `postgresql_service_state` | `"started"` | Service state |
| `postgresql_port` | `5432` | PostgreSQL port |
| `postgresql_listen_addresses` | `"localhost"` | Listen addresses |
### Security Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `postgresql_auth_method` | `"scram-sha-256"` | Authentication method |
| `postgresql_systemd_security` | `true` | Enable systemd security hardening |
| `postgresql_data_checksums` | `true` | Enable data checksums |
| `postgresql_ssl` | `false` | Enable SSL/TLS |
### Performance Configuration
| Variable | Default | Description |
|----------|---------|-------------|
| `postgresql_max_connections` | `100` | Maximum connections |
| `postgresql_shared_buffers` | `"128MB"` | Shared buffer size |
| `postgresql_effective_cache_size` | `"1GB"` | Effective cache size |
See `defaults/main.yml` for all available configuration options.
## Security Features
### SystemD Hardening
The role implements comprehensive systemd security restrictions:
- `NoNewPrivileges=true`
- `PrivateTmp=true`
- `ProtectHome=true`
- `ProtectSystem=strict`
- Memory execution protection
- System call filtering
### Authentication
- Secure `scram-sha-256` password authentication
- `peer` authentication for postgres superuser
- Local connections only by default
- Encrypted password storage
### Unix Socket Permissions
**Current Configuration**: Socket permissions are set to `0777` (world-readable/writable)
**Rationale**:
- Allows containers running as any UID to access the socket
- Needed for containers that start as root and switch to unprivileged users (e.g., Nextcloud's www-data)
- Security is maintained via password authentication (scram-sha-256)
- Sockets are local-only (not network-exposed)
**Security Considerations**:
- ✅ Any local process can connect to the socket
- ✅ But still requires valid username + password to authenticate
- ✅ Limited to processes on same host (not network)
- ✅ Passwords stored encrypted with scram-sha-256
**Alternative Approach (TCP)**:
If you prefer more restrictive socket permissions, you can use TCP instead:
```yaml
# In host_vars
postgresql_listen_addresses: "127.0.0.1" # Listen on localhost TCP
postgresql_unix_socket_permissions: "0770" # Restrict socket to group
# In application configs
# Use: host=127.0.0.1 port=5432
# Instead of: host=/var/run/postgresql
```
This provides the same security level (password-authenticated, localhost-only) but uses TCP instead of Unix sockets.
### File System Security
- Proper ownership and permissions
- Protected configuration files (mode 0600)
- Separate log directory with appropriate access
## Directory Structure
```
/var/lib/postgres/data/ # PostgreSQL data directory
/var/lib/postgres/ # PostgreSQL home directory
/var/log/postgresql/ # PostgreSQL logs
/etc/systemd/system/postgresql.service.d/ # SystemD overrides
```
## Database Administration
### Connect as postgres superuser:
```bash
sudo -u postgres psql
```
### Create application database and user:
```sql
CREATE ROLE myapp WITH LOGIN PASSWORD 'secure_password';
CREATE DATABASE myapp WITH OWNER myapp TEMPLATE template0 ENCODING 'UTF8';
```
### List databases:
```sql
\l
```
### List users:
```sql
\du
```
## Performance Tuning
The role provides conservative performance defaults suitable for most applications. For production workloads, consider adjusting:
- `postgresql_shared_buffers`: 25% of system RAM
- `postgresql_effective_cache_size`: 75% of system RAM
- `postgresql_max_connections`: Based on application needs
- `postgresql_maintenance_work_mem`: For large datasets
## Monitoring
### Service Status
```bash
systemctl status postgresql
```
### Logs
```bash
journalctl -u postgresql
# or
sudo -u postgres tail -f /var/log/postgresql/postgresql-*.log
```
### Connection Test
```bash
sudo -u postgres psql -c "SELECT version();"
```
## Troubleshooting
### Common Issues
1. **Permission Denied**: Ensure postgres user owns data directory
2. **Connection Refused**: Check service status and listen_addresses
3. **Authentication Failed**: Verify pg_hba.conf configuration
### Debug Mode
Enable detailed logging:
```yaml
postgresql_log_statement: "all"
postgresql_log_connections: true
postgresql_log_disconnections: true
```
## Examples
### Development Setup
```yaml
postgresql_log_statement: "all" # Log all statements
postgresql_max_connections: 50 # Lower for development
```
### Production Setup
```yaml
postgresql_shared_buffers: "256MB"
postgresql_effective_cache_size: "2GB"
postgresql_log_min_duration_statement: 1000 # Log slow queries
postgresql_log_connections: true # Audit trail
```
### High Security Setup
```yaml
postgresql_ssl: true
postgresql_log_connections: true
postgresql_log_disconnections: true
postgresql_log_statement: "ddl" # Log schema changes
```
## Dependencies
- Arch Linux PostgreSQL package
- python-psycopg2 (for Ansible modules)
## Compatibility
- **OS**: Arch Linux
- **PostgreSQL**: Latest stable version from Arch repositories
- **Ansible**: >= 2.9
## Contributing
When modifying this role:
1. Update this README for any new features
2. Test with example applications
3. Ensure security configurations remain intact
4. Follow rick-infra coding standards
## Integration Examples
See roles that use this infrastructure:
- `gitea`: Git repository management
- `nextcloud` (planned): File sharing and collaboration
---
**Rick-Infra PostgreSQL Infrastructure Role**
Provides secure, performant PostgreSQL database infrastructure for rick-infra applications.