Updated procedure to have project cloned to /opt/APP_NAME to be with registry
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

This commit is contained in:
continuist 2025-06-28 19:51:45 -04:00
parent 9420de4105
commit 718343a3d0
5 changed files with 238 additions and 399 deletions

View file

@ -498,21 +498,25 @@ exit
# Switch to SERVICE_USER (registry directory owner)
sudo su - SERVICE_USER
# Create SSL directory
mkdir -p /opt/registry/ssl
# Create system SSL directory for registry certificates
sudo mkdir -p /etc/ssl/registry
# Generate self-signed certificate
openssl req -x509 -newkey rsa:4096 -keyout /opt/registry/ssl/registry.key -out /opt/registry/ssl/registry.crt -days 365 -nodes -subj "/C=US/ST=State/L=City/O=Organization/CN=YOUR_CI_CD_IP"
# Get your actual IP address
YOUR_ACTUAL_IP=$(curl -4 -s ifconfig.me)
echo "Your IP address is: $YOUR_ACTUAL_IP"
# Generate self-signed certificate with actual IP in system directory
sudo openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/registry/registry.key -out /etc/ssl/registry/registry.crt -days 365 -nodes -subj "/C=US/ST=State/L=City/O=Organization/CN=$YOUR_ACTUAL_IP"
# Set proper permissions
chmod 600 /opt/registry/ssl/registry.key
chmod 644 /opt/registry/ssl/registry.crt
sudo chmod 600 /etc/ssl/registry/registry.key
sudo chmod 644 /etc/ssl/registry/registry.crt
# Exit SERVICE_USER shell
exit
```
**Important**: Replace `YOUR_CI_CD_IP` with your actual CI/CD Linode IP address in the certificate generation command.
**Important**: The certificate is now generated in the system SSL directory `/etc/ssl/registry/` with your actual CI/CD Linode IP address automatically.
#### 4.3 Create Authentication File
@ -520,155 +524,86 @@ exit
# Switch to SERVICE_USER (registry directory owner)
sudo su - SERVICE_USER
# Create system auth directory for registry authentication
sudo mkdir -p /etc/registry/auth
# Create htpasswd file for authentication (required for push operations only)
mkdir -p /opt/registry/auth
htpasswd -Bbn push-user "$(openssl rand -base64 32)" > /opt/registry/auth/auth.htpasswd
sudo htpasswd -Bbn push-user "$(openssl rand -base64 32)" > /tmp/auth.htpasswd
sudo mv /tmp/auth.htpasswd /etc/registry/auth/auth.htpasswd
# Exit SERVICE_USER shell
exit
```
**What this does**: Creates user credentials for registry authentication.
**What this does**: Creates user credentials for registry authentication in the system auth directory.
- `push-user`: Can push images (used by CI/CD pipeline for deployments)
**Note**: Pull operations are public and don't require authentication, but push operations require these credentials.
#### 4.3.1 Clone Repository for Registry Configuration
```bash
# Switch to DEPLOY_USER (who has sudo access)
sudo su - DEPLOY_USER
# Create application directory and clone repository
sudo mkdir -p /opt/APP_NAME
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME
cd /opt
sudo git clone https://your-forgejo-instance/your-username/APP_NAME.git
sudo chown -R SERVICE_USER:SERVICE_USER APP_NAME/
# Verify the registry folder exists
ls -la /opt/APP_NAME/registry/
# Exit DEPLOY_USER shell
exit
```
**Important**: Replace `your-forgejo-instance`, `your-username`, and `APP_NAME` with your actual Forgejo instance URL, username, and application name.
**What this does**:
- DEPLOY_USER creates the directory structure and clones the repository
- SERVICE_USER owns all the files for security
- Registry configuration files are now available at `/opt/APP_NAME/registry/`
#### 4.4 Create Docker Compose for Registry
```bash
# Switch to SERVICE_USER (registry directory owner)
sudo su - SERVICE_USER
cat > /opt/registry/docker-compose.yml << 'EOF'
version: '3.8'
services:
registry:
image: registry:2
ports:
- "5000:5000"
volumes:
- ./config.yml:/etc/docker/registry/config.yml:ro
- ./auth/auth.htpasswd:/etc/docker/registry/auth/auth.htpasswd:ro
- ./ssl/registry.crt:/etc/docker/registry/ssl/registry.crt:ro
- ./ssl/registry.key:/etc/docker/registry/ssl/registry.key:ro
- registry_data:/var/lib/registry
restart: unless-stopped
networks:
- registry_network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "https://localhost:5000/v2/", "--no-check-certificate"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
registry-ui:
image: joxit/docker-registry-ui:latest
expose:
- "80"
environment:
- REGISTRY_TITLE=APP_NAME Registry
- REGISTRY_URL=https://YOUR_CI_CD_IP:8080
depends_on:
registry:
condition: service_healthy
restart: unless-stopped
networks:
- registry_network
nginx:
image: nginx:alpine
ports:
- "8080:443"
volumes:
- ./ssl:/etc/nginx/ssl:ro
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- registry-ui
restart: unless-stopped
networks:
- registry_network
volumes:
registry_data:
networks:
registry_network:
driver: bridge
EOF
# The registry configuration files are already available in the cloned repository
# at /opt/APP_NAME/registry/
# No file copying is needed - we'll use the files directly from the repository
# Exit SERVICE_USER shell
exit
```
**Important**: Replace `YOUR_CI_CD_IP` with your actual CI/CD Linode IP address in the `REGISTRY_URL` environment variable.
**Important**: The repository should be cloned in the previous step (4.3.1) to `/opt/APP_NAME/`. The registry configuration files are used directly from the repository.
**Note**: We updated the volume mounts to explicitly map individual certificate files to their expected locations in the registry container.
#### 4.4.1 Create Nginx Configuration
#### 4.4.1 Update Configuration with Actual IP Address
```bash
# Switch to SERVICE_USER (registry directory owner)
sudo su - SERVICE_USER
cat > /opt/registry/nginx.conf << 'EOF'
events {
worker_connections 1024;
}
cd /opt/APP_NAME/registry
http {
upstream registry_ui {
server registry-ui:80;
}
# Get your actual IP address
YOUR_ACTUAL_IP=$(curl -4 -s ifconfig.me)
echo "Your IP address is: $YOUR_ACTUAL_IP"
upstream registry_api {
server registry:5000;
}
server {
listen 443 ssl;
server_name YOUR_CI_CD_IP;
ssl_certificate /etc/nginx/ssl/registry.crt;
ssl_certificate_key /etc/nginx/ssl/registry.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Proxy registry API requests
location /v2/ {
proxy_pass https://registry_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
proxy_ssl_verify off;
}
# Proxy registry UI requests
location / {
proxy_pass http://registry_ui;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
}
EOF
# Replace placeholder IP addresses in configuration files
sed -i "s/YOUR_CI_CD_IP/$YOUR_ACTUAL_IP/g" docker-compose.yml
sed -i "s/YOUR_CI_CD_IP/$YOUR_ACTUAL_IP/g" nginx.conf
# Exit SERVICE_USER shell
exit
```
**Important**: Replace `YOUR_CI_CD_IP` with your actual CI/CD Linode IP address in the nginx configuration.
**Important**: This step replaces all instances of `YOUR_CI_CD_IP` with your actual CI/CD Linode IP address in both the docker-compose.yml and nginx.conf files in the repository.
#### 4.5 Install Required Tools
@ -683,7 +618,7 @@ sudo apt install -y apache2-utils
# Switch to SERVICE_USER (registry directory owner)
sudo su - SERVICE_USER
cd /opt/registry
cd /opt/APP_NAME/registry
docker compose up -d
# Exit SERVICE_USER shell
@ -693,11 +628,8 @@ exit
#### 4.7 Test Registry Setup
```bash
# Switch to SERVICE_USER (registry directory owner)
sudo su - SERVICE_USER
# Check if containers are running
cd /opt/registry
cd /opt/APP_NAME/registry
docker compose ps
# Test registry API (HTTPS via nginx)
@ -781,7 +713,7 @@ exit
```bash
# Get the push user credentials
PUSH_USER="push-user"
PUSH_PASSWORD=$(grep push-user /opt/registry/auth/auth.htpasswd | cut -d: -f2)
PUSH_PASSWORD=$(grep push-user /etc/registry/auth/auth.htpasswd | cut -d: -f2)
# Copy the certificate to Docker's trusted certificates
sudo cp /opt/registry/ssl/registry.crt /usr/local/share/ca-certificates/registry.crt
@ -1120,274 +1052,4 @@ curl http://localhost:5000/v2/_catalog
```bash
cat ~/.ssh/id_ed25519.pub
```
**Important**: Copy this public key - you'll need it for the production server setup.
### Step 11: Configure Forgejo Actions Runner
#### 11.1 Get Runner Token
1. Go to your Forgejo repository
2. Navigate to Settings → Actions → Runners
3. Click "New runner"
4. Copy the registration token
#### 11.2 Configure Runner
```bash
# Get the registration token from your Forgejo repository
# Go to Settings → Actions → Runners → New runner
# Copy the registration token
# Configure the runner
forgejo-runner register \
--instance https://your-forgejo-instance \
--token YOUR_TOKEN \
--name "ci-cd-runner" \
--labels "ubuntu-latest,docker" \
--no-interactive
```
#### 11.3 Start Runner
```bash
sudo systemctl start forgejo-runner.service
sudo systemctl status forgejo-runner.service
```
#### 11.4 Test Runner Configuration
```bash
# Check if the runner is running
sudo systemctl status forgejo-runner.service
# Check runner logs
sudo journalctl -u forgejo-runner.service -f --no-pager
# Test runner connectivity (in a separate terminal)
forgejo-runner list
# Verify runner appears in Forgejo
# Go to your Forgejo repository → Settings → Actions → Runners
# You should see your runner listed as "ci-cd-runner" with status "Online"
```
**Expected Output**:
- `systemctl status` should show "active (running)"
- `forgejo-runner list` should show your runner
- Forgejo web interface should show the runner as online
**If something goes wrong**:
- Check logs: `sudo journalctl -u forgejo-runner.service -f`
- Verify token: Make sure the registration token is correct
- Check network: Ensure the runner can reach your Forgejo instance
- Restart service: `sudo systemctl restart forgejo-runner.service`
---
## Part 2: Production Linode Setup
### Step 12: Initial System Setup
#### 12.1 Update the System
```bash
sudo apt update && sudo apt upgrade -y
```
#### 12.2 Configure Timezone
```bash
# Configure timezone interactively
sudo dpkg-reconfigure tzdata
# Verify timezone setting
date
```
**What this does**: Opens an interactive dialog to select your timezone. Navigate through the menus to choose your preferred timezone (e.g., UTC, America/New_York, Europe/London, Asia/Tokyo).
**Expected output**: After selecting your timezone, the `date` command should show the current date and time in your selected timezone.
#### 12.3 Configure /etc/hosts
```bash
# Add localhost entries for both IPv4 and IPv6
echo "127.0.0.1 localhost" | sudo tee -a /etc/hosts
echo "::1 localhost ip6-localhost ip6-loopback" | sudo tee -a /etc/hosts
echo "YOUR_PRODUCTION_IPV4_ADDRESS localhost" | sudo tee -a /etc/hosts
echo "YOUR_PRODUCTION_IPV6_ADDRESS localhost" | sudo tee -a /etc/hosts
# Verify the configuration
cat /etc/hosts
```
**What this does**:
- Adds localhost entries for both IPv4 and IPv6 addresses to `/etc/hosts`
- Ensures proper localhost resolution for both IPv4 and IPv6
**Important**: Replace `YOUR_PRODUCTION_IPV4_ADDRESS` and `YOUR_PRODUCTION_IPV6_ADDRESS` with the actual IPv4 and IPv6 addresses of your Production Linode obtained from your Linode dashboard.
**Expected output**: The `/etc/hosts` file should show entries for `127.0.0.1`, `::1`, and your Linode's actual IP addresses all mapping to `localhost`.
#### 12.4 Install Essential Packages
```bash
sudo apt install -y \
curl \
wget \
git \
ca-certificates \
apt-transport-https \
software-properties-common \
ufw \
fail2ban \
htop \
nginx \
certbot \
python3-certbot-nginx
```
### Step 13: Create Users
#### 13.1 Create the SERVICE_USER User
```bash
# Create dedicated group for the service account
sudo groupadd -r SERVICE_USER
# Create service account user with dedicated group
sudo useradd -r -g SERVICE_USER -s /bin/bash -m -d /home/SERVICE_USER SERVICE_USER
echo "SERVICE_USER:$(openssl rand -base64 32)" | sudo chpasswd
```
#### 13.2 Verify Users
```bash
sudo su - SERVICE_USER
whoami
pwd
exit
sudo su - DEPLOY_USER
whoami
pwd
exit
```
### Step 14: Install Docker
#### 14.1 Add Docker Repository
```bash
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
```
#### 14.2 Install Docker Packages
```bash
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
```
#### 14.3 Configure Docker for Service Account
```bash
sudo usermod -aG docker SERVICE_USER
```
### Step 15: Install Docker Compose
```bash
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
```
### Step 16: Configure Security
#### 16.1 Configure Firewall
```bash
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
```
#### 16.2 Configure Fail2ban
```bash
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
```
### Step 17: Create Application Directory
#### 17.1 Create Directory Structure
```bash
sudo mkdir -p /opt/APP_NAME
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME
```
**Note**: Replace `APP_NAME` with your actual application name. This directory name can be controlled via the `APP_NAME` secret in your Forgejo repository settings. If you set the `APP_NAME` secret to `myapp`, the deployment directory will be `/opt/myapp`.
#### 17.2 Create SSL Directory (Optional - for domain users)
```bash
sudo mkdir -p /opt/APP_NAME/nginx/ssl
sudo chown SERVICE_USER:SERVICE_USER /opt/APP_NAME/nginx/ssl
```
### Step 18: Clone Repository and Set Up Application Files
#### 18.1 Switch to SERVICE_USER User
```bash
sudo su - SERVICE_USER
```
#### 18.2 Clone Repository
```bash
cd /opt/APP_NAME
git clone https://your-forgejo-instance/your-username/APP_NAME.git .
```
**Important**: The repository includes a pre-configured `nginx/nginx.conf` file that handles both SSL and non-SSL scenarios, with proper security headers, rate limiting, and CORS configuration. This file will be automatically used by the Docker Compose setup.
**Important**: The repository also includes a pre-configured `.forgejo/workflows/ci.yml` file that handles the complete CI/CD pipeline including testing, building, and deployment. This workflow is already set up to work with the private registry and production deployment.
**Note**: Replace `your-forgejo-instance` and `your-username/APP_NAME` with your actual Forgejo instance URL and repository path.
#### 18.3 Create Environment File
The repository doesn't include a `.env.example` file for security reasons. The CI/CD pipeline will create the `.env` file dynamically during deployment. However, for manual testing or initial setup, you can create a basic `.env` file:
```bash
cat > /opt/APP_NAME/.env << 'EOF'
# Production Environment Variables
POSTGRES_PASSWORD=your_secure_password_here
REGISTRY=YOUR_CI_CD_IP:5000
IMAGE_NAME=APP_NAME
IMAGE_TAG=latest
# Database Configuration
POSTGRES_DB=sharenet
POSTGRES_USER=sharenet
DATABASE_URL=postgresql://sharenet:your_secure_password_here@postgres:5432/sharenet
# Application Configuration
NODE_ENV=production
RUST_LOG=info
RUST_BACKTRACE=1
EOF
```
**Important**: Replace `YOUR_CI_CD_IP`
```

52
registry/README.md Normal file
View file

@ -0,0 +1,52 @@
# Docker Registry Configuration
This folder contains the configuration files for the Docker Registry setup used in the CI/CD pipeline.
## Files
- `docker-compose.yml` - Docker Compose configuration for registry, registry-ui, and nginx services
- `nginx.conf` - Nginx reverse proxy configuration for SSL termination and routing
- `config.yml` - Docker Registry configuration file
- `README.md` - This file
## Architecture
This setup uses a hybrid approach for optimal maintainability and security:
### Repository Files (Version Controlled)
- Configuration files in `/opt/APP_NAME/registry/`
- Easy to update via git pull
- Version controlled and tracked
### System Files (Not Version Controlled)
- SSL certificates in `/etc/ssl/registry/`
- Authentication files in `/etc/registry/auth/`
- Registry data in Docker volume `/var/lib/registry`
## Usage
The setup process will:
1. Clone the repository to `/opt/APP_NAME/`
2. Create system directories for certificates and auth
3. Generate SSL certificates in `/etc/ssl/registry/`
4. Create authentication files in `/etc/registry/auth/`
5. Start the registry services using the hybrid configuration
## Configuration Notes
- **Registry**: Runs on port 5000 with HTTPS
- **Nginx**: Provides SSL termination and reverse proxy on port 8080
- **Registry UI**: Web interface accessible via nginx on port 8080
- **Authentication**: Uses htpasswd for push authentication
- **Storage**: Uses Docker volume for persistent data
- **Configuration**: Version controlled in repository
- **Certificates**: Stored in system SSL directory
## Security
- SSL certificates are self-signed and stored in system SSL directory
- Authentication files are stored in system auth directory
- Configuration is version controlled and easily auditable
- All communication uses HTTPS
- Clear separation between config, auth, and data

21
registry/config.yml Normal file
View file

@ -0,0 +1,21 @@
version: 0.1
log:
level: info
storage:
filesystem:
rootdirectory: /var/lib/registry
delete:
enabled: true
http:
addr: :5000
tls:
certificate: /etc/docker/registry/ssl/registry.crt
key: /etc/docker/registry/ssl/registry.key
headers:
X-Content-Type-Options: [nosniff]
X-Frame-Options: [DENY]
X-XSS-Protection: [1; mode=block]
auth:
htpasswd:
realm: basic-realm
path: /etc/docker/registry/auth/auth.htpasswd

View file

@ -0,0 +1,56 @@
version: '3.8'
services:
registry:
image: registry:2
ports:
- "5000:5000"
volumes:
- /opt/APP_NAME/registry/config.yml:/etc/docker/registry/config.yml:ro
- /etc/registry/auth/auth.htpasswd:/etc/docker/registry/auth/auth.htpasswd:ro
- /etc/ssl/registry/registry.crt:/etc/docker/registry/ssl/registry.crt:ro
- /etc/ssl/registry/registry.key:/etc/docker/registry/ssl/registry.key:ro
- registry_data:/var/lib/registry
restart: unless-stopped
networks:
- registry_network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "https://localhost:5000/v2/", "--no-check-certificate"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
registry-ui:
image: joxit/docker-registry-ui:latest
expose:
- "80"
environment:
- REGISTRY_TITLE=ShareNet Registry
- REGISTRY_URL=https://YOUR_CI_CD_IP:8080
depends_on:
registry:
condition: service_healthy
restart: unless-stopped
networks:
- registry_network
nginx:
image: nginx:alpine
ports:
- "8080:443"
volumes:
- /etc/ssl/registry:/etc/nginx/ssl:ro
- /opt/APP_NAME/registry/nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- registry-ui
restart: unless-stopped
networks:
- registry_network
volumes:
registry_data:
networks:
registry_network:
driver: bridge

48
registry/nginx.conf Normal file
View file

@ -0,0 +1,48 @@
events {
worker_connections 1024;
}
http {
upstream registry_ui {
server registry-ui:80;
}
upstream registry_api {
server registry:5000;
}
server {
listen 443 ssl;
server_name YOUR_CI_CD_IP;
ssl_certificate /etc/nginx/ssl/registry.crt;
ssl_certificate_key /etc/nginx/ssl/registry.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Proxy registry API requests
location /v2/ {
proxy_pass https://registry_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
proxy_ssl_verify off;
}
# Proxy registry UI requests
location / {
proxy_pass http://registry_ui;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_connect_timeout 30s;
proxy_send_timeout 30s;
proxy_read_timeout 30s;
}
}
}