Add CI/CD workflows for development and production deployments
Some checks failed
Deploy Development / deploy (push) Failing after 29s
Some checks failed
Deploy Development / deploy (push) Failing after 29s
- Created `deploy-dev.yml` for automated deployment to the development server on push to the `dev` branch. - Created `deploy.yml` for automated deployment to the production server on push to the `main` or `master` branches. - Added deployment instructions in `DEPLOYMENT-PORTAINER.md` for using Portainer and Traefik. - Documented Gitea Actions deployment process in `DEPLOYMENT.md`. - Configured Traefik SSL settings in `TRAEFIK-SSL-CONFIG.md` for both development and production environments. - Implemented a deployment script `deploy.sh` for manual deployments. - Added Docker Compose configurations for development (`docker-compose.portainer.dev.yml`) and production (`docker-compose.portainer.yml`) environments. - Updated main `docker-compose.yml` to support Traefik integration and environment variable configurations.
This commit is contained in:
316
TRAEFIK-SSL-CONFIG.md
Normal file
316
TRAEFIK-SSL-CONFIG.md
Normal file
@@ -0,0 +1,316 @@
|
||||
# Traefik SSL Configuration for MerchBay Admin
|
||||
|
||||
This document explains how to configure paid SSL certificates for production and automatic Let's Encrypt for development.
|
||||
|
||||
## Network Configuration
|
||||
|
||||
All deployments use the external network: `traefik-public`
|
||||
|
||||
```bash
|
||||
# Ensure the network exists
|
||||
docker network inspect traefik-public >/dev/null 2>&1 || docker network create traefik-public
|
||||
```
|
||||
|
||||
## Development (dev.merchbay.app) - Automatic SSL
|
||||
|
||||
Development uses Let's Encrypt for automatic SSL certificate generation.
|
||||
|
||||
### Traefik Configuration
|
||||
|
||||
Ensure your Traefik has Let's Encrypt configured:
|
||||
|
||||
```yaml
|
||||
# traefik.yml or dynamic config
|
||||
certificatesResolvers:
|
||||
letsencrypt:
|
||||
acme:
|
||||
email: admin@merchbay.app
|
||||
storage: /letsencrypt/acme.json
|
||||
httpChallenge:
|
||||
entryPoint: web
|
||||
```
|
||||
|
||||
### Application Labels (Already configured in docker-compose)
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt"
|
||||
```
|
||||
|
||||
## Production (merchbay.app) - Paid SSL Certificate
|
||||
|
||||
Production uses a paid SSL certificate (e.g., from GoDaddy, Namecheap, Cloudflare).
|
||||
|
||||
### Step 1: Prepare SSL Certificate Files
|
||||
|
||||
You should have these files from your SSL provider:
|
||||
- `merchbay.app.crt` - Certificate file
|
||||
- `merchbay.app.key` - Private key file
|
||||
- `ca-bundle.crt` - CA bundle (optional, for chain)
|
||||
|
||||
Create a combined certificate file:
|
||||
|
||||
```bash
|
||||
# Create SSL directory in Traefik
|
||||
mkdir -p /opt/traefik/certs
|
||||
|
||||
# Copy your certificate and key
|
||||
sudo cp merchbay.app.crt /opt/traefik/certs/
|
||||
sudo cp merchbay.app.key /opt/traefik/certs/
|
||||
|
||||
# If you have a CA bundle, create a full chain
|
||||
cat merchbay.app.crt ca-bundle.crt > /opt/traefik/certs/merchbay.app-fullchain.crt
|
||||
|
||||
# Set proper permissions
|
||||
sudo chmod 600 /opt/traefik/certs/*.key
|
||||
sudo chmod 644 /opt/traefik/certs/*.crt
|
||||
```
|
||||
|
||||
### Step 2: Configure Traefik File Provider
|
||||
|
||||
Create a dynamic configuration file for Traefik:
|
||||
|
||||
```bash
|
||||
sudo nano /opt/traefik/dynamic/certs.yml
|
||||
```
|
||||
|
||||
Add:
|
||||
|
||||
```yaml
|
||||
# /opt/traefik/dynamic/certs.yml
|
||||
tls:
|
||||
certificates:
|
||||
- certFile: /certs/merchbay.app-fullchain.crt
|
||||
keyFile: /certs/merchbay.app.key
|
||||
stores:
|
||||
- default
|
||||
stores:
|
||||
default:
|
||||
defaultCertificate:
|
||||
certFile: /certs/merchbay.app-fullchain.crt
|
||||
keyFile: /certs/merchbay.app.key
|
||||
```
|
||||
|
||||
### Step 3: Update Traefik docker-compose.yml
|
||||
|
||||
Ensure Traefik has file provider enabled and certificates mounted:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v2.10
|
||||
command:
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.network=traefik-public"
|
||||
- "--providers.file.directory=/etc/traefik/dynamic"
|
||||
- "--providers.file.watch=true"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.websecure.address=:443"
|
||||
# Let's Encrypt for dev
|
||||
- "--certificatesresolvers.letsencrypt.acme.email=admin@merchbay.app"
|
||||
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
||||
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
- /opt/traefik/certs:/certs:ro
|
||||
- /opt/traefik/dynamic:/etc/traefik/dynamic:ro
|
||||
- traefik-letsencrypt:/letsencrypt
|
||||
networks:
|
||||
- traefik-public
|
||||
```
|
||||
|
||||
### Step 4: Restart Traefik
|
||||
|
||||
```bash
|
||||
cd /path/to/traefik
|
||||
docker compose restart traefik
|
||||
|
||||
# Verify certificates are loaded
|
||||
docker compose logs traefik | grep -i cert
|
||||
```
|
||||
|
||||
## Application Configuration
|
||||
|
||||
### Development Branch (dev)
|
||||
|
||||
File: `docker-compose.portainer.dev.yml`
|
||||
|
||||
- Domain: `dev.merchbay.app`
|
||||
- SSL: Let's Encrypt (automatic)
|
||||
- Certificate Resolver: `letsencrypt`
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.routers.merchbay-admin-dev.rule=Host(`dev.merchbay.app`)"
|
||||
- "traefik.http.routers.merchbay-admin-dev.tls.certresolver=letsencrypt"
|
||||
```
|
||||
|
||||
### Production Branch (main)
|
||||
|
||||
File: `docker-compose.portainer.yml`
|
||||
|
||||
- Domain: `merchbay.app`
|
||||
- SSL: Paid certificate (via Traefik file provider)
|
||||
- No certresolver label (uses default store)
|
||||
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.http.routers.merchbay-admin.rule=Host(`merchbay.app`)"
|
||||
- "traefik.http.routers.merchbay-admin.tls=true"
|
||||
# No certresolver - uses file provider certificate
|
||||
```
|
||||
|
||||
## Gitea Secrets Configuration
|
||||
|
||||
### Development Secrets
|
||||
|
||||
```
|
||||
DEV_DB_HOST=dev-mysql-host
|
||||
DEV_DB_PORT=3306
|
||||
DEV_DB_DATABASE=merchbay_admin_dev
|
||||
DEV_DB_USERNAME=dev_user
|
||||
DEV_DB_PASSWORD=dev_password
|
||||
```
|
||||
|
||||
### Production Secrets
|
||||
|
||||
```
|
||||
PROD_DEPLOY_HOST=prod-server-ip
|
||||
PROD_DEPLOY_USER=deploy
|
||||
PROD_DEPLOY_SSH_KEY=-----BEGIN RSA PRIVATE KEY-----...
|
||||
PROD_DEPLOY_PORT=22
|
||||
PROD_DB_HOST=prod-mysql-host
|
||||
PROD_DB_PORT=3306
|
||||
PROD_DB_DATABASE=merchbay_admin
|
||||
PROD_DB_USERNAME=prod_user
|
||||
PROD_DB_PASSWORD=prod_password
|
||||
```
|
||||
|
||||
### Shared Secrets (if using same server)
|
||||
|
||||
```
|
||||
DEPLOY_HOST=your-server-ip
|
||||
DEPLOY_USER=deploy
|
||||
DEPLOY_SSH_KEY=-----BEGIN RSA PRIVATE KEY-----...
|
||||
DEPLOY_PORT=22
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
### Check Development SSL
|
||||
|
||||
```bash
|
||||
# Check certificate issuer (should be Let's Encrypt)
|
||||
echo | openssl s_client -servername dev.merchbay.app -connect dev.merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer
|
||||
# Should show: issuer=C = US, O = Let's Encrypt, CN = R3
|
||||
```
|
||||
|
||||
### Check Production SSL
|
||||
|
||||
```bash
|
||||
# Check certificate issuer (should be your SSL provider)
|
||||
echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/dev/null | openssl x509 -noout -issuer
|
||||
# Should show your paid SSL provider
|
||||
|
||||
# Check certificate validity
|
||||
echo | openssl s_client -servername merchbay.app -connect merchbay.app:443 2>/dev/null | openssl x509 -noout -dates
|
||||
```
|
||||
|
||||
### Verify in Browser
|
||||
|
||||
1. Visit https://dev.merchbay.app
|
||||
- Certificate should be issued by "Let's Encrypt Authority X3"
|
||||
|
||||
2. Visit https://merchbay.app
|
||||
- Certificate should be issued by your paid SSL provider
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Development SSL Not Working
|
||||
|
||||
```bash
|
||||
# Check Let's Encrypt logs
|
||||
docker logs traefik | grep letsencrypt
|
||||
|
||||
# Verify acme.json permissions
|
||||
ls -l /path/to/letsencrypt/acme.json
|
||||
# Should be: -rw------- (600)
|
||||
|
||||
# Check DNS
|
||||
dig dev.merchbay.app +short
|
||||
# Should return your server IP
|
||||
```
|
||||
|
||||
### Production SSL Not Working
|
||||
|
||||
```bash
|
||||
# Verify Traefik can read certificates
|
||||
docker exec traefik ls -l /certs/
|
||||
|
||||
# Check dynamic configuration is loaded
|
||||
docker exec traefik cat /etc/traefik/dynamic/certs.yml
|
||||
|
||||
# Verify certificate format
|
||||
openssl x509 -in /opt/traefik/certs/merchbay.app-fullchain.crt -text -noout
|
||||
|
||||
# Check private key
|
||||
openssl rsa -in /opt/traefik/certs/merchbay.app.key -check
|
||||
```
|
||||
|
||||
### Certificate Mismatch
|
||||
|
||||
```bash
|
||||
# Verify certificate and key match
|
||||
openssl x509 -noout -modulus -in /opt/traefik/certs/merchbay.app.crt | openssl md5
|
||||
openssl rsa -noout -modulus -in /opt/traefik/certs/merchbay.app.key | openssl md5
|
||||
# Both should output the same hash
|
||||
```
|
||||
|
||||
## Renewing Certificates
|
||||
|
||||
### Development (Let's Encrypt)
|
||||
|
||||
Automatic renewal every 60 days. No action needed.
|
||||
|
||||
### Production (Paid SSL)
|
||||
|
||||
Before certificate expiration:
|
||||
|
||||
1. Download new certificate from your SSL provider
|
||||
2. Update files in `/opt/traefik/certs/`
|
||||
3. Restart Traefik: `docker compose restart traefik`
|
||||
4. Verify: `curl -vI https://merchbay.app`
|
||||
|
||||
## DNS Configuration
|
||||
|
||||
### Development
|
||||
|
||||
```
|
||||
Type: A
|
||||
Name: dev.merchbay.app
|
||||
Value: YOUR_SERVER_IP
|
||||
TTL: 3600
|
||||
```
|
||||
|
||||
### Production
|
||||
|
||||
```
|
||||
Type: A
|
||||
Name: merchbay.app (or @)
|
||||
Value: YOUR_SERVER_IP
|
||||
TTL: 3600
|
||||
|
||||
Type: A
|
||||
Name: www.merchbay.app
|
||||
Value: YOUR_SERVER_IP
|
||||
TTL: 3600
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Keep certificates private**: Never commit SSL keys to git
|
||||
2. **Use strong permissions**: 600 for private keys, 644 for certificates
|
||||
3. **Monitor expiration**: Set reminders 30 days before expiration
|
||||
4. **Use HSTS**: Add header after SSL is working correctly
|
||||
5. **Enable OCSP stapling**: Improves SSL performance
|
||||
6. **Regular updates**: Keep Traefik updated for security patches
|
||||
Reference in New Issue
Block a user