From 28212b9d5d6f65e9c5000e6cc17cf0d758408479 Mon Sep 17 00:00:00 2001 From: viljarb Date: Tue, 31 Mar 2026 13:25:18 +0200 Subject: [PATCH] modified: .gitignore new file: Dockerfile.certbot new file: Dockerfile.nginx new file: Makefile new file: compose.certbot.yml new file: docker-compose.yml new file: entrypoint-certbot.sh new file: entrypoint-nginx.sh new file: nginx-gitea.conf.template new file: nginx.conf.template --- .gitignore | 6 ++++ Dockerfile.certbot | 6 ++++ Dockerfile.nginx | 27 +++++++++++++++ Makefile | 11 ++++++ compose.certbot.yml | 22 ++++++++++++ docker-compose.yml | 73 +++++++++++++++++++++++++++++++++++++++ entrypoint-certbot.sh | 21 +++++++++++ entrypoint-nginx.sh | 41 ++++++++++++++++++++++ nginx-gitea.conf.template | 25 ++++++++++++++ nginx.conf.template | 40 +++++++++++++++++++++ 10 files changed, 272 insertions(+) create mode 100644 Dockerfile.certbot create mode 100644 Dockerfile.nginx create mode 100755 Makefile create mode 100644 compose.certbot.yml create mode 100644 docker-compose.yml create mode 100644 entrypoint-certbot.sh create mode 100644 entrypoint-nginx.sh create mode 100644 nginx-gitea.conf.template create mode 100644 nginx.conf.template diff --git a/.gitignore b/.gitignore index 414dd73..b51e349 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,11 @@ .vscode/* .vscode/**/* +gitea +gitea/* gitea/** +html +html/* html/** +logs +logs/* logs/** diff --git a/Dockerfile.certbot b/Dockerfile.certbot new file mode 100644 index 0000000..c2fb590 --- /dev/null +++ b/Dockerfile.certbot @@ -0,0 +1,6 @@ +FROM certbot/certbot + +COPY entrypoint-certbot.sh /entrypoint-certbot.sh +RUN chmod +x /entrypoint-certbot.sh + +ENTRYPOINT ["/entrypoint-certbot.sh"] diff --git a/Dockerfile.nginx b/Dockerfile.nginx new file mode 100644 index 0000000..d3a85a4 --- /dev/null +++ b/Dockerfile.nginx @@ -0,0 +1,27 @@ +FROM nginx:alpine + +ARG DOMAIN +ARG EMAIL +ARG GITEA_DOMAIN +ENV DOMAIN=${DOMAIN} +ENV EMAIL=${EMAIL} +ENV GITEA_DOMAIN=${GITEA_DOMAIN} + +# Install gettext (for envsubst) and openssl +RUN apk add --no-cache gettext openssl + +# Copy nginx config templates (generated at runtime with envsubst) +COPY nginx.conf.template /etc/nginx/nginx.conf.template +COPY nginx-gitea.conf.template /etc/nginx/nginx-gitea.conf.template + +# Copy HTML content +COPY html /usr/share/nginx/html + +# Copy and set up entrypoint +COPY entrypoint-nginx.sh /entrypoint-nginx.sh +RUN chmod +x /entrypoint-nginx.sh + +EXPOSE 80 443 + +ENTRYPOINT ["/entrypoint-nginx.sh"] +CMD ["nginx", "-g", "daemon off;"] diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..c9a3e7e --- /dev/null +++ b/Makefile @@ -0,0 +1,11 @@ +dev: + docker compose up --build + +down: + docker compose down + +cert: + DOMAIN=viljarb.online GITEA_DOMAIN=gitea.viljarb.online GITEA_ROOT_URL=https://gitea.viljarb.online/ EMAIL=viljarb@tutanota.com docker compose -f compose.certbot.yml --profile certbot run --rm certbot + +prod: + DOMAIN=viljarb.online GITEA_DOMAIN=gitea.viljarb.online GITEA_ROOT_URL=https://gitea.viljarb.online/ EMAIL=viljarb@tutanota.com docker compose up --build diff --git a/compose.certbot.yml b/compose.certbot.yml new file mode 100644 index 0000000..fdde899 --- /dev/null +++ b/compose.certbot.yml @@ -0,0 +1,22 @@ +services: + certbot: + profiles: + - certbot # Only run via: docker compose --profile certbot run --rm certbot + network_mode: host + build: + context: . + dockerfile: Dockerfile.certbot + environment: + - DOMAIN=${DOMAIN} + - EMAIL=${EMAIL} + - GITEA_DOMAIN=${GITEA_DOMAIN} + volumes: + - certs:/etc/letsencrypt + ports: + - "80:80" + restart: "no" + + + +volumes: + certs: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..cde0a52 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,73 @@ + +networks: + default: + external: false + +services: + #certbot: + # profiles: + # - certbot # Only run via: docker compose --profile certbot run --rm certbot + # network_mode: host + # build: + # context: . + # dockerfile: Dockerfile.certbot + # environment: + # - DOMAIN=${DOMAIN} + # - EMAIL=${EMAIL} + # - GITEA_DOMAIN=${GITEA_DOMAIN} + # volumes: + # - certs:/etc/letsencrypt + # ports: + # - "80:80" + # restart: "no" + + nginx: + build: + context: . + dockerfile: Dockerfile.nginx + args: + - DOMAIN=${DOMAIN} + - EMAIL=${EMAIL} + - GITEA_DOMAIN=${GITEA_DOMAIN} + environment: + - DOMAIN=${DOMAIN} + - EMAIL=${EMAIL} + - GITEA_DOMAIN=${GITEA_DOMAIN} + networks: + - default + volumes: + - certs:/etc/letsencrypt + - ./html:/usr/share/nginx/html + - ./logs:/var/log/nginx/visitors + ports: + - "80:80" + - "443:443" + + gitea: + image: docker.io/gitea/gitea + environment: + - USER_UID=1000 + - USER_GID=1000 + - ROOT_URL=${GITEA_ROOT_URL} + - DOMAIN=${GITEA_DOMAIN} + - SSH_DOMAIN=${GITEA_DOMAIN} + - SSH_PORT=2222 + - GITEA__log__ROOT_PATH=/var/log/gitea + - GITEA__log__MODE=file + restart: always + networks: + - default + volumes: + - ./gitea:/data + - ./logs:/var/log/gitea + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + ports: + - "4000:3000" + - "2222:2222" + + + + +volumes: + certs: \ No newline at end of file diff --git a/entrypoint-certbot.sh b/entrypoint-certbot.sh new file mode 100644 index 0000000..ba34eb2 --- /dev/null +++ b/entrypoint-certbot.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env sh +set -e + +if [ -z "$DOMAIN" ] || [ -z "$EMAIL" ]; then + echo "Skipping certificate (development mode)" + exit 0 +fi + +# Build domain list for cert (DOMAIN + optional GITEA_DOMAIN) +DOMAINS="-d $DOMAIN" +if [ -n "$GITEA_DOMAIN" ]; then + DOMAINS="$DOMAINS -d $GITEA_DOMAIN" +fi + +# get/renew cert +certbot certonly --standalone \ + $DOMAINS \ + --email "$EMAIL" \ + --agree-tos \ + --non-interactive \ + --keep-until-expiring diff --git a/entrypoint-nginx.sh b/entrypoint-nginx.sh new file mode 100644 index 0000000..aa669d5 --- /dev/null +++ b/entrypoint-nginx.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env sh +set -e + +if [ -n "$DOMAIN" ] && [ -n "$EMAIL" ]; then + # production: get Let's Encrypt cert + if [ ! -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]; then + certbot certonly --standalone \ + -d "$DOMAIN" \ + --email "$EMAIL" \ + --agree-tos \ + --non-interactive + fi + export SSL_CERTIFICATE="/etc/letsencrypt/live/$DOMAIN/fullchain.pem" + export SSL_CERTIFICATE_KEY="/etc/letsencrypt/live/$DOMAIN/privkey.pem" +else + # development: self-signed cert + echo "Development mode: using self-signed certificate" + mkdir -p /etc/nginx/certs + if [ ! -f /etc/nginx/certs/cert.pem ]; then + openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout /etc/nginx/certs/key.pem \ + -out /etc/nginx/certs/cert.pem \ + -subj "/CN=localhost" + fi + export DOMAIN="localhost" + export SSL_CERTIFICATE="/etc/nginx/certs/cert.pem" + export SSL_CERTIFICATE_KEY="/etc/nginx/certs/key.pem" +fi + +# generate nginx config from template +envsubst '${DOMAIN} ${SSL_CERTIFICATE} ${SSL_CERTIFICATE_KEY}' < /etc/nginx/nginx.conf.template > /etc/nginx/nginx.conf + +# generate gitea config when GITEA_DOMAIN is set +mkdir -p /etc/nginx/conf.d +if [ -n "$GITEA_DOMAIN" ]; then + envsubst '${GITEA_DOMAIN} ${SSL_CERTIFICATE} ${SSL_CERTIFICATE_KEY}' < /etc/nginx/nginx-gitea.conf.template > /etc/nginx/conf.d/gitea.conf +else + echo "# Gitea not configured" > /etc/nginx/conf.d/gitea.conf +fi + +exec nginx -g "daemon off;" diff --git a/nginx-gitea.conf.template b/nginx-gitea.conf.template new file mode 100644 index 0000000..f10ad0c --- /dev/null +++ b/nginx-gitea.conf.template @@ -0,0 +1,25 @@ + server { + listen 80; + server_name ${GITEA_DOMAIN}; + return 301 https://$host$request_uri; + } + + server { + listen 443 ssl; + server_name ${GITEA_DOMAIN}; + ssl_certificate ${SSL_CERTIFICATE}; + ssl_certificate_key ${SSL_CERTIFICATE_KEY}; + ssl_protocols TLSv1.2 TLSv1.3; + + location / { + proxy_pass http://gitea:3000; + 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_set_header X-Forwarded-Host $host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 86400; + } + } diff --git a/nginx.conf.template b/nginx.conf.template new file mode 100644 index 0000000..a4d3474 --- /dev/null +++ b/nginx.conf.template @@ -0,0 +1,40 @@ +worker_processes auto; +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + sendfile on; + keepalive_timeout 65; + + log_format visitor_ip '$remote_addr - $time_iso8601'; + access_log /var/log/nginx/visitors/visitors.log visitor_ip; + + server { + listen 80; + server_name ${DOMAIN}; + return 301 https://$host$request_uri; + } + + server { + listen 443 ssl; + server_name ${DOMAIN}; + root /usr/share/nginx/html; + index index.html; + + ssl_certificate ${SSL_CERTIFICATE}; + ssl_certificate_key ${SSL_CERTIFICATE_KEY}; + ssl_protocols TLSv1.2 TLSv1.3; + + location / { + try_files $uri $uri/ /index.html; + } + } + + include /etc/nginx/conf.d/gitea.conf; +}