Self-Hosting PocketBase on Linux VPS in Pakistan: Lightweight Open-Source Backend Guide

Complete production guide to self-hosting PocketBase on Linux VPS in Pakistan. Deploy an open-source real-time backend in a single Go binary with embedded SQLite, real-time WebSockets, auth, and S3-compatible storage without recurring USD cloud fees.

Self-Hosting PocketBase on Linux VPS in Pakistan: Lightweight Open-Source Backend Guide

Building modern mobile and web applications requires rapid feature delivery. For years, mobile app developers, digital agencies, and software houses across Pakistan turned to Google Firebase or Supabase as their default Backend-as-a-Service (BaaS). However, evolving macroeconomic conditions, unpredictable US Dollar (USD) subscription invoicing, and heavy architectural overhead have forced technical leaders to reconsider their infrastructure choices.

Firebase bills on a per-read, per-write, and per-stored-gigabyte model priced exclusively in US Dollars. An unexpected algorithmic loop, an unindexed query, or a burst in active users can turn an affordable prototype into an unsustainable four-figure monthly cloud invoice. Compounding this challenge, Pakistani software houses must navigate State Bank of Pakistan (SBP) foreign exchange limits, bank withholding taxes on foreign digital services, and credit card transaction quota caps.

Meanwhile, self-hosting complex BaaS stacks like Supabase or Appwrite introduces heavy resource footprints. These multi-container architectures require running PostgreSQL, Redis, PostgREST, GoTrue auth, Kong API gateways, and storage daemons simultaneously, consuming 1.5GB to 2.5GB of RAM before processing a single user request.

PocketBase changes this equation completely. Packaged as a single standalone Go binary with an embedded SQLite database, PocketBase provides built-in user authentication, role-based access rules, real-time subscriptions over Server-Sent Events (SSE), file storage handling, and an administrative dashboard while consuming less than 40MB to 50MB of RAM at idle.

This production guide walks through deploying, tuning, securing, and maintaining PocketBase on an enterprise Linux VPS in Pakistan.


Macroeconomic and Operational Rationale for PocketBase in Pakistan

Currency Volatility and Banking Restrictions

Software export agencies and indie developers in Pakistan operate under strict monetary and banking constraints:

  • Advance Withholding Tax: Pakistani financial institutions deduct advance withholding tax (ranging from 5% for tax filers to 10% or more for non-filers) on cross-border transactions charged to corporate credit cards.
  • Foreign Exchange Quotas: SBP foreign exchange regulations limit international digital transaction quotas. Software teams often face transaction rejections when cloud invoices cycle at month-end.
  • Uncapped Pay-as-You-Go Risk: Firebase’s pay-per-read/write model exposes startups to catastrophic billing spikes caused by infinite loops, denial-of-wallet scraping attacks, or malformed reactive frontend subscriptions.
  • Predictable Local Billing: Hosting PocketBase on an enterprise Pakistan Linux VPS provides fixed-cost, transparent monthly budgeting paid in Pakistani Rupees (PKR) without card limits or foreign transaction fees.

Resource Footprint: Single Binary vs Container Heavyweights

The following comparison illustrates why PocketBase is uniquely suited for cost-effective virtual servers:

Backend Solution Deployment Format Memory Baseline (Idle) Database Engine Minimum Viable VPS Spec
PocketBase Single Go Binary 35 MB - 50 MB Embedded SQLite (WAL) 1 vCPU, 1 GB RAM
Supabase (Self-Hosted) 12+ Docker Containers 1.5 GB - 2.5 GB PostgreSQL + PostgREST + Kong 2 vCPU, 4 GB RAM
Appwrite 15+ Docker Containers 1.8 GB - 3.0 GB MariaDB + Redis + Traefik 2 vCPU, 4 GB RAM
Firebase (Managed) Proprietary Cloud SaaS N/A (Serverless) Google Cloud Firestore Pay-per-operation (USD)

A high-performance Linux VPS with 2 vCPUs and 2GB or 4GB of RAM can comfortably host PocketBase alongside Nginx, Redis, and Litestream replication, handling hundreds of concurrent requests with negligible system strain.


Technical Architecture of PocketBase

PocketBase combines core application backend services into a cohesive, highly compiled unit:

+-------------------------------------------------------------------------+
|                              PocketBase App                             |
|                                                                         |
|  +---------------------+   +---------------------+   +---------------+  |
|  | Admin UI Dashboard  |   | REST & Real-time    |   | File Storage  |  |
|  | (Embedded Svelte)   |   | SSE / WebSocket API |   | (Local / S3)  |  |
|  +----------+----------+   +----------+----------+   +-------+-------+  |
|             |                         |                      |          |
|  +----------v-------------------------v----------------------v-------+  |
|  |                 Go Routing & Business Logic Hook Engine           |  |
|  |               (JavaScript pb_hooks / Compiled Go APIs)            |  |
|  +------------------------------------+------------------------------+  |
|                                       |                                 |
|  +------------------------------------v------------------------------+  |
|  |                      Embedded SQLite Engine                       |  |
|  |       (WAL Mode + Mutex Concurrency + In-Memory Page Cache)       |  |
|  +------------------------------------+------------------------------+  |
+---------------------------------------|---------------------------------+
                                        v
                            [ Persistent NVMe Storage ]

Core Components

  1. Go Runtime and Web Engine: PocketBase is written in Go using Echo as its HTTP routing core. Go’s lightweight goroutine scheduler allows the server to handle thousands of concurrent client connections with minimal memory allocation.
  2. Embedded SQLite with WAL Mode: Rather than executing network roundtrips to an external database like PostgreSQL or MySQL over a TCP socket, PocketBase embeds SQLite directly within its process memory. Database operations execute as low-latency C-level function calls.
  3. Real-Time Event Bus (Server-Sent Events): Clients subscribe to record changes (Create, Update, Delete) via persistent HTTP SSE streams. Whenever a record in a subscribed collection changes, PocketBase immediately broadcasts the event to authorized listeners.
  4. Pluggable File Storage: PocketBase manages file uploads automatically, supporting local disk storage out of the box or offloading to S3-compatible object storage (e.g., MinIO or Cloudflare R2).
  5. Extensibility via JavaScript Hooks (pb_hooks): Developers can customize backend workflows, validate payloads, send transactional emails, or trigger custom APIs by writing standard ES6 JavaScript files placed in the pb_hooks directory without compiling Go code.

Production Deployment on Ubuntu 24.04/22.04 LTS

Follow these steps to deploy PocketBase securely on a clean Ubuntu VPS instance.

Step 1: System Provisioning and User Isolation

Never execute PocketBase as the root user. Create a dedicated system user and establish proper directory structures:

# Update base repositories and install core utilities
sudo apt update && sudo apt install -y unzip curl wget ufw certbot

# Create an isolated system user without interactive login shell
sudo useradd --system --no-create-home --shell /usr/sbin/nologin pocketbase

# Create directories for binary, configuration, and data
sudo mkdir -p /var/www/pocketbase/pb_data
sudo mkdir -p /var/www/pocketbase/pb_public
sudo mkdir -p /var/www/pocketbase/pb_hooks

Step 2: Download and Install the PocketBase Binary

Verify and fetch the latest compiled Linux binary from GitHub:

# Fetch latest version release tag
PB_VERSION=$(curl -s https://api.github.com/repos/pocketbase/pocketbase/releases/latest | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')

echo "Downloading PocketBase v${PB_VERSION}..."

cd /tmp
wget "https://github.com/pocketbase/pocketbase/releases/download/v${PB_VERSION}/pocketbase_${PB_VERSION}_linux_amd64.zip"

# Unpack directly into application directory
sudo unzip -o "pocketbase_${PB_VERSION}_linux_amd64.zip" -d /var/www/pocketbase/
rm -f "pocketbase_${PB_VERSION}_linux_amd64.zip"

# Grant non-root ownership and restrictive permissions
sudo chown -R pocketbase:pocketbase /var/www/pocketbase
sudo chmod 750 /var/www/pocketbase
sudo chmod 700 /var/www/pocketbase/pb_data

Step 3: Configure Systemd Service

Create a systemd unit file to manage PocketBase lifecycle events, automatic restarts on failure, and process resource boundaries:

# /etc/systemd/system/pocketbase.service
[Unit]
Description=PocketBase Realtime Backend Service
After=network.target

[Service]
Type=simple
User=pocketbase
Group=pocketbase
WorkingDirectory=/var/www/pocketbase
ExecStart=/var/www/pocketbase/pocketbase serve --http="127.0.0.1:8090" --dir="/var/www/pocketbase/pb_data"

# Restart behavior
Restart=always
RestartSec=5s

# Security hardening and sandboxing
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true
PrivateTmp=true

# High concurrency file descriptor limits
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target

Enable and start the service:

sudo systemctl daemon-reload
sudo systemctl enable pocketbase
sudo systemctl start pocketbase

# Verify operational status
sudo systemctl status pocketbase

PocketBase will initialize its internal SQLite database inside /var/www/pocketbase/pb_data and bind to 127.0.0.1:8090.


SQLite Production Tuning for High Concurrency

SQLite is remarkably fast when configured correctly. Because it runs in-process without network overhead, read latency is measured in microseconds. However, default out-of-the-box SQLite configurations favor conservative embedded devices rather than high-throughput web servers.

PocketBase automatically applies Write-Ahead Logging (WAL) mode to its primary database connections. When building custom integrations or fine-tuning database pragmas on pure NVMe storage arrays, ensure the following pragmas are active:

-- 1. Enable Write-Ahead Logging for non-blocking concurrent reads
PRAGMA journal_mode = WAL;

-- 2. Relax disk sync frequency without risking file integrity
PRAGMA synchronous = NORMAL;

-- 3. Prevent locking exceptions during concurrent write contention (5000ms delay)
PRAGMA busy_timeout = 5000;

-- 4. Enable memory-mapped I/O for 256MB active page cache
PRAGMA mmap_size = 268435456;

-- 5. Increase internal page cache to ~64MB (negative value denotes kibibytes)
PRAGMA cache_size = -64000;

-- 6. Store temporary tables and indices directly in RAM
PRAGMA temp_store = MEMORY;

Explaining the Pragmas

  • journal_mode = WAL: In traditional rollback journal mode, writing to the database locks out all readers entirely. In WAL mode, SQLite appends changes to a separate -wal file. Readers continue accessing the main database file concurrently without blocking writers, and writers do not block readers.
  • synchronous = NORMAL: In FULL sync mode, every single transaction forces an fsync() system call to physical disk platters. NORMAL sync guarantees that WAL writes commit safely while eliminating redundant disk flushes, reducing disk write latency by over 70%.
  • busy_timeout = 5000: Under heavy concurrent write operations (such as multiple users purchasing tickets or submitting form data simultaneously), a second write operation might encounter a temporary file lock. Instead of throwing an immediate SQLITE_BUSY error, this parameter instructs SQLite to sleep and retry for up to 5 seconds.
  • mmap_size = 268435456: Direct memory mapping allows the Linux kernel to map 256MB of the SQLite database file directly into the PocketBase virtual memory space, bypassing costly user-space read buffer copies.

On pure NVMe storage arrays with these parameters, an embedded SQLite database routinely processes 10,000+ read operations per second with sub-millisecond latencies.


Reverse Proxy and SSL Termination

Never expose PocketBase’s internal port 8090 directly to the public internet. Use a battle-tested reverse proxy like Nginx or Caddy to handle SSL termination, rate limiting, and HTTP/2 connection multiplexing.

Option A: Nginx Production Configuration

Create the virtual host configuration at /etc/nginx/sites-available/pocketbase.conf:

# Upstream definition for PocketBase local loopback
upstream pocketbase_backend {
    server 127.0.0.1:8090;
    keepalive 32;
}

server {
    listen 80;
    listen [::]:80;
    server_name api.youragency.pk;

    # Automated Let's Encrypt challenge route
    location /.well-known/acme-challenge/ {
        root /var/www/html;
    }

    # Redirect all HTTP traffic to HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name api.youragency.pk;

    # SSL Certificate Paths (Managed via Certbot)
    ssl_certificate /etc/letsencrypt/live/api.youragency.pk/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.youragency.pk/privkey.pem;

    # Modern TLS Security Parameters
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    ssl_session_tickets off;

    # Security Headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Allow up to 50MB for mobile photo/file attachments
    client_max_body_size 50M;

    # PocketBase Admin UI and API Proxy
    location / {
        proxy_pass http://pocketbase_backend;
        
        # Standard HTTP Proxy Headers
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Critical for Real-Time SSE (Server-Sent Events) and WebSockets
        proxy_http_version 1.1;
        proxy_set_header Connection '';
        proxy_set_header Upgrade $http_upgrade;
        proxy_buffering off;
        proxy_cache off;
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

Enable the configuration and obtain Let’s Encrypt certificates:

sudo ln -s /etc/nginx/sites-available/pocketbase.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

# Generate TLS certificate
sudo certbot --nginx -d api.youragency.pk

Note on SSE Connection Streaming: The directives proxy_buffering off; and proxy_read_timeout 86400s; are critical. If proxy buffering is enabled, Nginx will hold back real-time database change events until its internal 4KB buffer fills up, breaking live updates in mobile apps.


Client SDK Integration: Flutter and Next.js

PocketBase provides official client SDKs for Dart/Flutter and JavaScript/TypeScript.

1. Flutter Integration Example

Add the client package to your Flutter project’s pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  pocketbase: ^0.19.0

Initialize the client and establish real-time subscriptions in your Flutter service layer:

import 'package:flutter/material.dart';
import 'package:pocketbase/pocketbase.dart';

class PocketBaseService {
  static final PocketBase pb = PocketBase('https://api.youragency.pk');

  // Authenticate user via email and password
  static Future<RecordAuth> loginUser(String email, String password) async {
    try {
      final authData = await pb.collection('users').authWithPassword(email, password);
      return authData;
    } catch (e) {
      throw Exception('Authentication failed: $e');
    }
  }

  // Subscribe to real-time order updates
  static void listenToOrders(Function(RecordSubscriptionEvent) onEvent) {
    pb.collection('orders').subscribe('*', (event) {
      // Handles 'create', 'update', and 'delete' actions in real time
      onEvent(event);
    });
  }

  // Unsubscribe when widget disposes
  static void unsubscribeOrders() {
    pb.collection('orders').unsubscribe('*');
  }
}

2. Next.js (TypeScript) Client Integration

Install the official JavaScript SDK:

npm install pocketbase

Instantiate the singleton client in lib/pocketbase.ts:

import PocketBase from 'pocketbase';

export const pb = new PocketBase('https://api.youragency.pk');

// Ensure cookie persistence for Next.js SSR / App Router
export function getAuthenticatedUser() {
  return pb.authStore.isValid ? pb.authStore.model : null;
}

// Real-time record listener
export function subscribeToProjectTasks(projectId: string, callback: (data: any) => void) {
  pb.collection('tasks').subscribe('*', function (e) {
    if (e.record.project === projectId) {
      callback(e);
    }
  });

  return () => {
    pb.collection('tasks').unsubscribe('*');
  };
}

Custom Backend Logic with pb_hooks

Rather than maintaining a separate Node.js or Python microservice to process business rules, PocketBase features an integrated JavaScript execution engine powered by Goja.

Create a hook file at /var/www/pocketbase/pb_hooks/orders.pb.js:

/// <reference path="../pb_data/types.d.ts" />

// Triggered automatically before an order record is created
onRecordBeforeCreateRequest((e) => {
    const totalAmount = e.record.get("total_amount");
    
    // Business validation: prevent zero-value orders
    if (totalAmount <= 0) {
        throw new BadRequestError("Order total must be greater than PKR 0");
    }

    // Automatically set default order status
    e.record.set("status", "pending_payment");
}, "orders");

// Triggered after an order is successfully created
onRecordAfterCreateRequest((e) => {
    const customerEmail = e.record.get("customer_email");
    const orderId = e.record.id;

    // Send order confirmation email via built-in mailer
    const message = new MailerMessage({
        from: {
            address: $app.settings().meta.senderAddress,
            name: $app.settings().meta.senderName,
        },
        to: [{ address: customerEmail }],
        subject: `Order Confirmation #${orderId}`,
        html: `<p>Thank you for your order. Your tracking ID is <strong>${orderId}</strong>.</p>`,
    });

    $app.newMailClient().send(message);
}, "orders");

Whenever PocketBase detects files inside pb_hooks/, it dynamically compiles and executes them within its Go process without restarting the service.


Disaster Recovery: Streaming Replication with Litestream

Because SQLite stores all records in a local disk file (pb_data/data.db), standard relational database replication tools (such as PostgreSQL streaming replication) do not apply.

The standard tool for continuous SQLite disaster recovery is Litestream. Litestream runs alongside PocketBase as a background daemon, intercepting WAL write transactions and streaming them instantaneously to an offsite S3-compatible bucket (e.g., MinIO, Backblaze B2, or Cloudflare R2).

[ PocketBase Writes ]
         |
         v
[ /pb_data/data.db-wal ] <--- (Litestream monitors changes)
         |
         v
[ Litestream Daemon ] -------> (Real-time S3 Encrypted Streaming)
                                       |
                                       v
                            [ Offsite Object Storage ]

Installing and Configuring Litestream

Install Litestream on your Ubuntu host:

wget https://github.com/benbjohnson/litestream/releases/download/v0.3.13/litestream-v0.3.13-linux-amd64.deb
sudo dpkg -i litestream-v0.3.13-linux-amd64.deb

Create /etc/litestream.yml:

dbs:
  - path: /var/www/pocketbase/pb_data/data.db
    replicas:
      - type: s3
        bucket: my-company-backups
        path: pocketbase/data.db
        endpoint: https://s3.ap-southeast-1.amazonaws.com
        access-key-id: YOUR_S3_ACCESS_KEY
        secret-access-key: YOUR_S3_SECRET_KEY

Create a systemd unit for Litestream (/etc/systemd/system/litestream.service):

[Unit]
Description=Litestream SQLite Continuous Replication
After=network.target

[Service]
Type=simple
User=pocketbase
ExecStart=/usr/local/bin/litestream replicate -config /etc/litestream.yml
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target

Start Litestream:

sudo systemctl daemon-reload
sudo systemctl enable --now litestream

In the event of physical hardware failure, your entire database can be restored to the exact second of failure with a single command:

litestream restore -config /etc/litestream.yml /var/www/pocketbase/pb_data/data.db

Hardware Scaling: When to Move Beyond Shared Virtualization

While PocketBase’s single-binary architecture operates efficiently on standard virtual machines, high-traffic consumer mobile applications encounter distinct hardware boundaries as their user bases grow.

+-------------------------------------------------------------------------+
|                  Application Scale and Infrastructure Fit               |
|                                                                         |
|  [ 1 - 25,000 Daily Active Users ]                                      |
|  * Standard Linux VPS (1-2 vCPUs, 2GB RAM, Shared NVMe)                 |
|  * Sub-millisecond SQLite queries                                       |
|  * Adequate for MVPs, client apps, and agency backends                  |
|                                                                         |
|  [ 25,000 - 50,000 Daily Active Users ]                                 |
|  * High-Compute Linux VPS (4-8 vCPUs, 8-16GB RAM, Dedicated Virtual IOPS)|
|  * Litestream offsite streaming active                                  |
|  * In-memory page cache scaled to 512MB                                 |
|                                                                         |
|  [ 50,000+ Daily Active Users / Heavy Write Bursts ]                    |
|  * Dedicated Bare-Metal Servers                                         |
|  * Unshared enterprise NVMe drives (Zero hypervisor disk throttling)    |
|  * Pure physical memory buses (Zero memory overcommitment)              |
|  * Predictable sub-10ms domestic latency across Pakistani ISPs          |
+-------------------------------------------------------------------------+

1. Storage I/O Contention and Noisy Neighbors

Virtual private servers operate on multi-tenant hypervisors. When neighboring VMs on the host node execute aggressive disk operations, virtual disk I/O latency spikes. Because SQLite WAL writes rely on consistent NVMe write acknowledgment, shared disk throttling can cause write queue latency to cascade into HTTP request timeouts.

2. Multi-Core Concurrent SSE Connections

When an application scales beyond 30,000 to 50,000 concurrent mobile devices maintaining open SSE or WebSocket streams, the Linux kernel must manage thousands of persistent TCP sockets. Dedicated CPU cores eliminate hypervisor scheduling latency, ensuring continuous event broadcast without dropping connections.

3. Transitioning to Bare-Metal Hardware

When your mobile application or SaaS platform reaches this scale, migrating to enterprise Dedicated Servers provides unmetered bare-metal hardware:

  • Dedicated Enterprise NVMe Storage: Raw PCIe 4.0/5.0 NVMe arrays operating without hypervisor abstraction layers deliver millions of random read/write IOPS directly to SQLite.
  • Physical RAM Bandwidth: Unconstrained access to physical ECC DDR4/DDR5 channels allows SQLite to maintain multi-gigabyte databases fully resident in RAM cache.
  • Domestic Network Peering: Hosting on high-speed Dedicated Servers in Pakistan routes traffic directly through domestic internet exchanges (PIX) and major local carriers (PTCL, Nayatel, StormFiber, Transworld, and Jazz). This reduces roundtrip latency for Pakistani mobile users to under 15ms.

Production Security and Hardening Checklist

Before launching your PocketBase backend to public app stores, ensure the following hardening steps are complete:

  • Change Default Admin URL: Access your PocketBase admin dashboard at https://api.youragency.pk/_/ immediately after deployment, configure a strong password with 16+ characters, and enable Multi-Factor Authentication (MFA).
  • Restrict Collection API Rules: By default, ensure collection API access rules are explicitly scoped. Never leave write or delete rules empty (""), which permits unrestricted public access. Use rule expressions such as @request.auth.id != "" or @request.auth.role = "admin".
  • Configure Automated Firewall: Restrict open inbound ports on Ubuntu via UFW to only SSH (22), HTTP (80), and HTTPS (443):
    sudo ufw default deny incoming
    sudo ufw default allow outgoing
    sudo ufw allow 22/tcp
    sudo ufw allow 80/tcp
    sudo ufw allow 443/tcp
    sudo ufw enable
  • Enable Daily Local Snapshot Crons: In addition to Litestream streaming, schedule nightly SQLite database backups via cron:
    # Run nightly at 03:00 AM
    0 3 * * * sqlite3 /var/www/pocketbase/pb_data/data.db ".backup '/var/backups/pb_data_$(date +\%F).db'"

Summary

Self-hosting PocketBase on an enterprise Linux VPS gives Pakistani software teams, mobile developers, and digital agencies complete independence from volatile USD cloud pricing and restrictive international payment gateways. With a memory baseline of under 50MB, an embedded SQLite engine capable of thousands of requests per second, and built-in real-time subscriptions, PocketBase delivers an efficient and sustainable backend foundation.

ENTERPRISE CLOUD INFRASTRUCTURE

Deploy Production-Ready Linux VPS for Your Backend

Eliminate recurring USD SaaS fees. Host PocketBase, SQLite, Flutter backends, and full-stack applications on NextGen high-speed Linux VPS nodes with pure NVMe storage, dedicated static IPv4, and 24/7 senior infrastructure engineering support in Pakistan.