docs/self-hosting/deployment-options/docker-compose.mdx
Learn how to deploy Infisical using Docker Compose. This method runs Infisical and its dependencies (PostgreSQL and Redis) as containers on a single Docker host. It's ideal for trying out Infisical, development environments, or small-scale deployments that don't require high availability.
The short video below walks through deploying Infisical with Docker Compose, covering each step from setup to a running instance.
<div style={{ position: "relative", paddingBottom: "56.25%", height: 0, overflow: "hidden", maxWidth: "100%" }}> <iframe src="https://www.youtube.com/embed/cr-e7Zp9UtE" title="YouTube video player" style={{ position: "absolute", top: 0, left: 0, width: "100%", height: "100%", border: 0 }} allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowFullScreen ></iframe> </div>The following are minimum requirements for running Infisical with Docker Compose:
| Component | Minimum | Recommended |
|---|---|---|
| CPU | 2 cores | 4 cores |
| RAM | 4 GB | 8 GB |
| Disk | 20 GB | 50 GB+ (SSD recommended) |
These requirements include resources for Infisical, PostgreSQL, and Redis containers. For larger deployments with many secrets or users, increase resources accordingly.
```bash
docker --version
docker compose version
```
You should see version information for both commands. If not, install Docker and Docker Compose following the official documentation.
<Tabs>
<Tab title="curl">
```bash
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
```
</Tab>
<Tab title="wget">
```bash
wget -O docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
```
</Tab>
</Tabs>
<Tabs>
<Tab title="curl">
```bash
curl -o .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
```
</Tab>
<Tab title="wget">
```bash
wget -O .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
```
</Tab>
</Tabs>
Once downloaded, the credentials file will be saved to your working directory as `.env` file. View all available configurations [here](/self-hosting/configuration/envars).
<Warning>
The `.env` file contains secrets that control the security of your deployment. Do not commit it to version control, and protect access to it:
```bash
chmod 600 .env
```
</Warning>
```bash
docker compose -f docker-compose.prod.yml up -d
```
This command starts three containers:
- **backend**: The main Infisical application (exposed on host port 80, internal port 8080)
- **db**: PostgreSQL database for storing encrypted secrets
- **redis**: Redis for caching and job queues
```bash
docker compose -f docker-compose.prod.yml ps
```
You should see all three services with a status of `Up`. Next, verify Infisical is responding:
```bash
curl -s http://localhost:80/api/status | head -c 100
```
If successful, open your browser and navigate to `http://localhost:80` (or your configured domain) to create your admin account.
<Tip>
The first user to sign up becomes the instance administrator. Make sure to complete this step before exposing Infisical to others.
</Tip>
Podman Compose is an alternative way to run Infisical using Podman as a replacement for Docker. Podman is backwards compatible with Docker Compose files.
<Steps> <Step title="Verify prerequisites"> Confirm that Podman and Podman Compose are installed:```bash
podman version
podman-compose version
```
If not installed, follow the [Podman installation guide](https://podman-desktop.io/docs/installation) and [Podman Compose guide](https://podman-desktop.io/docs/compose).
<Tabs>
<Tab title="curl">
```bash
curl -o docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
```
</Tab>
<Tab title="wget">
```bash
wget -O docker-compose.prod.yml https://raw.githubusercontent.com/Infisical/infisical/main/docker-compose.prod.yml
```
</Tab>
</Tabs>
<Tabs>
<Tab title="curl">
```bash
curl -o .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
```
</Tab>
<Tab title="wget">
```bash
wget -O .env https://raw.githubusercontent.com/Infisical/infisical/main/.env.example
```
</Tab>
</Tabs>
Once downloaded, the credentials file will be saved to your working directory as `.env` file. View all available configurations [here](/self-hosting/configuration/envars).
```bash
podman machine init --now
podman machine set --rootful
podman machine start
```
<Note>
If using a rootless Podman install, you can skip `podman machine set --rootful`.
</Note>
Access the UI at `http://localhost:80`.
To stop all Infisical services:
docker compose -f docker-compose.prod.yml down
To restart services:
docker compose -f docker-compose.prod.yml up -d
To restart a specific service (e.g., after configuration changes):
docker compose -f docker-compose.prod.yml restart backend
The Docker Compose configuration uses named volumes to persist data:
| Volume | Purpose | Data Stored |
|---|---|---|
pg_data | PostgreSQL data | All encrypted secrets, users, projects, and configuration |
redis_data | Redis data | Cache and job queue data (can be regenerated) |
To view volumes:
docker volume ls | grep -E "pg_data|redis_data"
To back up the PostgreSQL volume:
docker compose -f docker-compose.prod.yml exec db pg_dump -U infisical infisical > backup_$(date +%Y%m%d_%H%M%S).sql
To view logs from all services:
docker compose -f docker-compose.prod.yml logs -f
To view logs from a specific service:
docker compose -f docker-compose.prod.yml logs -f backend
docker compose -f docker-compose.prod.yml logs -f db
docker compose -f docker-compose.prod.yml logs -f redis
To view the last 100 lines of logs:
docker compose -f docker-compose.prod.yml logs --tail=100 backend
Logs are also available directly from Docker:
docker logs <container_name> --since 1h
**Required ports:**
| Port | Service | Access |
|------|---------|--------|
| 80 | HTTP (Infisical) | Public (or internal network) |
| 443 | HTTPS (if using TLS) | Public (or internal network) |
**Internal ports (should NOT be exposed publicly):**
| Port | Service | Notes |
|------|---------|-------|
| 5432 | PostgreSQL | Container-to-container only |
| 6379 | Redis | Container-to-container only |
**UFW (Ubuntu/Debian):**
```bash
# Allow HTTP/HTTPS
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Ensure database ports are not exposed
sudo ufw deny 5432/tcp
sudo ufw deny 6379/tcp
sudo ufw enable
```
**firewalld (RHEL/CentOS):**
```bash
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
```
<Warning>
Never expose PostgreSQL (5432) or Redis (6379) ports to the public internet. These should only be accessible within the Docker network.
</Warning>
```env
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=your-smtp-username
SMTP_PASSWORD=your-smtp-password
[email protected]
SMTP_FROM_NAME=Infisical
```
**Common SMTP providers:**
<Tabs>
<Tab title="AWS SES">
```env
SMTP_HOST=email-smtp.us-east-1.amazonaws.com
SMTP_PORT=587
SMTP_USERNAME=your-ses-smtp-username
SMTP_PASSWORD=your-ses-smtp-password
[email protected]
SMTP_FROM_NAME=Infisical
```
</Tab>
<Tab title="SendGrid">
```env
SMTP_HOST=smtp.sendgrid.net
SMTP_PORT=587
SMTP_USERNAME=apikey
SMTP_PASSWORD=your-sendgrid-api-key
[email protected]
SMTP_FROM_NAME=Infisical
```
</Tab>
<Tab title="Gmail">
```env
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
SMTP_PASSWORD=your-app-password
[email protected]
SMTP_FROM_NAME=Infisical
```
<Note>
For Gmail, you must use an [App Password](https://support.google.com/accounts/answer/185833) instead of your regular password.
</Note>
</Tab>
</Tabs>
After updating the `.env` file, restart Infisical:
```bash
docker compose -f docker-compose.prod.yml restart backend
```
**1. Obtain SSL certificates** (e.g., via Let's Encrypt):
```bash
sudo apt install certbot
sudo certbot certonly --standalone -d secrets.example.com
```
**2. Create NGINX configuration directory:**
```bash
mkdir -p ./nginx/certs
sudo cp /etc/letsencrypt/live/secrets.example.com/fullchain.pem ./nginx/certs/
sudo cp /etc/letsencrypt/live/secrets.example.com/privkey.pem ./nginx/certs/
```
**3. Add NGINX service to `docker-compose.prod.yml`:**
```yaml
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/certs:/etc/nginx/certs:ro
depends_on:
- backend
```
**4. Create `./nginx/nginx.conf`:**
```nginx
events {}
http {
server {
listen 80;
server_name secrets.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name secrets.example.com;
ssl_certificate /etc/nginx/certs/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/privkey.pem;
location / {
proxy_pass http://backend:8080;
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;
}
}
}
```
**5. Update `.env`:**
```env
SITE_URL=https://secrets.example.com
```
**6. Restart services:**
```bash
docker compose -f docker-compose.prod.yml down
docker compose -f docker-compose.prod.yml up -d
```
Update your `.env`:
```env
DB_CONNECTION_URI=postgresql://<user>:<password>@<host>:5432/<dbname>
REDIS_URL=redis://:<password>@<host>:6379
```
Remove or comment out `db` and `redis` services in `docker-compose.prod.yml`.
Ensure firewall/VPC access to these services is properly configured.
**Database backup:**
```bash
docker compose -f docker-compose.prod.yml exec db pg_dump -U infisical infisical > backup_$(date +%Y%m%d).sql
```
**Automated daily backups (cron):**
```bash
# Add to crontab (crontab -e)
0 2 * * * cd /path/to/infisical && docker compose -f docker-compose.prod.yml exec -T db pg_dump -U infisical infisical > /backups/infisical_$(date +\%Y\%m\%d).sql
```
**Restore from backup:**
```bash
docker compose -f docker-compose.prod.yml exec -T db psql -U infisical infisical < backup.sql
```
<Warning>
Also back up your `ENCRYPTION_KEY` from the `.env` file. Without this key, you cannot decrypt secrets even if you restore the database.
</Warning>
**1. Add to `.env`:**
```env
OTEL_TELEMETRY_COLLECTION_ENABLED=true
OTEL_EXPORT_TYPE=prometheus
```
**2. Expose port `9464` in `docker-compose.prod.yml`** by adding to the backend service:
```yaml
ports:
- "80:8080"
- "9464:9464"
```
**3. Configure Prometheus** to scrape `localhost:9464` or the container DNS.
See the [Monitoring Guide](/self-hosting/guides/monitoring-telemetry) for full setup.
**1. Back up your database:**
```bash
docker compose -f docker-compose.prod.yml exec db pg_dump -U infisical infisical > backup_before_upgrade.sql
```
**2. Update the image tag** in `docker-compose.prod.yml` to the desired version.
**3. Pull and restart:**
```bash
docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d
```
**4. Verify the upgrade:**
```bash
docker compose -f docker-compose.prod.yml logs -f backend
```
Watch for successful database migration messages. See the [Upgrade Guide](/self-hosting/guides/upgrading-infisical) for more details.
**View startup logs:**
```bash
docker compose -f docker-compose.prod.yml logs
```
**Common causes:**
- Port 80 already in use: Stop other services or change the port mapping
- Insufficient memory: Ensure at least 4GB RAM is available
- Invalid `.env` file: Check for syntax errors or missing required variables
**Verify database credentials:**
```bash
docker compose -f docker-compose.prod.yml exec db psql -U infisical -c "SELECT 1"
```
**Check Infisical logs for connection errors:**
```bash
docker compose -f docker-compose.prod.yml logs backend | grep -i "database\|postgres\|connection"
```
If the database was corrupted, you may need to restore from backup or recreate the volume:
```bash
docker compose -f docker-compose.prod.yml down -v # WARNING: Deletes all data
docker compose -f docker-compose.prod.yml up -d
```
**Check if the port is listening:**
```bash
sudo netstat -tlnp | grep :80
# or
sudo ss -tlnp | grep :80
```
**Check firewall rules:**
```bash
sudo ufw status
# or
sudo firewall-cmd --list-all
```
**Verify SITE_URL is correct** in your `.env` file and matches how you're accessing Infisical.
**Check Infisical logs for email errors:**
```bash
docker compose -f docker-compose.prod.yml logs backend | grep -i "smtp\|email\|mail"
```
**Common issues:**
- Incorrect SMTP credentials
- Firewall blocking outbound port 587 or 465
- SMTP provider requires specific authentication (e.g., Gmail App Passwords)
**Check for slow database queries:**
```bash
docker compose -f docker-compose.prod.yml exec db psql -U infisical -c "SELECT * FROM pg_stat_activity WHERE state = 'active'"
```
**Solutions:**
- Increase container memory limits in `docker-compose.prod.yml`
- Add more CPU cores to the host
- Consider migrating to a managed database for better performance
```bash
# Connect to the database
docker compose -f docker-compose.prod.yml exec db psql -U infisical
# Find the user
SELECT id, email FROM users WHERE email = '[email protected]';
# The password must be reset through the application password reset flow
# or by deleting and recreating the user
```
For security reasons, passwords are hashed and cannot be directly reset in the database. Use the "Forgot Password" flow if SMTP is configured, or contact Infisical support for assistance.
Your Infisical instance should now be running on port 80 (or 443 if using TLS). Visit http://localhost:80 or https://<your-domain> to access your instance.