Project

General

Profile

Support #737

Updated by Daniel Curtis over 6 years ago

{{>toc}} 

 This is a guide on using nginx to create a reverse proxy package cache for FreeBSD pkgng, ports, installer packages. The intent is to allow development of commonly used applications during times that I am not connected to the internet. 

 h2. Prepare the Environment 

 * Make sure the system is up to date: 
 <pre> 
 pkg update && pkg upgrade 
 </pre> 

 h2. Install Nginx 

 * Install nginx: 
 <pre> 
 pkg install nginx 
 </pre> 

 * Enable nginx at boot: 
 <pre> 
 sysrc nginx_enable=YES 
 </pre> 

 * Create a configuration directory to make managing individual server blocks easier 
 <pre> 
 mkdir /usr/local/etc/nginx/conf.d 
 </pre> 

 * Edit the main nginx config file: 
 <pre> 
 vi /usr/local/etc/nginx/nginx.conf 
 </pre> 
 #* And strip down the config file and add the include statement at the end to make it easier to handle various server blocks: 
 <pre> 
 worker_processes    1; 
 error_log    /var/log/nginx-error.log; 

 events { 
     worker_connections    1024; 
 } 

 http { 
     include         mime.types; 
     default_type    application/octet-stream; 
     sendfile          on; 
     keepalive_timeout    65; 

     # nginx may need to resolve domain names at run time 
     resolver 208.67.222.222 208.67.220.220; 

     # Load config files from the /etc/nginx/conf.d directory 
     include /usr/local/etc/nginx/conf.d/*.conf; 
 } 
 </pre> 

 h2. Caching pkgng 

 h3. Pkgng Nginx Cache Config 

 * Create the directory for the cache and adjust the permissions so nginx can write files to it: 
 <pre> 
 mkdir /var/cache/pkgmirror 
 chown www:www /var/cache/pkgmirror 
 </pre> 

 * Configure nginx as our dynamic cache: 
 <pre> 
 vi /etc/nginx/conf.d/pkgmirror.example.com.conf 
 </pre> 
 #* And add the following: 
 <pre> 
 server { 
     listen        80; 
     server_name pkgmirror.example.com; 
     root          /var/cache/pkgmirror; 
     autoindex     on; 

     # Requests for actual packages should be served directly from cache if available. 
     #     If not available, retrieve and save the package from an upstream mirror. 
     location / { 
         try_files $uri @pkg_mirror; 
     } 

     # Retrieve package from upstream mirrors and cache for future requests 
     location @pkg_mirror { 
         proxy_store on; 
         proxy_redirect off; 
         proxy_cache_revalidate on; 
         proxy_cache_min_uses 3; 
         proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; 
         proxy_store_access user:rw group:rw all:r; 
         proxy_next_upstream error timeout http_404; 
         proxy_pass http://pkg-mirrors$request_uri; 
     } 
 } 

 # Upstream FreeBSD Mirrors 
 upstream pkg-mirrors { 
     server localhost:8007; 
     server localhost:8008 backup; 
     server localhost:8009 backup; 
 } 

 # FreeBSD Global Mirror Proxy Configuration 
 server { 
     listen        8007; 
     server_name localhost; 

     location / { 
         proxy_pass         http://pkg.FreeBSD.org$request_uri; 
         proxy_set_header Host pkg.FreeBSD.org; 
     } 
 } 

 # FreeBSD US West Mirror Proxy Configuration 
 server { 
     listen        8008; 
     server_name localhost; 

     location / { 
         proxy_pass         http://pkg.us-west.FreeBSD.org$request_uri; 
         proxy_set_header Host pkg.us-west.FreeBSD.org; 
     } 
 } 

 # FreeBSD US East Mirror Proxy Configuration 
 server { 
     listen        8009; 
     server_name localhost; 

     location / { 
         proxy_pass         http://pkg.us-east.FreeBSD.org$request_uri; 
         proxy_set_header Host pkg.us-east.FreeBSD.org; 
     } 
 } 
 </pre> 

 * Restart nginx: 
 <pre> 
 service restart nginx 
 </pre> 

 h3. Using a Private Update System Repo 

 * Edit the pkg repo config file: 
 <pre> 
 mkdir -p /usr/local/etc/pkg/repos 
 vi /usr/local/etc/pkg/repos/FreeBSD.conf 
 </pre> 
 * Add the following line to use the this new proxy cache with quarterly updates 
 <pre> 
 FreeBSD: { 
   url: "pkg+http://pkgmirror.example.com/${ABI}/quarterly", "pkg+http://pkgmirror.example.com/${ABI}/latest", 
   mirror_type: "srv", 
   enabled: yes 
 } 
 </pre> 

 h3. Cache Cleaning 

 * The following command will clean the package cache: 
 <pre> 
 setenv PKG_CACHEDIR /var/cache/pkgmirror 
 pkg clean 
 </pre> 

 h2. Caching the Ports Tree 

 h3. Pkgng Nginx Cache Config 

 * Create the directory for the cache and adjust the permissions so nginx can write files to it: 
 <pre> 
 mkdir /var/cache/portsmirror 
 chown www:www /var/cache/portsmirror 
 </pre> 

 * Configure nginx as our dynamic cache: 
 <pre> 
 vi /etc/nginx/conf.d/portsmirror.example.com.conf 
 </pre> 
 #* And add the following: 
 <pre> 
 # nginx may need to resolve domain names at run time 
 server { 
     listen        80; 
     server_name portsmirror.example.com; 
     root          /var/cache/portsmirror; 
     autoindex     on; 

     # Requests for actual packages should be served directly from cache if available. 
     #     If not available, retrieve and save the package from an upstream mirror. 
     location / { 
         try_files $uri @ports_mirror; 
     } 

     # Retrieve package from upstream mirrors and cache for future requests 
     location @ports_mirror { 
         proxy_store      on; 
         proxy_redirect off; 
         proxy_cache_revalidate on; 
         proxy_cache_min_uses 3; 
         proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; 
         proxy_store_access    user:rw group:rw all:r; 
         proxy_next_upstream error timeout http_404; 
         proxy_pass            http://ports-mirrors$request_uri; 
     } 
 } 

 # Upstream FreeBSD Mirrors 
 upstream ports-mirrors { 
     server localhost:8010; 
     server localhost:8011 backup; 
     server localhost:8012 backup; 
 } 

 # FreeBSD Global Mirror Proxy Configuration 
 server { 
     listen        8010; 
     server_name localhost; 

     location / { 
         proxy_pass         http://your-org.portsnap.freebsd.org$request_uri; 
         proxy_set_header Host your-org.portsnap.freebsd.org; 
     } 
 } 

 # FreeBSD US West Mirror Proxy Configuration 
 server { 
     listen        8011; 
     server_name localhost; 

     location / { 
         proxy_pass         http://sourcefire.portsnap.freebsd.org$request_uri; 
         proxy_set_header Host sourcefire.portsnap.freebsd.org; 
     } 
 } 

 # FreeBSD US East Mirror Proxy Configuration 
 server { 
     listen        8012; 
     server_name localhost; 

     location / { 
         proxy_pass         http://isc.portsnap.freebsd.org$request_uri; 
         proxy_set_header Host isc.portsnap.freebsd.org; 
     } 
 } 
 </pre> 

 * Restart nginx: 
 <pre> 
 service restart nginx 
 </pre> 

 h3. Download Ports Tree 

 * Edit the portsnap config file: 
 <pre> 
 vi /etc/portsnap 
 </pre> 
 #* And change the SERVERNAME variable to the local proxy: 
 <pre> 
 SERVERNAME=portsmirror.example.com 
 </pre> 

 * Set the http_proxy environment variable: 
 <pre> 
 setenv http_proxy http://portsmirror.example.com 
 </pre> 

 * Then fetch the latest ports tree: 
 <pre> 
 portsnap fetch extract 
 </pre> 

 h3. FreeBSD Install Cache Config 

 * Create the directory for the cache and adjust the permissions so nginx can write files to it: 
 <pre> 
 mkdir /var/cache/freebsdmirror 
 chown www:www /var/cache/freebsdmirror 
 </pre> 

 * Configure nginx as our dynamic cache: 
 <pre> 
 vi /etc/nginx/conf.d/freebsdmirror.example.com.conf 
 </pre> 
 #* And add the following: 
 <pre> 
 server { 
     listen        80; 
     server_name freebsdmirror.example.com; 
     root          /var/cache/freebsdmirror; 
     autoindex     on; 

     # Requests for actual packages should be served directly from cache if available. 
     #     If not available, retrieve and save the package from an upstream mirror. 
     location ~ \.txz$ { 
         try_files $uri @freebsd_mirror; 
     } 

     # Retrieve package from upstream mirrors and cache for future requests 
     location @freebsd_mirror { 
         proxy_store      on; 
         proxy_redirect off; 
         proxy_cache_revalidate on; 
         proxy_cache_min_uses 3; 
         proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; 
         proxy_store_access    user:rw group:rw all:r; 
         proxy_next_upstream error timeout http_404; 
         proxy_pass            http://freebsd-mirrors$request_uri; 
     } 
 } 

 # Upstream FreeBSD Mirrors 
 upstream freebsd-mirrors { 
     server localhost:8013; 
     server localhost:8014 backup; 
     server localhost:8015 backup; 
 } 

 # FreeBSD Global Mirror Proxy Configuration 
 server { 
     listen        8013; 
     server_name localhost; 

     location / { 
         proxy_pass         http://ftp.FreeBSD.org$request_uri; 
         proxy_set_header Host ftp.FreeBSD.org; 
     } 
 } 

 # FreeBSD Mirror Proxy 2 Configuration 
 server { 
     listen        8014; 
     server_name localhost; 

     location / { 
         proxy_pass         http://ftp2.FreeBSD.org$request_uri; 
         proxy_set_header Host ftp2.FreeBSD.org; 
     } 
 } 

 # FreeBSD Mirror Proxy 3 Configuration 
 server { 
     listen        8015; 
     server_name localhost; 

     location / { 
         proxy_pass         http://ftp3.FreeBSD.org$request_uri; 
         proxy_set_header Host ftp3.FreeBSD.org; 
     } 
 } 
 </pre> 

 * Restart nginx: 
 <pre> 
 service restart nginx 
 </pre> 

 * Now during an installation of FreeBSD, during the mirror selection phase select *Other* and use the new installer URL: 
 <pre> 
 http://freebsdmirror.example.com/pub/FreeBSD/releases/amd64/amd64/10.2-RELEASE 
 </pre> 

 h2. -Pkg Metadata Backup- 

 *NOTE*: The pkg metadata rotation method is a much more robust solution 

 * Install rename: 
 <pre> 
 pkg install rename 
 </pre> 

 * Create the pkg metadata backup script: 
 <pre> 
 vi /usr/local/bin/backup-pkg-meta.sh 
 </pre> 
 #* And add the following: 
 <pre> 
 #!/bin/sh 
 cd /var/cache/pkgmirror 

 find . -name "meta.txz" -exec renamex -s/\.txz/\.txz\.bak/g {} \; 
 find . -name "packagesite.txz" -exec renamex -s/\.txz/\.txz\.bak/g {} \; 
 </pre> 
 #* Make the script executable: 
 <pre> 
 chmod +x /usr/local/bin/backup-pkg-meta.sh 
 </pre> 

 * Since the nginx proxy cache config is set to cache the pkg metadata files, they need to be moved so the newer metadata files can be downloaded and cached. Run the script frequently or cron job to run the script: 
 <pre> 
 backup-pkg-meta.sh 
 </pre> 

 h2. Pkg Metadata Rotation 

 * Create a pkg metadata rotation script: 
 <pre> 
 vi /usr/local/bin/rotate-pkgmirror-meta.sh 
 </pre> 
 #* And add the following: 
 <pre> 
 #!/bin/sh 
 # Rotate the metadata archives for the pkg mirror 

 IP_HOST=8.8.8.8 

 META_PACKAGE=meta.txz 
 META_BACKUP="${META_PACKAGE}.bak" 
 META_TMP="${META_PACKAGE}.tmp" 
 PACKAGESITE_PACKAGE=packagesite.txz 
 PACKAGESITE_BACKUP="${PACKAGESITE_PACKAGE}.bak" 

 LOCAL_PATH=/var/cache/pkgmirror/FreeBSD:11:amd64/quarterly/ LOCAL_PATH=/var/cache/pkgmirror/FreeBSD:11:amd64/latest/ 
 LOCAL_META_PACKAGE_PATH="${LOCAL_PATH}${META_PACKAGE}" 
 LOCAL_META_BACKUP_PATH="${LOCAL_PATH}${META_BACKUP}" 
 LOCAL_META_TMP_PATH="${LOCAL_PATH}${META_TMP}" 
 LOCAL_PACKAGESITE_PACKAGE_PATH="${LOCAL_PATH}${PACKAGESITE_PACKAGE}" 
 LOCAL_PACKAGESITE_BACKUP_PATH="${LOCAL_PATH}${PACKAGESITE_BACKUP}" 

 REMOTE_PATH=http://pkg.freebsd.org/FreeBSD:11:amd64/quarterly/ 
 REMOTE_META_PATH="${REMOTE_PATH}${META_PACKAGE}" 
 REMOTE_PACKAGESITE_PATH="${REMOTE_PATH}${PACKAGESITE_PACKAGE}" 

 if ping -q -c1 -W1 ${IP_HOST} >/dev/null ; then 
   echo "IPv4 is up. Fetching current meta.txz." 

   fetch -qo ${LOCAL_META_TMP_PATH} ${REMOTE_META_PATH} 
 
   if `diff ${LOCAL_META_PACKAGE_PATH} ${LOCAL_META_TMP_PATH} >/dev/null` ; then 
     echo "meta.txz is current. Cleaning up and not rotating." 
     rm ${LOCAL_META_TMP_PATH} 
   else  
     echo "meta.txz is different. Updating and rotating meta.txz/packagesite.txz." 
  
     mv ${LOCAL_META_PACKAGE_PATH} ${LOCAL_META_BACKUP_PATH}  
     mv ${LOCAL_PACKAGESITE_PACKAGE_PATH} ${LOCAL_PACKAGESITE_BACKUP_PATH}  
     mv ${LOCAL_META_TMP_PATH} ${LOCAL_META_PACKAGE_PATH} 

     fetch -o ${LOCAL_PACKAGESITE_PACKAGE_PATH} ${REMOTE_PACKAGESITE_PATH}  
   fi 
 else 
   echo "IPv4 is down. Not rotating." 
 fi 
 </pre> 

 * Make the script executable: 
 <pre> 
 chmod +x /usr/local/bin/rotate-pkgmirror-meta.sh 
 </pre> 

 * Edit the crontab: 
 <pre> 
 crontab -e 
 </pre> 
 #* And add the following to run the script every half hour: 
 <pre> 
 */30 * * * * /usr/local/bin/rotate-pkgmirror-meta.sh >/tmp/rotate-pkgmirror.log 
 </pre>

Back