¶Updates
EmacsConf 2023 is this weekend! (Dec 2 and 3)
Check out the talks here: https://emacsconf.org/2023/talks/
Hoot 0.2.0 has been released!
Many important new features! FFI, record types, more library functions https://spritely.institute/news/guile-hoot-v020-released.html
Check out this awesome use case - React-style UI with s-expressions :) https://spritely.institute/news/building-interactive-web-pages-with-guile-hoot.html
The Matrix bridge isn’t coming back…
https://matrix.org/blog/2023/11/28/shutting-down-bridge-to-libera-chat/
¶Hosting a Git Forge on the Web with Guix
Let’s pick up where we left off on the last stream and get Forgejo running in a Guix container!
Here’s what we’ll try to do:
- Finish getting the container working correctly
- Test out the new Forgejo instance by creating a repo and pushing to it
- Try setting up Laminar for CI
Reference:
¶Previous Forgejo Package and Container Config
(use-modules (gnu) (guix gexp) (guix packages) (guix download) (guix build utils) (guix build-system gnu) (guix build-system copy) (nonguix build-system binary) ((guix licenses) #:prefix license:)) (use-package-modules version-control gcc bash certs admin linux) (use-service-modules certbot shepherd configuration networking ssh web) (define forgejo (let ((version "1.20.5-0")) (package (name "forgejo") (version version) (source (origin (method url-fetch) (uri (string-append "https://codeberg.org/forgejo/forgejo/releases/download/v" version "/forgejo-" version "-linux-amd64")) (file-name "forgejo") (sha256 (base32 "0jj13qwq67acbqsina3gqi5fr2lsm80jxjmm26i1ixxhf0r0w641")))) (build-system binary-build-system) (arguments `(#:phases (modify-phases %standard-phases (add-after 'unpack 'chmod-to-allow-patchelf (lambda _ (chmod "forgejo" #o755)))) #:install-plan `(("forgejo" "bin/")))) (propagated-inputs (list git git-lfs bash)) (home-page "https://forgejo.org") (synopsis "A self-hosted lightweight software forge.") (description "Forgejo is a self-hosted lightweight software forge.") (license license:expat)))) (define-configuration/no-serialization forgejo-configuration (forgejo (file-like forgejo) "The forgejo package.") (domain (string "foo") "The domain name of the server.") (user (string "git") "The name of the user under which Forgejo will be executed.") (group (string "git") "The name of the group under which Forgejo will be executed.")) (define (forgejo-configuration->file config) (mixed-text-file "forgejo.ini" " APP_NAME = Crafter Tools RUN_USER = " (forgejo-configuration-user config) " WORK_PATH = /srv/forgejo RUN_MODE = prod [git] HOME_PATH = " (forgejo-configuration-user config) " [database] DB_TYPE = sqlite3 HOST = 127.0.0.1:3306 NAME = forgejo USER = forgejo PASSWD = SCHEMA = SSL_MODE = disable PATH = /srv/forgejo/data/forgejo.db LOG_SQL = false [repository] ROOT = /srv/forgejo/data/forgejo-repositories [server] SSH_DOMAIN = " (forgejo-configuration-domain config) " DOMAIN = localhost HTTP_PORT = 3000 ROOT_URL = https://" (forgejo-configuration-domain config) ":3000/ APP_DATA_PATH = /srv/forgejo/data DISABLE_SSH = false SSH_PORT = 22 LFS_START_SERVER = true LFS_JWT_SECRET = 1_yZPWVD-sFZmGSvMjt9_eMqjiHm1V5_oWEhmw8i3IM OFFLINE_MODE = false [lfs] PATH = /srv/forgejo/data/lfs [mailer] ENABLED = false [service] REGISTER_EMAIL_CONFIRM = false ENABLE_NOTIFY_MAIL = false DISABLE_REGISTRATION = false ALLOW_ONLY_EXTERNAL_REGISTRATION = false ENABLE_CAPTCHA = false REQUIRE_SIGNIN_VIEW = false DEFAULT_KEEP_EMAIL_PRIVATE = true DEFAULT_ALLOW_CREATE_ORGANIZATION = true DEFAULT_ENABLE_TIMETRACKING = true NO_REPLY_ADDRESS = noreply.localhost [openid] ENABLE_OPENID_SIGNIN = true ENABLE_OPENID_SIGNUP = true [cron.update_checker] ENABLED = false [session] PROVIDER = file [log] MODE = console LEVEL = info ROOT_PATH = /srv/forgejo/log [repository.pull-request] DEFAULT_MERGE_STYLE = merge [repository.signing] DEFAULT_TRUST_MODEL = committer [security] INSTALL_LOCK = true INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MDAyNDAwMTh9.3MFnsZWtz-Qu1I5mC1TWIXyhdGN6pDJsYE1iSugEhdM PASSWORD_HASH_ALGO = pbkdf2_hi [oauth2] JWT_SECRET = DrvU6DPu8tIRVmeDfpmwLakm5m_IY13Cv00uMWaBo34 ")) ;; TODO: Generate the tokens using `forgejo generate secret INTERNAL_TOKEN` etc by using a more elaborate gexp: ;; #~(begin ;; (let* ((forgejo (forgejo-configuration-forgejo config)) ;; (forgejo-bin (file-append forgejo "/bin/forgejo")) ;; (INTERNAL_TOKEN (system* #$forgejo-bin "generate" "secret" "INTERNAL_TOKEN"))) ;; ;; Write out the entire configuration file, inserting the generated tokens ;; )) (define (forgejo-shepherd-service config) "Return a <shepherd-service> for Forgejo with config." (let* ((forgejo (forgejo-configuration-forgejo config)) (forgejo-bin (file-append forgejo "/bin/forgejo")) (forgejo-cfg (forgejo-configuration->file config))) (list (shepherd-service (documentation "Run the Forgejo Git forge") (requirement '(networking user-processes)) (provision '(forgejo)) (start #~(make-forkexec-constructor (list #$forgejo-bin "--config" #$forgejo-cfg) #:user #$(forgejo-configuration-user config) #:group #$(forgejo-configuration-group config) #:environment-variables (append (default-environment-variables) (list (string-append "HOME=/home/" #$(forgejo-configuration-user config)))))) (stop #~(make-kill-destructor)))))) (define %forgejo-accounts (list (user-group (name "git") (system? #t)) (user-account (name "git") (group "git") (system? #t) (comment "Forgejo User") (home-directory "/home/git") ;; (shell (file-append shadow "/sbin/nologin")) ))) (define %forgejo-activation #~(begin (use-modules (guix build utils)) (mkdir-p "/srv/forgejo") (let ((user (getpwnam "git"))) (chown "/srv/forgejo" (passwd:uid user) (passwd:gid user))))) (define forgejo-service-type (service-type (name 'forgejo) (extensions (list (service-extension shepherd-root-service-type forgejo-shepherd-service) (service-extension account-service-type (const %forgejo-accounts)) (service-extension activation-service-type (const %forgejo-activation)))) (default-value (forgejo-configuration)) (description "Run Forgejo."))) ;; (define (cert-path host file) ;; (format #f "/etc/letsencrypt/live/~a/~a.pem" host (symbol->string file))) (operating-system (host-name "crafter-forge") (timezone "Etc/UTC") (locale "en_US.utf8") (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets '("unused")))) (firmware '()) (file-systems %base-file-systems) ;; minimal packages for remote debugging (packages (list coreutils bash iproute procps forgejo)) ;; basic services (services (list (service dhcp-client-service-type) ;; (service certbot-service-type ;; (certbot-configuration ;; (email "[email protected]") ;; (webroot "/srv/http/certbot") ;; (certificates ;; (list ;; (certificate-configuration ;; (domains '("crafter.tools")) ;; (deploy-hook ;; (program-file ;; "nginx-deploy-hook" ;; #~(let ((pid (call-with-input-file "/var/run/nginx/pid" read))) ;; (kill pid sighup))))))))) ;; (service nginx-service-type ;; (nginx-configuration ;; (server-blocks ;; (list (nginx-server-configuration ;; (listen '("443 ssl http2" ;; "[::]:443 ssl http2" ;; "8448 ssl http2" ;; "[::]:8448 ssl http2")) ;; (server-name '("crafter.tools")) ;; (root "/srv/http/crafter.tools") ;; (ssl-certificate (cert-path "crafter.tools" 'fullchain)) ;; (ssl-certificate-key (cert-path "crafter.tools" 'privkey)) ;; (raw-content '("client_max_body_size 20m;")) ;; (locations ;; (list (nginx-location-configuration ;; (uri "/_matrix/") ;; ;; note: this must be the same as the conduit port! ;; (body '("proxy_pass http://127.0.0.1:6167$request_uri;" ;; "proxy_set_header host $http_host;" ;; "proxy_buffering off;" ;; "proxy_read_timeout 5m;")))))))))) (service syslog-service-type (syslog-configuration)) (service forgejo-service-type (forgejo-configuration (domain "crafter.tools"))))))
¶run.sh
#!/bin/sh cd /root mkdir -p /var/data/letsencrypt $(guix time-machine -C channels.scm -- system container --network --share=/var/data=/srv --share=/var/data/letsencrypt=/etc/letsencrypt config.scm)
¶forge.service
[Unit] Description=Forge Service Wants=guix-daemon.service [Service] ExecStart=/bin/sh -c /root/run.sh [Install] WantedBy=multi-user.target
¶Setting up the Host VM
# Unblock port 80 echo net.ipv4.ip_unprivileged_port_start=80 >> /etc/sysctl.conf sysctl --system # Configure the firewall # TODO: How to persist across reboots? ufw enable ufw allow http ufw allow https # Set up the service mkdir -p /var/data/certs ln -sf /root/cons.service /etc/systemd/system/cons.service # Run the service for the first time to generate certificates /root/run.sh guix container exec 6623 /var/lib/certbot/renew-certificates # Run the service for real systemctl enable cons.service systemctl start cons.service