Digital product design in Pakistan has matured rapidly over the past decade. Software houses in Lahore, product studios in Karachi, and emerging tech collectives in Islamabad now deliver complex enterprise applications, fintech platforms, and consumer SaaS to clients across North America, Europe, and the GCC.
However, the modern design stack relies heavily on proprietary SaaS platforms—most notably Figma. While Figma transformed multiplayer interface design, its commercial pricing model has become an unsustainable operational liability for Pakistani technology agencies operating under strict foreign currency constraints, high banking withholding taxes, and tightening data sovereignty mandates.
Deploying a self-hosted instance of Penpot on a private Linux Virtual Private Server (VPS) provides Pakistani design teams with an open-source, web-standard (SVG/CSS) collaborative design platform that eliminates per-editor recurring USD subscription fees, keeps client intellectual property completely sovereign, and ensures sub-20ms multiplayer canvas responsiveness.
This guide delivers a complete, production-grade deployment architecture for engineering leads, agency CTOs, and systems administrators deploying Penpot on Ubuntu Linux.
The Economic and Regulatory Reality of Proprietary Design Tools in Pakistan
For a digital agency with 15 to 30 product designers, UI/UX researchers, and frontend developers, licensing proprietary tools in US Dollars creates systemic operational overhead:
Per-Seat Foreign Currency Drain
Figma operates on a per-editor billing model:
- Professional Tier: $12 to $15 per editor/month.
- Organization Tier: $45 per editor/month.
- Enterprise Tier: $75 per editor/month.
For a mid-sized team of 20 designers on the Organization tier, an agency incurs an annual software expenditure of $10,800 USD. At prevailing Pakistani Rupee exchange rates (PKR 280–300 per USD), this equates to over PKR 3,000,000 to PKR 3,240,000 annually in recurring software rent alone.
Banking FX Caps and SBP Withholding Taxes
Under State Bank of Pakistan (SBP) foreign exchange guidelines, corporate credit and debit cards face stringent limits on foreign currency digital transactions.
Furthermore, Section 236Y of the Income Tax Ordinance imposes an Advance Withholding Tax (WHT) of 5% for active tax filers (and up to 10% for non-filers) on all outward international card payments, in addition to standard bank card issuance charges (3% to 5% foreign currency conversion markups). A monthly USD invoice of $900 effectively costs an agency between PKR 280,000 and PKR 310,000 once statutory deductions and currency spreads are factored in.
Client IP Sovereignty and Non-Disclosure Agreements (NDAs)
Pakistani software export houses frequently design proprietary enterprise workflows, healthcare portals, and fintech interfaces for overseas clients. When designs are hosted on third-party multi-tenant US cloud servers, agencies remain exposed to:
- Changes in proprietary terms of service and unexpected account locks.
- Client audit failures concerning non-EU/non-GCC data residency clauses.
- Unintentional cloud metadata sharing and telemetry ingestion.
Self-hosting Penpot on a dedicated Linux VPS retains 100% of the design database, font files, vector components, and version history within your own private infrastructure.
Architectural Comparison: Penpot vs. Proprietary Cloud SaaS
| Architectural Dimension | Proprietary Cloud SaaS (Figma) | Self-Hosted Penpot on Linux VPS |
|---|---|---|
| Underlying File Format | Closed, proprietary binary schema | Open-standard native SVG and CSS code |
| Licensing Model | Recurring per-editor monthly fee in USD | 100% Open Source (MPL 2.0); fixed infrastructure cost in PKR |
| Data Storage Location | Multi-tenant shared US cloud data centers | Private dedicated VPS or on-premise server |
| Real-time Engine | Proprietary WebAssembly / C++ cloud engine | Clojure HotSpot JVM + Redis pub/sub WebSocket server |
| Code Inspection | Synthetic CSS/Tailwind emulation | Native CSS Grid, Flexbox, and SVG DOM layout |
| Self-Hosting / Air-Gapped | Unavailable | Fully supported on bare-metal or virtualized Linux |
| User Onboarding Limits | Strictly capped by paid license seats | Unlimited editors, viewers, and guest review accounts |
Penpot Technical Architecture Overview
Penpot is engineered from the ground up as a cloud-native, distributed microservice application built on web standards:
[ Client Browsers / Desktop Apps ]
│
▼ (HTTPS / WSS on Port 443)
[ Nginx Reverse Proxy ]
│ │
│ (HTTP) │ (Upgrade: WebSocket)
▼ ▼
[ penpot-frontend ] [ penpot-backend ] ◄──► [ penpot-redis ]
(Nginx Static) (Clojure JVM) (Session / PubSub)
│
┌──────────────┼──────────────┐
▼ ▼ ▼
[ PostgreSQL 16 ] [ penpot-exporter ] [ Persistent Asset Volume ]
(Metadata & DB) (Node.js/Puppeteer) (/opt/penpot/assets)
The system comprises five core services:
penpot-frontend: A lightweight container serving the compiled ClojureScript web application, styling sheets, and static UI bundles.penpot-backend: A high-throughput Clojure application running on the Java Virtual Machine (HotSpot JVM). It executes business logic, database queries, and multi-user synchronization.penpot-websocket: An embedded asynchronous notification and event-streaming service inside the backend that coordinates real-time multiplayer cursor positions and canvas updates over WebSockets (/ws/notifications).penpot-exporter: A dedicated Node.js microservice utilizing headless Chromium (Puppeteer) to execute heavy vector and raster exports (SVG, PDF, PNG) asynchronously without degrading primary canvas latency.penpot-postgres&penpot-redis: PostgreSQL handles persistent data structures (teams, projects, component libraries, file revisions), while Redis coordinates cache distribution and transient message queues.
Hardware and Virtualization Sizing Matrix
The primary performance bottleneck in self-hosted Penpot environments is JVM memory exhaustion and disk I/O bottlenecks during vector parsing. Match your infrastructure to your active design team size:
| Design Team Size | Concurrent Active Artboards | Recommended Infrastructure | Minimum CPU & RAM | Storage Type |
|---|---|---|---|---|
| Small Studio (1–8 Designers) | 50–150 artboards | Cloud VPS | 4 vCPU cores, 8 GB RAM | 80 GB NVMe |
| Mid-Size Agency (10–30 Designers) | 200–800 artboards | Enterprise Cloud VPS | 8 vCPU cores, 16 GB RAM | 250 GB NVMe |
| Software House (30–60 Designers) | 1,000+ screens | High-RAM VPS or Dedicated Server | 16 vCPU cores, 32 GB RAM | 500 GB Enterprise NVMe |
| Enterprise / Multi-Team (60+ Designers) | Massive design systems | Bare-Metal Dedicated Server | Dual AMD EPYC / Intel Xeon, 64 GB+ RAM | RAID-1 Enterprise NVMe |
Step-by-Step Production Deployment on Ubuntu 24.04/22.04 LTS
Step 1: System Provisioning and Docker Engine Setup
Update base packages and install official Docker engine with the Compose V2 plugin:
# Update repository package lists
sudo apt-get update && sudo apt-get upgrade -y
# Install prerequisite security packages
sudo apt-get install -y ca-certificates curl gnupg lsb-release
# Add Docker official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Set up repository
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker CE and Compose V2
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Enable and start Docker service
sudo systemctl enable --now docker
Step 2: Establish the Penpot Directory Structure
Create dedicated host directories for configurations, database persistence, and uploaded assets:
sudo mkdir -p /opt/penpot/{assets,postgres,redis}
cd /opt/penpot
Step 3: Configure Environment Variables (config.env)
Generate strong cryptographic keys and configure production variables:
# Generate secret keys
PENPOT_SECRET_KEY=$(openssl rand -hex 32)
POSTGRES_PASSWORD=$(openssl rand -hex 24)
Create /opt/penpot/config.env:
## ------------------------------------------------------------------
## PENPOT CORE PRODUCTION CONFIGURATION
## ------------------------------------------------------------------
# Public domain and URI configuration
PENPOT_PUBLIC_URI=https://penpot.youragency.pk
# Database credentials
PENPOT_DATABASE_URI=postgresql://penpot-postgres/penpot
PENPOT_DATABASE_USERNAME=penpot
PENPOT_DATABASE_PASSWORD=SuperSecurePostgresPasswordHere
# Redis Cache URI
PENPOT_REDIS_URI=redis://penpot-redis/0
# Asset Directory & Storage
PENPOT_ASSETS_STORAGE_BACKEND=assets-fs
PENPOT_STORAGE_ASSETS_FS_DIRECTORY=/opt/data/assets
# Exporter Service URI
PENPOT_EXPORTER_URI=http://penpot-exporter:6001
# Application Security Secret Key
PENPOT_SECRET_KEY=ReplaceWithGenerated32ByteHexSecretKey
# Team Registration Policies (Disable public registration after setup)
PENPOT_REGISTRATION_ENABLED=true
PENPOT_ALLOW_DEMO_USERS=false
# JVM Memory Tuning (Crucial for Component Libraries)
PENPOT_JVM_OPTS=-Xms2g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=100
## ------------------------------------------------------------------
## CORPORATE SMTP RELAY CONFIGURATION
## ------------------------------------------------------------------
# Team invitations and password resets depend on valid outbound email
PENPOT_SMTP_DEFAULT_FROM[email protected]
PENPOT_SMTP_DEFAULT_REPLY_TO[email protected]
PENPOT_SMTP_HOST=mail.youragency.pk
PENPOT_SMTP_PORT=587
PENPOT_SMTP_USER[email protected]
PENPOT_SMTP_PASSWORD=YourCorporateEmailPasswordHere
PENPOT_SMTP_TLS=true
PENPOT_SMTP_SSL=false
Step 4: Author the Production docker-compose.yaml
Save the following specification in /opt/penpot/docker-compose.yaml:
version: "3.8"
networks:
penpot-net:
driver: bridge
volumes:
penpot_postgres_data:
driver: local
penpot_assets_data:
driver: local
services:
penpot-frontend:
image: penpotapp/frontend:latest
restart: unless-stopped
container_name: penpot-frontend
networks:
- penpot-net
ports:
- "127.0.0.1:9001:80"
volumes:
- penpot_assets_data:/opt/data/assets
env_file:
- config.env
depends_on:
- penpot-backend
- penpot-exporter
penpot-backend:
image: penpotapp/backend:latest
restart: unless-stopped
container_name: penpot-backend
networks:
- penpot-net
volumes:
- penpot_assets_data:/opt/data/assets
env_file:
- config.env
depends_on:
- penpot-postgres
- penpot-redis
penpot-exporter:
image: penpotapp/exporter:latest
restart: unless-stopped
container_name: penpot-exporter
networks:
- penpot-net
env_file:
- config.env
penpot-postgres:
image: postgres:16-alpine
restart: unless-stopped
container_name: penpot-postgres
networks:
- penpot-net
volumes:
- penpot_postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: penpot
POSTGRES_USER: penpot
POSTGRES_PASSWORD: SuperSecurePostgresPasswordHere
penpot-redis:
image: redis:7-alpine
restart: unless-stopped
container_name: penpot-redis
networks:
- penpot-net
Launch the stack in detached mode:
docker compose up -d
Verify service status:
docker compose ps
Java Virtual Machine (JVM) Sizing and Memory Optimization
A common issue encountered when self-hosting Penpot on default configurations is the Clojure backend crashing with java.lang.OutOfMemoryError: Java heap space when handling complex UI design systems with hundreds of nested components and typography styles.
In config.env, we configured:
PENPOT_JVM_OPTS=-Xms2g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=100
Technical Breakdown:
-Xms2g: Allocates an initial heap of 2 Gigabytes on startup, preventing dynamic memory resizing latency.-Xmx4g: Sets the maximum heap threshold to 4 Gigabytes. On an 8 GB or 16 GB Linux VPS, this leaves ample unallocated memory for PostgreSQL’s buffer pool (shared_buffers) and the Node.js headless Chromium exporter processes.-XX:+UseG1GC: Enables the Garbage-First Garbage Collector, designed for multi-processor machines with large memory spaces. It divides heap space into regions, minimizing stop-the-world pauses.-XX:MaxGCPauseMillis=100: Sets a soft target of 100 milliseconds for pause times. This ensures that real-time WebSocket communication remains uninterrupted, avoiding multiplayer cursor stuttering.
Nginx Reverse Proxy with WebSocket Upgrades and TLS
Penpot requires a robust reverse proxy to terminate TLS, handle large binary asset uploads (complex SVGs, high-resolution mockups, custom font files), and sustain persistent WebSocket connections.
Install Nginx and Certbot:
sudo apt-get install -y nginx certbot python3-certbot-nginx
Obtain an SSL certificate:
sudo certbot certonly --nginx -d penpot.youragency.pk
Create /etc/nginx/sites-available/penpot:
# Upstream definition for frontend container
upstream penpot_backend {
server 127.0.0.1:9001;
keepalive 32;
}
server {
listen 80;
listen [::]:80;
server_name penpot.youragency.pk;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name penpot.youragency.pk;
ssl_certificate /etc/letsencrypt/live/penpot.youragency.pk/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/penpot.youragency.pk/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# Maximum file upload size (Critical for large font packs and mockups)
client_max_body_size 120M;
# Security Headers
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Standard Application Delivery
location / {
proxy_pass http://penpot_backend;
proxy_http_version 1.1;
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;
proxy_connect_timeout 90s;
proxy_send_timeout 90s;
proxy_read_timeout 90s;
}
# Real-Time Collaborative Canvas WebSocket Upgrade Path
location /ws/notifications {
proxy_pass http://penpot_backend/ws/notifications;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
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;
# Keep alive settings for sustained multi-hour design sessions
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
}
Enable the configuration and reload Nginx:
sudo ln -s /etc/nginx/sites-available/penpot /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Configuring Custom Typography and Corporate Font Libraries
A major requirement for branding and UI/UX studios in Pakistan is the ability to render custom commercial fonts, local typography (such as bespoke Urdu Nastaliq or Arabic display typefaces), and proprietary corporate type families.
Uploading Custom Fonts via System Workspace
Penpot allows organization administrators to upload .ttf, .otf, and .woff2 font files directly through the web UI under Team Settings > Fonts.
To ensure fonts are preserved across container updates:
- Ensure the
penpot_assets_datavolume is backed by a permanent host directory or persistent Docker volume. - Ensure directory permissions allow the container’s internal non-root user (UID
1001) to write to the asset directory:
sudo chown -R 1001:1001 /var/lib/docker/volumes/penpot_penpot_assets_data/_data
Once uploaded, custom typography is converted and stored within the persistent asset store, ensuring every designer on the team renders identical glyph metrics without local font file mismatch errors.
Automated Disaster Recovery and Cold Backup Strategy
Design files and version history represent hundreds of hours of agency billable work. A robust backup policy must snapshot both the PostgreSQL relational metadata and the file asset volume.
Create /opt/scripts/backup-penpot.sh:
#!/usr/bin/env bash
set -eo pipefail
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_DIR="/var/backups/penpot"
POSTGRES_CONTAINER="penpot-postgres"
ASSETS_PATH="/var/lib/docker/volumes/penpot_penpot_assets_data/_data"
mkdir -p "${BACKUP_DIR}"
echo "[$(date)] Starting Penpot production backup..."
# 1. Dump PostgreSQL relational metadata
docker exec -t "${POSTGRES_CONTAINER}" pg_dump -U penpot penpot | gzip > "${BACKUP_DIR}/penpot_db_${TIMESTAMP}.sql.gz"
# 2. Archive persistent asset files (SVGs, uploaded images, custom fonts)
tar -czf "${BACKUP_DIR}/penpot_assets_${TIMESTAMP}.tar.gz" -C "${ASSETS_PATH}" .
# 3. Prune local backups older than 14 days
find "${BACKUP_DIR}" -type f -name "*.tar.gz" -mtime +14 -delete
find "${BACKUP_DIR}" -type f -name "*.sql.gz" -mtime +14 -delete
echo "[$(date)] Backup completed successfully."
Make the script executable:
sudo chmod +x /opt/scripts/backup-penpot.sh
Off-Site Cloud Synchronization
Use rclone or the AWS CLI to sync backups to an off-site S3-compatible bucket every midnight:
# Add to crontab via `sudo crontab -e`
0 2 * * * /opt/scripts/backup-penpot.sh && rclone sync /var/backups/penpot remote-s3:agency-penpot-backups/
When to Scale: Linux VPS vs. Bare-Metal Dedicated Servers
While a shared or dedicated virtual private server (VPS) is the ideal cost-effective foundation for teams up to 30 or 40 designers, fast-growing software export houses and product design studios eventually encounter physical scaling boundaries:
The Virtualization Ceiling
- vCPU Steal Time: In virtualized environments, multi-tenant neighbor activity can introduce micro-spikes in CPU steal time. In multiplayer design tools, a 50ms scheduling delay causes visible cursor hitching and sync lag.
- Concurrent Chromium Rendering: When multiple teams trigger simultaneous exports of 100-screen mobile UI flows to 3x PNGs or multi-page PDFs, the
penpot-exportercontainer spawns multiple headless Chromium instances. This can saturate shared hypervisor CPU cores. - Memory Pressure: As design libraries grow into thousands of shared design tokens, variants, and vector assets, the Clojure HotSpot JVM requires 8 GB to 16 GB of dedicated heap alone.
Moving to Dedicated Bare-Metal Infrastructure
When your agency exceeds 50 simultaneous contributors across multiple design pods, migrating to bare-metal Dedicated Servers provides:
- 100% Guaranteed Physical Hardware: Zero hypervisor overhead, eliminating CPU steal and lock contention during large exports.
- Unmetered Low-Latency Bandwidth: Fast asset streaming and WebSocket throughput without multi-tenant throttling.
- Local Data Ingestion: For defense, enterprise banking, and high-security government contracts in Pakistan, running on Dedicated Servers in Pakistan ensures that sensitive design assets and system architecture schematics never leave the sovereign physical borders of the country.
Conclusion: Reclaiming Autonomy Over Your Agency Design Stack
Proprietary SaaS lock-in no longer needs to be a mandatory cost of doing business for Pakistani digital product agencies. By deploying self-hosted Penpot on high-performance Linux VPS infrastructure, digital agencies eliminate fluctuating foreign exchange fees, bypass corporate card withholding taxes, and ensure ironclad client data sovereignty.
With proper JVM memory tuning, Nginx WebSocket optimization, and automated off-site backups, a self-hosted Penpot environment provides your creative team with an enterprise-grade, lightning-fast design environment tailored entirely to your workflow.
Deploy Self-Hosted Penpot on Nextgen High-Performance VPS
Eliminate recurring USD per-seat SaaS costs and secure 100% intellectual property sovereignty for your digital agency. Experience ultra-low latency canvas collaboration on dedicated Linux VPS and bare-metal servers backed by local Pakistani payment methods.
