Permify is distributed as a Docker image (ghcr.io/permify/permify) and a pre-built binary. Choose the method that matches your environment.
By default Permify listens on port 3476 for HTTP/REST and port 3478 for gRPC. In-memory storage is used unless you configure a database.
Verify your installation
After starting Permify with any method below, confirm it is running:
curl http://localhost:3476/healthz
A healthy instance returns SERVING.
Installation methods
Docker
Homebrew
AWS ECS
Railway
Fly.io
Google Cloud
Pull and run the container
docker run -p 3476:3476 -p 3478:3478 ghcr.io/permify/permify
This starts Permify with in-memory storage. Data is lost when the container stops.Mount a config file
Create a config.yaml based on the configuration reference, then mount it:docker run \
-p 3476:3476 \
-p 3478:3478 \
-v /path/to/config:/config \
ghcr.io/permify/permify
The directory mounted at /config must contain your config.yaml. Configure with flags instead (optional)
You can pass any configuration option as a CLI flag:docker run \
-p 3476:3476 \
-p 3478:3478 \
ghcr.io/permify/permify \
serve \
--database-engine=postgres \
--database-uri="postgres://user:password@host:5432/permify"
To see all flags:docker run ghcr.io/permify/permify --help
Verify
curl http://localhost:3476/healthz
Install via Homebrew
brew install permify/tap/permify
Start Permify
To use a config file:permify serve --config=/path/to/config.yaml
Verify
curl http://localhost:3476/healthz
Deploy Permify to AWS using Elastic Container Service (ECS) on EC2.Create an EC2 security group
Create a security group with the following inbound rules:| Type | Protocol | Port | Source |
|---|
| Custom TCP | TCP | 3476 | 0.0.0.0/0, ::/0 |
| Custom TCP | TCP | 3478 | 0.0.0.0/0, ::/0 |
| SSH | TCP | 22 | 0.0.0.0/0 |
Use the same VPC you will assign to your ECS cluster. Create an ECS cluster
In the AWS console, navigate to Elastic Container Service → Clusters → Create Cluster.
- Choose EC2 Linux + Networking.
- Select your instance type (e.g.
t4g.large; t2.micro for free-tier testing).
- Choose the VPC and subnet from step 1 and enable auto-assign public IP.
- Select the security group created in step 1.
Create a task definition
Navigate to ECS → Task Definitions → Create new task definition and choose the EC2 launch type.Add a container with the following settings:
- Image URI:
ghcr.io/permify/permify:latest
- Memory limit: 1024 MiB (adjust to your instance size)
- Port mappings:
3476 → 3476 (HTTP), 3478 → 3478 (gRPC)
- Command:
serve,--database-engine=postgres,--database-uri=postgres://user:password@db-host:5432/permify
Run the task
Go to your cluster, click Run new Task, choose the EC2 launch type, and select the task definition you just created.
Verify
Find the Public IPv4 DNS of your EC2 instance in the AWS console and run:curl http://<public-ipv4-dns>:3476/healthz
Add a PostgreSQL database
In your Railway project, click + New and add a PostgreSQL service. Railway will inject a DATABASE_URL environment variable automatically.
Set environment variables
In the Permify service settings, add:PERMIFY_DATABASE_ENGINE=postgres
PERMIFY_DATABASE_URI=${{Postgres.DATABASE_URL}}
PERMIFY_DATABASE_AUTO_MIGRATE=true
Verify
Open the Railway-generated URL and append /healthz:curl https://<your-railway-domain>/healthz
Create a Fly app
fly launch --image ghcr.io/permify/permify:latest
Follow the prompts to choose a region and app name.Provision a PostgreSQL database
fly postgres create
fly postgres attach --app <your-permify-app> <your-postgres-app>
This injects a DATABASE_URL secret into your app.Set configuration secrets
fly secrets set \
PERMIFY_DATABASE_ENGINE=postgres \
PERMIFY_DATABASE_URI="$(fly postgres connection-string)" \
PERMIFY_DATABASE_AUTO_MIGRATE=true
Verify
curl https://<your-app>.fly.dev/healthz
Enable required APIs
gcloud services enable compute.googleapis.com containerregistry.googleapis.com
Create a Compute Engine instance
gcloud compute instances create permify \
--machine-type=e2-medium \
--image-family=cos-stable \
--image-project=cos-cloud \
--tags=permify-server
Open firewall ports
gcloud compute firewall-rules create allow-permify \
--allow=tcp:3476,tcp:3478 \
--target-tags=permify-server
SSH in and run the container
gcloud compute ssh permify -- \
docker run -d \
-p 3476:3476 \
-p 3478:3478 \
-e PERMIFY_DATABASE_ENGINE=postgres \
-e PERMIFY_DATABASE_URI="postgres://user:password@<cloud-sql-ip>:5432/permify" \
ghcr.io/permify/permify
Verify
curl http://<external-ip>:3476/healthz
Database setup
For any production deployment you should use PostgreSQL instead of in-memory storage.
PostgreSQL 13.8 or later is required. Permify validates the version at startup and exits on older versions.
Minimal configuration
database:
engine: postgres
uri: postgres://user:password@host:5432/permify?sslmode=require
auto_migrate: true
max_connections: 20
min_connections: 2
max_connection_lifetime: 30m
max_connection_idle_time: 5m
For the Watch API
If you use the Watch API, you must also enable commit timestamp tracking on your PostgreSQL instance:
ALTER SYSTEM SET track_commit_timestamp = on;
Then restart PostgreSQL for the change to take effect.
Multi-replica deployments with pgcat
When running multiple Permify replicas, use pgcat as a connection pooler in front of PostgreSQL to prevent connection exhaustion:
database:
engine: postgres
writer:
uri: postgresql://postgres:DB_PASSWORD@pgcat:6432/permify?plan_cache_mode=force_custom_plan&default_query_exec_mode=cache_describe
reader:
uri: postgresql://postgres:DB_PASSWORD@pgcat:6432/permify?plan_cache_mode=force_custom_plan&default_query_exec_mode=cache_describe
max_connections: 1
min_connections: 0
See the full setup guide in the Configuration reference.