Maintenance
Day-to-day maintenance for a self-hosted rtCloud instance: upgrading, backing up, restoring, and troubleshooting common issues.
Common Commands
Use these commands regularly to manage your rtCloud containers. Run them from the directory containing docker-compose.production.yml.
# Check status and health of all containers
docker compose -f docker-compose.production.yml ps
# View live logs (all services)
docker compose -f docker-compose.production.yml logs -f
# View logs for the app only
docker compose -f docker-compose.production.yml logs -f rtcloud
# Restart a single container
docker compose -f docker-compose.production.yml restart rtcloud
# Stop all services
docker compose -f docker-compose.production.yml down
# Start all services
docker compose -f docker-compose.production.yml up -d
# Open a shell inside the app container
docker compose -f docker-compose.production.yml exec rtcloud bash
Upgrading
rtCloud updates are distributed as new Docker image tags. Upgrading pulls the latest image and recreates the app container. Database migrations run automatically on startup.
1. Pull the latest image:
docker compose -f docker-compose.production.yml pull
2. Recreate the app container:
docker compose -f docker-compose.production.yml up -d
Docker replaces only the containers whose image has changed. The MySQL container and all named volumes are unaffected.
Pinning a Version
To upgrade to a specific version instead of latest, update RTCLOUD_IMAGE in .env:
RTCLOUD_IMAGE=rtawebteam/rta-smartsurvey:1.2.3
Then run docker compose pull and up -d as above.
Downgrading
Downgrading is generally not recommended, as database migrations cannot be reversed. If a downgrade is necessary, restore from a database backup taken before the upgrade.
Backup and Restore
Backup the Database
Run this command to export the application database to a SQL file:
docker compose -f docker-compose.production.yml exec mysql \
mysqldump -u root -p"$(grep MYSQL_ROOT_PASSWORD .env | cut -d= -f2)" smartsurvey \
> backup-$(date +%Y%m%d-%H%M%S).sql
The backup file is written to your current directory on the host.
Restore the Database
docker compose -f docker-compose.production.yml exec -T mysql \
mysql -u root -p"$(grep MYSQL_ROOT_PASSWORD .env | cut -d= -f2)" smartsurvey \
< backup-20240101-120000.sql
Backup Uploaded Files
Survey submissions often include uploaded files (photos, audio, documents) stored in named Docker volumes. Back them up separately from the database:
# Backup uploads
docker run --rm \
-v rtcloud_uploads:/data \
-v "$(pwd):/backup" \
alpine tar czf /backup/uploads-$(date +%Y%m%d).tar.gz -C /data .
# Backup audio recordings
docker run --rm \
-v rtcloud_audios:/data \
-v "$(pwd):/backup" \
alpine tar czf /backup/audios-$(date +%Y%m%d).tar.gz -C /data .
Replace rtcloud_uploads and rtcloud_audios with your actual volume names (prefixed by COMPOSE_PROJECT_NAME) if you changed the default.
Restore Uploaded Files
docker run --rm \
-v rtcloud_uploads:/data \
-v "$(pwd):/backup" \
alpine tar xzf /backup/uploads-20240101.tar.gz -C /data
Automated Daily Backups
Add a cron job on the host to run backups automatically. Edit the root crontab with crontab -e:
# Daily database backup at 2:00 AM, keep 30 days of history
0 2 * * * cd /opt/rtcloud && docker compose -f docker-compose.production.yml exec -T mysql \
mysqldump -u root -p"$(grep MYSQL_ROOT_PASSWORD .env | cut -d= -f2)" smartsurvey \
> /backups/db-$(date +\%Y\%m\%d).sql && \
find /backups -name "db-*.sql" -mtime +30 -delete
Troubleshooting
App container not starting
Check the container logs for error messages:
docker compose -f docker-compose.production.yml logs rtcloud
Common causes:
- Missing or invalid environment variables in
.env - MySQL not yet ready (wait 60 seconds and check again)
- Port conflict — another process is already using
APP_PORT
MySQL not healthy
docker compose -f docker-compose.production.yml logs mysql
Common causes:
MYSQL_ROOT_PASSWORDnot set in.env- Corrupted data volume (rare — check disk space with
df -h)
MySQL can take 30–60 seconds to initialize on the very first boot. Wait and check again before assuming failure.
Port already in use
Change APP_PORT or SHINY_PORT in .env to a free port, then recreate the containers:
docker compose -f docker-compose.production.yml up -d --force-recreate
To find what is using a port on the host:
lsof -i :8080
400 CSRF Token Could Not Be Verified
This error appears in local or reverse-proxy environments where the request origin does not match the expected host. Disable CSRF validation for local development only:
CSRF_VALIDATION_ENABLED=false
Then restart the app:
docker compose -f docker-compose.production.yml up -d --force-recreate rtcloud
Do not disable CSRF validation in production. If this error occurs in production, ensure your reverse proxy is forwarding the correct
HostandX-Forwarded-Forheaders.
Forgot the Admin Password
Reset the admin password directly in the database. Connect to the MySQL container and update the password hash:
Step 1 — Generate the new password hash. Replace newpassword with your desired password:
docker compose -f docker-compose.production.yml exec rtcloud php -r "
\$salt = trim(shell_exec(\"mysql -h mysql -u root -p\\\"\${MYSQL_ROOT_PASSWORD}\\\" \${MYSQL_DATABASE} -se \\\"SELECT salt FROM ss_user WHERE username='admin';\\\"\"));
echo md5(\$salt . 'newpassword') . PHP_EOL;
"
Step 2 — Update the hash in the database:
docker compose -f docker-compose.production.yml exec mysql \
mysql -u root -p"${MYSQL_ROOT_PASSWORD}" smartsurvey \
-e "UPDATE ss_user SET password='<hash_from_step_1>' WHERE username='admin';"
Container keeps restarting
Check if the health check is failing:
docker compose -f docker-compose.production.yml ps
docker inspect rtcloud-app --format '{{json .State.Health}}'
The app health check calls the /health endpoint. If it fails repeatedly, check the application logs for startup errors.
Disk space full
Identify what is consuming space:
# Check host disk usage
df -h
# Check Docker disk usage (images, containers, volumes)
docker system df
# Remove unused images and stopped containers (safe to run)
docker system prune
Do not use docker system prune --volumes as this will delete application data.
Health Checks
Each service has an automatic health check. Container status reflects the result:
| Container | Check Method | Start Period | Interval |
|---|---|---|---|
rtcloud-app | HTTP GET /health | 90 seconds | 30 seconds |
rtcloud-mysql | mysqladmin ping | 30 seconds | 10 seconds |
rtcloud-keycloak | HTTP GET :9000/health/live | 120 seconds | 30 seconds |
Containers with a failing health check are automatically restarted according to the RESTART_POLICY setting (default: unless-stopped).