Install without Docker
Install self-hosted Quackback without Docker using Bun 1.4+ and PostgreSQL 14+ with pgvector and pg_trgm, run it under systemd or PM2, and keep it updated.
Install self-hosted Quackback directly on a server with Bun and PostgreSQL, without Docker. Use this if you prefer to run the app without containers.
Prerequisites
Bun
Version 1.4.0 or higher.
# Install Bun
curl -fsSL https://bun.sh/install | bash
# Verify installation
bun --versionPostgreSQL
Version 14 or higher, with these extensions:
vector(pgvector 0.5.0 or newer) for similarity searchpg_trgm(from the PostgreSQL contrib package) for text search
PostgreSQL is the only datastore you need. Background jobs, caches, and realtime events all run on it, so there is no Redis or queue service to install, and pg_cron is not required. See System requirements for connection-mode and privilege requirements.
Other tools
- Git
- OpenSSL (for generating secrets)
Installation steps
1. Clone the repository
git clone https://github.com/quackbackio/quackback.git
cd quackback2. Install dependencies
bun install3. Configure the environment
Copy the example environment file and generate a secret:
cp .env.example .env
openssl rand -base64 32Edit .env. Do not wrap values in quotes.
# Required settings
DATABASE_URL=postgresql://quackback:your_password@localhost:5432/quackback
SECRET_KEY=your-generated-secret-key-at-least-32-characters
BASE_URL=https://feedback.yourcompany.com
# One reverse proxy in front of the app (see the reverse proxy guide)
TRUSTED_PROXY_HOPS=1See Environment variables for all options, and Configure email delivery to set up outbound email.
4. Set up PostgreSQL
Install PostgreSQL
Any version from 14 up works. These examples install PostgreSQL 18.
Ubuntu or Debian:
# Add the PostgreSQL APT repository
sudo sh -c 'echo "deb https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
# Install PostgreSQL 18 and pgvector
sudo apt update
sudo apt install postgresql-18 postgresql-18-pgvectormacOS (Homebrew):
brew install postgresql@18
brew services start postgresql@18
brew install pgvectorRHEL, CentOS, or Fedora:
# Install the PostgreSQL repo
sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm
# Install PostgreSQL and extensions
sudo dnf install -y postgresql18-server postgresql18-contrib pgvector_18Create the database and user
sudo -u postgres psql-- Create user
CREATE USER quackback WITH PASSWORD 'your_secure_password';
-- Create database
CREATE DATABASE quackback OWNER quackback;
-- Connect to database
\c quackback
-- Enable required extensions (Quackback also tries this on startup)
CREATE EXTENSION IF NOT EXISTS vector;
CREATE EXTENSION IF NOT EXISTS pg_trgm;
-- Grant permissions
GRANT ALL PRIVILEGES ON DATABASE quackback TO quackback;
GRANT ALL ON SCHEMA public TO quackback;5. Run migrations
bun run db:migrateThis creates all tables and indexes. Before it changes anything, the migrator checks the PostgreSQL version, the extensions, and the database user's privileges, and stops with a clear message if something is missing.
6. Build the application
bun run buildThis creates a production build in apps/web/.output/.
7. Start the server
bun run --cwd apps/web startThe server starts on port 3000 by default.
Process management
Warning: For production, use a process manager to keep Quackback running and restart it automatically on failures.
systemd (recommended)
Create /etc/systemd/system/quackback.service:
[Unit]
Description=Quackback Feedback Platform
After=network.target postgresql.service
Requires=postgresql.service
[Service]
Type=simple
User=quackback
Group=quackback
WorkingDirectory=/opt/quackback
Environment=NODE_ENV=production
EnvironmentFile=/opt/quackback/.env
ExecStart=/home/quackback/.bun/bin/bun run --cwd apps/web start
Restart=always
RestartSec=10
# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/quackback
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=quackback
[Install]
WantedBy=multi-user.targetEnable and start it:
sudo systemctl daemon-reload
sudo systemctl enable quackback
sudo systemctl start quackback
sudo systemctl status quackback
# View logs
journalctl -u quackback -fTip: One instance handles everything by default (
QUACKBACK_ROLE=all, the default when the variable is unset). To scale HTTP and background processing separately, add a second systemd unit withEnvironment=QUACKBACK_ROLE=workerand set the first unit'sQUACKBACK_ROLE=web. See Scale with multiple replicas.
PM2 (alternative)
# Install PM2
bun install -g pm2
# Create an ecosystem file
cat > ecosystem.config.js << 'EOF'
module.exports = {
apps: [{
name: 'quackback',
cwd: '/opt/quackback/apps/web',
script: '.output/server/index.mjs',
interpreter: 'bun',
env: {
NODE_ENV: 'production',
PORT: 3000
},
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '1G'
}]
}
EOF
pm2 start ecosystem.config.js
pm2 save
pm2 startupDirectory structure
Recommended production layout:
/opt/quackback/
.env Environment configuration
apps/web/.output/ Built application
packages/ Internal packages
node_modules/ Dependencies
package.json
bun.lockSecurity considerations
File permissions
# Create a dedicated user
sudo useradd -r -s /bin/false quackback
# Set ownership
sudo chown -R quackback:quackback /opt/quackback
# Restrict the .env file
sudo chmod 600 /opt/quackback/.envFirewall
# UFW example
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP (for redirect)
sudo ufw allow 443/tcp # HTTPS
sudo ufw enableWarning: Do not expose port 3000 directly. Put a reverse proxy in front of it.
Update Quackback
Warning: Upgrading from 0.13? Read Upgrade from 0.13 to 0.14 first. It has one-time steps.
1. Stop the service
sudo systemctl stop quackback2. Back up the database
pg_dump -Fc quackback > quackback_backup_$(date +%Y%m%d).dump3. Pull updates
cd /opt/quackback
git pull origin main4. Install dependencies
bun install5. Run migrations
bun run db:migrate6. Rebuild
bun run build7. Restart the service
sudo systemctl start quackbackTip: To track releases instead of the latest code, check out a release tag (for example
git checkout v0.14.0) rather than pullingmain.
Update script
Save this as /opt/quackback/update.sh to automate the process:
#!/bin/bash
set -e
cd /opt/quackback
echo "Stopping service..."
sudo systemctl stop quackback
echo "Creating backup..."
pg_dump -Fc quackback > /var/backups/quackback/quackback_$(date +%Y%m%d_%H%M%S).dump
echo "Pulling updates..."
git pull origin main
echo "Installing dependencies..."
bun install
echo "Running migrations..."
bun run db:migrate
echo "Building..."
bun run build
echo "Starting service..."
sudo systemctl start quackback
echo "Update complete!"Health checks
# Liveness: the process is up
curl http://localhost:3000/api/health/live
# Readiness: database, migrations, and background workers
curl http://localhost:3000/api/health/ready
# Database connection
psql $DATABASE_URL -c "SELECT 1"
# Service status
sudo systemctl status quackbackTroubleshooting
Port already in use
# Find what's using port 3000
sudo lsof -i :3000Stop that process, or change PORT in .env.
Database connection failed
Check the connection string format (postgresql://user:password@host:port/database) and test it:
psql "postgresql://quackback:password@localhost:5432/quackback" -c "SELECT 1"Permission denied
Make sure the quackback user owns all files:
sudo chown -R quackback:quackback /opt/quackbackBuild fails
Clear the cache and reinstall:
rm -rf node_modules
rm -rf apps/web/.output
bun install
bun run buildMigrations fail
Check the database user's permissions:
GRANT ALL PRIVILEGES ON DATABASE quackback TO quackback;
GRANT ALL ON SCHEMA public TO quackback;Related articles
Was this helpful?
Your feedback shapes what we write next.
