DATABASE_URL

Everything regarding the DATABASE_URL environment variable

This article applies to: OSS Self-Hosted

The DATABASE_URL environment variable is a standardized way to specify database connection details in Password Pusher. It follows the RFC 3986 URI standard and is commonly used across various deployment environments and hosting platforms.

Overview

Password Pusher supports two database backends:

  1. SQLite3 (default) - File-based database with persistent storage via Docker volumes, perfect for single-server deployments
  2. PostgreSQL - Robust relational database for distributed or high-availability setups

The DATABASE_URL contains a URL string with all information needed to connect to your database, including the database type, host, port, database name, and authentication credentials.

Important: Remember to replace the placeholders in these examples (e.g., username, password, hostname, port, database_name) with your actual credentials and database information.

Note: Additional connection options can be provided by adding query parameters to the URL: ?option1=value1&option2=value2

SQLite3

SQLite3 is the default database backend. If DATABASE_URL is not specified, Password Pusher automatically uses SQLite3 under /opt/PasswordPusher/storage. When using the provided docker-compose.yml, that storage directory is a persistent volume and survives container restarts and upgrades.

Format

For SQLite3, the DATABASE_URL format is:

sqlite3:///path/to/database/file.sqlite3

or the shorter format:

sqlite3:path/to/database/file.sqlite3
  • sqlite3:// or sqlite3: is the protocol
  • The path can be absolute or relative to the application root
  • Use three slashes (///) for absolute paths

Examples

Absolute path (recommended for Docker):

sqlite3:///opt/PasswordPusher/storage/db/production.sqlite3

Relative path (same default location):

sqlite3:storage/db/production.sqlite3

Default (when DATABASE_URL is not set):

The container entrypoint defaults to sqlite3:storage/db/production.sqlite3. Older installs that still have db/db.sqlite3 keep that deprecated path until you move the file into storage/db/.

In most Docker setups you can omit DATABASE_URL entirely and mount persistent storage as shown below.

Persistence

Mount /opt/PasswordPusher/storage. That directory holds the SQLite database (storage/db/production.sqlite3) and uploaded files.

Using Docker volumes (default in docker-compose.yml):

volumes:
  - pwpush-storage:/opt/PasswordPusher/storage

volumes:
  pwpush-storage:

Using bind mounts:

volumes:
  - /host/path/to/storage:/opt/PasswordPusher/storage

Do not mount over /opt/PasswordPusher/db.

That path contains application migration source files (db/migrate/), not just the database. Overlaying a host directory or named volume on /opt/PasswordPusher/db hides those files from Rails. Upgrades then skip migrations (you may see ****** NO FILE ****** in db:migrate:status), and the app can crash looking for new tables.

Mount Result
/opt/PasswordPusher/storage Correct — persists DB + uploads, migrations stay available
/opt/PasswordPusher/db Incorrect — hides db/migrate/ and breaks upgrades
Only the .sqlite3 file (legacy) Works, but prefer migrating to storage/

Legacy installs that already store SQLite under /opt/PasswordPusher/db:

  1. Back up the database file
  2. Move it to storage/db/production.sqlite3 (include -wal / -shm files if present)
  3. Change the volume mount to /opt/PasswordPusher/storage
  4. Remove a custom DATABASE_URL pointing at /opt/PasswordPusher/db/..., or update it to the storage path
  5. Restart — pending migrations apply automatically

If you must keep a database file under /opt/PasswordPusher/db temporarily, bind-mount only the SQLite file, never the entire db/ directory:

volumes:
  - ./data/production.sqlite3:/opt/PasswordPusher/db/production.sqlite3

Prefer migrating to /opt/PasswordPusher/storage when you can.

Note: Without a volume, the database lives only in the container filesystem and is lost when the container is removed. Always use a volume for production.

When to Use SQLite3

SQLite3 is ideal for:

  • Single-server deployments
  • Development and testing environments
  • Small to medium-sized installations
  • Scenarios where simplicity is preferred over scalability

For production deployments requiring high availability, multiple servers, or advanced features, consider PostgreSQL instead.

PostgreSQL

PostgreSQL is a robust, production-ready database backend suitable for distributed deployments, high-availability setups, and environments requiring advanced database features.

Format

For PostgreSQL, the DATABASE_URL follows this format:

postgres://username:password@hostname:port/database_name

Components:

  • postgres:// - The protocol identifier
  • username:password - Your PostgreSQL authentication credentials
  • hostname - The host where your PostgreSQL server is running (can be a hostname, IP address, or Docker service name)
  • port - The port number (default is 5432)
  • database_name - The name of your PostgreSQL database

Examples

Local PostgreSQL server:

postgres://myuser:mypassword@localhost:5432/pwpush_db

Remote PostgreSQL server:

postgres://myuser:mypassword@db.example.com:5432/pwpush_db

Docker Compose (using service name):

postgres://pwpush_user:pwpush_passwd@postgres:5432/pwpush_db

With SSL connection:

postgres://myuser:mypassword@db.example.com:5432/pwpush_db?sslmode=require

Important Notes

Hostname Restrictions: Hostname values with underscores (_) are not supported due to RFC 3986 URI standards. Use hyphens (-) instead. See issue #1602 for details.

Special Characters in Passwords: If your password contains special characters that conflict with URI encoding (such as %, ^, #, :, etc.), you may need to URL-encode them. See the Valid Characters section below.

When to Use PostgreSQL

PostgreSQL is recommended for:

  • Production deployments requiring high availability
  • Multi-server or distributed setups
  • Environments with high traffic or large datasets
  • Scenarios requiring database replication or backups
  • When using the separate worker container (pglombardo/pwpush-worker)

Configuration Examples

Docker Compose

Using SQLite3 with persistent volume:

services:
  pwpush:
    image: docker.io/pglombardo/pwpush:stable
    environment:
      # SQLite3 is the default. Omit DATABASE_URL, or set:
      # DATABASE_URL: sqlite3:///opt/PasswordPusher/storage/db/production.sqlite3
    volumes:
      - pwpush-storage:/opt/PasswordPusher/storage

volumes:
  pwpush-storage:

Using PostgreSQL:

services:
  postgres:
    image: postgres:15
    environment:
      POSTGRES_USER: pwpush_user
      POSTGRES_PASSWORD: pwpush_passwd
      POSTGRES_DB: pwpush_db
    volumes:
      - postgres-data:/var/lib/postgresql/data

  pwpush:
    image: docker.io/pglombardo/pwpush:stable
    depends_on:
      - postgres
    environment:
      DATABASE_URL: postgres://pwpush_user:pwpush_passwd@postgres:5432/pwpush_db

volumes:
  postgres-data:

Environment Variables

Set DATABASE_URL as an environment variable:

export DATABASE_URL="postgres://myuser:mypassword@localhost:5432/pwpush_db"

Or in a .env file:

DATABASE_URL=postgres://myuser:mypassword@localhost:5432/pwpush_db

Valid Characters and URL Encoding

The DATABASE_URL follows the RFC 3986 URI standard, which restricts certain characters that can be used in URI components.

Restricted Characters

The following characters are not allowed in usernames, passwords, hostnames, or database names without URL encoding:

% ^ # _ :

Common Issues and Solutions

Underscores in hostnames: Hostnames with underscores (_) are not supported. Use hyphens (-) instead.

Example:

  • db_server.example.com (not supported)
  • db-server.example.com (supported)

Special characters in passwords: If your password contains special characters like %, ^, #, :, you need to URL-encode them:

Character URL-Encoded
% %25
^ %5E
# %23
: %3A

Example:

  • Original password: my#pass:word
  • URL-encoded: my%23pass%3Aword
  • Full DATABASE_URL: postgres://user:my%23pass%3Aword@localhost:5432/db

Tip: Use this regex tool to test your DATABASE_URL string for RFC 3986 compliance.

Note: This is an internet standard (RFC 3986), not a limitation introduced by Password Pusher. Most modern applications and deployment platforms follow this standard.

Troubleshooting

Common Issues

Database connection fails:

  • Verify the database server is running and accessible
  • Check that the hostname, port, username, password, and database name are correct
  • Ensure network connectivity between the application and database server
  • For Docker Compose, use the service name as the hostname

“Hostname with underscores not supported” error:

  • Replace underscores (_) with hyphens (-) in hostnames
  • This is a limitation of the URI standard, not Password Pusher

Password with special characters fails:

  • URL-encode special characters in your password
  • Consider using a password without special characters if possible
  • Use environment files or Docker secrets instead of command-line arguments

SQLite database not persisting:

  • Verify that volumes are properly configured in your docker-compose.yml or docker run command
  • Confirm the mount target is /opt/PasswordPusher/storage (not /opt/PasswordPusher/db)
  • Check volume mount permissions
  • Ensure the path exists and is writable
  • For Docker Compose, verify the volume is defined in both the service and the top-level volumes section

Migrations not running / missing tables after upgrade (for example notify_by_emails):

  • Confirm you are not mounting a volume over /opt/PasswordPusher/db
  • Inside the container, ls /opt/PasswordPusher/db/migrate should list migration files from the image
  • db:migrate:status showing ****** NO FILE ****** usually means the mount hid those files
  • Fix the volume to /opt/PasswordPusher/storage, restart, and let the entrypoint run migrations

See Also