Portainer Deployment Guide for EAS Station

> Complete instructions for deploying, maintaining, and upgrading EAS Station using Portainer

Table of Contents


Overview

This guide provides complete instructions for deploying and maintaining EAS Station using Portainer, a popular Docker management UI. Portainer simplifies Docker operations through a web interface, making it ideal for managing emergency alerting infrastructure.

What you'll learn:
  • How to deploy EAS Station as a Portainer stack
  • How to configure environment variables through Portainer
  • How to update to the latest builds
  • How to monitor and maintain your deployment
  • How to backup and restore your data

Prerequisites

Before deploying EAS Station in Portainer, ensure you have:

Required

  • Portainer installed and running (Community Edition or Business Edition)
  • Portainer CE 2.19+ recommended
  • Access to the Portainer web interface
  • Docker Engine 24+ on the host system
  • Sufficient resources:
  • 4GB RAM minimum (8GB recommended for heavy workloads)
  • 20GB free disk space (more if storing many audio files)
  • Network access for pulling Docker images and NOAA/IPAWS feeds

Database Options (Choose One)

  • Option A (Recommended): External PostgreSQL 15+ with PostGIS 3.x extension
  • Can be a managed database service (AWS RDS, Azure Database, etc.)
  • Can be a separate PostgreSQL container
  • Provides better data persistence and backup options
  • Option B: Embedded PostgreSQL using the embedded-db profile
  • Simpler setup, database runs in the same stack
  • Requires configuring volume backups

Optional Hardware (for full functionality)

  • SDR devices for alert verification (RTL-SDR, Airspy, etc.)
  • Raspberry Pi GPIO for relay control (if using hardware transmitter keying)
  • Alpha Protocol LED sign for display integration

Initial Setup

Preparing the Environment File

Before creating the stack in Portainer, understand the environment configuration:

If deploying from Git (recommended):
  • Portainer automatically loads stack.env from the repository with default values
  • You only need to override critical variables (SECRET_KEY, database credentials, location)
  • See Stack Configuration section below
If using Web Editor method:
  • You'll need to configure all environment variables manually
  • Download .env.example from the repository as a reference:
  https://github.com/KR8MER/eas-station/blob/main/.env.example
  
Required preparation (both methods):
  1. Generate a secure SECRET_KEY:
   python3 -c "import secrets; print(secrets.token_hex(32))"
   
Save this value - you'll need it for the Portainer environment configuration.
  1. Prepare your database credentials:
  • If using external PostgreSQL: note your host, port, database name, user, and password
  • If using embedded PostgreSQL: decide on a strong password for the database
  1. Note your deployment preferences:
  • Timezone (e.g., America/New_York)
  • Default location (county, state, SAME codes)
  • Whether you want EAS broadcasting enabled
  • LED sign IP (if applicable)

Creating the Stack in Portainer

Step 1: Access Portainer Stacks

  1. Log in to your Portainer instance
  2. Select your Environment (usually "local" or the name of your Docker host)
  3. Navigate to Stacks in the left sidebar
  4. Click + Add stack

Step 2: Stack Name

Field: Name Value: eas-station (or your preferred name)Guidelines:
  • Use lowercase letters, numbers, hyphens, and underscores only
  • Must be unique within your Portainer environment
  • Suggestion: eas-station or eas-station-prod

> ๐Ÿ’ก Tip: The stack name becomes part of container names (e.g., eas-stationapp1)


Step 3: Build Method

Field: Build method Recommended: Git RepositoryOptions:
Method When to Use Pros Cons
Git Repository โœ… Standard deployment Easy updates, version control, auto-loads stack.env Requires internet access
Web editor Quick testing, custom modifications No external dependencies Manual updates required
Upload Offline deployments Works without Git Must manually upload files
Custom template Reusable configurations Standardized deployments Initial setup complexity
Recommendation: Use Git Repository for production deployments.

Step 4: Git Repository Configuration

4.1 Authentication

Field: Authentication Value: Leave unchecked (public repository)

If you fork the repository and make it private:

  • Check Authentication
  • Enter your GitHub username
  • Generate and enter a Personal Access Token (not your password)

4.2 Repository URL

Field: Repository URL Value: https://github.com/KR8MER/eas-stationImportant:
  • โœ… Use HTTPS URL (not SSH)
  • โœ… Ensure you can access this URL from your browser
  • โœ… Double-check for typos

4.3 Skip TLS Verification

Field: Skip TLS Verification Value: Leave unchecked

Only check this if:

  • You're using a private Git server with self-signed certificates
  • You understand the security implications

4.4 Repository Reference

Field: Repository reference Value: refs/heads/main (recommended)Format: refs/heads/<branch> or refs/tags/<tag>Common Values:
Value Description When to Use
refs/heads/main Latest stable code Production (recommended)
(leave blank) Same as refs/heads/main Also acceptable
refs/tags/v2.3.12 Specific version Pin to exact version
refs/heads/develop Development branch Testing new features
Examples:
refs/heads/main           # Track main branch
refs/tags/v2.3.12         # Pin to version 2.3.12
refs/heads/feature-branch # Track specific branch

> ๐Ÿ”’ Production Tip: Use tagged releases (e.g., refs/tags/v2.3.12) for production to prevent unexpected changes.

4.5 Compose Path

Field: Compose path Value: docker-compose.yml OR docker-compose.embedded-db.ymlWhich one to use:
File Database When to Use
docker-compose.yml External You have existing PostgreSQL/PostGIS (recommended)
docker-compose.embedded-db.yml Embedded All-in-one stack with database included
Path Format:
  • Relative to repository root
  • Must include file extension (.yml or .yaml)
  • Case-sensitive on Linux systems
Examples:
docker-compose.yml                    # Standard
docker-compose.embedded-db.yml        # With embedded database
docker-compose.production.yml         # Custom production file (if you create one)

4.6 Additional Paths (Optional)

Field: Additional paths Value: Leave empty (not needed for EAS Station)

This field is for including additional compose files to override or extend the main file. For example:

docker-compose.override.yml


Step 5: GitOps Updates (Formerly "Automatic Updates")

Field: GitOps updates Recommended: Enable for automatic updates

What is GitOps Updates?

GitOps updates automatically redeploy your stack when the Git repository changes. This keeps your deployment synchronized with your repository without manual intervention.

Configuration Options

Option 1: Webhook Method (Recommended)
  1. โœ… Check GitOps updates
  2. Select Webhook mechanism
  3. Click Show webhook URL (appears after enabling)
  4. Copy the webhook URL
  5. In GitHub:
  • Go to repository Settings โ†’ Webhooks โ†’ Add webhook
  • Paste webhook URL as Payload URL
  • Content type: application/json
  • Select Just the push event
  • Click Add webhook
Result: Stack automatically redeploys on every push to the branch.Option 2: Polling Method
  1. โœ… Check GitOps updates
  2. Select Polling mechanism
  3. Set polling interval:
  • 5 minutes - Frequent updates (uses more resources)
  • 15 minutes - Balanced (recommended)
  • 60 minutes - Minimal resource usage
Result: Portainer checks repository every N minutes and redeploys if changes detected.Option 3: Disabled (Manual Updates)
  1. โฌœ Leave GitOps updates unchecked
  2. You must manually click "Pull and redeploy" to update
Recommendation for EAS Station:
Environment GitOps Setting Reason
Production Polling (15-60 min) Controlled, predictable updates
Staging Webhook Immediate testing of changes
Development Disabled Manual control over deployments

> โš ๏ธ Warning: Automatic updates will restart your stack. For critical systems, test updates in staging first.


Step 6: Enable Relative Path Volumes

Field: Enable relative path volumes Value: Leave unchecked (not needed)

This option allows volume paths relative to the compose file location. EAS Station uses absolute paths and named volumes, so this isn't required.


Step 7: Alternative - Web Editor Method

If you chose Web editor instead of Git Repository:

  1. Copy the contents of docker-compose.yml from the repository:
   https://github.com/KR8MER/eas-station/blob/main/docker-compose.yml
   
  1. Paste into the Web editor in Portainer
  2. Modify as needed for your environment
  3. Note: You won't get automatic stack.env loading - must configure all variables manually

Stack Configuration

Step 8: Environment Variables

Understanding stack.env File Operation

Important: The behavior of stack.env differs based on deployment method:
Deployment Method stack.env Behavior
Git Repository File must already exist in the Git repo (โœ… it does!)
Web editor Auto-created from what you configure below
Upload Auto-created from what you configure below
Custom template Auto-created from what you configure below
For Git Repository deployments (recommended):
  • โœ… Portainer automatically loads stack.env from the repository
  • โœ… All default values are already set
  • โœ… You only override critical variables
What variables are already set in stack.env:
  • All Flask application settings
  • Default database connection parameters
  • CAP poller configuration
  • Logging settings
  • Location defaults
  • EAS broadcast settings (disabled by default)
  • TTS provider settings
  • Docker/infrastructure metadata

> ๐Ÿ’ก Key Point: When deploying from Git, you only need to override 5-7 variables. Everything else uses sensible defaults from stack.env!

> ๐Ÿ“ฆ Versioning: The running release number now comes directly from the repository VERSION manifest. You no longer need to set APPBUILDVERSION in your stack environment.

Configuration Options

In the Portainer stack configuration, scroll down to Environment variables. You have three options:

Option A: Advanced Mode (Recommended)

Click "Advanced mode" and paste your environment variables in .env format:

CORE APPLICATION SETTINGS

SECRET_KEY=your-generated-secret-key-here NOAAUSERAGENT=Your-Organization Emergency Alert Hub/2.1 FLASK_DEBUG=false FLASK_ENV=production

DATABASE CONNECTION

POSTGRES_HOST=your-database-host POSTGRES_PORT=5432 POSTGRES_DB=alerts POSTGRES_USER=postgres POSTGRES_PASSWORD=your-secure-database-password

CAP POLLER SETTINGS

POLLINTERVALSEC=180 CAP_TIMEOUT=30

LOGGING

LOG_LEVEL=INFO

LOCATION DEFAULTS

DEFAULTTIMEZONE=America/NewYork DEFAULTCOUNTYNAME=Your County DEFAULTSTATECODE=OH DEFAULTZONECODES=OHZ016,OHC137

SAME/EAS BROADCAST (if enabled)

EASBROADCASTENABLED=false EAS_ORIGINATOR=WXR EASSTATIONID=EASNODES EASATTENTIONTONE_SECONDS=8

DOCKER/INFRASTRUCTURE

TZ=America/New_York WATCHTOWERLABELENABLE=true

Option B: Simple Mode

Click "+ Add environment variable" for each setting and enter them individually.

Option C: Use Auto-Loaded Defaults (Easiest) โœ… Recommended for Git Deployments

If deploying from Git, Portainer automatically loads stack.env. You only need to override critical variables:

Step-by-step:
  1. Leave the advanced mode OFF - stay in simple mode
  2. Click "+ Add environment variable" for each variable below
  3. Add only these essential variables:
Name Value Example
SECRET_KEY Your generated secret 9d821419d2b70c5a5572cd8e73f1e1d0f7ac4b65b6ac77684c517106c8079498
POSTGRES_HOST Database hostname host.docker.internal or alerts-db or postgres.example.com
POSTGRES_PASSWORD Database password your-secure-password
POSTGRES_DB Database name alerts (or your preferred name)
POSTGRES_USER Database username postgres (or your preferred user)
Optional overrides (add only if different from defaults):
Name Value Example
DEFAULTCOUNTYNAME Your county Putnam County
DEFAULTSTATECODE Your state OH
DEFAULTTIMEZONE Your timezone America/NewYork
DEFAULTZONECODES NOAA zones OHZ016,OHC137
  1. Do NOT add: Variables you want to keep at their defaults - stack.env handles them automatically!
Example configuration:
Name: SECRET_KEY
Value: 9d821419d2b70c5a5572cd8e73f1e1d0f7ac4b65b6ac77684c517106c8079498

Name: POSTGRES_HOST Value: host.docker.internal

Name: POSTGRES_PASSWORD Value: casaos

Name: POSTGRES_DB Value: casaos

Name: POSTGRES_USER Value: casaos

Name: DEFAULTCOUNTYNAME Value: Your County Name

Name: DEFAULTSTATECODE Value: OH

> โœ… Result: You configure 5-7 variables instead of 40+. The rest use defaults from stack.env.

Critical Variables Reference

Must configure:
  • SECRET_KEY - Generated secure random string
  • POSTGRES_HOST - Database hostname
  • POSTGRES_PASSWORD - Secure database password
Should configure:
  • DEFAULT_TIMEZONE - Your local timezone
  • DEFAULTCOUNTYNAME - Your county name
  • DEFAULTSTATECODE - Your state abbreviation
  • DEFAULTZONECODES - Your NOAA zone codes
Optional but recommended:
  • EASBROADCASTENABLED - Set to true if you want audio generation
  • LEDSIGNIP - If you have an LED sign
  • IPAWSCAPFEED_URLS - If using IPAWS feeds

Step 9: Registries

Field: Registries Value: None (leave empty)

What are Registries?

Registries are Docker container registries where images are stored (e.g., Docker Hub, GitHub Container Registry, private registries).

For EAS Station:

  • โœ… No registry selection needed
  • Images pull from Docker Hub (public)
  • The Dockerfile builds the image locally from the git repository

When to Configure Registries:

You would configure registries if:

  • You're using a private Docker registry
  • You're pulling from GitHub Container Registry (ghcr.io)
  • You need authentication to pull images
  • You're in an air-gapped environment with a local registry

For standard EAS Station deployment: Leave this field empty.

Step 10: Access Control

Field: Enable access control Recommended: Enable for multi-user Portainer installations

Option 1: Administrators Only (Recommended)

โœ… Check "Enable access control" โœ… Select "Restrict to administrators only"

Effect:
  • Only Portainer administrators can view/manage this stack
  • Regular users won't see the stack
  • Best for production deployments
When to use:
  • Production EAS Station deployments
  • Sensitive emergency alert systems
  • Multi-tenant Portainer environments

Option 2: Specific Users/Teams

โœ… Check "Enable access control" โœ… Select "Restrict to a set of users and/or teams"

Configuration:
  1. Select users from dropdown
  2. Select teams from dropdown
  3. Choose access level for each:
  • View - Read-only access
  • Manage - Can restart, update, view logs
  • Full control - Can delete and reconfigure
When to use:
  • Team-based management
  • Training environments
  • Shared emergency management operations

Option 3: No Restrictions

โฌœ Leave "Enable access control" unchecked

Effect:
  • All Portainer users can view and manage the stack
  • Suitable for single-user installations
When to use:
  • Personal/home labs
  • Single-administrator Portainer setups
  • Development environments

Recommendation for EAS Station:

Environment Access Control Setting
Production โœ… Enabled Administrators only
Staging โœ… Enabled Specific operations team
Development โฌœ Optional No restrictions OK

> ๐Ÿ”’ Security Tip: Always enable access control for production emergency alerting systems to prevent unauthorized modifications.


Using External PostgreSQL Database

If you're using an external PostgreSQL database:

Database Setup

  1. Create the database:
   CREATE DATABASE alerts;
   
  1. Enable PostGIS:
   \c alerts
   CREATE EXTENSION IF NOT EXISTS postgis;
   CREATE EXTENSION IF NOT EXISTS postgis_topology;
   
  1. Verify PostGIS installation:
   SELECT PostGIS_Version();
   

Environment Configuration

Set these variables in Portainer:

POSTGRES_HOST=your-db-host.example.com
POSTGRES_PORT=5432
POSTGRES_DB=alerts
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your-database-password
For Docker Desktop users: If the database is on your host machine, use:
POSTGRES_HOST=host.docker.internal

Using Embedded PostgreSQL Database

To use the embedded PostgreSQL database that runs within the stack:

Step 1: Use the Embedded Compose File

When creating the stack, use:

  • Compose path: docker-compose.embedded-db.yml

Or if using web editor, copy the embedded compose file from:

https://github.com/KR8MER/eas-station/blob/main/docker-compose.embedded-db.yml

Step 2: Configure Database Variables

POSTGRES_HOST=alerts-db
POSTGRES_PORT=5432
POSTGRES_DB=alerts
POSTGRES_USER=postgres
POSTGRES_PASSWORD=change-this-to-secure-password

Step 3: Enable the Profile (if needed)

If using the standard docker-compose.yml with profiles:

  1. Scroll to Advanced deployment settings
  2. Find Profiles
  3. Add: embedded-db

This activates the alerts-db service defined in the compose file.


Step 11: Actions (Final Review)

Field: Actions section at the bottom of the form

Before clicking "Deploy the stack," take a moment to review what you've configured:

Pre-Deployment Checklist

โœ… Stack name is set correctly โœ… Git Repository method selected (or your chosen method) โœ… Repository URL is correct: https://github.com/KR8MER/eas-station โœ… Repository reference is set: refs/heads/main (or your chosen ref) โœ… Compose path is correct: docker-compose.yml or docker-compose.embedded-db.yml โœ… GitOps updates configured (if desired) โœ… Environment variables are set:

  • SECRET_KEY - secure random value
  • POSTGRES_HOST - database hostname
  • POSTGRES_PASSWORD - secure password
  • Database credentials (DB, USER)
  • Location settings (optional overrides)
โœ… Access control configured (if multi-user)

Available Actions

At the bottom of the form, you'll see:

  1. ๐Ÿ—‘๏ธ Cancel - Discard changes and return to stacks list
  2. ๐Ÿ“‹ Copy - Copy configuration to clipboard (useful for backup)
  3. ๐Ÿš€ Deploy the stack - Create and start the stack

Deploying the Stack

Step 1: Click Deploy the Stack Button

Once you've completed all configuration steps and reviewed the checklist above:

  1. Scroll to the bottom of the form
  2. Click the green "Deploy the stack" button
  3. Wait - do not close the browser window

> ๐Ÿ’ก Pro Tip: Before clicking deploy, use the Copy button to save your configuration to a text file for your records.

Step 2: Monitor Initial Deployment

Portainer will now:

  1. Pull the repository (if using Git method)
  • Clones the Git repository
  • Loads the compose file
  • Reads stack.env automatically
  1. Load environment variables
  • Combines stack.env with your overrides
  • Validates variable substitutions
  1. Pull/Build Docker image
  • First deployment: Builds image from Dockerfile (may take 5-10 minutes)
  • Subsequent deployments: Rebuilds only if code changed
  1. Create containers
  • Creates: app, poller, ipaws-poller containers
  • Also creates alerts-db if using embedded database
  1. Set up networking and volumes
  • Creates default bridge network
  • Creates named volumes (if using embedded DB)

Step 3: Monitor Deployment

  1. Watch the Logs tab to see the deployment progress
  2. Look for these success indicators:
  • Successfully built eas-station:latest
  • Database connection successful
  • Starting Gunicorn workers
  • Listening at: http://0.0.0.0:5000

Step 4: Verify Containers

Navigate to Containers and verify all services are running:

  • โœ… eas-station_app - Status: Running
  • โœ… eas-station_poller - Status: Running
  • โœ… eas-station_ipaws-poller - Status: Running
  • โœ… eas-station_alerts-db - Status: Running (if using embedded DB)

Post-Deployment Configuration

Step 1: Access the Application

  1. Open your web browser
  2. Navigate to: http://your-server-ip:5000
  3. You should see the EAS Station dashboard

Step 2: Complete First-Time Setup

If SECRET_KEY wasn't configured, you'll be redirected to the setup wizard:

  1. Follow the on-screen prompts
  2. Set a secure SECRET_KEY
  3. Configure database connection
  4. Save configuration
  5. Restart the stack in Portainer

Step 3: Create Admin Account

  1. Navigate to: http://your-server-ip:5000/admin
  2. Complete the First-Time Administrator Setup:
  • Enter a username (letters, numbers, ., _, - only)
  • Create a strong password (minimum 8 characters)
  • Confirm password
  1. Click Create Account
  2. Sign in with your new credentials

Step 4: Configure Location Settings

  1. Go to Admin โ†’ Location Settings
  2. Set your:
  • County name and state code
  • NOAA zone codes
  • Area search terms
  • Map center coordinates
  • SAME location codes for broadcasting

Step 5: Upload Geographic Boundaries (Optional)

If you have GeoJSON boundary files:

  1. Go to Admin โ†’ Boundaries
  2. Select boundary type (county, district, etc.)
  3. Upload your GeoJSON file
  4. Verify boundaries appear on the map

Step 6: Configure SDR Receivers (Optional)

If you have SDR hardware:

  1. Go to Settings โ†’ Radio Receivers
  2. Click Auto-Detect Devices
  3. Add detected receivers or create manual configurations
  4. Test each receiver
  5. Enable auto-start for automatic monitoring

Updating to Latest Build

Method 1: Pull and Redeploy (Recommended)

This is the safest method for Portainer-managed stacks:

Step 1: Pull Latest Changes

  1. In Portainer, navigate to Stacks
  2. Select your eas-station stack
  3. Click Pull and redeploy (if using Git repository method)
  4. Or click Editor โ†’ Pull latest changes

Step 2: Review Changes

  1. Review any changes to the compose file
  2. Check for new environment variables in .env.example
  3. Add any new required variables to your stack environment

Step 3: Redeploy

  1. Click Update the stack
  2. Portainer will:
  • Pull the latest code from Git
  • Rebuild the Docker image if needed
  • Recreate containers with updated code
  • Preserve volumes and data

Step 4: Verify Update

  1. Check container logs for successful startup
  2. Visit the web interface
  3. Check Admin โ†’ System Operations for the new version number
  4. Run a test poll: Admin โ†’ Manual Trigger Poll

Method 2: Using Watchtower

Watchtower can automatically update your containers:

Setup Watchtower (One-Time)

Add Watchtower to your stack or as a separate container:

watchtower:
  image: containrrr/watchtower:latest
  volumes:
  • /var/run/docker.sock:/var/run/docker.sock
environment:
  • WATCHTOWERPOLLINTERVAL=86400 # Check daily
  • WATCHTOWER_CLEANUP=true
  • WATCHTOWERLABELENABLE=true
command: --label-enable --cleanup

Enable Auto-Update Labels

Ensure your stack environment has:

WATCHTOWERLABELENABLE=true

Watchtower will automatically check for and apply updates daily.

Method 3: In-App Upgrade Tool

For advanced users with terminal access:

  1. Access the app container through Portainer:
  • Containers โ†’ eas-station_app โ†’ Console
  • Select /bin/bash and click Connect
  1. Run the upgrade tool:
   python tools/inplace_upgrade.py
   
  1. The tool will:
  • Fetch the latest code from Git
  • Rebuild the Docker image
  • Apply database migrations
  • Restart services
  • Preserve your data

Maintenance Tasks

Regular Maintenance Schedule

Daily

  • Check Health Dashboard: http://your-server:5000/system_health
  • Review Latest Alerts: Verify poller is fetching new alerts
  • Monitor Container Status: Ensure all containers are running in Portainer

Weekly

  • Review Logs: Check for any errors or warnings
  • In Portainer: Containers โ†’ Select container โ†’ Logs
  • Test Manual Broadcast: If using EAS features
  • Check Disk Space: Verify sufficient space for database and audio files
  • Review Compliance Dashboard: http://your-server:5000/admin/compliance

Monthly

  • Backup Database: See Backup and Restore
  • Update Stack: Pull latest changes and redeploy
  • Review User Accounts: Remove unused accounts
  • Check SDR Health: Verify receiver functionality
  • Required Monthly Test (RMT): If operating as certified station

Quarterly

  • Review Documentation: Check for updated guides
  • Security Audit: Review passwords, update credentials
  • Performance Review: Check resource usage trends
  • Disaster Recovery Test: Verify backup restoration process

Routine Operations via Portainer

Restarting Services

To restart a specific service:

  1. Containers โ†’ Select container
  2. Click Restart
  3. Monitor logs for successful restart

To restart the entire stack:

  1. Stacks โ†’ Select eas-station
  2. Click Stop
  3. Wait for all containers to stop
  4. Click Start

Viewing Logs

  1. Containers โ†’ Select container
  2. Click Logs
  3. Use search/filter to find specific events
  4. Adjust lines (50, 100, 500, 1000)
  5. Toggle Auto-refresh to monitor in real-time

Checking Resource Usage

  1. Containers โ†’ Select container
  2. View Quick stats panel:
  • CPU usage percentage
  • Memory usage
  • Network I/O
  • Block I/O

Or use Stats page for all containers:

  • Dashboard โ†’ Stats


Backup and Restore

Automated Backup via Web UI

  1. Navigate to Admin โ†’ System Operations
  2. Click Run Backup
  3. Enter an optional label (e.g., "pre-upgrade")
  4. Click Start Backup
  5. Download the backup files when complete

Manual Database Backup

Using Portainer Console

  1. Containers โ†’ Select eas-station_alerts-db (or your database container)
  2. Click Console
  3. Select /bin/bash โ†’ Connect
  4. Run backup command:
   pgdump -U postgres alerts > /tmp/backup$(date +%Y%m%d_%H%M%S).sql
   
  1. Copy backup file from container:
  • Containers โ†’ Select database container
  • Click Copy from container
  • Path: /tmp/backup_*.sql
  • Download to your local machine

Using Portainer Exec Feature

  1. Containers โ†’ eas-station_app
  2. Console โ†’ /bin/bash
  3. Run backup script:
   python tools/create_backup.py --label portainer-backup
   

Scheduling Automated Backups

Method 1: Portainer Webhooks + External Cron

  1. In your stack, click Webhooks
  2. Create a webhook for backup operations
  3. Use external cron or scheduled task to call webhook

Method 2: Add Backup Container to Stack

Add to your docker-compose.yml:

backup:
  image: eas-station:latest
  command:
  • /bin/bash
  • -c
  • |
while true; do sleep 86400 # Daily backups python tools/create_backup.py --label daily-auto done volumes:
  • ./backups:/app/backups
env_file:
  • .env

Restoring from Backup

Via Portainer Console

  1. Upload backup file to container:
  • Containers โ†’ Select database container
  • Copy to container
  • Upload your .sql backup file to /tmp/
  1. Access database console:
  • Containers โ†’ Select eas-station_alerts-db
  • Console โ†’ /bin/bash
  1. Restore database:
   psql -U postgres -d alerts < /tmp/your_backup.sql
   

Full Stack Restore

  1. Stop the stack:
  • Stacks โ†’ eas-station โ†’ Stop
  1. Remove old volumes (if needed):
  • Volumes โ†’ Select eas-station_alerts-db-data
  • Remove volume (โš ๏ธ This deletes all data!)
  1. Restore .env file:
  • Update stack environment variables from backup
  1. Restart stack:
  • Stacks โ†’ eas-station โ†’ Start
  1. Restore database:
  • Follow database restore steps above

Monitoring and Health Checks

Built-in Health Endpoints

EAS Station provides several monitoring endpoints:

Endpoint Purpose Expected Response
/health Basic health check {"status": "ok"}
/ping Simple ping test {"status": "pong"}
/api/system_status System status summary JSON with stats
/api/system_health Detailed health metrics JSON with all metrics

Portainer Health Monitoring

Container Health Status

Portainer shows health status for each container:

  1. Containers โ†’ View list
  2. Look for health indicator icons:
  • ๐ŸŸข Green: Healthy
  • ๐ŸŸก Yellow: Starting/Unhealthy
  • ๐Ÿ”ด Red: Failed/Stopped

Setting Up Alerts (Portainer Business)

If using Portainer Business Edition:

  1. Settings โ†’ Notifications
  2. Create notification webhook (Slack, email, etc.)
  3. Set alerts for:
  • Container stopped
  • Container health check failed
  • High resource usage
  • Stack update failures

External Monitoring Integration

Prometheus Metrics (Future Enhancement)

Add Prometheus exporter to stack:

prometheus:
  image: prom/prometheus:latest
  volumes:
  • ./prometheus.yml:/etc/prometheus/prometheus.yml
ports:
  • "9090:9090"

Uptime Monitoring

Use external services to monitor:

  • HTTP endpoint: http://your-server:5000/health
  • Expected response: 200 OK
  • Alert if down for > 2 minutes

Log Aggregation

For production deployments, consider:

  • Portainer Logs: View directly in Portainer interface
  • Docker Logging Drivers: Configure JSON file, syslog, or other drivers
  • External Tools: ELK Stack, Grafana Loki, Papertrail, etc.

Troubleshooting

Common Issues in Portainer

Issue: Stack fails to deploy

Symptoms:
  • Red error message in Portainer
  • Containers won't start
  • "Failed to create network" errors
Solutions:
  1. Check compose syntax:
  • Use Validate button in web editor
  • Ensure YAML indentation is correct
  1. Review environment variables:
  • Verify all required variables are set
  • Check for typos in variable names
  • Ensure no special characters cause parsing issues
  1. Check port conflicts:
  • In Containers, verify port 5000 isn't already in use
  • Change port mapping if needed: 8080:5000
  1. Review logs:
  • Stacks โ†’ eas-station โ†’ Logs
  • Look for specific error messages

Issue: Containers restart loop

Symptoms:
  • Container status shows "Restarting"
  • Logs show repeated startup attempts
  • Services never become healthy
Solutions:
  1. Check database connection:
   # In Portainer console for app container
   python -c "import psycopg2; print('Testing...')"
   
  1. Verify SECRET_KEY is set:
  • Check environment variables in Portainer
  • Ensure SECRET_KEY exists and is not empty
  1. Review startup logs:
  • Look for Python tracebacks
  • Check for missing dependencies
  1. Disable restart policy temporarily:
  • Edit stack, change restart: unless-stopped to restart: "no"
  • Redeploy to see full error output

Issue: Can't pull latest updates

Symptoms:
  • "Pull and redeploy" fails
  • "Authentication required" errors
  • "Repository not found" errors
Solutions:
  1. Verify Git repository URL:
  • Correct: https://github.com/KR8MER/eas-station
  • Check for typos
  1. Check network connectivity:
  • Portainer server must have internet access
  • Test: Containers โ†’ Any container โ†’ Console โ†’ ping github.com
  1. Try manual method:
  • Use Editor mode
  • Copy updated compose file manually
  • Click Update the stack

Issue: Database connection fails

Symptoms:
  • Errors: "could not connect to server"
  • Database unavailable warnings in logs
  • Admin panel shows database offline
Solutions:
  1. Verify database container is running:
  • Containers โ†’ Check alerts-db status
  • If stopped, click Start
  1. Check POSTGRES_HOST setting:
  • External DB: Use hostname or host.docker.internal
  • Embedded DB: Use alerts-db or postgres
  1. Test database connection:
   # In app container console
   pgisready -h $POSTGRESHOST -U $POSTGRESUSER -d $POSTGRESDB
   
  1. Review database logs:
  • Containers โ†’ alerts-db โ†’ Logs
  • Look for connection rejections or authentication errors
  1. Verify PostGIS extension:
   # In database container console
   psql -U postgres -d alerts -c "SELECT PostGIS_Version();"
   

Issue: Environment variables not applied

Symptoms:
  • Changes to .env don't take effect
  • Application uses old/default values
  • Features remain disabled after enabling
Solutions:
  1. Redeploy the stack:
  • Environment changes require redeployment
  • Stacks โ†’ eas-station โ†’ Update the stack
  1. Verify variables are saved:
  • Stacks โ†’ eas-station โ†’ Editor
  • Scroll to environment variables section
  • Confirm your changes are present
  1. Check variable syntax:
  • No quotes needed in Portainer advanced mode
  • Use = not : (.env format, not YAML)
  • No comments allowed in advanced mode
  1. Force recreation:
  • Enable Re-pull image and redeploy
  • Enable Force re-deployment
  • Click Update the stack

Getting Help

If you encounter issues not covered here:

  1. Check container logs in Portainer:
  • Containers โ†’ Select container โ†’ Logs
  • Look for error messages and stack traces
  1. Review main documentation:
  1. Check system health:
  • Access: http://your-server:5000/system_health
  • Look for red indicators
  1. Search GitHub Issues:
  • Visit: https://github.com/KR8MER/eas-station/issues
  • Search for similar problems
  1. Open a new issue:
  • Include Portainer version
  • Include relevant logs (redact secrets!)
  • Describe steps to reproduce
  • Include environment details

Advanced Configuration

Custom Docker Networks

If you need to connect EAS Station to other stacks:

  1. Create a custom network in Portainer:
  • Networks โ†’ Add network
  • Name: eas-network
  • Driver: bridge
  1. Modify stack to use custom network:
   networks:
     default:
       external: true
       name: eas-network
   

Resource Limits

To prevent resource exhaustion:

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M

Volume Mounting for Persistence

To persist generated EAS audio files:

services:
  app:
    volumes:
  • eas-messages:/app/static/eas_messages
  • eas-backups:/app/backups

volumes: eas-messages: eas-backups:

Using Docker Secrets (Portainer Business)

For enhanced security with Portainer Business:

  1. Secrets โ†’ Add secret
  2. Create secrets for sensitive values:
  • db_password
  • secret_key
  • azurespeechkey
  1. Reference in compose file:
   services:
     app:
       secrets:
  • db_password
  • secret_key
environment: POSTGRESPASSWORDFILE: /run/secrets/db_password SECRETKEYFILE: /run/secrets/secret_key

secrets: db_password: external: true secret_key: external: true

Multi-Stack Deployments

For redundancy, deploy multiple instances:

  1. Create separate stacks:
  • eas-station-primary
  • eas-station-backup
  1. Use different ports:
   # Primary
   ports:
  • "5000:5000"

# Backup ports:

  • "5001:5000"

  1. Configure load balancer (nginx, HAProxy, etc.)

Webhook Integration

To trigger stack updates via webhook:

  1. Stacks โ†’ eas-station โ†’ Webhooks
  2. Copy webhook URL
  3. Configure GitHub webhook (optional):
  • Repository: https://github.com/KR8MER/eas-station
  • Settings โ†’ Webhooks โ†’ Add webhook
  • Payload URL: Your Portainer webhook URL
  • Content type: application/json
  • Events: Push events on main branch
  1. Stack auto-updates on new commits

Best Practices Summary

โœ… Do:

  • Use Git repository method for easy updates
  • Set strong SECRET_KEY and database passwords
  • Enable automatic backups
  • Monitor container health regularly
  • Review logs weekly
  • Test updates in non-production first
  • Document your configuration changes
  • Keep Portainer itself updated

โŒ Don't:

  • Use default passwords in production
  • Skip backups before updates
  • Ignore container restart loops
  • Delete volumes without backups
  • Expose sensitive ports to internet
  • Run with FLASK_DEBUG=true in production
  • Commit secrets to version control


Quick Reference

Essential Portainer Paths

Task Navigation
View stack Stacks โ†’ eas-station
Update stack Stacks โ†’ eas-station โ†’ Editor โ†’ Update
View containers Containers
View logs Containers โ†’ Select โ†’ Logs
Access console Containers โ†’ Select โ†’ Console
Manage volumes Volumes
Create backup Containers โ†’ app โ†’ Console โ†’ python tools/create_backup.py

Key Environment Variables

Variable Purpose Required
SECRET_KEY Session security Yes
POSTGRES_HOST Database hostname Yes
POSTGRES_PASSWORD Database password Yes
EASBROADCASTENABLED Enable audio generation No
DEFAULT_TIMEZONE Local timezone Recommended
LEDSIGNIP LED sign address Optional

Useful Commands (via Console)

Check Python version

python --version

Test database connection

python -c "from app_core import db; db.session.execute('SELECT 1')"

Run backup

python tools/create_backup.py

Check app version

cat VERSION

List environment variables

env | grep EAS

View disk usage

df -h

Check memory

free -h

Made with โ˜• and ๐Ÿ“ป for Amateur Radio Emergency Communications73 de KR8MER ๐Ÿ“ก
Last updated: 2025-11-02 Version: 2.3.12

This document is served from docs/deployment/PORTAINER_DEPLOYMENT.md in the EAS Station installation.