Add Template to deploy forgejo.
This template allows deploying a forgejo en either Scaleway or Hetzner (untested) without much knowledge about them. It DOES require knowledge about Terragrunt and ansible. A wizard of sorts is provided but it will not guarantee success without some knowledge about the underlying technology.
This commit is contained in:
parent
a9f546f92a
commit
822e42dbb8
48 changed files with 6846 additions and 2 deletions
63
ansible/roles/forgejo/templates/Caddyfile.j2
Normal file
63
ansible/roles/forgejo/templates/Caddyfile.j2
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
# Caddyfile for Forgejo
|
||||
# Caddy automatically obtains and renews TLS certificates via Let's Encrypt
|
||||
|
||||
{% if forgejo_enable_letsencrypt %}
|
||||
{{ forgejo_domain }} {
|
||||
# Reverse proxy to Forgejo
|
||||
reverse_proxy localhost:{{ forgejo_http_port }} {
|
||||
# WebSocket support (needed for real-time features)
|
||||
header_up X-Real-IP {remote_host}
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
header_up X-Forwarded-Proto {scheme}
|
||||
|
||||
# Timeouts for large Git operations
|
||||
transport http {
|
||||
read_timeout 600s
|
||||
write_timeout 600s
|
||||
}
|
||||
}
|
||||
|
||||
# Security headers
|
||||
header {
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains"
|
||||
X-Frame-Options "SAMEORIGIN"
|
||||
X-Content-Type-Options "nosniff"
|
||||
X-XSS-Protection "1; mode=block"
|
||||
}
|
||||
|
||||
# Request body size for large uploads (Git push, LFS)
|
||||
request_body {
|
||||
max_size 100MB
|
||||
}
|
||||
|
||||
# Logging
|
||||
log {
|
||||
output file /var/log/caddy/forgejo_access.log {
|
||||
roll_size 100mb
|
||||
roll_keep 5
|
||||
}
|
||||
format json
|
||||
}
|
||||
|
||||
# TLS configuration (automatic via Let's Encrypt)
|
||||
tls {{ letsencrypt_email }}
|
||||
}
|
||||
{% else %}
|
||||
# HTTP-only configuration (not recommended for production)
|
||||
:80 {
|
||||
reverse_proxy localhost:{{ forgejo_http_port }} {
|
||||
header_up X-Real-IP {remote_host}
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
header_up X-Forwarded-Proto {scheme}
|
||||
}
|
||||
|
||||
request_body {
|
||||
max_size 100MB
|
||||
}
|
||||
|
||||
log {
|
||||
output file /var/log/caddy/forgejo_access.log
|
||||
format json
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
219
ansible/roles/forgejo/templates/app.ini.j2
Normal file
219
ansible/roles/forgejo/templates/app.ini.j2
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
; Forgejo Configuration File
|
||||
; Generated by Ansible
|
||||
|
||||
APP_NAME = Forgejo: {{ forgejo_domain }}
|
||||
RUN_MODE = prod
|
||||
RUN_USER = {{ forgejo_user }}
|
||||
WORK_PATH = /data/gitea
|
||||
|
||||
[repository]
|
||||
ROOT = /data/git/repositories
|
||||
SCRIPT_TYPE = bash
|
||||
DEFAULT_BRANCH = main
|
||||
DEFAULT_PRIVATE = last
|
||||
MAX_CREATION_LIMIT = -1
|
||||
ENABLE_PUSH_CREATE_USER = true
|
||||
ENABLE_PUSH_CREATE_ORG = true
|
||||
DISABLE_HTTP_GIT = {{ forgejo_disable_http_git | lower }}
|
||||
|
||||
[repository.local]
|
||||
LOCAL_COPY_PATH = /data/gitea/tmp/local-repo
|
||||
|
||||
[repository.upload]
|
||||
ENABLED = true
|
||||
TEMP_PATH = /data/gitea/uploads
|
||||
FILE_MAX_SIZE = 100
|
||||
MAX_FILES = 10
|
||||
|
||||
[lfs]
|
||||
ENABLED = {{ forgejo_enable_lfs | lower }}
|
||||
PATH = /data/lfs
|
||||
MAX_FILE_SIZE = {{ forgejo_lfs_max_file_size }}
|
||||
|
||||
[server]
|
||||
; Forgejo listens on HTTP internally; Caddy handles TLS termination
|
||||
PROTOCOL = http
|
||||
DOMAIN = {{ forgejo_domain }}
|
||||
ROOT_URL = {{ forgejo_protocol }}://{{ forgejo_domain }}/
|
||||
HTTP_ADDR = 0.0.0.0
|
||||
HTTP_PORT = 3000
|
||||
DISABLE_SSH = false
|
||||
SSH_DOMAIN = {{ forgejo_domain }}
|
||||
SSH_PORT = {{ forgejo_ssh_port }}
|
||||
SSH_LISTEN_PORT = 22
|
||||
OFFLINE_MODE = false
|
||||
APP_DATA_PATH = /data/gitea
|
||||
LANDING_PAGE = explore
|
||||
LFS_START_SERVER = {{ forgejo_enable_lfs | lower }}
|
||||
|
||||
[database]
|
||||
DB_TYPE = {{ forgejo_db_type }}
|
||||
; Use host.docker.internal to reach host PostgreSQL from container
|
||||
HOST = host.docker.internal:{{ forgejo_db_port }}
|
||||
NAME = {{ forgejo_db_name }}
|
||||
USER = {{ forgejo_db_user }}
|
||||
PASSWD = {{ forgejo_db_password }}
|
||||
SCHEMA =
|
||||
SSL_MODE = disable
|
||||
CHARSET = utf8mb4
|
||||
LOG_SQL = false
|
||||
MAX_IDLE_CONNS = 30
|
||||
MAX_OPEN_CONNS = 100
|
||||
CONN_MAX_LIFETIME = 3600
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
SECRET_KEY = {{ vault_forgejo_secret_key | default('') }}
|
||||
INTERNAL_TOKEN = {{ vault_forgejo_internal_token | default('') }}
|
||||
PASSWORD_COMPLEXITY = lower,upper,digit,spec
|
||||
MIN_PASSWORD_LENGTH = 10
|
||||
PASSWORD_HASH_ALGO = argon2
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = {{ forgejo_disable_registration | lower }}
|
||||
REQUIRE_SIGNIN_VIEW = {{ forgejo_require_signin_view | lower }}
|
||||
REGISTER_EMAIL_CONFIRM = {{ forgejo_enable_email | lower }}
|
||||
ENABLE_NOTIFY_MAIL = {{ forgejo_enable_email | lower }}
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = true
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ORG_VISIBILITY = private
|
||||
ENABLE_CAPTCHA = true
|
||||
ENABLE_TIMETRACKING = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
ENABLE_USER_HEATMAP = true
|
||||
|
||||
[service.explore]
|
||||
REQUIRE_SIGNIN_VIEW = {{ forgejo_require_signin_view | lower }}
|
||||
DISABLE_USERS_PAGE = false
|
||||
|
||||
{% if forgejo_enable_email %}
|
||||
[mailer]
|
||||
ENABLED = true
|
||||
SMTP_ADDR = {{ forgejo_email_host }}
|
||||
SMTP_PORT = {{ forgejo_email_port }}
|
||||
FROM = {{ forgejo_email_from }}
|
||||
USER = {{ forgejo_email_user }}
|
||||
PASSWD = {{ forgejo_email_password }}
|
||||
SUBJECT_PREFIX = [{{ forgejo_domain }}]
|
||||
MAILER_TYPE = smtp
|
||||
IS_TLS_ENABLED = true
|
||||
{% endif %}
|
||||
|
||||
[session]
|
||||
PROVIDER = file
|
||||
PROVIDER_CONFIG = /data/gitea/sessions
|
||||
COOKIE_SECURE = {{ (forgejo_protocol == 'https') | lower }}
|
||||
COOKIE_NAME = i_like_forgejo
|
||||
COOKIE_DOMAIN = {{ forgejo_domain }}
|
||||
GC_INTERVAL_TIME = 86400
|
||||
SESSION_LIFE_TIME = 86400
|
||||
|
||||
[picture]
|
||||
DISABLE_GRAVATAR = {{ forgejo_disable_gravatar | lower }}
|
||||
ENABLE_FEDERATED_AVATAR = false
|
||||
|
||||
[attachment]
|
||||
ENABLED = true
|
||||
PATH = /data/attachments
|
||||
MAX_SIZE = 100
|
||||
MAX_FILES = 10
|
||||
|
||||
[time]
|
||||
DEFAULT_UI_LOCATION = UTC
|
||||
|
||||
[log]
|
||||
MODE = console, file
|
||||
LEVEL = {{ forgejo_log_level }}
|
||||
ROOT_PATH = /data/gitea/log
|
||||
ENABLE_XORM_LOG = false
|
||||
|
||||
[log.console]
|
||||
LEVEL = {{ forgejo_log_level }}
|
||||
COLORIZE = false
|
||||
|
||||
[log.file]
|
||||
LEVEL = {{ forgejo_log_level }}
|
||||
FILE_NAME = forgejo.log
|
||||
MAX_SIZE_SHIFT = 28
|
||||
DAILY_ROTATE = true
|
||||
MAX_DAYS = 7
|
||||
|
||||
[git]
|
||||
MAX_GIT_DIFF_LINES = 1000
|
||||
MAX_GIT_DIFF_LINE_CHARACTERS = 5000
|
||||
MAX_GIT_DIFF_FILES = 100
|
||||
GC_ARGS =
|
||||
|
||||
[git.timeout]
|
||||
DEFAULT = 360
|
||||
MIGRATE = 600
|
||||
MIRROR = 300
|
||||
CLONE = 300
|
||||
PULL = 300
|
||||
GC = 60
|
||||
|
||||
{% if forgejo_enable_2fa %}
|
||||
[two_factor]
|
||||
ENABLED = true
|
||||
{% endif %}
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = false
|
||||
ENABLE_OPENID_SIGNUP = false
|
||||
|
||||
[cron]
|
||||
ENABLED = true
|
||||
RUN_AT_START = false
|
||||
|
||||
[cron.update_mirrors]
|
||||
SCHEDULE = @every 10m
|
||||
|
||||
[cron.repo_health_check]
|
||||
SCHEDULE = @every 24h
|
||||
TIMEOUT = 60s
|
||||
|
||||
[cron.check_repo_stats]
|
||||
SCHEDULE = @every 24h
|
||||
|
||||
[cron.cleanup_hook_task_table]
|
||||
SCHEDULE = @every 24h
|
||||
CLEANUP_TYPE = OlderThan
|
||||
OLDER_THAN = 168h
|
||||
|
||||
[cron.update_migration_poster_id]
|
||||
SCHEDULE = @every 24h
|
||||
|
||||
[cron.sync_external_users]
|
||||
SCHEDULE = @every 24h
|
||||
UPDATE_EXISTING = true
|
||||
|
||||
[api]
|
||||
ENABLE_SWAGGER = false
|
||||
MAX_RESPONSE_ITEMS = 50
|
||||
DEFAULT_PAGING_NUM = 30
|
||||
DEFAULT_GIT_TREES_PER_PAGE = 1000
|
||||
DEFAULT_MAX_BLOB_SIZE = 10485760
|
||||
|
||||
[oauth2]
|
||||
ENABLED = true
|
||||
JWT_SECRET = {{ vault_forgejo_jwt_secret | default('') }}
|
||||
|
||||
[webhook]
|
||||
QUEUE_LENGTH = 1000
|
||||
DELIVER_TIMEOUT = 15
|
||||
SKIP_TLS_VERIFY = false
|
||||
PAGING_NUM = 10
|
||||
|
||||
[metrics]
|
||||
ENABLED = {{ forgejo_enable_prometheus | lower }}
|
||||
TOKEN = {{ vault_forgejo_metrics_token | default('') }}
|
||||
|
||||
[task]
|
||||
QUEUE_TYPE = channel
|
||||
QUEUE_LENGTH = 10000
|
||||
QUEUE_CONN_STR =
|
||||
QUEUE_BATCH_NUMBER = 20
|
||||
|
||||
[indexer]
|
||||
ISSUE_INDEXER_TYPE = db
|
||||
REPO_INDEXER_ENABLED = true
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# Docker Compose override for Prometheus monitoring
|
||||
# Generated by Ansible
|
||||
# This file extends the main docker-compose.yml
|
||||
|
||||
services:
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- ./monitoring/data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.path=/prometheus'
|
||||
- '--storage.tsdb.retention.time=15d'
|
||||
- '--web.enable-lifecycle'
|
||||
ports:
|
||||
# Only bind to localhost for security - not exposed externally
|
||||
- "127.0.0.1:{{ prometheus_port | default(9090) }}:9090"
|
||||
networks:
|
||||
- forgejo-network
|
||||
|
||||
networks:
|
||||
forgejo-network:
|
||||
external: true
|
||||
name: {{ forgejo_base_path | basename }}_default
|
||||
76
ansible/roles/forgejo/templates/docker-compose.yml.j2
Normal file
76
ansible/roles/forgejo/templates/docker-compose.yml.j2
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
services:
|
||||
forgejo:
|
||||
image: {{ forgejo_docker_image }}:{{ forgejo_version }}
|
||||
container_name: forgejo
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- USER_UID={{ forgejo_uid }}
|
||||
- USER_GID={{ forgejo_gid }}
|
||||
- FORGEJO__database__DB_TYPE={{ forgejo_db_type }}
|
||||
- FORGEJO__database__HOST=host.docker.internal:{{ forgejo_db_port }}
|
||||
- FORGEJO__database__NAME={{ forgejo_db_name }}
|
||||
- FORGEJO__database__USER={{ forgejo_db_user }}
|
||||
- FORGEJO__database__PASSWD={{ forgejo_db_password }}
|
||||
{% if forgejo_use_redis %}
|
||||
- FORGEJO__cache__ENABLED=true
|
||||
- FORGEJO__cache__ADAPTER=redis
|
||||
- FORGEJO__cache__HOST=redis://redis:{{ redis_port }}/0
|
||||
- FORGEJO__session__PROVIDER=redis
|
||||
- FORGEJO__session__PROVIDER_CONFIG=redis://redis:{{ redis_port }}/0
|
||||
{% endif %}
|
||||
extra_hosts:
|
||||
- "host.docker.internal:host-gateway"
|
||||
volumes:
|
||||
- {{ forgejo_data_path }}/git:/data/git
|
||||
- {{ forgejo_data_path }}/attachments:/data/attachments
|
||||
- {{ forgejo_data_path }}/lfs:/data/lfs
|
||||
- {{ forgejo_config_path }}/app.ini:/data/gitea/conf/app.ini
|
||||
- {{ forgejo_custom_path }}:/data/gitea/custom
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
ports:
|
||||
- "127.0.0.1:{{ forgejo_http_port }}:3000"
|
||||
- "{{ forgejo_ssh_port }}:22"
|
||||
networks:
|
||||
- forgejo
|
||||
{% if forgejo_use_redis %}
|
||||
depends_on:
|
||||
- redis
|
||||
{% endif %}
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/api/healthz"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 40s
|
||||
|
||||
{% if forgejo_use_redis %}
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: forgejo-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- {{ forgejo_data_path }}/redis:/data
|
||||
networks:
|
||||
- forgejo
|
||||
command: redis-server --appendonly yes
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "5m"
|
||||
max-file: "3"
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 30s
|
||||
timeout: 3s
|
||||
retries: 3
|
||||
{% endif %}
|
||||
|
||||
networks:
|
||||
forgejo:
|
||||
driver: bridge
|
||||
19
ansible/roles/forgejo/templates/forgejo.service.j2
Normal file
19
ansible/roles/forgejo/templates/forgejo.service.j2
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
[Unit]
|
||||
Description=Forgejo Git Server (Docker Compose)
|
||||
Documentation=https://forgejo.org/docs/latest/
|
||||
After=docker.service
|
||||
Requires=docker.service
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
WorkingDirectory={{ forgejo_base_path }}
|
||||
ExecStart=/usr/bin/docker compose up -d
|
||||
ExecStop=/usr/bin/docker compose down
|
||||
ExecReload=/usr/bin/docker compose restart
|
||||
TimeoutStartSec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
33
ansible/roles/forgejo/templates/forgejo_backup.sh.j2
Normal file
33
ansible/roles/forgejo/templates/forgejo_backup.sh.j2
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#!/bin/bash
|
||||
# Forgejo Backup Script
|
||||
# Generated by Ansible
|
||||
|
||||
set -e
|
||||
|
||||
BACKUP_DIR="{{ forgejo_backup_path }}"
|
||||
TIMESTAMP=$(date +%Y%m%dT%H%M%S)
|
||||
LOG_FILE="/var/log/forgejo-backup.log"
|
||||
|
||||
echo "[$(date)] Starting Forgejo backup..." | tee -a "$LOG_FILE"
|
||||
|
||||
# Create database backup
|
||||
pg_dump -U {{ forgejo_db_user }} {{ forgejo_db_name }} | gzip > "$BACKUP_DIR/database-$TIMESTAMP.sql.gz"
|
||||
echo "[$(date)] Database backed up" | tee -a "$LOG_FILE"
|
||||
|
||||
# Backup repositories
|
||||
tar -czf "$BACKUP_DIR/repositories-$TIMESTAMP.tar.gz" -C {{ forgejo_data_path }} git
|
||||
echo "[$(date)] Repositories backed up" | tee -a "$LOG_FILE"
|
||||
|
||||
# Backup configuration
|
||||
tar -czf "$BACKUP_DIR/config-$TIMESTAMP.tar.gz" {{ forgejo_config_path }} {{ forgejo_base_path }}/docker-compose.yml
|
||||
echo "[$(date)] Configuration backed up" | tee -a "$LOG_FILE"
|
||||
|
||||
# Backup data
|
||||
tar -czf "$BACKUP_DIR/data-$TIMESTAMP.tar.gz" -C {{ forgejo_data_path }} attachments lfs avatars
|
||||
echo "[$(date)] Data backed up" | tee -a "$LOG_FILE"
|
||||
|
||||
# Clean old backups
|
||||
find "$BACKUP_DIR" -type f -name "*.gz" -mtime +{{ forgejo_backup_retention_days }} -delete
|
||||
echo "[$(date)] Old backups cleaned" | tee -a "$LOG_FILE"
|
||||
|
||||
echo "[$(date)] Backup completed successfully" | tee -a "$LOG_FILE"
|
||||
24
ansible/roles/forgejo/templates/postgres_backup.sh.j2
Normal file
24
ansible/roles/forgejo/templates/postgres_backup.sh.j2
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#!/bin/bash
|
||||
# PostgreSQL Backup Script
|
||||
# Generated by Ansible
|
||||
|
||||
set -e
|
||||
|
||||
BACKUP_DIR="{{ forgejo_backup_path }}"
|
||||
TIMESTAMP=$(date +%Y%m%dT%H%M%S)
|
||||
LOG_FILE="/var/log/postgres-backup.log"
|
||||
|
||||
# Ensure backup directory exists
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
echo "[$(date)] Starting PostgreSQL backup..." | tee -a "$LOG_FILE"
|
||||
|
||||
# Create database backup
|
||||
sudo -u postgres pg_dump {{ forgejo_db_name }} | gzip > "$BACKUP_DIR/postgres-$TIMESTAMP.sql.gz"
|
||||
|
||||
echo "[$(date)] PostgreSQL backup completed: postgres-$TIMESTAMP.sql.gz" | tee -a "$LOG_FILE"
|
||||
|
||||
# Clean old PostgreSQL backups (keep last {{ forgejo_backup_retention_days }} days)
|
||||
find "$BACKUP_DIR" -type f -name "postgres-*.sql.gz" -mtime +{{ forgejo_backup_retention_days }} -delete
|
||||
|
||||
echo "[$(date)] Old PostgreSQL backups cleaned" | tee -a "$LOG_FILE"
|
||||
42
ansible/roles/forgejo/templates/prometheus.yml.j2
Normal file
42
ansible/roles/forgejo/templates/prometheus.yml.j2
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Prometheus configuration for Forgejo monitoring
|
||||
# Generated by Ansible
|
||||
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
# Forgejo metrics endpoint
|
||||
- job_name: 'forgejo'
|
||||
scheme: http
|
||||
static_configs:
|
||||
- targets: ['forgejo:3000']
|
||||
metrics_path: /metrics
|
||||
bearer_token: '{{ vault_forgejo_metrics_token | default("") }}'
|
||||
|
||||
# Prometheus self-monitoring
|
||||
- job_name: 'prometheus'
|
||||
static_configs:
|
||||
- targets: ['localhost:9090']
|
||||
|
||||
{% if forgejo_db_type == 'postgres' %}
|
||||
# PostgreSQL metrics (if postgres_exporter is enabled)
|
||||
# Uncomment and configure if you add postgres_exporter
|
||||
# - job_name: 'postgres'
|
||||
# static_configs:
|
||||
# - targets: ['postgres_exporter:9187']
|
||||
{% endif %}
|
||||
|
||||
{% if forgejo_use_redis %}
|
||||
# Redis metrics (if redis_exporter is enabled)
|
||||
# Uncomment and configure if you add redis_exporter
|
||||
# - job_name: 'redis'
|
||||
# static_configs:
|
||||
# - targets: ['redis_exporter:9121']
|
||||
{% endif %}
|
||||
|
||||
# Node metrics (if node_exporter is enabled)
|
||||
# Uncomment and configure if you add node_exporter
|
||||
# - job_name: 'node'
|
||||
# static_configs:
|
||||
# - targets: ['node_exporter:9100']
|
||||
14
ansible/roles/forgejo/templates/ufw-forgejo.j2
Normal file
14
ansible/roles/forgejo/templates/ufw-forgejo.j2
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
[Forgejo]
|
||||
title=Forgejo Git Forge
|
||||
description=Forgejo self-hosted Git service (web interface)
|
||||
ports=80,443/tcp
|
||||
|
||||
[Forgejo-SSH]
|
||||
title=Forgejo Git SSH
|
||||
description=Forgejo Git operations over SSH
|
||||
ports={{ forgejo_ssh_port }}/tcp
|
||||
|
||||
[Forgejo-Full]
|
||||
title=Forgejo Full
|
||||
description=Forgejo web interface and Git SSH
|
||||
ports=80,443,{{ forgejo_ssh_port }}/tcp
|
||||
Loading…
Add table
Add a link
Reference in a new issue