Internal
Public Access
Fix duplicate user field in tasks migration
Remove duplicate AddField operation for tag.user field in tasks/migrations/0002_initial.py. The migration was attempting to add the user ForeignKey field twice, causing PostgreSQL to fail with "column 'user_id' of relation 'tags' already exists". 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.5
parent
5a2585e9bd
commit
4e903b688d
@@ -0,0 +1,289 @@
|
|||||||
|
# KeepItGoing Server - Portainer Stack Deployment Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This guide will walk you through deploying the KeepItGoing server to your Docker server using Portainer Stacks with Git repository integration.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Portainer installed and accessible
|
||||||
|
- Access to your Docker server via Portainer
|
||||||
|
- Git repository: `https://git.firebugit.com/Firebug_IT/KeepItGoingServer.git`
|
||||||
|
- Git credentials configured in Portainer (or repository is public)
|
||||||
|
|
||||||
|
## Deployment Steps
|
||||||
|
|
||||||
|
### Step 1: Access Portainer
|
||||||
|
|
||||||
|
1. Log into your Portainer instance
|
||||||
|
2. Select your Docker environment
|
||||||
|
3. Navigate to **Stacks** in the left sidebar
|
||||||
|
|
||||||
|
### Step 2: Create New Stack
|
||||||
|
|
||||||
|
1. Click **+ Add stack** button
|
||||||
|
2. Enter stack name: `keepitgoing`
|
||||||
|
|
||||||
|
### Step 3: Configure Git Repository
|
||||||
|
|
||||||
|
1. Select **Git Repository** as the build method
|
||||||
|
2. Fill in the following details:
|
||||||
|
|
||||||
|
**Repository URL:**
|
||||||
|
```
|
||||||
|
https://git.firebugit.com/Firebug_IT/KeepItGoingServer.git
|
||||||
|
```
|
||||||
|
|
||||||
|
**Repository reference:** `refs/heads/main`
|
||||||
|
|
||||||
|
**Compose path:** `docker-compose.yml`
|
||||||
|
|
||||||
|
**Authentication:**
|
||||||
|
- If repository is private, enable authentication
|
||||||
|
- Username: `keith@firebugit.com`
|
||||||
|
- Password: (your Git password)
|
||||||
|
- Or use an access token if available
|
||||||
|
|
||||||
|
### Step 4: Configure Environment Variables
|
||||||
|
|
||||||
|
Scroll down to the **Environment variables** section and paste the following:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Django Core Settings
|
||||||
|
SECRET_KEY=Zfb$!,3Gm\b,x~:a)9@k*Gun.#F{ju3dH-G8aWp4R"&NQ{1x>14v#)EbhpB*XMWD
|
||||||
|
DEBUG=False
|
||||||
|
ALLOWED_HOSTS=keepitgoing.app,www.keepitgoing.app,localhost
|
||||||
|
CSRF_TRUSTED_ORIGINS=https://keepitgoing.app,https://www.keepitgoing.app
|
||||||
|
SITE_DOMAIN=keepitgoing.app
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DB_NAME=keepitgoing
|
||||||
|
DB_USER=keepitgoing
|
||||||
|
DB_PASSWORD=6SWh6Pz01hBFGNzWM0Pszz2moluqxyv7
|
||||||
|
DB_ROOT_PASSWORD=l7xF4j20HxqE2ZGNDR2FIoCCYwb6tDMq
|
||||||
|
DB_HOST=mariadb
|
||||||
|
DB_PORT=3306
|
||||||
|
|
||||||
|
# Redis Configuration
|
||||||
|
REDIS_URL=redis://redis:6379/0
|
||||||
|
|
||||||
|
# Email Configuration (Dreamhost SMTP)
|
||||||
|
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
|
||||||
|
EMAIL_HOST=smtp.dreamhost.com
|
||||||
|
EMAIL_PORT=587
|
||||||
|
EMAIL_USE_TLS=True
|
||||||
|
EMAIL_HOST_USER=kig@keepitgoing.app
|
||||||
|
EMAIL_HOST_PASSWORD=Frankenmonster1!
|
||||||
|
DEFAULT_FROM_EMAIL=KeepItGoing <kig@keepitgoing.app>
|
||||||
|
SERVER_EMAIL=kig@keepitgoing.app
|
||||||
|
|
||||||
|
# Email Verification
|
||||||
|
EMAIL_VERIFICATION_TOKEN_EXPIRY_HOURS=24
|
||||||
|
|
||||||
|
# CORS Configuration
|
||||||
|
CORS_ALLOWED_ORIGINS=https://keepitgoing.app,https://www.keepitgoing.app
|
||||||
|
|
||||||
|
# SaaS Mode
|
||||||
|
SAAS_MODE=False
|
||||||
|
|
||||||
|
# Gunicorn Configuration
|
||||||
|
GUNICORN_WORKERS=3
|
||||||
|
GUNICORN_TIMEOUT=60
|
||||||
|
|
||||||
|
# Django Settings Module
|
||||||
|
DJANGO_SETTINGS_MODULE=config.settings.selfhosted
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Deploy the Stack
|
||||||
|
|
||||||
|
1. Scroll to the bottom
|
||||||
|
2. Click **Deploy the stack**
|
||||||
|
3. Portainer will:
|
||||||
|
- Clone the Git repository
|
||||||
|
- Pull/build the Docker images
|
||||||
|
- Start all 5 containers (mariadb, redis, web, celery-worker, celery-beat)
|
||||||
|
|
||||||
|
### Step 6: Monitor Deployment
|
||||||
|
|
||||||
|
1. Wait for the stack to deploy (2-5 minutes for first deployment)
|
||||||
|
2. In Portainer, go to **Stacks** > **keepitgoing**
|
||||||
|
3. Check the status of all containers:
|
||||||
|
- ✅ keepitgoing-db (mariadb)
|
||||||
|
- ✅ keepitgoing-redis
|
||||||
|
- ✅ keepitgoing-web
|
||||||
|
- ✅ keepitgoing-celery-worker
|
||||||
|
- ✅ keepitgoing-celery-beat
|
||||||
|
|
||||||
|
### Step 7: View Logs
|
||||||
|
|
||||||
|
Click on each container to view logs and ensure they started correctly:
|
||||||
|
|
||||||
|
**Web container logs should show:**
|
||||||
|
```
|
||||||
|
✓ MariaDB is ready!
|
||||||
|
Running database migrations...
|
||||||
|
✓ Migrations complete
|
||||||
|
Collecting static files...
|
||||||
|
✓ Static files collected
|
||||||
|
Starting Gunicorn WSGI server...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 8: Create Django Superuser
|
||||||
|
|
||||||
|
1. In Portainer, navigate to **Containers**
|
||||||
|
2. Click on **keepitgoing-web** container
|
||||||
|
3. Click **Console** button
|
||||||
|
4. Select **Connect** with `/bin/bash` shell
|
||||||
|
5. Run the following command:
|
||||||
|
```bash
|
||||||
|
python manage.py createsuperuser
|
||||||
|
```
|
||||||
|
6. Follow the prompts to create your admin account
|
||||||
|
|
||||||
|
### Step 9: Configure Nginx Proxy Manager
|
||||||
|
|
||||||
|
1. Open your Nginx Proxy Manager
|
||||||
|
2. Go to **Hosts** > **Proxy Hosts**
|
||||||
|
3. Click **Add Proxy Host**
|
||||||
|
4. Configure as follows:
|
||||||
|
|
||||||
|
**Details tab:**
|
||||||
|
- Domain Names: `keepitgoing.app` (and `www.keepitgoing.app` if needed)
|
||||||
|
- Scheme: `http`
|
||||||
|
- Forward Hostname/IP:
|
||||||
|
- If NPM is on same Docker network: `keepitgoing-web`
|
||||||
|
- If NPM is on same server but different network: `localhost` or server IP
|
||||||
|
- Port: `8000`
|
||||||
|
- Cache Assets: ✅ (enabled)
|
||||||
|
- Block Common Exploits: ✅ (enabled)
|
||||||
|
- Websockets Support: ✅ (enabled)
|
||||||
|
|
||||||
|
**SSL tab:**
|
||||||
|
- SSL Certificate: Request a new SSL certificate
|
||||||
|
- Force SSL: ✅ (enabled)
|
||||||
|
- HTTP/2 Support: ✅ (enabled)
|
||||||
|
- HSTS Enabled: ✅ (enabled)
|
||||||
|
|
||||||
|
5. Save the proxy host
|
||||||
|
|
||||||
|
### Step 10: Test the Deployment
|
||||||
|
|
||||||
|
1. Visit `https://keepitgoing.app/api/` - Should show API root
|
||||||
|
2. Visit `https://keepitgoing.app/admin/` - Should show Django admin login
|
||||||
|
3. Log in with your superuser credentials
|
||||||
|
4. Test user registration flow (requires email verification)
|
||||||
|
|
||||||
|
## Post-Deployment
|
||||||
|
|
||||||
|
### Updating the Stack
|
||||||
|
|
||||||
|
When you push new code to the Git repository:
|
||||||
|
|
||||||
|
1. In Portainer, go to **Stacks** > **keepitgoing**
|
||||||
|
2. Click **⚙️ Editor** button
|
||||||
|
3. Enable **Pull latest image** (if needed)
|
||||||
|
4. Click **↻ Git pull and redeploy** at the bottom
|
||||||
|
5. Portainer will pull the latest code and redeploy
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
1. Click **⬇️ Pull and redeploy** button on the stack page
|
||||||
|
|
||||||
|
### Viewing Logs
|
||||||
|
|
||||||
|
In Portainer:
|
||||||
|
- **Stacks** > **keepitgoing** > **Logs** - View all container logs
|
||||||
|
- **Containers** > Select container > **Logs** - View individual container logs
|
||||||
|
|
||||||
|
### Managing Containers
|
||||||
|
|
||||||
|
All containers are visible in:
|
||||||
|
- **Stacks** > **keepitgoing** - Stack overview
|
||||||
|
- **Containers** - Individual container management
|
||||||
|
|
||||||
|
### Database Backups
|
||||||
|
|
||||||
|
To backup the database:
|
||||||
|
|
||||||
|
1. Go to **Containers** > **keepitgoing-db**
|
||||||
|
2. Click **Console**
|
||||||
|
3. Run:
|
||||||
|
```bash
|
||||||
|
mysqldump -u root -p keepitgoing > /tmp/backup.sql
|
||||||
|
```
|
||||||
|
4. Enter root password: `l7xF4j20HxqE2ZGNDR2FIoCCYwb6tDMq`
|
||||||
|
5. Use **File browser** to download `/tmp/backup.sql`
|
||||||
|
|
||||||
|
### Scaling
|
||||||
|
|
||||||
|
To scale the web service for more capacity:
|
||||||
|
|
||||||
|
1. Stop the stack
|
||||||
|
2. Edit `docker-compose.yml` in Git
|
||||||
|
3. Add to web service:
|
||||||
|
```yaml
|
||||||
|
deploy:
|
||||||
|
replicas: 3
|
||||||
|
```
|
||||||
|
4. Push to Git and redeploy in Portainer
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Container won't start
|
||||||
|
|
||||||
|
1. Check logs in Portainer
|
||||||
|
2. Verify environment variables are set correctly
|
||||||
|
3. Ensure MariaDB and Redis are healthy before web/celery start
|
||||||
|
|
||||||
|
### Database connection errors
|
||||||
|
|
||||||
|
1. Check `keepitgoing-db` container is running
|
||||||
|
2. Verify `DB_PASSWORD` matches in environment variables
|
||||||
|
3. Check `DATABASE_URL` is correctly formatted
|
||||||
|
|
||||||
|
### Can't access via domain
|
||||||
|
|
||||||
|
1. Verify Nginx Proxy Manager configuration
|
||||||
|
2. Check port 8000 is accessible from NPM
|
||||||
|
3. Verify `ALLOWED_HOSTS` includes your domain
|
||||||
|
4. Check firewall rules
|
||||||
|
|
||||||
|
### Email not sending
|
||||||
|
|
||||||
|
1. Verify SMTP credentials are correct
|
||||||
|
2. Check Dreamhost allows SMTP from your server IP
|
||||||
|
3. View web container logs for email errors
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- ✅ `.env.docker` is **not** in Git repository (contains secrets)
|
||||||
|
- ✅ Environment variables are stored in Portainer (encrypted)
|
||||||
|
- ✅ Database passwords are randomly generated
|
||||||
|
- ✅ SSL/TLS enforced via Nginx Proxy Manager
|
||||||
|
- ✅ DEBUG=False in production
|
||||||
|
- ✅ All containers run as non-root users
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues or questions:
|
||||||
|
- Check container logs in Portainer
|
||||||
|
- Review `README.md` in the repository
|
||||||
|
- Check Django admin for application-specific issues
|
||||||
|
|
||||||
|
## Stack Information
|
||||||
|
|
||||||
|
**Services:**
|
||||||
|
- **web** - Django/Gunicorn (port 8000)
|
||||||
|
- **mariadb** - MariaDB 11.2 database
|
||||||
|
- **redis** - Redis 7 cache/broker
|
||||||
|
- **celery-worker** - Background task processor
|
||||||
|
- **celery-beat** - Scheduled task scheduler
|
||||||
|
|
||||||
|
**Volumes:**
|
||||||
|
- `keepitgoing_db_data` - Database persistence
|
||||||
|
- `keepitgoing_redis_data` - Redis persistence
|
||||||
|
- `keepitgoing_static_files` - Collected static files
|
||||||
|
- `./media` - User uploaded files (avatars)
|
||||||
|
|
||||||
|
**Networks:**
|
||||||
|
- `keepitgoing_frontend` - External network (web service)
|
||||||
|
- `keepitgoing_backend` - Internal network (database, redis)
|
||||||
@@ -35,11 +35,6 @@ class Migration(migrations.Migration):
|
|||||||
name='user',
|
name='user',
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tasks', to=settings.AUTH_USER_MODEL),
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tasks', to=settings.AUTH_USER_MODEL),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
|
||||||
model_name='tag',
|
|
||||||
name='user',
|
|
||||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='tags', to=settings.AUTH_USER_MODEL),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='task',
|
model_name='task',
|
||||||
name='group',
|
name='group',
|
||||||
|
|||||||
Reference in New Issue
Block a user