Self-hosted climate transparency for enterprises
This guide covers all installation scenarios: local development, enterprise self-hosting, and public site deployment.
This section provides a step-by-step guide for companies deploying OpenEco on their own infrastructure.
OpenEco is self-hosted software. Each company runs its own isolated deployment with its own PostgreSQL database. You can deploy on:
Time estimate: 2-4 hours for a pilot deployment, 1-2 days for production.
Option A: Single Host (Recommended for Pilots)
Option B: Kubernetes/OKD/OpenShift (Production)
For Single Host Deployment:
Install Podman or Docker
RHEL/CentOS/Fedora:
sudo dnf install podman podman-compose
Ubuntu/Debian:
sudo apt-get update
sudo apt-get install podman podman-compose
# or
sudo apt-get install docker.io docker-compose
podman --version # Should show 4.x or higher
podman-compose --version
For Kubernetes Deployment:
kubectl or oc CLIOption 1: Managed PostgreSQL (Recommended for Production)
Use your company’s managed PostgreSQL service:
Steps:
openecoCREATE USER openeco_user WITH PASSWORD 'your-secure-password';
GRANT ALL PRIVILEGES ON DATABASE openeco TO openeco_user;
postgresql://openeco_user:password@postgres.mycorp.internal:5432/openeco?schema=public
Option 2: Containerized PostgreSQL (For Pilots)
If you don’t have managed PostgreSQL, run it in a container:
podman run --name openeco-postgres \
-e POSTGRES_PASSWORD=your-secure-password \
-e POSTGRES_DB=openeco \
-e POSTGRES_USER=openeco_user \
-p 5432:5432 \
-v openeco-postgres-data:/var/lib/postgresql/data \
-d postgres:15
Important: For production, use managed PostgreSQL with automated backups.
Create a file to store your configuration. You’ll need these variables:
Required Variables:
# Database Connection (REQUIRED)
DATABASE_URL="postgresql://openeco_user:password@host:5432/openeco?schema=public"
# Authentication Secret (REQUIRED)
# Generate with: openssl rand -base64 32
NEXTAUTH_SECRET="your-long-random-secret-minimum-32-characters"
# Application URL (REQUIRED)
# The public URL where OpenEco will be accessible
NEXTAUTH_URL="https://climate.yourcompany.com"
NEXT_PUBLIC_APP_URL="https://climate.yourcompany.com"
# Application Name (OPTIONAL)
NEXT_PUBLIC_APP_NAME="OpenEco"
Generate NEXTAUTH_SECRET:
openssl rand -base64 32
Security Note: Never commit these values to version control. Use environment variables or secrets management.
For Single Host (Podman/Docker Compose):
git clone https://github.com/Open-Eco/oe-core.git
cd oe-core/deploy
compose.prod.yml:
version: '3.8'
services:
web:
image: ghcr.io/open-eco/oe-core:web-latest
container_name: openeco-web
ports:
- "3000:3000"
environment:
DATABASE_URL: ${DATABASE_URL}
NEXTAUTH_URL: ${NEXTAUTH_URL}
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET}
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL}
NEXT_PUBLIC_APP_NAME: ${NEXT_PUBLIC_APP_NAME:-OpenEco}
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
.env file in the same directory:
# .env
DATABASE_URL=postgresql://openeco_user:password@postgres:5432/openeco?schema=public
NEXTAUTH_URL=https://climate.yourcompany.com
NEXTAUTH_SECRET=your-generated-secret-here
NEXT_PUBLIC_APP_URL=https://climate.yourcompany.com
NEXT_PUBLIC_APP_NAME=OpenEco
podman-compose -f compose.prod.yml up -d
# or
docker-compose -f compose.prod.yml up -d
podman logs -f openeco-web
For Kubernetes/OKD/OpenShift:
kubectl create namespace openeco
kubectl create secret generic openeco-secrets \
--namespace=openeco \
--from-literal=DATABASE_URL="postgresql://user:pass@host:5432/openeco" \
--from-literal=NEXTAUTH_SECRET="your-secret-here"
kubectl create configmap openeco-config \
--namespace=openeco \
--from-literal=NEXTAUTH_URL="https://climate.yourcompany.com" \
--from-literal=NEXT_PUBLIC_APP_URL="https://climate.yourcompany.com" \
--from-literal=NEXT_PUBLIC_APP_NAME="OpenEco"
cd oe-core/deploy/okd
kubectl apply -f deployment-web.yaml
kubectl apply -f service-web.yaml
# For Kubernetes
kubectl apply -f ingress.yaml
# For OpenShift
oc apply -f route.yaml
The database schema needs to be initialized. Run this one-time migration:
For Single Host:
podman run --rm \
--env DATABASE_URL="postgresql://openeco_user:password@postgres:5432/openeco?schema=public" \
ghcr.io/open-eco/oe-core:web-latest \
npx prisma db push
For Kubernetes:
kubectl run openeco-migrate --rm -i --tty \
--namespace=openeco \
--image=ghcr.io/open-eco/oe-core:web-latest \
--env="DATABASE_URL=postgresql://..." \
-- npx prisma db push
Expected output:
✔ Generated Prisma Client
Your database is now in sync with your Prisma schema.
Set up NGINX (Recommended):
# RHEL/CentOS/Fedora
sudo dnf install nginx
# Ubuntu/Debian
sudo apt-get install nginx
sudo nano /etc/nginx/sites-available/openeco
server {
listen 80;
server_name climate.yourcompany.com;
location / {
proxy_pass http://localhost:3000;
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;
proxy_cache_bypass $http_upgrade;
}
}
sudo ln -s /etc/nginx/sites-available/openeco /etc/nginx/sites-enabled/
sudo nginx -t # Test configuration
sudo systemctl reload nginx
sudo dnf install certbot python3-certbot-nginx
# or
sudo apt-get install certbot python3-certbot-nginx
sudo certbot --nginx -d climate.yourcompany.com
Alternative: Use Traefik or Caddy (both have automatic SSL)
Point your domain to your server:
DNS Records:
Type: A
Name: climate (or @ for root domain)
Value: [Your server's IP address]
TTL: 3600
Or if using a load balancer:
Type: CNAME
Name: climate
Value: [Your load balancer hostname]
TTL: 3600
Verify DNS propagation:
dig climate.yourcompany.com
# or
nslookup climate.yourcompany.com
https://climate.yourcompany.com
# Single host
podman logs -f openeco-web
# Kubernetes
kubectl logs -f deployment/openeco-web -n openeco
# Verify data is being stored
psql -h postgres-host -U openeco_user -d openeco -c "SELECT COUNT(*) FROM \"User\";"
Monitoring:
/api/health endpointBackups:
# Example cron job for PostgreSQL backup
0 2 * * * pg_dump -h postgres-host -U openeco_user openeco > /backups/openeco-$(date +\%Y\%m\%d).sql
Use this checklist to ensure you’ve completed all steps:
NEXTAUTH_SECRET generated (32+ characters)DATABASE_URL tested and workingNEXTAUTH_URL matches your domainApplication won’t start:
podman logs openeco-webpsql $DATABASE_URL -c "SELECT 1;"Database connection errors:
DATABASE_URL format is correctSSL/HTTPS issues:
sudo nginx -tsudo firewall-cmd --list-portssudo certbot certificates502 Bad Gateway:
podman ps or kubectl get podsAfter deployment:
For more details, see:
OpenEco is designed to be deployed in the following environments. All of them use the same OCI image for the web application; only the runtime and infrastructure differ.
| Environment | Recommended Pattern | Notes |
|---|---|---|
| Linux Server | Podman/Docker + Compose (single host) | Primary, simplest path for pilots and production. See Option A: Single Host. |
| Windows Server | Run Linux containers via WSL2 or a small Linux VM | Windows Server hosts a Linux VM/WSL2 instance that runs the same Podman/Docker + Compose stack as Linux. IIS/NGINX on Windows can reverse proxy to the Linux VM if desired. |
| Kubernetes / OKD / OpenShift | Native K8s/OKD deployment | Use the manifests in deploy/okd/ with the same web image. See Option B: Kubernetes / OKD / OpenShift. |
Key idea:
# Clone the repository
git clone https://github.com/Open-Eco/oe-core.git
cd oe-core
# Install dependencies
cd web
npm install
# Configure environment
cp .env.example .env.local
# Edit .env.local with your database credentials
# Run database migrations
npm run db:push
# Start development server
npm run dev
Visit http://localhost:3000
Create web/.env.local:
# Database (required)
DATABASE_URL="postgresql://user:password@localhost:5432/openeco?schema=public"
# Auth (required)
NEXTAUTH_SECRET="your-secret-key-min-32-chars"
NEXTAUTH_URL="http://localhost:3000"
# App (optional)
NEXT_PUBLIC_APP_URL="http://localhost:3000"
NEXT_PUBLIC_APP_NAME="OpenEco"
Option 1: Containerized (Recommended)
# Podman
podman run --name openeco-postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=openeco \
-p 5432:5432 -d postgres:15
# Docker
docker run --name openeco-postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=openeco \
-p 5432:5432 -d postgres:15
Option 2: System PostgreSQL
# Create database
createdb openeco
Each enterprise runs its own isolated deployment with its own PostgreSQL database.
| Model | Best For | Complexity |
|---|---|---|
| Single Host | Pilots, small teams | Low |
| Kubernetes/OKD | Production, HA | Medium |
| Cloud Marketplace | AWS/Azure/GCP users | Low |
Managed PostgreSQL (Recommended for Production):
openecopostgresql://openeco_user:password@postgres.mycorp.internal:5432/openeco?schema=public
Containerized PostgreSQL (Pilots):
podman run --name openeco-postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=openeco \
-p 5432:5432 -d postgres:15
Use deploy/compose.dev.yml as a starting point:
services:
web:
image: ghcr.io/open-eco/oe-core:web-latest
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://openeco_user:password@postgres:5432/openeco?schema=public
NEXTAUTH_URL: https://climate.yourcompany.com
NEXTAUTH_SECRET: change-me-to-a-long-random-secret
NEXT_PUBLIC_APP_URL: https://climate.yourcompany.com
NEXT_PUBLIC_APP_NAME: OpenEco
cd deploy
# Podman Compose
podman-compose -f compose.dev.yml up -d
# Docker Compose
docker-compose -f compose.dev.yml up -d
# One-off migration job
podman run --rm \
--env DATABASE_URL=postgresql://... \
ghcr.io/open-eco/oe-core:web-latest \
npx prisma db push
Visit https://climate.yourcompany.com
kubectl or oc CLI configured# Build with Buildah
buildah bud -t registry.example.com/openeco/web:latest ./web
# Push
podman push registry.example.com/openeco/web:latest
Edit deploy/okd/config-and-secrets.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: openeco-config
data:
NEXTAUTH_URL: "https://climate.yourcompany.com"
NEXT_PUBLIC_APP_URL: "https://climate.yourcompany.com"
---
apiVersion: v1
kind: Secret
metadata:
name: openeco-secrets
type: Opaque
stringData:
DATABASE_URL: "postgresql://user:pass@postgres:5432/openeco"
NEXTAUTH_SECRET: "your-secret-key"
Apply:
kubectl apply -f deploy/okd/config-and-secrets.yaml
# or
oc apply -f deploy/okd/config-and-secrets.yaml
kubectl apply -f deploy/okd/deployment-web.yaml
kubectl apply -f deploy/okd/service-web.yaml
Kubernetes Ingress:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: openeco-web
spec:
rules:
- host: climate.yourcompany.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: openeco-web
port:
number: 80
OpenShift Route:
apiVersion: route.openshift.io/v1
kind: Route
metadata:
name: openeco-web
spec:
host: climate.yourcompany.com
to:
kind: Service
name: openeco-web
tls:
termination: edge
For each enterprise:
openeco-acme, openeco-contosoDATABASE_URL (separate Postgres instance/schema)NEXTAUTH_URL (their domain)Platform: Pterodactyl Panel
Domain: demo.open-eco.org
Best for: Demo sites, previews, small teams (non-enterprise production)
Vercel provides automatic deployments from GitHub with zero configuration for Next.js applications.
Time: ~10 minutes
Cost: Free tier available, pay-as-you-go for production
For complete Vercel deployment guide, see:
OpenEco demo is hosted on Pterodactyl, a game server management platform that can manage Docker containers for applications. The demo runs as a full OpenEco instance with demo data stored in browser sessionStorage.
Option 1: Using Docker Compose (Standalone)
./scripts/pterodactyl-setup.sh
# Edit environment variables
vi deploy/pterodactyl/.env
cd deploy/pterodactyl
docker-compose -f docker-compose.demo.yml up -d
docker-compose -f docker-compose.demo.yml exec web npx prisma db push
Option 2: Using Pterodactyl Panel
OpenEco Demodeploy/pterodactyl/pterodactyl-egg.json)ghcr.io/open-eco/oe-core:web-latestnpm run startDATABASE_URL=postgresql://openeco_demo:password@postgres:5432/openeco_demo?schema=public
NEXTAUTH_SECRET=your-secret-key-min-32-chars
NEXTAUTH_URL=https://demo.open-eco.org
NEXT_PUBLIC_APP_URL=https://demo.open-eco.org
NODE_ENV=production
PORT=3000
DATABASE_URL with correct connection stringnpx prisma generate && npx prisma db pushFor complete setup instructions, troubleshooting, and maintenance:
sessionStorage (no persistent server-side data)./scripts/pterodactyl-deploy.sh --pull --migrate --restart to updatePlatform: GitHub Pages
Domain: docs.open-eco.org
Deploy from a branchmain, Folder: /docsecho "docs.open-eco.org" > docs/CREDENTIALS
Type: CNAME
Name: docs
Value: open-eco.github.io
main (when docs/ changes)# Demo site (Vercel)
Type: CNAME
Name: demo (or @)
Value: cname.vercel-dns.com
# Documentation (GitHub Pages)
Type: CNAME
Name: docs
Value: open-eco.github.io
:v1.1.0)image: tag in manifests or compose filekubectl apply -f or podman-compose up -dKubernetes/OKD performs rolling updates automatically.
:v1.0.0)image: back to previous tagDATABASE_URLNEXTAUTH_SECRET (32+ random bytes)NEXTAUTH_URLNEXT_PUBLIC_APP_URLpodman logs openeco-webDATABASE_URL formatNeed help? Open an issue on GitHub.