Initial commit of Forgejo configuration
This commit is contained in:
commit
ce9b28917b
16 changed files with 860 additions and 0 deletions
27
.gitignore
vendored
Normal file
27
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Terraform files
|
||||
terraform/.terraform/
|
||||
terraform/terraform.tfstate
|
||||
terraform/terraform.tfstate.backup
|
||||
terraform/.terraform.lock.hcl
|
||||
terraform/crash.log
|
||||
|
||||
# Ansible files
|
||||
ansible/*.retry
|
||||
|
||||
# SSH keys
|
||||
*.pem
|
||||
*.key
|
||||
id_rsa*
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Editor files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*~
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
147
DEPLOYMENT_GUIDE.md
Normal file
147
DEPLOYMENT_GUIDE.md
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
# Forgejo Deployment Guide
|
||||
|
||||
This guide provides detailed step-by-step instructions for deploying the Forgejo git repository on a GCP VM with SSL.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Google Cloud Platform account with project ID: `homelab-454516`
|
||||
2. Terraform installed locally
|
||||
3. Ansible installed locally
|
||||
4. SSH key pair at `~/.ssh/id_rsa` and `~/.ssh/id_rsa.pub`
|
||||
5. DuckDNS account with subdomain: `bootknockery.duckdns.org`
|
||||
|
||||
## Deployment Steps
|
||||
|
||||
### 1. Infrastructure Provisioning with Terraform
|
||||
|
||||
```bash
|
||||
# Navigate to the terraform directory
|
||||
cd terraform
|
||||
|
||||
# Initialize Terraform
|
||||
terraform init
|
||||
|
||||
# Apply the Terraform configuration
|
||||
terraform apply
|
||||
```
|
||||
|
||||
This will create a GCP VM in the `us-central1-a` zone with the following specifications:
|
||||
- Machine type: e2-medium
|
||||
- Disk size: 50GB
|
||||
- Operating system: Debian
|
||||
|
||||
### 2. Update DuckDNS
|
||||
|
||||
Ensure your DuckDNS subdomain (`bootknockery.duckdns.org`) points to the VM's external IP address.
|
||||
|
||||
### 3. Deploy Forgejo with Ansible
|
||||
|
||||
```bash
|
||||
# Navigate to the ansible directory
|
||||
cd ../ansible
|
||||
|
||||
# Run the Ansible playbook
|
||||
ansible-playbook -i inventory.yml forgejo.yml
|
||||
```
|
||||
|
||||
This will:
|
||||
- Install Docker and Docker Compose
|
||||
- Deploy Forgejo in a Docker container
|
||||
- Configure Nginx as a reverse proxy
|
||||
- Set up SSL with Let's Encrypt
|
||||
- Configure SQLite with WAL mode for better performance
|
||||
|
||||
### 4. Verify the Deployment
|
||||
|
||||
1. Access Forgejo via HTTPS:
|
||||
```
|
||||
https://bootknockery.duckdns.org
|
||||
```
|
||||
|
||||
2. Check that SSL is properly configured:
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo certbot certificates"
|
||||
```
|
||||
|
||||
3. Verify that SQLite WAL mode is active:
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo ls -la /opt/forgejo/data/gitea/gitea.db*"
|
||||
```
|
||||
You should see additional files like `gitea.db-wal` and `gitea.db-shm`.
|
||||
|
||||
## Post-Deployment Configuration
|
||||
|
||||
### Initial Forgejo Setup
|
||||
|
||||
When you first access Forgejo, you'll need to:
|
||||
|
||||
1. Set up the admin account
|
||||
2. Configure the database settings (SQLite is already configured)
|
||||
3. Set up repository settings
|
||||
|
||||
### SSH Access for Git Operations
|
||||
|
||||
To use Git over SSH:
|
||||
|
||||
```bash
|
||||
# Add to ~/.ssh/config
|
||||
Host bootknockery.duckdns.org
|
||||
Port 222
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_rsa
|
||||
```
|
||||
|
||||
Then clone repositories using:
|
||||
```bash
|
||||
git clone git@bootknockery.duckdns.org:username/repository.git
|
||||
```
|
||||
|
||||
## Maintenance Tasks
|
||||
|
||||
### SSL Certificate Renewal
|
||||
|
||||
SSL certificates are automatically renewed weekly. To manually renew:
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo /etc/cron.weekly/certbot-renew"
|
||||
```
|
||||
|
||||
### Database Backup
|
||||
|
||||
To back up the Forgejo database:
|
||||
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo cp /opt/forgejo/data/gitea/gitea.db ~/backup_gitea.db"
|
||||
scp -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS:~/backup_gitea.db ./
|
||||
```
|
||||
|
||||
### Updating Forgejo
|
||||
|
||||
To update Forgejo to a newer version:
|
||||
|
||||
1. Edit `ansible/templates/docker-compose.yml.j2` to update the image version
|
||||
2. Run the Ansible playbook again:
|
||||
```bash
|
||||
cd ansible
|
||||
ansible-playbook -i inventory.yml forgejo.yml
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Cannot access Forgejo via HTTPS**
|
||||
- Check Nginx status: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo systemctl status nginx"`
|
||||
- Verify SSL certificates: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo ls -la /etc/letsencrypt/live/bootknockery.duckdns.org/"`
|
||||
|
||||
2. **Forgejo container not running**
|
||||
- Check Docker status: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo docker ps"`
|
||||
- View Forgejo logs: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo docker logs forgejo"`
|
||||
|
||||
3. **SSL certificate issues**
|
||||
- Check certificate logs: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo tail -f /var/log/letsencrypt/letsencrypt.log"`
|
||||
- Force renewal: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo /etc/cron.weekly/certbot-renew"`
|
||||
|
||||
4. **Performance issues**
|
||||
- Verify WAL mode: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo ls -la /opt/forgejo/data/gitea/gitea.db*"`
|
||||
- Check system resources: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "top"`
|
||||
142
README.md
Normal file
142
README.md
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
# GCP Data Engineering VM with Forgejo
|
||||
|
||||
This project sets up a reusable Google Cloud Platform (GCP) virtual machine for data engineering and machine learning projects, with Forgejo as the first installed module.
|
||||
|
||||
## Technologies Used
|
||||
|
||||
- **Terraform**: For infrastructure provisioning and state management
|
||||
- **Cloud-init**: For initial VM setup and configuration with Debian
|
||||
- **Ansible**: For configuration management and application deployment
|
||||
- **Docker & Docker Compose**: For containerized applications
|
||||
- **Forgejo**: Open source git repository that can be accessed through a DuckDNS subdomain
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
.
|
||||
├── ansible/ # Ansible playbooks and configurations
|
||||
│ ├── forgejo.yml # Forgejo installation playbook
|
||||
│ ├── inventory.yml # Ansible inventory file
|
||||
│ └── templates/ # Jinja2 templates for configurations
|
||||
│ ├── app.ini.j2 # Forgejo app configuration
|
||||
│ ├── docker-compose.yml.j2 # Docker Compose template
|
||||
│ ├── nginx.conf.j2 # Nginx configuration with SSL support
|
||||
│ └── certbot-renew.j2 # SSL certificate renewal script
|
||||
├── cloud-init/ # Cloud-init scripts
|
||||
│ └── cloud-init.sh # Initial VM setup script
|
||||
├── terraform/ # Terraform configurations
|
||||
│ ├── main.tf # Main Terraform configuration
|
||||
│ ├── variables.tf # Variable definitions
|
||||
│ └── terraform.tfvars.example # Example variable values
|
||||
├── deploy.sh # Deployment automation script
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. Google Cloud Platform account with a project
|
||||
2. Terraform installed locally
|
||||
3. Ansible installed locally
|
||||
4. SSH key pair for VM access
|
||||
5. DuckDNS subdomain for Forgejo access
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Configure Terraform Variables
|
||||
|
||||
Copy the example variables file and edit it with your GCP project details:
|
||||
|
||||
```bash
|
||||
cp terraform/terraform.tfvars.example terraform/terraform.tfvars
|
||||
```
|
||||
|
||||
Edit `terraform/terraform.tfvars` with your GCP project ID, preferred region/zone, and SSH key path.
|
||||
|
||||
### 2. Configure Ansible Inventory
|
||||
|
||||
Edit `ansible/inventory.yml` to set your DuckDNS subdomain and admin email for Let's Encrypt SSL certificates.
|
||||
|
||||
### 3. Run the Deployment Script
|
||||
|
||||
```bash
|
||||
./deploy.sh
|
||||
```
|
||||
|
||||
This script will:
|
||||
- Initialize and apply Terraform configuration to create the VM
|
||||
- Update the Ansible inventory with the VM's IP address
|
||||
- Wait for the VM to be ready
|
||||
- Run the Ansible playbook to install and configure Forgejo
|
||||
|
||||
## Accessing Forgejo
|
||||
|
||||
Once deployment is complete, Forgejo will be accessible at:
|
||||
|
||||
```
|
||||
https://your-duckdns-subdomain.duckdns.org
|
||||
```
|
||||
|
||||
The deployment automatically configures:
|
||||
- HTTPS with Let's Encrypt SSL certificates
|
||||
- Automatic HTTP to HTTPS redirection
|
||||
- Weekly SSL certificate renewal
|
||||
- SQLite with WAL mode for improved performance
|
||||
|
||||
SSH access to the Forgejo Git server will be available on port 222:
|
||||
|
||||
```bash
|
||||
ssh -p 222 git@your-duckdns-subdomain.duckdns.org
|
||||
```
|
||||
|
||||
## Performance Optimizations
|
||||
|
||||
### SQLite WAL Mode
|
||||
|
||||
The deployment configures SQLite to use Write-Ahead Logging (WAL) mode for better performance. This provides:
|
||||
- Improved write performance with concurrent operations
|
||||
- Better read concurrency (readers don't block writers)
|
||||
- Reduced disk I/O
|
||||
- Improved durability and crash recovery
|
||||
|
||||
To modify this setting, edit the `ansible/templates/app.ini.j2` file:
|
||||
|
||||
```ini
|
||||
[database]
|
||||
SQLITE_JOURNAL_MODE = WAL
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
- **Machine Type**: Edit `terraform/terraform.tfvars` to change the VM size
|
||||
- **Forgejo Configuration**: Modify `ansible/templates/app.ini.j2` to customize Forgejo settings
|
||||
- **Additional Applications**: Add new Ansible playbooks in the `ansible` directory
|
||||
|
||||
## Maintenance
|
||||
|
||||
- **Terraform State**: The Terraform state is stored locally in `terraform/terraform.tfstate`
|
||||
- **VM Updates**: SSH into the VM and run standard Debian update commands
|
||||
- **Forgejo Updates**: Update the Docker image version in `ansible/templates/docker-compose.yml.j2`
|
||||
- **SSL Certificate Renewal**: Certificates are automatically renewed weekly via a cron job
|
||||
- **Database Backups**: To back up the Forgejo database, copy `/opt/forgejo/data/gitea/gitea.db*` from the VM
|
||||
- **Monitoring**: Check the status of services with:
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo systemctl status nginx"
|
||||
ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo docker ps"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **SSH Access**: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS`
|
||||
- **Logs**:
|
||||
- Forgejo logs: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo docker logs forgejo"`
|
||||
- Nginx logs: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo tail -f /var/log/nginx/error.log"`
|
||||
- SSL certificate logs: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo tail -f /var/log/letsencrypt/letsencrypt.log"`
|
||||
- **Connectivity**: Ensure GCP firewall rules allow traffic on ports 80, 443, 22, 3000, and 222
|
||||
- **SSL Issues**:
|
||||
- Check certificate status: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo certbot certificates"`
|
||||
- Force certificate renewal: `ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo /etc/cron.weekly/certbot-renew"`
|
||||
- **Database Performance**: If experiencing slowdowns, check SQLite WAL mode is working:
|
||||
```bash
|
||||
ssh -i ~/.ssh/id_rsa debian@VM_IP_ADDRESS "sudo ls -la /opt/forgejo/data/gitea/gitea.db*"
|
||||
```
|
||||
You should see additional files like `gitea.db-wal` and `gitea.db-shm` if WAL mode is active.
|
||||
124
ansible/forgejo.yml
Normal file
124
ansible/forgejo.yml
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
---
|
||||
- name: Install and configure Forgejo
|
||||
hosts: all
|
||||
become: true
|
||||
vars:
|
||||
forgejo_domain: "{{ duckdns_subdomain }}.duckdns.org"
|
||||
forgejo_data_dir: /opt/forgejo
|
||||
forgejo_user_uid: 1000
|
||||
forgejo_user_gid: 1000
|
||||
forgejo_http_port: 3000
|
||||
forgejo_ssh_port: 222
|
||||
|
||||
tasks:
|
||||
- name: Ensure Forgejo directory exists
|
||||
file:
|
||||
path: "{{ forgejo_data_dir }}"
|
||||
state: directory
|
||||
owner: "{{ forgejo_user_uid }}"
|
||||
group: "{{ forgejo_user_gid }}"
|
||||
mode: '0755'
|
||||
|
||||
- name: Create Forgejo docker-compose.yml
|
||||
template:
|
||||
src: templates/docker-compose.yml.j2
|
||||
dest: "{{ forgejo_data_dir }}/docker-compose.yml"
|
||||
owner: "{{ forgejo_user_uid }}"
|
||||
group: "{{ forgejo_user_gid }}"
|
||||
mode: '0644'
|
||||
|
||||
- name: Create app.ini configuration file
|
||||
template:
|
||||
src: templates/app.ini.j2
|
||||
dest: "{{ forgejo_data_dir }}/app.ini"
|
||||
owner: "{{ forgejo_user_uid }}"
|
||||
group: "{{ forgejo_user_gid }}"
|
||||
mode: '0644'
|
||||
|
||||
- name: Start Forgejo with Docker Compose
|
||||
community.docker.docker_compose_v2:
|
||||
project_src: "{{ forgejo_data_dir }}"
|
||||
state: present
|
||||
become: true
|
||||
become_user: debian
|
||||
|
||||
- name: Install Nginx
|
||||
apt:
|
||||
name: nginx
|
||||
state: present
|
||||
update_cache: yes
|
||||
|
||||
- name: Configure Nginx for Forgejo
|
||||
template:
|
||||
src: templates/nginx.conf.j2
|
||||
dest: /etc/nginx/sites-available/forgejo
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
|
||||
- name: Enable Nginx site
|
||||
file:
|
||||
src: /etc/nginx/sites-available/forgejo
|
||||
dest: /etc/nginx/sites-enabled/forgejo
|
||||
state: link
|
||||
|
||||
- name: Remove default Nginx site
|
||||
file:
|
||||
path: /etc/nginx/sites-enabled/default
|
||||
state: absent
|
||||
|
||||
- name: Restart Nginx
|
||||
service:
|
||||
name: nginx
|
||||
state: restarted
|
||||
enabled: yes
|
||||
|
||||
- name: Pull Certbot Docker image
|
||||
community.docker.docker_image:
|
||||
name: certbot/certbot
|
||||
source: pull
|
||||
when: admin_email is defined
|
||||
|
||||
- name: Stop Nginx before obtaining SSL certificate
|
||||
service:
|
||||
name: nginx
|
||||
state: stopped
|
||||
when: admin_email is defined
|
||||
|
||||
- name: Obtain SSL certificate with Certbot Docker
|
||||
block:
|
||||
- name: Run Certbot Docker to obtain SSL certificate
|
||||
command: >
|
||||
docker run --rm -p 80:80 -p 443:443
|
||||
-v /etc/letsencrypt:/etc/letsencrypt
|
||||
-v /var/lib/letsencrypt:/var/lib/letsencrypt
|
||||
certbot/certbot certonly --standalone
|
||||
-d {{ forgejo_domain }} --non-interactive --agree-tos
|
||||
-m {{ admin_email }}
|
||||
args:
|
||||
creates: /etc/letsencrypt/live/{{ forgejo_domain }}/fullchain.pem
|
||||
register: certbot_output
|
||||
failed_when: certbot_output.rc != 0 and certbot_output.stderr is not search("already exists")
|
||||
- name: Handle certbot errors
|
||||
debug:
|
||||
msg: "Certbot error: {{ certbot_output.stderr }}"
|
||||
when: certbot_output is failed
|
||||
when: admin_email is defined
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Start Nginx after obtaining SSL certificate
|
||||
service:
|
||||
name: nginx
|
||||
state: started
|
||||
when: admin_email is defined
|
||||
|
||||
- name: Set up SSL certificate renewal
|
||||
block:
|
||||
- name: Create SSL certificate renewal script
|
||||
template:
|
||||
src: templates/certbot-renew.j2
|
||||
dest: /etc/cron.weekly/certbot-renew
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
when: admin_email is defined
|
||||
8
ansible/inventory.yml
Normal file
8
ansible/inventory.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
all:
|
||||
hosts:
|
||||
data_engineering_vm:
|
||||
ansible_host: "34.67.170.119"
|
||||
ansible_user: debian
|
||||
ansible_ssh_private_key_file: "~/.ssh/id_rsa"
|
||||
duckdns_subdomain: "bootknockery" # Replace with your actual DuckDNS subdomain
|
||||
admin_email: "jaypeedaylee@gmail.com" # Replace with your email for Let's Encrypt
|
||||
77
ansible/templates/app.ini.j2
Normal file
77
ansible/templates/app.ini.j2
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
APP_NAME = Forgejo
|
||||
RUN_USER = git
|
||||
RUN_MODE = prod
|
||||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||
|
||||
[repository.upload]
|
||||
TEMP_PATH = /data/gitea/uploads
|
||||
|
||||
[server]
|
||||
APP_DATA_PATH = /data/gitea
|
||||
DOMAIN = {{ forgejo_domain }}
|
||||
SSH_DOMAIN = {{ forgejo_domain }}
|
||||
HTTP_PORT = 3000
|
||||
ROOT_URL = https://{{ forgejo_domain }}/
|
||||
DISABLE_SSH = false
|
||||
SSH_PORT = {{ forgejo_ssh_port }}
|
||||
SSH_LISTEN_PORT = 22
|
||||
LFS_START_SERVER = true
|
||||
LFS_CONTENT_PATH = /data/git/lfs
|
||||
LFS_JWT_SECRET =
|
||||
OFFLINE_MODE = false
|
||||
|
||||
[database]
|
||||
PATH = /data/gitea/gitea.db
|
||||
DB_TYPE = sqlite3
|
||||
SQLITE_JOURNAL_MODE = WAL
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_PATH = /data/gitea/indexers/issues.bleve
|
||||
|
||||
[session]
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
||||
PROVIDER = file
|
||||
|
||||
[picture]
|
||||
AVATAR_UPLOAD_PATH = /data/gitea/avatars
|
||||
REPOSITORY_AVATAR_UPLOAD_PATH = /data/gitea/repo-avatars
|
||||
|
||||
[attachment]
|
||||
PATH = /data/gitea/attachments
|
||||
|
||||
[log]
|
||||
MODE = console
|
||||
LEVEL = info
|
||||
ROOT_PATH = /data/gitea/log
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY =
|
||||
INTERNAL_TOKEN =
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = false
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = false
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
NO_REPLY_ADDRESS = noreply.example.org
|
||||
|
||||
[oauth2]
|
||||
JWT_SECRET =
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = true
|
||||
ENABLE_OPENID_SIGNUP = true
|
||||
37
ansible/templates/certbot-renew.j2
Normal file
37
ansible/templates/certbot-renew.j2
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
# Certbot renewal script for Forgejo SSL certificates
|
||||
# Automatically created by Ansible
|
||||
|
||||
# Set up logging
|
||||
LOG_FILE="/var/log/certbot-renewal.log"
|
||||
echo "$(date): Starting certificate renewal" >> $LOG_FILE
|
||||
|
||||
# Stop Nginx to free up port 80
|
||||
echo "$(date): Stopping Nginx" >> $LOG_FILE
|
||||
systemctl stop nginx
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$(date): Failed to stop Nginx" >> $LOG_FILE
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run Certbot renewal
|
||||
echo "$(date): Running Certbot renewal" >> $LOG_FILE
|
||||
docker run --rm -p 80:80 -p 443:443 \
|
||||
-v /etc/letsencrypt:/etc/letsencrypt \
|
||||
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
|
||||
certbot/certbot renew --standalone --non-interactive
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$(date): Certbot renewal failed" >> $LOG_FILE
|
||||
# Even if renewal fails, we should restart Nginx
|
||||
fi
|
||||
|
||||
# Start Nginx again
|
||||
echo "$(date): Starting Nginx" >> $LOG_FILE
|
||||
systemctl start nginx
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$(date): Failed to start Nginx" >> $LOG_FILE
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "$(date): Certificate renewal completed successfully" >> $LOG_FILE
|
||||
21
ansible/templates/docker-compose.yml.j2
Normal file
21
ansible/templates/docker-compose.yml.j2
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
networks:
|
||||
forgejo:
|
||||
external: false
|
||||
|
||||
services:
|
||||
server:
|
||||
image: codeberg.org/forgejo/forgejo:10
|
||||
container_name: forgejo
|
||||
environment:
|
||||
- USER_UID={{ forgejo_user_uid }}
|
||||
- USER_GID={{ forgejo_user_gid }}
|
||||
restart: always
|
||||
networks:
|
||||
- forgejo
|
||||
volumes:
|
||||
- {{ forgejo_data_dir }}/data:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- '{{ forgejo_http_port }}:3000'
|
||||
- '{{ forgejo_ssh_port }}:22'
|
||||
12
ansible/templates/nginx-forgejo.conf.j2
Normal file
12
ansible/templates/nginx-forgejo.conf.j2
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name {{ forgejo_domain }};
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:{{ forgejo_http_port }}/;
|
||||
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;
|
||||
}
|
||||
}
|
||||
32
ansible/templates/nginx.conf.j2
Normal file
32
ansible/templates/nginx.conf.j2
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
server {
|
||||
listen 80;
|
||||
server_name {{ forgejo_domain }};
|
||||
|
||||
# Redirect all HTTP requests to HTTPS
|
||||
location / {
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name {{ forgejo_domain }};
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/{{ forgejo_domain }}/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/{{ forgejo_domain }}/privkey.pem;
|
||||
|
||||
# SSL configuration
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:{{ forgejo_http_port }}/;
|
||||
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;
|
||||
}
|
||||
}
|
||||
44
cloud-init/cloud-init.sh
Normal file
44
cloud-init/cloud-init.sh
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Update and install dependencies
|
||||
apt-get update
|
||||
apt-get install -y \
|
||||
apt-transport-https \
|
||||
ca-certificates \
|
||||
curl \
|
||||
gnupg \
|
||||
lsb-release \
|
||||
python3 \
|
||||
python3-pip \
|
||||
git \
|
||||
unzip
|
||||
|
||||
# Install Docker
|
||||
curl -fsSL https://download.docker.com/linux/debian/gpg | 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/debian \
|
||||
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
apt-get update
|
||||
apt-get install -y docker-ce docker-ce-cli containerd.io
|
||||
|
||||
# Install Docker Compose
|
||||
curl -L "https://github.com/docker/compose/releases/download/v2.20.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||
chmod +x /usr/local/bin/docker-compose
|
||||
|
||||
# Add debian user to docker group
|
||||
usermod -aG docker debian
|
||||
|
||||
# Install Ansible
|
||||
pip3 install ansible
|
||||
|
||||
# Create directory for Ansible playbooks
|
||||
mkdir -p /opt/ansible
|
||||
chown -R debian:debian /opt/ansible
|
||||
|
||||
# Create directory for Forgejo
|
||||
mkdir -p /opt/forgejo
|
||||
chown -R debian:debian /opt/forgejo
|
||||
|
||||
# Signal cloud-init completion
|
||||
touch /var/lib/cloud/instance/boot-finished
|
||||
61
deploy.sh
Executable file
61
deploy.sh
Executable file
|
|
@ -0,0 +1,61 @@
|
|||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${YELLOW}Starting deployment of GCP Data Engineering VM with Forgejo...${NC}"
|
||||
|
||||
# Check if terraform is installed
|
||||
if ! command -v terraform &> /dev/null; then
|
||||
echo -e "${RED}Terraform is not installed. Please install it first.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if ansible is installed
|
||||
if ! command -v ansible &> /dev/null; then
|
||||
echo -e "${RED}Ansible is not installed. Please install it first.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if terraform.tfvars exists
|
||||
if [ ! -f terraform/terraform.tfvars ]; then
|
||||
echo -e "${YELLOW}terraform.tfvars not found. Creating from example file...${NC}"
|
||||
cp terraform/terraform.tfvars.example terraform/terraform.tfvars
|
||||
echo -e "${RED}Please edit terraform/terraform.tfvars with your GCP project details before continuing.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Initialize Terraform
|
||||
echo -e "${GREEN}Initializing Terraform...${NC}"
|
||||
cd terraform
|
||||
terraform init
|
||||
|
||||
# Apply Terraform configuration
|
||||
echo -e "${GREEN}Applying Terraform configuration...${NC}"
|
||||
terraform apply -auto-approve
|
||||
|
||||
# Get the VM IP address
|
||||
VM_IP=$(terraform output -raw instance_ip)
|
||||
echo -e "${GREEN}VM created with IP: ${VM_IP}${NC}"
|
||||
cd ..
|
||||
|
||||
# Update Ansible inventory with VM IP
|
||||
echo -e "${GREEN}Updating Ansible inventory with VM IP...${NC}"
|
||||
sed -i "s/ansible_host: \"{{ vm_ip_address }}\"/ansible_host: \"${VM_IP}\"/g" ansible/inventory.yml
|
||||
|
||||
# Wait for VM to be ready
|
||||
echo -e "${YELLOW}Waiting for VM to be ready (60 seconds)...${NC}"
|
||||
sleep 60
|
||||
|
||||
# Run Ansible playbook
|
||||
echo -e "${GREEN}Running Ansible playbook to configure Forgejo...${NC}"
|
||||
cd ansible
|
||||
ansible-playbook -i inventory.yml forgejo.yml
|
||||
|
||||
echo -e "${GREEN}Deployment completed successfully!${NC}"
|
||||
echo -e "${YELLOW}Forgejo should be accessible at https://your-duckdns-subdomain.duckdns.org${NC}"
|
||||
echo -e "${YELLOW}Please allow a few minutes for DNS propagation and SSL certificate setup.${NC}"
|
||||
66
terraform/main.tf
Normal file
66
terraform/main.tf
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
terraform {
|
||||
required_providers {
|
||||
google = {
|
||||
source = "hashicorp/google"
|
||||
version = "~> 4.0"
|
||||
}
|
||||
}
|
||||
backend "local" {
|
||||
path = "terraform.tfstate"
|
||||
}
|
||||
}
|
||||
|
||||
provider "google" {
|
||||
project = var.project_id
|
||||
region = var.region
|
||||
zone = var.zone
|
||||
}
|
||||
|
||||
resource "google_compute_instance" "data_engineering_vm" {
|
||||
name = var.instance_name
|
||||
machine_type = var.machine_type
|
||||
zone = var.zone
|
||||
|
||||
boot_disk {
|
||||
initialize_params {
|
||||
image = "debian-cloud/debian-11"
|
||||
size = var.disk_size_gb
|
||||
}
|
||||
}
|
||||
|
||||
network_interface {
|
||||
network = "default"
|
||||
access_config {
|
||||
// Ephemeral public IP
|
||||
}
|
||||
}
|
||||
|
||||
metadata = {
|
||||
ssh-keys = "${var.ssh_username}:${file(var.ssh_pub_key_path)}"
|
||||
}
|
||||
|
||||
metadata_startup_script = file("${path.module}/../cloud-init/cloud-init.sh")
|
||||
|
||||
tags = ["http-server", "https-server", "ssh"]
|
||||
|
||||
service_account {
|
||||
scopes = ["cloud-platform"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_compute_firewall" "forgejo" {
|
||||
name = "allow-forgejo"
|
||||
network = "default"
|
||||
|
||||
allow {
|
||||
protocol = "tcp"
|
||||
ports = ["22", "80", "443", "3000", "222"]
|
||||
}
|
||||
|
||||
source_ranges = ["0.0.0.0/0"]
|
||||
target_tags = ["http-server", "https-server", "ssh"]
|
||||
}
|
||||
|
||||
output "instance_ip" {
|
||||
value = google_compute_instance.data_engineering_vm.network_interface[0].access_config[0].nat_ip
|
||||
}
|
||||
8
terraform/terraform.tfvars
Normal file
8
terraform/terraform.tfvars
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
project_id = "homelab-454516"
|
||||
region = "us-central1"
|
||||
zone = "us-central1-a"
|
||||
instance_name = "data-engineering-vm"
|
||||
machine_type = "e2-medium"
|
||||
disk_size_gb = 50
|
||||
ssh_username = "debian"
|
||||
ssh_pub_key_path = "~/.ssh/id_rsa.pub"
|
||||
8
terraform/terraform.tfvars.example
Normal file
8
terraform/terraform.tfvars.example
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
project_id = "your-gcp-project-id"
|
||||
region = "us-central1"
|
||||
zone = "us-central1-a"
|
||||
instance_name = "data-engineering-vm"
|
||||
machine_type = "e2-medium"
|
||||
disk_size_gb = 50
|
||||
ssh_username = "debian"
|
||||
ssh_pub_key_path = "~/.ssh/id_rsa.pub"
|
||||
46
terraform/variables.tf
Normal file
46
terraform/variables.tf
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
variable "project_id" {
|
||||
description = "The GCP project ID"
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "region" {
|
||||
description = "The GCP region"
|
||||
type = string
|
||||
default = "us-central1"
|
||||
}
|
||||
|
||||
variable "zone" {
|
||||
description = "The GCP zone"
|
||||
type = string
|
||||
default = "us-central1-a"
|
||||
}
|
||||
|
||||
variable "instance_name" {
|
||||
description = "Name of the VM instance"
|
||||
type = string
|
||||
default = "data-engineering-vm"
|
||||
}
|
||||
|
||||
variable "machine_type" {
|
||||
description = "The machine type for the VM"
|
||||
type = string
|
||||
default = "e2-medium"
|
||||
}
|
||||
|
||||
variable "disk_size_gb" {
|
||||
description = "Boot disk size in GB"
|
||||
type = number
|
||||
default = 50
|
||||
}
|
||||
|
||||
variable "ssh_username" {
|
||||
description = "SSH username for the VM"
|
||||
type = string
|
||||
default = "debian"
|
||||
}
|
||||
|
||||
variable "ssh_pub_key_path" {
|
||||
description = "Path to the SSH public key file"
|
||||
type = string
|
||||
default = "~/.ssh/id_rsa.pub"
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue