Redash remains one of the most approachable open-source tools for building dashboards, sharing SQL queries, and collaborating on data.
While the project is no longer actively maintained upstream, the community builds (10.x) are still widely used for internal analytics.
In this article, I’ll show how to bring up Redash quickly on Debian 12 using Docker Compose. We’ll focus on the two files that matter most: the .env and the docker-compose.yaml.
This assumes you already have Docker Engine and Docker Compose v2 installed.
1. Directory Layout
Create a workspace for your Redash stack:
| 0 1 2 3 4 | sudo mkdir -p /var/app/docker/redash-example cd /var/app/docker/redash-example mkdir -p data/postgres data/redis logs | 
This folder will hold:
- data/postgres→ PostgreSQL data files
- data/redis→ Redis persistence
- logs→ container logs if needed
- .envand- docker-compose.yaml
2. Environment File (.env)
The .env file holds all credentials and configuration. Redash services will consume these automatically.
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | # ========================= # Redash on Docker (.env) # ========================= # ---- Postgres POSTGRES_USER=redash POSTGRES_PASSWORD=change_me_strong_pw POSTGRES_DB=redash # ---- Redis REDIS_PASSWORD=another_strong_pw # ---- Redash image REDASH_IMAGE=redash/redash:10.1.0.b50633 # ---- Core secrets REDASH_SECRET_KEY=REPLACE_WITH_64B_BASE64 REDASH_COOKIE_SECRET=REPLACE_WITH_32B_BASE64 # ---- App behavior REDASH_RATELIMIT_ENABLED=true REDASH_LOG_LEVEL=INFO REDASH_MULTI_ORG=false REDASH_WEB_WORKERS=4 REDASH_SCHEDULED_QUEUE_NAME=scheduled REDASH_ADHOC_QUERY_TIME_LIMIT=600 REDASH_QUERY_TIME_LIMIT=1800 REDASH_CORS_ACCESS_CONTROL_ALLOW_ORIGIN=* # ---- External URL REDASH_HOST=http://localhost:50001 # ---- SMTP / Email REDASH_MAIL_SERVER=smtp-relay.local REDASH_MAIL_PORT=587 REDASH_MAIL_USE_TLS=true REDASH_MAIL_USE_SSL=false REDASH_MAIL_USERNAME=no-reply@example.com REDASH_MAIL_PASSWORD=supersecret # ========================= # NOTE: # Do NOT put REDASH_DATABASE_URL or REDASH_REDIS_URL here. # They are built dynamically in docker-compose.yaml. # ========================= | 
Tip, generate strong random secrets with:
| 0 1 2 3 | openssl rand -base64 64   # for REDASH_SECRET_KEY openssl rand -base64 32   # for REDASH_COOKIE_SECRET | 
3. Docker Compose File (docker-compose.yaml)
This Compose file brings up five containers: PostgreSQL, Redis, the Redash server, a worker, and a scheduler.
Since the host already has Nginx, we don’t run Nginx inside the stack — instead we bind the server on localhost:50001.
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | name: redash-example services:   postgres:     image: postgres:14-alpine     restart: unless-stopped     environment:       POSTGRES_USER: ${POSTGRES_USER}       POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}       POSTGRES_DB: ${POSTGRES_DB}     volumes:       - ./data/postgres:/var/lib/postgresql/data     healthcheck:       test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]       interval: 10s       timeout: 5s       retries: 10   redis:     image: redis:7-alpine     command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD}"]     restart: unless-stopped     volumes:       - ./data/redis:/data     healthcheck:       test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "PING"]       interval: 10s       timeout: 5s       retries: 10   server:     image: ${REDASH_IMAGE}     depends_on:       postgres:         condition: service_healthy       redis:         condition: service_healthy     restart: unless-stopped     env_file: .env     environment:       REDASH_DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}"       REDASH_REDIS_URL: "redis://:${REDIS_PASSWORD}@redis:6379/0"       REDASH_SECRET_KEY: ${REDASH_SECRET_KEY}       REDASH_COOKIE_SECRET: ${REDASH_COOKIE_SECRET}       REDASH_LOG_LEVEL: ${REDASH_LOG_LEVEL:-INFO}       REDASH_HOST: ${REDASH_HOST}       GUNICORN_CMD_ARGS: "--timeout 120 --graceful-timeout 120 --workers ${REDASH_WEB_WORKERS:-2}"     command: server     ports:       - "127.0.0.1:50001:5000"     healthcheck:       test: ["CMD", "wget", "-q", "-O-", "http://localhost:5000/healthcheck"]       interval: 10s       timeout: 5s       retries: 30   worker:     image: ${REDASH_IMAGE}     depends_on:       server:         condition: service_started     restart: unless-stopped     env_file: .env     environment:       REDASH_DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}"       REDASH_REDIS_URL: "redis://:${REDIS_PASSWORD}@redis:6379/0"       REDASH_SECRET_KEY: ${REDASH_SECRET_KEY}       QUEUES: "queries,scheduled,celery,schemas,periodic,emails,default"       WORKERS_COUNT: "2"     command: worker   scheduler:     image: ${REDASH_IMAGE}     depends_on:       server:         condition: service_started     restart: unless-stopped     env_file: .env     environment:       REDASH_DATABASE_URL: "postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}"       REDASH_REDIS_URL: "redis://:${REDIS_PASSWORD}@redis:6379/0"       REDASH_SECRET_KEY: ${REDASH_SECRET_KEY}       QUEUES: "scheduled,celery"     command: scheduler | 
4. Initialize Redash
Bring the services up:
| 0 1 2 3 4 5 | docker compose pull docker compose up -d postgres redis docker compose run --rm server create_db docker compose up -d | 
Check logs:
| 0 1 2 | docker compose logs -f server | 
Visit: http://localhost:50001
5. Integrate with Host Nginx
If your Debian host already runs Nginx for other sites, just add a vhost:
| 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | server {   listen 443 ssl http2;   server_name analytics.example.com;   ssl_certificate /etc/letsencrypt/live/analytics.example.com/fullchain.pem;   ssl_certificate_key /etc/letsencrypt/live/analytics.example.com/privkey.pem;   location / {     proxy_pass         http://127.0.0.1:50001;     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;   } } | 
Reload:
| 0 1 2 | sudo nginx -t && sudo systemctl reload nginx | 
Now Redash is available at https://analytics.example.com.
6. Sending Email
Test SMTP from inside the container:
| 0 1 2 | docker compose run --rm server manage send_test_mail | 
If configured correctly, Redash will send a test message from the REDASH_MAIL_DEFAULT_SENDER.
Closing Notes
That’s all it takes: a .env for configuration, and a docker-compose.yaml for orchestration.
This pattern keeps the stack self-contained while leaving room for scaling or migrating later (for example, moving Postgres to RDS, or Redis to a managed service).
If you already run Nginx on your host, exposing Redash only to 127.0.0.1:50001 is the cleanest way to avoid conflicts and keep your surface minimal.
Happy dashing!!
