sharenet/PRODUCTION_SETUP_GUIDE.md
continuist 7eee42cea8
Some checks are pending
CI/CD Pipeline / Test Backend (push) Waiting to run
CI/CD Pipeline / Test Frontend (push) Waiting to run
CI/CD Pipeline / Build and Push Docker Images (push) Blocked by required conditions
CI/CD Pipeline / Deploy to Production (push) Blocked by required conditions
Add CI/CD and production flow
2025-06-27 01:38:09 -04:00

27 KiB

Production Linode Setup Guide

This guide covers setting up your Production Linode for hosting the APP_NAME application with Docker, SSL/TLS, and automated deployments.

Architecture Overview

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Forgejo Host  │    │   CI/CD Linode  │    │ Production Linode│
│   (Repository)  │    │ (Actions Runner)│    │ (Docker Deploy) │
│                 │    │ + Docker Registry│   │                 │
└─────────────────┘    └─────────────────┘    └─────────────────┘
         │                       │                       │
         │                       │                       │
         └─────────── Push ──────┼───────────────────────┘
                                 │
                                 └─── Deploy ────────────┘

Prerequisites

  • Ubuntu 24.04 LTS Linode with root access
  • Domain name pointing to the Production Linode's IP addresses
  • Basic familiarity with Linux commands and SSH
  • For CI/CD Integration: CI/CD Linode already set up and IP address ready
  • For Manual Deployment: Docker registry access (local or remote)

Quick Start

Basic Production Setup (Manual Deployment)

  1. Follow the basic production setup guide
  2. Set up SSL certificates for secure HTTPS access
  3. Configure application deployment with Docker Compose
  4. Test application functionality and monitoring

CI/CD Integration Setup (Automated Deployment)

  1. Complete basic production setup first
  2. Exchange SSH keys with CI/CD server
  3. Configure registry connection to CI/CD server
  4. Set up Forgejo repository secrets
  5. Test automated deployment pipeline

What's Included

Production Linode Features

  • Docker-based application deployment
  • SSL/TLS certificate management
  • Nginx reverse proxy with security headers
  • Automated backups and monitoring
  • Firewall and fail2ban protection

CI/CD Integration Features (Optional)

  • Secure SSH communication with CI/CD server
  • Automated deployment from CI/CD pipeline
  • Registry connection for image pulling
  • Forgejo Actions integration

Prerequisites and Initial Setup

What's Already Done (Assumptions)

This guide assumes you have already:

  1. Created an Ubuntu 24.04 LTS Linode with root access
  2. Set root password for the Linode
  3. Assigned DNS entries for your domain pointing to the Production Linode's IPv4 and IPv6 addresses
  4. Have SSH client installed on your local machine
  5. For CI/CD Integration: CI/CD Linode is set up and running with IP address ready
  6. For Manual Deployment: Have access to Docker images (local registry, Docker Hub, or other registry)

Note: The Production Linode needs a domain name for SSL certificates and public web access.

Step 0: Initial SSH Access and Verification

Before proceeding with the setup, you need to establish initial SSH access to your Production Linode.

0.1 Get Your Linode IP Address

From your Linode dashboard, note the IP address for:

  • Production Linode: YOUR_PRODUCTION_IP (IP address for SSH, domain for web access)

0.2 Test Initial SSH Access

Test SSH access to your Production Linode:

# Test Production Linode (IP address only)
ssh root@YOUR_PRODUCTION_IP

Expected output: SSH login prompt asking for root password.

If something goes wrong:

  • Verify the IP address is correct
  • Check that SSH is enabled on the Linode
  • Ensure your local machine can reach the Linode (no firewall blocking)

0.3 Verify DNS Configuration

On the Production Linode, verify DNS is properly configured for your domain:

# Check if domain resolves to this server
nslookup your-domain.com

# Check both IPv4 and IPv6
dig your-domain.com A
dig your-domain.com AAAA

Expected output: DNS records showing your Production Linode's IP addresses.

If something goes wrong:

  • Verify DNS propagation: dig your-domain.com +trace
  • Check DNS settings in your domain registrar
  • Wait for DNS propagation (can take up to 48 hours)

0.4 Test Domain Accessibility

Test that your domain is accessible on the Production Linode:

# Test HTTP access (should show default nginx/apache page or connection refused)
curl -I http://your-domain.com

# Test HTTPS access (should fail initially, but domain should resolve)
curl -I https://your-domain.com

Expected output:

  • HTTP: Either a web page or "Connection refused" (both are normal)
  • HTTPS: SSL error (expected before certificates are installed)

If something goes wrong:

  • Verify DNS propagation is complete
  • Check that port 80/443 is not blocked by firewall
  • Ensure the domain is pointing to the correct IP

0.5: Choose Your Names

Before proceeding, decide on:

  1. Service Account Name: Choose a username for the service account (e.g., appuser, deploy, service)

    • Replace SERVICE_USER in this guide with your chosen name
  2. Application Name: Choose a name for your application (e.g., myapp, webapp, api)

    • Replace APP_NAME in this guide with your chosen name

Example:

  • If you choose appuser as service account and myapp as application name:
    • Replace all SERVICE_USER with appuser
    • Replace all APP_NAME with myapp

Basic Production Setup

This section covers the essential setup for hosting your application. Skip to the next section if you only want manual deployments.

Step 1: Initial System Setup

1.1 Update the System

sudo apt update && sudo apt upgrade -y

What this does: Updates package lists and upgrades all installed packages to their latest versions.

Expected output: A list of packages being updated, followed by completion messages.

If something goes wrong:

  • Check your internet connection
  • Try running sudo apt update first, then sudo apt upgrade -y separately
  • If you get package conflicts, run sudo apt --fix-broken install

1.2 Install Essential Packages

sudo apt install -y \
    curl \
    wget \
    git \
    ca-certificates \
    apt-transport-https \
    software-properties-common \
    ufw \
    fail2ban \
    htop \
    nginx \
    certbot \
    python3-certbot-nginx

What this does: Installs web server, SSL tools, security packages, and utilities needed for production deployment.

Expected output: Package installation progress, ending with completion messages.

If something goes wrong:

  • Check if any packages failed to install
  • Run sudo apt install -f to fix broken dependencies
  • Ensure you have sufficient disk space: df -h

Step 2: Create Service Account

2.1 Create the SERVICE_USER User

sudo useradd -r -s /bin/bash -m -d /home/SERVICE_USER SERVICE_USER
sudo usermod -aG sudo SERVICE_USER
echo "SERVICE_USER:$(openssl rand -base64 32)" | sudo chpasswd

What this does:

  • Creates a dedicated service account named SERVICE_USER
  • Gives it sudo privileges for administrative tasks
  • Generates a random 32-character password

Expected output: No output (successful user creation is silent).

If something goes wrong:

  • If user already exists: sudo userdel -r SERVICE_USER then retry
  • Check user creation: id SERVICE_USER
  • Verify sudo access: sudo -u SERVICE_USER sudo -l

2.2 Verify Service Account

sudo su - SERVICE_USER
whoami
pwd

What this does: Switches to the SERVICE_USER user and verifies the setup.

Expected output:

SERVICE_USER
/home/SERVICE_USER

Step 3: Install Docker

3.1 Add Docker Repository

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update

What this does: Adds Docker's official repository to your system for the latest Docker versions.

Expected output: GPG key import confirmation and package list update.

3.2 Install Docker Packages

sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

What this does: Installs Docker Engine, CLI, container runtime, and Docker Compose.

Expected output: Package installation progress, ending with completion messages.

3.3 Configure Docker for Service Account

sudo usermod -aG docker SERVICE_USER

What this does: Adds the SERVICE_USER user to the docker group so it can run Docker commands without sudo.

Step 4: Install Docker Compose

sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

What this does: Downloads the latest Docker Compose binary and makes it executable.

Step 5: Configure Security

5.1 Configure Firewall

sudo ufw --force enable
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 3000/tcp
sudo ufw allow 3001/tcp

What this does: Configures firewall to allow only necessary ports for web traffic and application.

5.2 Configure Fail2ban

sudo systemctl enable fail2ban
sudo systemctl start fail2ban

What this does: Enables fail2ban to protect against brute force attacks.

Step 6: Create Application Directory

6.1 Create Directory Structure

sudo mkdir -p /opt/APP_NAME
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME

What this does: Creates a directory for the application and sets ownership to the SERVICE_USER user.

6.2 Create SSL Directory

sudo mkdir -p /opt/APP_NAME/nginx/ssl
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME/nginx/ssl

What this does: Creates a directory for SSL certificates.

Step 7: Set Up Application Files

7.1 Switch to SERVICE_USER User

sudo su - SERVICE_USER

7.2 Create Environment File

cat > /opt/APP_NAME/.env << 'EOF'
# Production Environment Variables
POSTGRES_PASSWORD=your_secure_password_here
REGISTRY=your-remote-registry.com:port
IMAGE_NAME=APP_NAME
IMAGE_TAG=latest

# Database Configuration
DATABASE_URL=postgresql://SERVICE_USER:your_secure_password_here@postgres:5432/APP_NAME

# Application Configuration
NODE_ENV=production
RUST_LOG=info
EOF

What this does: Creates environment variables for the application deployment.

Note: For manual deployments, you'll typically:

  • Pull images from a remote registry (private registry, GitHub Container Registry, etc.)
  • Update your-remote-registry.com:port with your actual registry URL
  • Configure docker-compose.yml to reference images from your registry

Examples for different registry types:

# Private registry
REGISTRY=registry.company.com:5000

# GitHub Container Registry
REGISTRY=ghcr.io

# GitLab Container Registry
REGISTRY=registry.gitlab.com

# AWS ECR
REGISTRY=123456789012.dkr.ecr.us-east-1.amazonaws.com

Examples for docker-compose.yml:

# For remote registry:
services:
  backend:
    image: your-remote-registry.com:port/APP_NAME-backend:latest
  frontend:
    image: your-remote-registry.com:port/APP_NAME-frontend:latest

7.3 Create Deployment Script

cat > /opt/APP_NAME/deploy.sh << 'EOF'
#!/bin/bash

# Deployment script for APP_NAME
set -e

echo "Deploying APP_NAME..."

# Pull latest images
docker-compose pull

# Stop existing containers
docker-compose down

# Start new containers
docker-compose up -d

# Clean up old images
docker image prune -f

echo "Deployment complete!"
echo "Check status with: docker-compose ps"
EOF

chmod +x /opt/APP_NAME/deploy.sh

What this does: Creates a deployment script for easy application updates.

7.4 Create Backup Script

cat > /opt/APP_NAME/backup.sh << 'EOF'
#!/bin/bash

# Backup script for APP_NAME
set -e

BACKUP_DIR="/opt/APP_NAME/backups"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p $BACKUP_DIR

# Backup database
docker-compose exec -T postgres pg_dump -U SERVICE_USER APP_NAME > $BACKUP_DIR/db_backup_$DATE.sql

# Backup configuration files
tar -czf $BACKUP_DIR/config_backup_$DATE.tar.gz .env docker-compose.yml nginx/

# Keep only last 7 days of backups
find $BACKUP_DIR -name "*.sql" -mtime +7 -delete
find $BACKUP_DIR -name "*.tar.gz" -mtime +7 -delete

echo "Backup completed: $BACKUP_DIR"
EOF

chmod +x /opt/APP_NAME/backup.sh

What this does: Creates a backup script for database and configuration files.

7.5 Create Monitoring Script

cat > /opt/APP_NAME/monitor.sh << 'EOF'
#!/bin/bash

echo "=== APP_NAME Application Status ==="
echo "Date: $(date)"
echo "Uptime: $(uptime)"
echo ""

echo "=== Docker Containers ==="
docker-compose ps
echo ""

echo "=== Application Logs (last 20 lines) ==="
docker-compose logs --tail=20
echo ""

echo "=== System Resources ==="
echo "CPU Usage:"
top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1
echo "Memory Usage:"
free -h | grep Mem
echo "Disk Usage:"
df -h /
echo ""

echo "=== Network Status ==="
netstat -tlnp | grep -E ':(80|443|3000|3001)'
echo ""

echo "=== SSL Certificate Status ==="
if [ -f "/opt/APP_NAME/nginx/ssl/cert.pem" ]; then
    openssl x509 -in /opt/APP_NAME/nginx/ssl/cert.pem -text -noout | grep -E "(Not Before|Not After)"
else
    echo "SSL certificate not found"
fi
EOF

chmod +x /opt/APP_NAME/monitor.sh

What this does: Creates a monitoring script to check application and system status.

Step 8: Set Up Automated Backups

sudo -u SERVICE_USER bash -c '(crontab -l 2>/dev/null; echo "0 2 * * * /opt/APP_NAME/backup.sh") | crontab -'

What this does: Schedules daily backups at 2 AM.

Step 9: Copy Application Files

sudo su - SERVICE_USER
cd /opt/APP_NAME
git clone https://your-forgejo-instance/your-username/APP_NAME.git .

What this does: Clones your application repository to the production server.

Note: Replace the URL with your actual repository URL.

Step 10: Set Up SSL Certificates

10.1 Install SSL Certificate

sudo certbot --nginx -d your-domain.com

What this does: Installs Let's Encrypt SSL certificate for your domain.

Expected output: Certificate installation confirmation and Nginx configuration updates.

10.2 Copy Certificates

sudo cp /etc/letsencrypt/live/your-domain.com/fullchain.pem /opt/APP_NAME/nginx/ssl/cert.pem
sudo cp /etc/letsencrypt/live/your-domain.com/privkey.pem /opt/APP_NAME/nginx/ssl/key.pem
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME/nginx/ssl/*

What this does: Copies SSL certificates to the application directory for Docker use.

Step 11: Test Basic Application

11.1 Test Application Deployment

cd /opt/APP_NAME
./deploy.sh

What this does: Deploys the application using Docker Compose.

Expected output: Deployment progress messages and completion.

11.2 Monitor Application

cd /opt/APP_NAME
./monitor.sh

Expected output: Application status, system resources, and recent logs.


CI/CD Integration Setup (Optional)

⚠️ SKIP THIS SECTION if you're only doing manual deployments!

This section covers integrating with a CI/CD pipeline for automated deployments.

Prerequisites for CI/CD Integration

  • CI/CD Linode already set up and running
  • CI/CD Linode IP address available
  • SSH access to CI/CD server

Step 1: Configure Docker for CI/CD Registry

1.1 Update Docker Daemon Configuration

# Configure Docker to allow connections to CI/CD registry
echo '{"insecure-registries": ["YOUR_CI_HOST_IP:5000"]}' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker

What this does: Configures Docker to allow connections to your CI/CD registry without SSL verification.

Note: Replace YOUR_CI_HOST_IP with your actual CI/CD server IP.

Step 2: Set Up SSH Keys for CI/CD Communication

2.1 Create SSH Directory

mkdir -p ~/.ssh
chmod 700 ~/.ssh

2.2 Generate SSH Key Pair

ssh-keygen -t ed25519 -C "production-server" -f ~/.ssh/id_ed25519 -N ""

What this does: Generates an Ed25519 SSH key pair for secure communication with the CI/CD server.

2.3 Create SSH Config

cat > ~/.ssh/config << 'EOF'
Host ci-cd
    HostName YOUR_CI_CD_IP
    User SERVICE_USER
    IdentityFile ~/.ssh/id_ed25519
    StrictHostKeyChecking no
    UserKnownHostsFile /dev/null
EOF

chmod 600 ~/.ssh/config

What this does: Creates SSH configuration for easy connection to the CI/CD server.

Note: Replace YOUR_CI_CD_IP with your actual CI/CD server IP.

Step 3: Exchange SSH Keys

3.1 Get Your Public Key

cat ~/.ssh/id_ed25519.pub

Important: Copy this public key - you'll need it for the CI/CD server setup.

3.2 Add CI/CD Server's Public Key

echo "CI_CD_PUBLIC_KEY_HERE" >> ~/.ssh/authorized_keys
sed -i 's/YOUR_CI_CD_IP/YOUR_ACTUAL_CI_CD_IP/g' ~/.ssh/config

What this does: Adds the CI/CD server's public key to allow secure communication.

Note: Replace CI_CD_PUBLIC_KEY_HERE with the actual public key from your CI/CD server.

Step 4: Update Application Configuration for CI/CD

4.1 Update Environment Variables

cd /opt/APP_NAME
nano .env

Required changes:

  • Replace your-registry-url:port with YOUR_CI_HOST_IP:5000
  • Replace your_secure_password_here with a strong database password
  • Update DATABASE_URL with the same password

Example:

# Change this line:
REGISTRY=your-registry-url:port

# To this (replace with your actual CI/CD IP):
REGISTRY=192.168.1.100:5000

Step 5: Test CI/CD Integration

5.1 Test SSH Connection

ssh ci-cd 'echo Connection successful'

Expected output: Connection successful.

5.2 Test Registry Connection

curl http://YOUR_ACTUAL_CI_IP:5000/v2/_catalog

Expected output: {"repositories":[]} or a list of available images.

Step 6: Configure Forgejo Repository Secrets

Go to your Forgejo repository → Settings → Secrets and Variables → Actions, and add:

  • CI_HOST: Your CI/CD Linode IP address
  • PROD_HOST: Your production Linode IP
  • PROD_USER: SSH username for production server (should be SERVICE_USER)
  • PROD_SSH_KEY: SSH private key for deployment (from CI/CD server)

Step 7: Test Automated Deployment

7.1 Push Code Changes

Make a small change to your code and push to trigger the CI/CD pipeline:

# In your local repository
echo "# Test deployment" >> README.md
git add README.md
git commit -m "Test CI/CD pipeline"
git push

7.2 Monitor Pipeline

  1. Go to your Forgejo repository
  2. Navigate to Actions tab
  3. Monitor the workflow execution
  4. Check for any errors or issues

7.3 Verify Deployment

After successful pipeline execution:

# Check application status
cd /opt/APP_NAME
docker-compose ps

# Check application logs
docker-compose logs

# Test application access
curl -I https://your-domain.com

Testing and Verification

Step 1: Test Application Access

# Test HTTP redirect to HTTPS
curl -I http://your-domain.com

# Test HTTPS access
curl -I https://your-domain.com

# Test application endpoints
curl -I https://your-domain.com/api/health

Expected output:

  • HTTP: 301 redirect to HTTPS
  • HTTPS: 200 OK response
  • API: Application-specific response

Step 2: Test Monitoring

cd /opt/APP_NAME
./monitor.sh

Expected output: Application status, system resources, and recent logs.

Step 3: Test Backup

cd /opt/APP_NAME
./backup.sh

Expected output: Backup completion message with file locations.

Step 4: Test Manual Deployment (if not using CI/CD)

cd /opt/APP_NAME
./pull-and-deploy.sh

Expected output: Pull progress messages, image download, and deployment completion.

Alternative manual process:

# Pull images manually
docker pull your-remote-registry.com:port/APP_NAME-backend:latest
docker pull your-remote-registry.com:port/APP_NAME-frontend:latest

# Deploy application
cd /opt/APP_NAME
./deploy.sh

Step 5: Manual Image Management (for non-CI/CD deployments)

If you're not using CI/CD, you'll need to pull and manage Docker images from your remote registry:

5.1 Configure Registry Authentication

# Login to your remote registry
docker login your-remote-registry.com:port

# For GitHub Container Registry
docker login ghcr.io -u YOUR_GITHUB_USERNAME -p YOUR_GITHUB_TOKEN

# For GitLab Container Registry
docker login registry.gitlab.com -u YOUR_GITLAB_USERNAME -p YOUR_GITLAB_TOKEN

# For AWS ECR
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.us-east-1.amazonaws.com

5.2 Pull Images from Remote Registry

# Pull backend image
docker pull your-remote-registry.com:port/APP_NAME-backend:latest

# Pull frontend image
docker pull your-remote-registry.com:port/APP_NAME-frontend:latest

# Verify images were pulled
docker images | grep APP_NAME

5.3 Update Application Configuration

# Update docker-compose.yml to use your remote registry images
cd /opt/APP_NAME
nano docker-compose.yml

# Example configuration:
# image: your-remote-registry.com:port/APP_NAME-backend:latest
# image: your-remote-registry.com:port/APP_NAME-frontend:latest

5.4 Create Manual Pull and Deploy Script

cat > /opt/APP_NAME/pull-and-deploy.sh << 'EOF'
#!/bin/bash

# Manual pull and deploy script
set -e

echo "Pulling APP_NAME images from remote registry..."

# Pull backend
docker pull your-remote-registry.com:port/APP_NAME-backend:latest

# Pull frontend
docker pull your-remote-registry.com:port/APP_NAME-frontend:latest

# Show pulled images
echo "Pulled images:"
docker images | grep APP_NAME

# Deploy application
cd /opt/APP_NAME
./deploy.sh

echo "Pull and deploy complete!"
EOF

chmod +x /opt/APP_NAME/pull-and-deploy.sh

What this does: Creates a script to pull images from your remote registry and deploy the application.

5.5 Create Image Update Script

cat > /opt/APP_NAME/update-images.sh << 'EOF'
#!/bin/bash

# Update images from remote registry
set -e

echo "Updating images from remote registry..."

# Pull latest images
docker-compose pull

# Show updated images
echo "Updated images:"
docker images | grep APP_NAME

echo "Update complete!"
echo "Run './deploy.sh' to deploy with new images"
EOF

chmod +x /opt/APP_NAME/update-images.sh

What this does: Creates a script to update images from your remote registry.


Troubleshooting

Common Issues

  1. Docker permission denied:

    sudo usermod -aG docker SERVICE_USER
    newgrp docker
    
  2. SSL certificate issues:

    sudo certbot certificates
    sudo certbot renew --dry-run
    
  3. Application not starting:

    cd /opt/APP_NAME
    docker-compose logs
    
  4. SSH connection failed (CI/CD integration only):

    ssh -v ci-cd 'echo test'
    
  5. Registry connection failed (CI/CD integration only):

    curl -v http://YOUR_CI_HOST_IP:5000/v2/_catalog
    

Manual Deployment Issues

  1. Registry authentication fails:

    # Check if you're logged in
    docker login your-remote-registry.com:port
    
    # For GitHub Container Registry
    docker login ghcr.io -u YOUR_GITHUB_USERNAME -p YOUR_GITHUB_TOKEN
    
    # For GitLab Container Registry
    docker login registry.gitlab.com -u YOUR_GITLAB_USERNAME -p YOUR_GITLAB_TOKEN
    
    # Check authentication status
    cat ~/.docker/config.json
    
  2. Images not found in remote registry:

    # Check if images exist in your registry
    docker pull your-remote-registry.com:port/APP_NAME-backend:latest
    
    # List local images
    docker images | grep APP_NAME
    
    # Check registry connectivity
    curl -v https://your-remote-registry.com:port/v2/_catalog
    
    # For GitHub Container Registry
    curl -H "Authorization: Bearer YOUR_GITHUB_TOKEN" https://ghcr.io/v2/_catalog
    
  3. Network connectivity issues:

    # Test basic connectivity
    ping your-remote-registry.com
    
    # Test port connectivity
    telnet your-remote-registry.com port
    
    # Check DNS resolution
    nslookup your-remote-registry.com
    
    # Test HTTPS connectivity
    curl -I https://your-remote-registry.com:port/v2/
    
  4. Application configuration issues:

    # Check environment variables
    cd /opt/APP_NAME
    cat .env
    
    # Validate docker-compose configuration
    docker-compose config
    
    # Check application logs
    docker-compose logs --tail=50
    
  5. Manual pull and deploy process issues:

    # Check if pull script exists
    ls -la /opt/APP_NAME/pull-and-deploy.sh
    
    # Run pull with verbose output
    bash -x /opt/APP_NAME/pull-and-deploy.sh
    
    # Check for pull errors
    docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.CreatedAt}}"
    
    # Verify docker-compose.yml references correct registry
    grep -A 5 "image:" /opt/APP_NAME/docker-compose.yml
    

Useful Commands

  • Check system resources: htop
  • Check disk space: df -h
  • Check memory usage: free -h
  • Check network: ip addr show
  • Check firewall: sudo ufw status
  • Check logs: sudo journalctl -f

Security Best Practices

  1. Service Account: Use dedicated SERVICE_USER user with limited privileges
  2. SSH Keys: Use Ed25519 keys with proper permissions (600/700)
  3. Firewall: Configure UFW to allow only necessary ports
  4. Fail2ban: Protect against brute force attacks
  5. SSL/TLS: Use Let's Encrypt certificates with automatic renewal
  6. Regular Backups: Automated daily backups of database and configuration
  7. Container Isolation: Applications run in isolated Docker containers
  8. Security Headers: Nginx configured with security headers

Monitoring and Maintenance

Daily Monitoring

# On Production server
cd /opt/APP_NAME
./monitor.sh

Weekly Maintenance

  1. Check disk space: df -h
  2. Review logs: docker-compose logs --tail=100
  3. Update system: sudo apt update && sudo apt upgrade
  4. Test backups: Verify backup files exist and are recent

Monthly Maintenance

  1. Review security: Check firewall rules and fail2ban status
  2. Update certificates: Ensure SSL certificates are valid
  3. Clean up old images: Remove unused Docker images
  4. Review monitoring: Check application performance and logs

Summary

Your Production Linode is now ready to host your application! The setup includes:

Basic Features (All Deployments)

  • Docker-based application deployment with SSL/TLS
  • Nginx reverse proxy with security headers
  • Automated backups and monitoring scripts
  • Firewall and fail2ban protection for security
  • Manual image management tools and scripts

CI/CD Integration Features (Optional)

  • Secure SSH communication with CI/CD server
  • Automated deployment from CI/CD pipeline
  • Registry connection for image pulling
  • Forgejo Actions integration

For ongoing maintenance and troubleshooting, refer to the troubleshooting section and monitoring scripts provided in this guide.