Keep database ports private
Bind to loopback for same-host applications or a specific private interface. Never expose 5432 or 6379 to the public internet.
sudo ss -lntp | grep -E ':(5432|6379)'Important: Firewall rules are defense in depth; also restrict each service's listen address.
Use PostgreSQL SCRAM
Set password_encryption to scram-sha-256 and restrict pg_hba.conf to the exact application network and database.
password_encryption = 'scram-sha-256'
listen_addresses = '127.0.0.1,<private-ip>'hostssl <database> <app-user> <private-cidr> scram-sha-256Create a least-privilege PostgreSQL role
Create a login role and assign only the database and schema rights the application needs. Set its password interactively so it does not enter shell history.
CREATE ROLE <app-user> LOGIN;
CREATE DATABASE <database> OWNER <app-user>;
\password <app-user>Configure Redis access
Enable protected mode, bind to loopback or a private interface, and use Redis 6+ ACL users with only required command categories and key patterns.
bind 127.0.0.1 <private-ip>
protected-mode yes
port 6379
user default off
user <app-user> on >REPLACE_IN_CONFIG ~<app-prefix>:* +@read +@writeImportant: Replace the placeholder directly in a protected Redis configuration or secret-managed ACL file—not in shell history or Git.
Reload and verify
Validate configuration, restart during an approved window, and test from allowed and denied network locations.
sudo systemctl restart postgresql redis-server
sudo systemctl --no-pager status postgresql redis-serverBack up and test restore
Create encrypted, access-controlled PostgreSQL backups and Redis snapshots, copy them off-host, and regularly prove restoration works.
pg_dump --format=custom --file=<backup-file> <database>Note: Do not place database passwords in commands. Use a protected password file or interactive prompt.
Final verification
- ✓ Public scans cannot reach ports 5432 or 6379
- ✓ PostgreSQL rejects unauthorized roles and networks
- ✓ Redis default user is disabled and the app ACL is restricted
- ✓ Service credentials are absent from Git and shell history
- ✓ A restore test succeeds from the latest backup