2025-10-30 12:18:57 +01:00
# Puffin App - Deployment Guide
2025-10-29 13:31:04 +01:00
2025-10-30 12:18:57 +01:00
This guide covers deploying the Puffin Offset application with **two separate containers** (frontend + backend) using Gitea Actions for automated builds and Docker Compose for orchestration.
2025-10-29 13:31:04 +01:00
## Architecture Overview
```
2025-10-30 12:18:57 +01:00
Code Push → Gitea → Actions Build → Container Registry → Production Server
↓ ↓
[Frontend Image] Docker Compose Stack
[Backend Image] ├─ Frontend (port 3800)
└─ Backend (port 3001)
↑
Host Nginx
(SSL + routing)
2025-10-29 13:31:04 +01:00
```
## CI/CD Pipeline
### Automated Build Process
When code is pushed to the `main` branch:
1. **Gitea Actions triggers** automatically
2. **Docker image is built** using the multi-stage Dockerfile
3. **Image is pushed** to Gitea's container registry with two tags:
- `latest` - Always points to the most recent build
- `main-<commit-sha>` - Specific commit for rollback capability
### Registry Location
Images are stored at:
```
code.puffinoffset.com/matt/puffin-app:latest
code.puffinoffset.com/matt/puffin-app:main-< sha >
```
## Portainer Deployment
### Prerequisites
1. **Portainer installed and accessible**
2. **Gitea registry credentials configured in Portainer**
3. **Environment variables prepared** (see below)
### Step 1: Configure Gitea Registry in Portainer
1. Navigate to **Portainer → Registries**
2. Click ** "Add registry"**
3. Configure:
- **Name**: `Gitea - code.puffinoffset.com`
- **Registry URL**: `code.puffinoffset.com`
- **Authentication**: Enabled
- **Username**: Your Gitea username (e.g., `matt` )
- **Password**: Gitea access token or password
4. Click ** "Add registry"**
### Step 2: Prepare Environment Variables
Create a `.env` file on your server with the required variables:
```bash
# Example: /path/to/puffin-app/.env
VITE_WREN_API_TOKEN=your-wren-api-token
VITE_FORMSPREE_CONTACT_ID=your-formspree-contact-id
VITE_FORMSPREE_OFFSET_ID=your-formspree-offset-id
```
**Note**: The env.sh script in the Docker image will inject these at runtime.
### Step 3: Create Portainer Stack
#### Option A: Using Portainer UI
1. Navigate to **Portainer → Stacks**
2. Click ** "Add stack"**
3. Configure:
- **Name**: `puffin-app`
- **Build method**: "Web editor"
4. Paste the contents of `docker-compose.portainer.yml`
5. In **Environment variables** section, add:
- Name: `ENV_FILE_PATH`
- Value: `/path/to/your/.env`
6. Click ** "Deploy the stack"**
#### Option B: Using Git Repository
1. Navigate to **Portainer → Stacks**
2. Click ** "Add stack"**
3. Configure:
- **Name**: `puffin-app`
- **Build method**: "Repository"
- **Repository URL**: `https://code.puffinoffset.com/matt/puffin-app.git`
- **Repository reference**: `refs/heads/main`
- **Compose path**: `docker-compose.portainer.yml`
- **Authentication**: Configure with your Gitea credentials
4. Click ** "Deploy the stack"**
### Step 4: Verify Deployment
1. Check that the container is running:
- Navigate to **Portainer → Containers**
- Look for `puffin-app-web-1` or similar
- Status should be "running"
2. Test the application:
- Access: `http://your-server:3800`
- Or via your Nginx reverse proxy configuration
3. Check logs if needed:
- Click on the container
- Select ** "Logs"** tab
## Updating to New Versions
### Method 1: Using Portainer UI (Recommended)
1. Navigate to **Portainer → Stacks**
2. Click on **puffin-app** stack
3. Click ** "Update the stack"**
4. Enable ** "Pull latest image version"**
5. Enable ** "Re-pull image and redeploy"**
6. Click ** "Update"**
Portainer will:
- Pull the latest image from Gitea registry
- Recreate the container with the new image
- Maintain your environment variables and configuration
### Method 2: Pull Specific Version
To rollback or deploy a specific commit:
1. Edit the stack in Portainer
2. Change the image tag from `latest` to `main-<commit-sha>`
```yaml
image: code.puffinoffset.com/matt/puffin-app:main-abc1234
```
3. Update the stack
## Monitoring Build Status
### Check Gitea Actions
1. Go to your Gitea repository: `https://code.puffinoffset.com/matt/puffin-app`
2. Navigate to ** "Actions"** tab
3. View recent workflow runs
4. Click on a run to see detailed logs
### Verify Image in Registry
1. In Gitea, navigate to ** "Packages"** or ** "Registry"**
2. Look for `puffin-app` images
3. Verify tags: `latest` and `main-<sha>` tags should be present
## Troubleshooting
### Build Failed in Gitea Actions
**Check the workflow logs:**
1. Go to Gitea → puffin-app → Actions
2. Click on the failed run
3. Review error messages
**Common issues:**
- Registry authentication failed: Check secrets.GITHUB_TOKEN is available
- Build errors: Review Dockerfile and build logs
- Network issues: Check runner connectivity
### Image Pull Failed in Portainer
**Error:** `unauthorized: authentication required`
**Solution:**
1. Verify registry is configured in Portainer (Step 1)
2. Check credentials are correct
3. Ensure registry URL is `code.puffinoffset.com` (no `https://` )
### Container Won't Start
**Check environment variables:**
1. Verify `.env` file exists on the host
2. Ensure volume mount path is correct in docker-compose.portainer.yml
3. Check container logs for missing env var errors
**Check port conflicts:**
1. Ensure port 3800 is not already in use
2. Run `netstat -tuln | grep 3800` on the host
### Application Not Accessible
**Verify container is running:**
```bash
docker ps | grep puffin-app
```
**Check nginx reverse proxy:**
- Review host Nginx configuration (`nginx-host.conf` )
- Ensure proxy_pass points to correct container port
- Test direct access: `http://server-ip:3800`
**Check firewall:**
```bash
# Example for ufw
sudo ufw status
sudo ufw allow 3800/tcp
```
## Environment Variables Reference
| Variable | Description | Required |
|----------|-------------|----------|
| `VITE_WREN_API_TOKEN` | Wren Climate API authentication token | Yes |
| `VITE_FORMSPREE_CONTACT_ID` | Formspree contact form endpoint ID | Yes |
| `VITE_FORMSPREE_OFFSET_ID` | Formspree offset order form endpoint ID | Yes |
| `NODE_ENV` | Node environment (set to `production` ) | Auto-set |
## Rollback Procedure
To rollback to a previous version:
1. Find the commit SHA of the working version
2. In Portainer, edit the stack
3. Change image tag to `main-<previous-sha>`
4. Update the stack
Example:
```yaml
# Before (current broken version)
image: code.puffinoffset.com/matt/puffin-app:latest
# After (rollback to specific commit)
image: code.puffinoffset.com/matt/puffin-app:main-ab0dbbd
```
## Security Best Practices
1. **Never commit `.env` file to git** (already in .gitignore)
2. **Use Gitea access tokens** instead of passwords for registry auth
3. **Restrict registry access** to necessary users
4. **Review Gitea Actions logs** for sensitive data exposure
5. **Keep base images updated** (node:20-alpine, nginx:alpine)
## Next Steps
- Set up monitoring/alerting for failed builds
- Configure automatic backups of `.env` file
- Implement health checks in docker-compose
- Set up SSL certificates via Let's Encrypt
- Configure log aggregation for production debugging