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)
- Follow the basic production setup guide
- Set up SSL certificates for secure HTTPS access
- Configure application deployment with Docker Compose
- Test application functionality and monitoring
CI/CD Integration Setup (Automated Deployment)
- Complete basic production setup first
- Exchange SSH keys with CI/CD server
- Configure registry connection to CI/CD server
- Set up Forgejo repository secrets
- 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:
- Created an Ubuntu 24.04 LTS Linode with root access
- Set root password for the Linode
- Assigned DNS entries for your domain pointing to the Production Linode's IPv4 and IPv6 addresses
- Have SSH client installed on your local machine
- For CI/CD Integration: CI/CD Linode is set up and running with IP address ready
- 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:
-
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
- Replace
-
Application Name: Choose a name for your application (e.g.,
myapp
,webapp
,api
)- Replace
APP_NAME
in this guide with your chosen name
- Replace
Example:
- If you choose
appuser
as service account andmyapp
as application name:- Replace all
SERVICE_USER
withappuser
- Replace all
APP_NAME
withmyapp
- Replace all
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, thensudo 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
withYOUR_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 addressPROD_HOST
: Your production Linode IPPROD_USER
: SSH username for production server (should beSERVICE_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
- Go to your Forgejo repository
- Navigate to Actions tab
- Monitor the workflow execution
- 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
-
Docker permission denied:
sudo usermod -aG docker SERVICE_USER newgrp docker
-
SSL certificate issues:
sudo certbot certificates sudo certbot renew --dry-run
-
Application not starting:
cd /opt/APP_NAME docker-compose logs
-
SSH connection failed (CI/CD integration only):
ssh -v ci-cd 'echo test'
-
Registry connection failed (CI/CD integration only):
curl -v http://YOUR_CI_HOST_IP:5000/v2/_catalog
Manual Deployment Issues
-
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
-
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
-
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/
-
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
-
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
- Service Account: Use dedicated
SERVICE_USER
user with limited privileges - SSH Keys: Use Ed25519 keys with proper permissions (600/700)
- Firewall: Configure UFW to allow only necessary ports
- Fail2ban: Protect against brute force attacks
- SSL/TLS: Use Let's Encrypt certificates with automatic renewal
- Regular Backups: Automated daily backups of database and configuration
- Container Isolation: Applications run in isolated Docker containers
- Security Headers: Nginx configured with security headers
Monitoring and Maintenance
Daily Monitoring
# On Production server
cd /opt/APP_NAME
./monitor.sh
Weekly Maintenance
- Check disk space:
df -h
- Review logs:
docker-compose logs --tail=100
- Update system:
sudo apt update && sudo apt upgrade
- Test backups: Verify backup files exist and are recent
Monthly Maintenance
- Review security: Check firewall rules and fail2ban status
- Update certificates: Ensure SSL certificates are valid
- Clean up old images: Remove unused Docker images
- 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.