# Deployment Guide Deploy Task Dashboard to a VPS using Apache2 as reverse proxy and Systemd for process management. ## Prerequisites - Linux VPS (Ubuntu/Debian recommended) - Apache2 with `mod_proxy`, `mod_proxy_http`, `mod_ssl`, `mod_headers`, `mod_rewrite` - Go 1.21+ (for building) - SSL certificate (Let's Encrypt recommended) ## Directory Structure ``` /site/{fqdn}/ ├── app # Compiled binary ├── data/ │ └── dashboard.db # SQLite database ├── public/ # Static assets (served by Apache) │ ├── css/ │ │ └── output.css │ └── js/ │ ├── htmx.min.js │ └── app.js ├── templates/ # HTML templates │ ├── index.html │ ├── login.html │ └── partials/ └── .env # Environment configuration ``` ## Build On your development machine or CI: ```bash # Build for Linux GOOS=linux GOARCH=amd64 go build -o app cmd/dashboard/main.go ``` ## Setup ### 1. Create Directory Structure ```bash export FQDN="your-domain.com" mkdir -p /site/${FQDN}/{data,public/css,public/js,templates/partials} ``` ### 2. Deploy Files ```bash # Copy binary cp app /site/${FQDN}/ # Copy static assets cp -r web/static/* /site/${FQDN}/public/ # Copy templates (including partials) cp -r web/templates/* /site/${FQDN}/templates/ ``` ### 3. Set Permissions **Important:** The app runs as `www-data`. All directories need 755, all files need 644. ```bash # Set ownership chown -R www-data:www-data /site/${FQDN} # Set directory permissions (755 = rwxr-xr-x) find /site/${FQDN} -type d -exec chmod 755 {} \; # Set file permissions (644 = rw-r--r--) find /site/${FQDN} -type f -exec chmod 644 {} \; # Make binary executable chmod +x /site/${FQDN}/app ``` ### 4. Configure Environment Create `/site/${FQDN}/.env`: ```bash # Required API Keys TODOIST_API_KEY=your_todoist_api_key TRELLO_API_KEY=your_trello_api_key TRELLO_TOKEN=your_trello_token # Optional PLANTOEAT_API_KEY=your_plantoeat_api_key # Paths (use absolute paths) DATABASE_PATH=/site/your-domain.com/data/dashboard.db TEMPLATE_DIR=/site/your-domain.com/templates STATIC_DIR=/site/your-domain.com/public # Server PORT=8080 DEBUG=false CACHE_TTL_MINUTES=5 # Default user credentials (change after first login!) DEFAULT_USER=admin DEFAULT_PASS=your_secure_password ``` Secure the file: ```bash chmod 600 /site/${FQDN}/.env chown www-data:www-data /site/${FQDN}/.env ``` ### 5. Install Systemd Service Copy the service file: ```bash cp deployment/task-dashboard.service /etc/systemd/system/task-dashboard@.service ``` The default service uses `EnvironmentFile`, but godotenv expects to load `.env` from the working directory. Create an override to source it properly: ```bash systemctl edit task-dashboard@${FQDN} ``` Add: ```ini [Service] ExecStart= ExecStart=/bin/bash -c 'cd /site/%i && source .env && ./app' ``` Enable and start: ```bash systemctl daemon-reload systemctl enable task-dashboard@${FQDN} systemctl start task-dashboard@${FQDN} # Check status systemctl status task-dashboard@${FQDN} ``` ### 6. Configure Apache Enable required modules: ```bash a2enmod proxy proxy_http ssl headers rewrite ``` Copy and customize Apache config: ```bash cp deployment/apache.conf /etc/apache2/sites-available/${FQDN}.conf # Replace ${FQDN} placeholders with your actual domain sed -i "s/\${FQDN}/${FQDN}/g" /etc/apache2/sites-available/${FQDN}.conf # Enable site a2ensite ${FQDN} # Test and reload apache2ctl configtest systemctl reload apache2 ``` ### 7. SSL Certificate (Let's Encrypt) ```bash apt install certbot python3-certbot-apache certbot --apache -d ${FQDN} ``` ## Verification 1. Check service is running: `systemctl status task-dashboard@${FQDN}` 2. Check logs: `journalctl -u task-dashboard@${FQDN} -f` 3. Visit `https://${FQDN}` and login with configured credentials 4. Change the default password after first login ## Updating ```bash # Stop service systemctl stop task-dashboard@${FQDN} # Deploy new binary cp app /site/${FQDN}/ # Update static assets if changed cp -r web/static/* /site/${FQDN}/public/ # Update templates if changed cp -r web/templates/* /site/${FQDN}/templates/ # Fix permissions chown -R www-data:www-data /site/${FQDN} find /site/${FQDN} -type d -exec chmod 755 {} \; find /site/${FQDN} -type f -exec chmod 644 {} \; chmod +x /site/${FQDN}/app chmod 600 /site/${FQDN}/.env # Start service systemctl start task-dashboard@${FQDN} ``` ## Troubleshooting ### Service won't start Check logs: ```bash journalctl -u task-dashboard@${FQDN} -e ``` Common issues: - **"TODOIST_API_KEY is required"**: The .env file isn't being loaded. Use the systemctl override to source it (see step 5). - **"readonly database"**: The `data/` directory isn't writable by www-data. Run `chown www-data:www-data /site/${FQDN}/data`. - **Template panic/nil pointer**: Template files have wrong permissions. Run `chmod 644` on all `.html` files. ### 502 Bad Gateway - Check if Go app is running: `systemctl status task-dashboard@${FQDN}` - Verify PORT in .env matches Apache ProxyPass (default: 8080) ### AH01144: No protocol handler was valid Apache proxy modules aren't loaded: ```bash a2enmod proxy proxy_http systemctl restart apache2 ``` ### 403 Forbidden on static files Permission issue. Fix: ```bash chmod -R 755 /site/${FQDN}/public find /site/${FQDN}/public -type f -exec chmod 644 {} \; chown -R www-data:www-data /site/${FQDN}/public ``` ### 404 on static files Static files not copied. Ensure the structure exists: ```bash ls -la /site/${FQDN}/public/css/output.css ls -la /site/${FQDN}/public/js/htmx.min.js ls -la /site/${FQDN}/public/js/app.js ``` If missing, copy from `web/static/`.