Amazon.co.uk Widgets

Log in

X
Running Gitea with Let’s Encrypt on macOS via Homebrew

Gitea is a lightweight, self-hosted Git service that’s perfect for personal projects or small teams. Setting it up with HTTPS using a Let’s Encrypt certificate on a local macOS machine can be tricky, especially with Homebrew installations. This guide walks you through a working setup, including running Gitea in the background and handling ACME challenges.

TL:DR – By using a custom LaunchAgent, you can run Gitea in the background with automatic Let’s Encrypt HTTPS, reliable background execution independent of Homebrew’s plist management, optional exposure on standard port 443 via pf redirects and automatic renewal of certificates with minimal fuss. This setup provides a secure, self-hosted Git service suitable for local networks or small teams.

 

git.yourdomain.co.uk A painless, self-hosted Git service
git.yourdomain.co.uk A painless, self-hosted Git service

1. Install Gitea via Homebrew

If you haven’t already installed Gitea:

brew install gitea

Create a working directory and a custom configuration folder:

mkdir -p /opt/homebrew/var/gitea
mkdir -p /opt/homebrew/var/gitea/custom/conf

2. Configure Gitea

Set up your app.ini in:

/opt/homebrew/var/gitea/custom/conf/app.ini

A minimal HTTPS configuration looks like:


[server]
PROTOCOL = https
DOMAIN = git.yourserver.co.uk
HTTP_PORT = 3000
ROOT_URL = https://git.yourserver.co.uk:3000/
ENABLE_ACME = true
ACME_FOLDER = /opt/homebrew/var/gitea/custom/conf/https
  • ENABLE_ACME = true allows Gitea to automatically obtain a Let’s Encrypt certificate.
  • Let’s Encrypt uses HTTP-01 or TLS-ALPN-01 challenges, which require your machine to be reachable externally on port 80 (and 443 for ALPN).

3. Set up environment variables

Gitea needs the GITEA_WORK_DIR and GITEA_CUSTOM environment variables set for background execution. Instead of relying on Homebrew’s plist, which is automatically created, and doesn't specify this correctly (for me), you'll need to create a custom LaunchAgent:

vi ~/Library/LaunchAgents/com.yourdomain.gitea.plist

Example plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.yourdomain.gitea</string>
    <key>ProgramArguments</key>
    <array>
        <string>/opt/homebrew/opt/gitea/bin/gitea</string>
        <string>web</string>
    </array>
    <key>EnvironmentVariables</key>
    <dict>
        <key>GITEA_WORK_DIR</key>
        <string>/opt/homebrew/var/gitea</string>
        <key>GITEA_CUSTOM</key>
        <string>/opt/homebrew/var/gitea/custom</string>
    </dict>
    <key>RunAtLoad</key>
    <true/>
    <key>KeepAlive</key>
    <true/>
    <key>StandardOutPath</key>
    <string>/opt/homebrew/var/log/gitea.log</string>
    <key>StandardErrorPath</key>
    <string>/opt/homebrew/var/log/gitea.log</string>
</dict>
</plist>
  • This replaces brew services, and avoids Homebrew deleting or overwriting plists with ones which won't work should you inadvertently start gitea using Homebrew to manage the service.
  • Logs are redirected to /opt/homebrew/var/log/gitea.log for easy monitoring.

4. Load the custom LaunchAgent

launchctl unload ~/Library/LaunchAgents/com.yourdomain.gitea.plist 2>/dev/null
launchctl load ~/Library/LaunchAgents/com.yourdomain.gitea.plist

Check that Gitea is running:

lsof -iTCP:3000 -sTCP:LISTEN
tail -f /opt/homebrew/var/log/gitea.log

Ensure port 80 is open on your router or firewall while the ACME challenge runs.

5. Optional: redirect HTTPS to standard port 443

Gitea listens internally on port 3000, but you can make it accessible on port 443 using macOS’s packet filter (pf):

  1. Edit /etc/pf.conf:
    rdr pass on lo0 inet proto tcp from any to any port 443 -> 127.0.0.1 port 3000
  2. Enable and reload:
    sudo pfctl -f /etc/pf.conf
    sudo pfctl -e
  3. Test:
    curl -vk https://git.yourserver.co.uk/

6. Key troubleshooting points

  • ACME/Let’s Encrypt failures: Usually caused by port 80 not being reachable externally. Ensure your router/firewall forwards port 80 to your Mac.
  • LaunchAgent errors (Input/output error): Often due to incorrect environment variables or inaccessible working directories. Validate plist syntax with:
    plutil -lint ~/Library/LaunchAgents/com.yourdomain.gitea.plist
      
    </li
  • Foreground vs background: Always test Gitea in the foreground first to verify certificates are issued successfully.
  • Watch our for gitea processes stopping your loaunch agent from running. Use ps -ax |grep giteato find the process id snd kill -9 processid to get rid of them.

Summary

By using a custom LaunchAgent, you can run Gitea in the background with:

  • Automatic Let’s Encrypt HTTPS
  • Reliable background execution independent of Homebrew’s plist management
  • Optional exposure on standard port 443 via pf redirects
  • Automatic renewal of certificates with minimal fuss

This setup provides a secure, self-hosted Git service suitable for local networks or small teams. See more about what I did with it to make my release management process more robust by Enabling Gitea actions with act_runner on macOS via Homebrew and moving From Local Builds to Production DevOps: Automating Joomla Extension Release Management.